Skip to content

Commit 7b83ecb

Browse files
Merge pull request #695 from OpenEVSE/jeremypoulter/issue29
Certificate management
2 parents b594e58 + db87203 commit 7b83ecb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+14145
-12662
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
- wt32-eth01
5252
- esp32-c3-devkitc-02
5353
- elecrow_esp32_hmi
54-
- elecrow_esp32_hmi_dev
54+
# - elecrow_esp32_hmi_dev
5555
- openevse_wifi_tft_v1
5656
- openevse_wifi_tft_v1_dev
5757

.github/workflows/build_gui.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ jobs:
7272
rm -f src/web_static/*.h
7373
7474
- name: Run PlatformIO
75-
run:
75+
run: |
7676
pio run
77+
git status
7778
7879
- name: Push any changed files
7980
uses: stefanzweifel/git-auto-commit-action@v5

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,17 @@ lib/ESPAL
8888
lib/MicroDebug
8989
lib/StreamSpy
9090
lib/MicroTasks
91+
lib/jeremypoulter/ArduinoMongoose
92+
lib/jeremypoulter/ConfigJson
93+
lib/jeremypoulter/OpenEVSE
94+
lib/jeremypoulter/ESPAL
95+
lib/jeremypoulter/Micro Debug
96+
lib/jeremypoulter/StreamSpy
97+
lib/jeremypoulter/MicroTasks
9198

9299
*.bin
93100
divert_sim/epoxyfsdata
94101
divert_sim/epoxyeepromdata
102+
103+
*.pem
95104
*.pem

api.yml

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ paths:
170170
$ref: ./models/Config.yaml
171171
examples: {}
172172
post:
173+
description: |
174+
Update the EVSE configuration
173175
operationId: updateConfig
174176
responses:
175177
'200':
@@ -233,6 +235,8 @@ paths:
233235
summary: Get the Manual Override status
234236
description: Returns the current state of the manual override.
235237
post:
238+
description: |
239+
Set the manual override
236240
requestBody:
237241
content:
238242
application/json:
@@ -279,6 +283,9 @@ paths:
279283
summary: Clear the manual override
280284
/claims:
281285
get:
286+
description: |
287+
List all claims made by EVSE clients.
288+
The response will be an array of EVSE claims.
282289
responses:
283290
'200':
284291
description: OK
@@ -294,6 +301,9 @@ paths:
294301
summary: List EVSE claims
295302
'/claims/{client}':
296303
get:
304+
description: |
305+
Get the claim information for a specific client.
306+
The response will be an EVSE claim.
297307
responses:
298308
'200':
299309
description: OK
@@ -431,6 +441,9 @@ paths:
431441
description: Numeric ID of the event
432442
get:
433443
summary: Get event details
444+
description: |
445+
This will get the details of a specific event in the schedule.
446+
The response will be the EVSE state to set for that event.
434447
responses:
435448
'200':
436449
description: OK
@@ -442,6 +455,8 @@ paths:
442455
tags:
443456
- Schedule
444457
post:
458+
description: |
459+
Update the details of a specific event in the schedule.
445460
responses:
446461
'200':
447462
$ref: '#/components/responses/UpdateSuccessful'
@@ -456,6 +471,8 @@ paths:
456471
- Schedule
457472
summary: Update event details
458473
delete:
474+
description: |
475+
Remove a specific event from the schedule.
459476
responses:
460477
'200':
461478
description: OK
@@ -523,7 +540,9 @@ paths:
523540
'404':
524541
$ref: '#/components/responses/NotFound'
525542
operationId: getEventBlock
526-
description: ''
543+
description: |
544+
Retrieve the log events for a specific block.
545+
The block index range is returned by the /logs endpoint.
527546
parameters:
528547
- schema:
529548
type: integer
@@ -817,6 +836,95 @@ paths:
817836
$ref: '#/components/responses/BadRequest'
818837
operationId: post-time
819838
description: Set the time and associated config options. If not setting the time the `/config` endpoint can be used.
839+
/certificates:
840+
get:
841+
summary: Get a list of certificates
842+
description: |
843+
Returns a list of certificates that have been uploaded to the OpenEVSE. The certificates are used to
844+
authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA
845+
certificates.
846+
operationId: listCertificates
847+
tags:
848+
- Certificates
849+
responses:
850+
'200':
851+
description: OK
852+
content:
853+
application/json:
854+
schema:
855+
type: object
856+
properties:
857+
certificates:
858+
type: array
859+
items:
860+
$ref: './models/Certificate.yaml'
861+
post:
862+
summary: Upload a certificate
863+
description: |
864+
Upload a certificate to the OpenEVSE. The certificate can be used to authenticate the OpenEVSE to the MQTT
865+
broker, provide a secure web interface or as additional root CA certificates.
866+
operationId: uploadCertificate
867+
tags:
868+
- Certificates
869+
requestBody:
870+
content:
871+
application/json:
872+
schema:
873+
$ref: './models/Certificate.yaml'
874+
responses:
875+
'200':
876+
$ref: '#/components/responses/UpdateSuccessful'
877+
'400':
878+
$ref: '#/components/responses/BadRequest'
879+
'/certificates/{id}':
880+
get:
881+
summary: Get a certificate
882+
description: |
883+
Returns a certificate that has been uploaded to the OpenEVSE. The certificate is used to
884+
authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA
885+
certificates.
886+
operationId: getCertificate
887+
tags:
888+
- Certificates
889+
parameters:
890+
- in: path
891+
name: id
892+
required: true
893+
schema:
894+
type: string
895+
responses:
896+
'200':
897+
description: OK
898+
content:
899+
application/json:
900+
schema:
901+
$ref: './models/Certificate.yaml'
902+
'400':
903+
$ref: '#/components/responses/BadRequest'
904+
'404':
905+
$ref: '#/components/responses/NotFound'
906+
delete:
907+
summary: Delete a certificate
908+
description: |
909+
Delete a certificate that has been uploaded to the OpenEVSE. The certificate is used to
910+
authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA
911+
certificates.
912+
operationId: deleteCertificate
913+
tags:
914+
- Certificates
915+
parameters:
916+
- in: path
917+
name: id
918+
required: true
919+
schema:
920+
type: string
921+
responses:
922+
'200':
923+
$ref: '#/components/responses/UpdateSuccessful'
924+
'400':
925+
$ref: '#/components/responses/BadRequest'
926+
'404':
927+
$ref: '#/components/responses/NotFound'
820928
components:
821929
schemas:
822930
Message:
@@ -963,3 +1071,4 @@ tags:
9631071
- name: Energy Meter
9641072
- name: Time
9651073
- name: Restart
1074+
- name: Certificates

docs/mqtt.md

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
### MQTT
1+
# MQTT
22

33
MQTT and MQTTS (secure) connections are supported for status and control.
44

@@ -20,46 +20,45 @@ When the device disconnects from MQTT the same message is posted with `state":"d
2020

2121
All subsequent MQTT status updates will by default be be posted to `openevse-xxxx` where `xxxx` is the last 4 characters of the device ID. This base-topic can be changed via the MQTT service page.
2222

23-
#### OpenEVSE Status via MQTT
23+
## OpenEVSE Status via MQTT
2424

2525
OpenEVSE can post its status values (e.g. amp, wh, temp1, temp2, temp3, pilot, status) to an MQTT server. Data will be published as a sub-topic of base topic, e.g `<base-topic>/amp`. Data is published to MQTT every 30s.
2626

2727
**The default `<base-topic>` is `openevse-xxxx` where `xxxx` is the last 4 characters of the device ID**
2828

2929
Claims & manual override are read accessible here:
30-
`<base-topic>/override/` : get manual override ([json data], {"state": "null"} when there's no override)
31-
`<base-topic>/override/set <json data> ` : set/update manual override ( data as refered from API : https://openevse.stoplight.io/docs/openevse-wifi-v4/e0ab0a4ad5e1e-set-the-manual-override )
30+
`<base-topic>/override/` : get manual override ([json data], `{"state": "null"}` when there's no override)
31+
`<base-topic>/override/set <json data>` : set/update manual override (data as refered from API : <https://openevse.stoplight.io/docs/openevse-wifi-v4/e0ab0a4ad5e1e-set-the-manual-override>)
3232
`<base-topic>/override/set toggle` : toggle manual override
3333
`<base-topic>/override/set clear` : clear manual override
3434

35-
`<base-topic>/claim/` : get mqtt service claim ([json data], {"state": "null"} when there's no claim )
36-
`<base-topic>/claim/set <json data>` : set/update claim from MQTT service. Has same priority as HTTP service. ( data as refered from API : https://openevse.stoplight.io/docs/openevse-wifi-v4/ebc578ffa7ca7-make-update-an-evse-claim )
35+
`<base-topic>/claim/` : get mqtt service claim ([json data], `{"state": "null"}` when there's no claim)
36+
`<base-topic>/claim/set <json data>` : set/update claim from MQTT service. Has same priority as HTTP service. (data as refered from API : <https://openevse.stoplight.io/docs/openevse-wifi-v4/ebc578ffa7ca7-make-update-an-evse-claim>)
3737
`<base-topic>/claim/set release` : release claim
3838

39-
Claim & override properties can be set independantly. Sending json with only some fields will update the current claim properties only.
39+
Claim & override properties can be set independantly. Sending json with only some fields will update the current claim properties only.
4040
To remove a selected claim/override property, just send "clear" as property parameter ( i.e. `<base-topic>/claim/set {"charge_current": "clear"}` )
4141

4242
Scheduler data:
43-
`<base-topic>/schedule/` : get scheduler data ([json data]
44-
`<base-topic>/schedule/set <json data>` : set/update schedules ( data as refered from API: https://openevse.stoplight.io/docs/openevse-wifi-v4/e87e6f3f90787-batch-update-schedule )
45-
`<base-topic>/schedule/clear <id> :`remove related event
43+
`<base-topic>/schedule/` : get scheduler data ([json data], `{"state": "null"}` when there's no shcedule)
44+
`<base-topic>/schedule/set <json data>` : set/update schedules ( data as refered from API: <https://openevse.stoplight.io/docs/openevse-wifi-v4/e87e6f3f90787-batch-update-schedule>)
45+
`<base-topic>/schedule/clear <id>` : remove related event
4646

4747
Limit:
48-
`<base-topic>/limit/` : get limit data ([json data]
49-
`<base-topic>/limit/set <json data>` : set/update limit ( data as refered from API:https://openevse.stoplight.io/docs/openevse-wifi-v4/c410fb5e48294-set-charge-limit )
50-
`<base-topic>/limit/set clear` : clear current limit
48+
`<base-topic>/limit/` : get limit data ([json data], `{"state": "null"}` when there's no limit)
49+
`<base-topic>/limit/set <json data>` : set/update limit ( data as refered from API: <https://openevse.stoplight.io/docs/openevse-wifi-v4/c410fb5e48294-set-charge-limit>)
50+
`<base-topic>/limit/set clear` : clear current limit
5151

5252
Main settings:
5353

54-
`<base-topic>/divertmode/set [1 | 2]` : enable (1)/ disable (2) divert mode
55-
`<base-topic>/shaper/set [0 | 1]` : temporary enable (1)/ disable (0) current shaper ( doesn't survive reboot )
54+
`<base-topic>/divertmode/set [1 | 2]` : enable (1)/ disable (2) divert mode
55+
`<base-topic>/shaper/set [0 | 1]` : temporary enable (1)/ disable (0) current shaper ( doesn't survive reboot )
5656
`<base-topic>/restart {"device": "gateway|evse"}` : restart the gateway or openevse module
5757

5858
Config:
5959

60-
`<base-topic>/config_version` : a volatile counter incremented for each config change
61-
`<base-topic>/config` : expose the configuration as a json object
62-
60+
`<base-topic>/config_version` : a volatile counter incremented for each config change
61+
`<base-topic>/config` : expose the configuration as a json object
6362

6463
MQTT setup is pre-populated with OpenEnergyMonitor [emonPi default MQTT server credentials](https://guide.openenergymonitor.org/technical/credentials/#mqtt).
6564

@@ -69,3 +68,36 @@ MQTT setup is pre-populated with OpenEnergyMonitor [emonPi default MQTT server c
6968
* After a few seconds `Connected: No` should change to `Connected: Yes` if connection is successful. Re-connection will be attempted every 10s. A refresh of the page may be needed.
7069

7170
*Note: `emon/xxxx` should be used as the base-topic if posting to emonPi MQTT server if you want the data to appear in emonPi Emoncms. See [emonPi MQTT docs](https://guide.openenergymonitor.org/technical/mqtt/).*
71+
72+
## Connecting to Cloud IoT services
73+
74+
### AWS IoT Core
75+
76+
Policy for AWS IoT Core:
77+
78+
```json
79+
{
80+
"Version": "2012-10-17",
81+
"Statement": [
82+
{
83+
"Effect": "Allow",
84+
"Action": "iot:Connect",
85+
"Resource": "arn:aws:iot:eu-west-2:489072314047:client/openevse-*"
86+
},
87+
{
88+
"Effect": "Allow",
89+
"Action": "iot:Subscribe",
90+
"Resource": "arn:aws:iot:eu-west-2:489072314047:topicfilter/openevse/*"
91+
},
92+
{
93+
"Effect": "Allow",
94+
"Action": [
95+
"iot:Receive",
96+
"iot:Publish",
97+
"iot:RetainPublish"
98+
],
99+
"Resource": "arn:aws:iot:eu-west-2:489072314047:topic/openevse/*"
100+
}
101+
]
102+
}
103+
```

models/Certificate.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
title: Certificate defenition
2+
allOf:
3+
- type: object
4+
properties:
5+
id:
6+
type: string
7+
description: 'The certificate ID, 64 bit hex number as a string'
8+
name:
9+
type: string
10+
description: 'The human readable certificate name'
11+
type:
12+
type: string
13+
description: 'The certificate type'
14+
certificate:
15+
type: string
16+
description: 'A PEM formatted certificate'
17+
private_key:
18+
type: string
19+
description: 'A PEM formatted private key'
20+
x-tags:
21+
- Certificates

platformio.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ debug_flags =
6666
#-D ENABLE_DEBUG_MICROTASKS
6767
#-D ENABLE_DEBUG_ENERGY_METER
6868
#-D ENABLE_DEBUG_MEMORY_MONITOR
69+
#-D ENABLE_DEBUG_CETRIFICATES
70+
#-D ENABLE_DEBUG_WEB_CETRIFICATES
71+
#-D ENABLE_DEBUG_MONGOOSE_MQTT_CLIENT
6972
src_build_flags =
7073
# -D ARDUINOJSON_USE_LONG_LONG
7174
# -D ENABLE_ASYNC_WIFI_SCAN

src/app_config.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ String lang;
4545
// Web server authentication (leave blank for none)
4646
String www_username;
4747
String www_password;
48+
String www_certificate_id;
4849

4950
// Advanced settings
5051
String esp_hostname;
@@ -66,6 +67,7 @@ uint32_t mqtt_port;
6667
String mqtt_topic;
6768
String mqtt_user;
6869
String mqtt_pass;
70+
String mqtt_certificate_id;
6971
String mqtt_solar;
7072
String mqtt_grid_ie;
7173
String mqtt_vrms;
@@ -153,6 +155,7 @@ ConfigOpt *opts[] =
153155
// Web server authentication (leave blank for none)
154156
new ConfigOptDefinition<String>(www_username, "", "www_username", "au"),
155157
new ConfigOptSecret(www_password, "", "www_password", "ap"),
158+
new ConfigOptDefenition<String>(www_certificate_id, "", "www_certificate_id", "wc"),
156159

157160
// Advanced settings
158161
new ConfigOptDefinition<String>(esp_hostname, esp_hostname_default, "hostname", "hn"),
@@ -177,6 +180,7 @@ ConfigOpt *opts[] =
177180
new ConfigOptDefinition<String>(mqtt_topic, esp_hostname, "mqtt_topic", "mt"),
178181
new ConfigOptDefinition<String>(mqtt_user, "emonpi", "mqtt_user", "mu"),
179182
new ConfigOptSecret(mqtt_pass, "emonpimqtt2016", "mqtt_pass", "mp"),
183+
new ConfigOptDefinition<String>(mqtt_certificate_id, "", "mqtt_certificate_id", "mct"),
180184
new ConfigOptDefinition<String>(mqtt_solar, "", "mqtt_solar", "mo"),
181185
new ConfigOptDefinition<String>(mqtt_grid_ie, "emon/emonpi/power1", "mqtt_grid_ie", "mg"),
182186
new ConfigOptDefinition<String>(mqtt_vrms, "emon/emonpi/vrms", "mqtt_vrms", "mv"),

0 commit comments

Comments
 (0)