@@ -67,173 +67,8 @@ void ArduinoOcppTask::initializeArduinoOcpp() {
6767
6868 OCPP_initialize (ocppSocket, (float ) VOLTAGE_DEFAULT, ArduinoOcpp::FilesystemOpt::Use, clockAdapter);
6969
70- ArduinoOcpp::FirmwareService *fwService = ArduinoOcpp::getFirmwareService ();
71- if (fwService) {
72- fwService->setOnInstall ([this ](String location) {
73-
74- updateUrl = location;
75-
76- #if 0 //TODO finish when HTTP FW download will be available in the OpenEVSE core
77-
78- //TODO HTTPUpdate has added the onProgress cb to its own class definition in Jun '21. Replace when available (https://github.com/espressif/arduino-esp32/commit/db4e7667afe0e169c5f00567f4b59ab8e0fc1532)
79- Update.onProgress([this](size_t index, size_t total) {
80- if (!updateUserNotified && index > 0) {
81- updateUserNotified = true;
82-
83- DBUG("Update via OCPP start\n");
84-
85- lcd->display(F("Updating WiFi"), 0, 0, 10 * 1000, LCD_CLEAR_LINE | LCD_DISPLAY_NOW);
86- lcd->display(F(""), 0, 1, 10 * 1000, LCD_CLEAR_LINE | LCD_DISPLAY_NOW);
87- }
88-
89- if (index < total) {
90- unsigned int percent = 0;
91- if (total / 100U != 0) {
92- percent = index / (total / 100U);
93- } else {
94- percent = 99;
95- }
96- DBUGVAR(percent);
97- String text = String(percent) + F("%");
98- if (lcd) lcd->display(text, 0, 1, 10 * 1000, LCD_DISPLAY_NOW);
99- DBUGF("Update: %d%%\n", percent);
100- } else {
101- lcd->display(F("Complete"), 0, 1, 10 * 1000, LCD_CLEAR_LINE | LCD_DISPLAY_NOW);
102- }
103- });
104-
105- // MongooseHttpClient client = MongooseHttpClient();
106- //
107- // client.get(updateUrl.c_str(), [](MongooseHttpClientResponse *response) {
108- // //if (response->contentLength() <
109- // //Update.begin
110- // });
111-
112- #endif
113- DBUGLN (F (" [ocpp] FW download not implemented yet! Ignore request" ));
114-
115- return true ;
116- });
117- }
118-
119- ArduinoOcpp::DiagnosticsService *diagService = ArduinoOcpp::getDiagnosticsService ();
120- if (diagService) {
121- diagService->setOnUploadStatusSampler ([this ] () {
122- if (diagFailure) {
123- return ArduinoOcpp::UploadStatus::UploadFailed;
124- } else if (diagSuccess) {
125- return ArduinoOcpp::UploadStatus::Uploaded;
126- } else {
127- return ArduinoOcpp::UploadStatus::NotUploaded;
128- }
129- });
130-
131- diagService->setOnUpload ([this ] (String &location, ArduinoOcpp::OcppTimestamp &startTime, ArduinoOcpp::OcppTimestamp &stopTime) {
132-
133- // reset reported state
134- diagSuccess = false ;
135- diagFailure = false ;
136-
137- // check if input URL is valid (maybe add Same-origin policy?)
138- unsigned int port_i = 0 ;
139- struct mg_str scheme, query, fragment;
140- if (mg_parse_uri (mg_mk_str (location.c_str ()), &scheme, NULL , NULL , &port_i, NULL , &query, &fragment)) {
141- DBUG (F (" [ocpp] Diagnostics upload, invalid URL: " ));
142- DBUGLN (location);
143- diagFailure = true ;
144- return false ;
145- }
146-
147- if (eventLog == NULL ) {
148- diagFailure = true ;
149- return false ;
150- }
151-
152- // create file to upload
153- #define BOUNDARY_STRING " -----------------------------WebKitFormBoundary7MA4YWxkTrZu0gW025636501"
154- const char *bodyPrefix PROGMEM = BOUNDARY_STRING " \r\n "
155- " Content-Disposition: form-data; name=\" file\" ; filename=\" diagnostics.log\"\r\n "
156- " Content-Type: application/octet-stream\r\n\r\n " ;
157- const char *bodySuffix PROGMEM = " \r\n\r\n " BOUNDARY_STRING " --\r\n " ;
158- const char *overflowMsg PROGMEM = " {\" diagnosticsMsg\" :\" requested search period exceeds maximum diagnostics upload size\" }" ;
159-
160- const size_t MAX_BODY_SIZE = 10000 ; // limit length of message
161- String body = String (' \0 ' );
162- body.reserve (MAX_BODY_SIZE);
163- body += bodyPrefix;
164- body += " [" ;
165- const size_t SUFFIX_RESERVED_AREA = MAX_BODY_SIZE - strlen (bodySuffix) - strlen (overflowMsg) - 2 ;
166-
167- bool firstEntry = true ;
168- bool overflow = false ;
169- for (uint32_t i = 0 ; i <= (eventLog->getMaxIndex () - eventLog->getMinIndex ()) && !overflow; i++) {
170- uint32_t index = eventLog->getMinIndex () + i;
171-
172- eventLog->enumerate(index, [this , startTime, stopTime, &body, SUFFIX_RESERVED_AREA, &firstEntry, &overflow] (String time, EventType type, const String &logEntry, EvseState managerState, uint8_t evseState, uint32_t evseFlags, uint32_t pilot, double energy, uint32_t elapsed, double temperature, double temperatureMax, uint8_t divertMode) {
173- if (overflow) return ;
174- ArduinoOcpp::OcppTimestamp timestamp = ArduinoOcpp::OcppTimestamp ();
175- if (!timestamp.setTime (time.c_str ())) {
176- DBUG (F (" [ocpp] Diagnostics upload, cannot parse timestamp format: " ));
177- DBUGLN (time);
178- return ;
179- }
180-
181- if (timestamp < startTime || timestamp > stopTime) {
182- return ;
183- }
184-
185- if (body.length () + logEntry.length () + 10 < SUFFIX_RESERVED_AREA) {
186- if (firstEntry)
187- firstEntry = false ;
188- else
189- body += " ," ;
190-
191- body += logEntry;
192- body += " \n " ;
193- } else {
194- overflow = true ;
195- return ;
196- }
197- });
198-
199- }
200-
201- if (overflow) {
202- if (!firstEntry)
203- body += " ,\r\n " ;
204- body += overflowMsg;
205- }
206-
207- body += " ]" ;
208-
209- body += bodySuffix;
210-
211- DBUG (F (" [ocpp] POST diagnostics file to " ));
212- DBUGLN (location);
213-
214- MongooseHttpClientRequest *request =
215- diagClient.beginRequest (location.c_str ());
216- request->setMethod (HTTP_POST);
217- request->addHeader (" Content-Type" , " multipart/form-data; boundary=" BOUNDARY_STRING);
218- request->setContent (body.c_str ());
219- request->onResponse ([this ] (MongooseHttpClientResponse *response) {
220- if (response->respCode () == 200 ) {
221- diagSuccess = true ;
222- } else {
223- diagFailure = true ;
224- }
225- });
226- request->onClose ([this ] (MongooseHttpClientResponse *response) {
227- if (!diagSuccess) {
228- // triggered onClose before onResponse
229- diagFailure = true ;
230- }
231- });
232- diagClient.send (request);
233-
234- return true ;
235- });
236- }
70+ initializeDiagnosticsService ();
71+ initializeFwService ();
23772
23873 DynamicJsonDocument *evseDetailsDoc = new DynamicJsonDocument (JSON_OBJECT_SIZE (6 ));
23974 JsonObject evseDetails = evseDetailsDoc->to <JsonObject>();
@@ -571,6 +406,137 @@ void ArduinoOcppTask::reconfigure() {
571406 loadEvseBehavior ();
572407}
573408
409+ void ArduinoOcppTask::initializeDiagnosticsService () {
410+ ArduinoOcpp::DiagnosticsService *diagService = ArduinoOcpp::getDiagnosticsService ();
411+ if (diagService) {
412+ diagService->setOnUploadStatusSampler ([this ] () {
413+ if (diagFailure) {
414+ return ArduinoOcpp::UploadStatus::UploadFailed;
415+ } else if (diagSuccess) {
416+ return ArduinoOcpp::UploadStatus::Uploaded;
417+ } else {
418+ return ArduinoOcpp::UploadStatus::NotUploaded;
419+ }
420+ });
421+
422+ diagService->setOnUpload ([this ] (String &location, ArduinoOcpp::OcppTimestamp &startTime, ArduinoOcpp::OcppTimestamp &stopTime) {
423+
424+ // reset reported state
425+ diagSuccess = false ;
426+ diagFailure = false ;
427+
428+ // check if input URL is valid
429+ unsigned int port_i = 0 ;
430+ struct mg_str scheme, query, fragment;
431+ if (mg_parse_uri (mg_mk_str (location.c_str ()), &scheme, NULL , NULL , &port_i, NULL , &query, &fragment)) {
432+ DBUG (F (" [ocpp] Diagnostics upload, invalid URL: " ));
433+ DBUGLN (location);
434+ diagFailure = true ;
435+ return false ;
436+ }
437+
438+ if (eventLog == NULL ) {
439+ diagFailure = true ;
440+ return false ;
441+ }
442+
443+ // create file to upload
444+ #define BOUNDARY_STRING " -----------------------------WebKitFormBoundary7MA4YWxkTrZu0gW025636501"
445+ const char *bodyPrefix PROGMEM = BOUNDARY_STRING " \r\n "
446+ " Content-Disposition: form-data; name=\" file\" ; filename=\" diagnostics.log\"\r\n "
447+ " Content-Type: application/octet-stream\r\n\r\n " ;
448+ const char *bodySuffix PROGMEM = " \r\n\r\n " BOUNDARY_STRING " --\r\n " ;
449+ const char *overflowMsg PROGMEM = " {\" diagnosticsMsg\" :\" requested search period exceeds maximum diagnostics upload size\" }" ;
450+
451+ const size_t MAX_BODY_SIZE = 10000 ; // limit length of message
452+ String body = String (' \0 ' );
453+ body.reserve (MAX_BODY_SIZE);
454+ body += bodyPrefix;
455+ body += " [" ;
456+ const size_t SUFFIX_RESERVED_AREA = MAX_BODY_SIZE - strlen (bodySuffix) - strlen (overflowMsg) - 2 ;
457+
458+ bool firstEntry = true ;
459+ bool overflow = false ;
460+ for (uint32_t i = 0 ; i <= (eventLog->getMaxIndex () - eventLog->getMinIndex ()) && !overflow; i++) {
461+ uint32_t index = eventLog->getMinIndex () + i;
462+
463+ eventLog->enumerate(index, [this , startTime, stopTime, &body, SUFFIX_RESERVED_AREA, &firstEntry, &overflow] (String time, EventType type, const String &logEntry, EvseState managerState, uint8_t evseState, uint32_t evseFlags, uint32_t pilot, double energy, uint32_t elapsed, double temperature, double temperatureMax, uint8_t divertMode) {
464+ if (overflow) return ;
465+ ArduinoOcpp::OcppTimestamp timestamp = ArduinoOcpp::OcppTimestamp ();
466+ if (!timestamp.setTime (time.c_str ())) {
467+ DBUG (F (" [ocpp] Diagnostics upload, cannot parse timestamp format: " ));
468+ DBUGLN (time);
469+ return ;
470+ }
471+
472+ if (timestamp < startTime || timestamp > stopTime) {
473+ return ;
474+ }
475+
476+ if (body.length () + logEntry.length () + 10 < SUFFIX_RESERVED_AREA) {
477+ if (firstEntry)
478+ firstEntry = false ;
479+ else
480+ body += " ," ;
481+
482+ body += logEntry;
483+ body += " \n " ;
484+ } else {
485+ overflow = true ;
486+ return ;
487+ }
488+ });
489+ }
490+
491+ if (overflow) {
492+ if (!firstEntry)
493+ body += " ,\r\n " ;
494+ body += overflowMsg;
495+ }
496+
497+ body += " ]" ;
498+
499+ body += bodySuffix;
500+
501+ DBUG (F (" [ocpp] POST diagnostics file to " ));
502+ DBUGLN (location);
503+
504+ MongooseHttpClientRequest *request =
505+ diagClient.beginRequest (location.c_str ());
506+ request->setMethod (HTTP_POST);
507+ request->addHeader (" Content-Type" , " multipart/form-data; boundary=" BOUNDARY_STRING);
508+ request->setContent (body.c_str ());
509+ request->onResponse ([this ] (MongooseHttpClientResponse *response) {
510+ if (response->respCode () == 200 ) {
511+ diagSuccess = true ;
512+ } else {
513+ diagFailure = true ;
514+ }
515+ });
516+ request->onClose ([this ] (MongooseHttpClientResponse *response) {
517+ if (!diagSuccess) {
518+ // triggered onClose before onResponse
519+ diagFailure = true ;
520+ }
521+ });
522+ diagClient.send (request);
523+
524+ return true ;
525+ });
526+ }
527+ }
528+
529+ void ArduinoOcppTask::initializeFwService () {
530+ // TODO finish when HTTP FW download will be available in the OpenEVSE core
531+ // ArduinoOcpp::FirmwareService *fwService = ArduinoOcpp::getFirmwareService();
532+ // if (fwService) {
533+ // fwService->setOnInstall([this](String location) {
534+ // ...
535+ // return true;
536+ // });
537+ // }
538+ }
539+
574540bool ArduinoOcppTask::operationIsAccepted (JsonObject payload) {
575541 const char *status = payload[" status" ] | " Invalid" ;
576542 return !strcmp (status, " Accepted" );
0 commit comments