diff --git a/SmartEVSE-3/src/evse.cpp b/SmartEVSE-3/src/evse.cpp index 4483f38c..8c62cd7f 100644 --- a/SmartEVSE-3/src/evse.cpp +++ b/SmartEVSE-3/src/evse.cpp @@ -256,7 +256,10 @@ char *downloadUrl = NULL; int downloadProgress = 0; int downloadSize = 0; // set by EXTERNAL logic through MQTT/REST to indicate cheap tariffs ahead until unix time indicated -uint8_t ColorOff[3]={0, 0, 0}; +uint8_t ColorOff[3] = {0, 0, 0}; // off +uint8_t ColorNormal[3] = {0, 255, 0}; // Green +uint8_t ColorSmart[3] = {0, 255, 0}; // Green +uint8_t ColorSolar[3] = {255, 170, 0}; // Orange //#define FW_UPDATE_DELAY 30 //DINGO TODO // time between detection of new version and actual update in seconds #define FW_UPDATE_DELAY 3600 // time between detection of new version and actual update in seconds @@ -411,14 +414,19 @@ void BlinkLed(void * parameter) { if (LedCount > 230) LedPwm = WAITING_LED_BRIGHTNESS; // LED 10% of time on, full brightness else LedPwm = 0; - if (Mode == MODE_SOLAR) { // Orange - RedPwm = LedPwm; - GreenPwm = LedPwm * 2 / 3; - } else { // Green - RedPwm = 0; - GreenPwm = LedPwm; + if (Mode == MODE_SOLAR) { // Orange for Solar, unless configured otherwise + RedPwm = LedPwm * ColorSolar[0] / 255; + GreenPwm = LedPwm * ColorSolar[1] / 255; + BluePwm = LedPwm * ColorSolar[2] / 255; + } else if (Mode == MODE_SMART) { // Green for Smart, unless configured otherwise + RedPwm = LedPwm * ColorNormal[0] / 255; + GreenPwm = LedPwm * ColorNormal[1] / 255; + BluePwm = LedPwm * ColorNormal[2] / 255; + } else { // Green for Normal, unless configured otherwise + RedPwm = LedPwm * ColorNormal[0] / 255; + GreenPwm = LedPwm * ColorNormal[1] / 255; + BluePwm = LedPwm * ColorNormal[2] / 255; } - BluePwm = 0; } #if ENABLE_OCPP @@ -476,14 +484,19 @@ void BlinkLed(void * parameter) { LedPwm = ease8InOutQuad(triwave8(LedCount)); // pre calculate new LedPwm value } - if (Mode == MODE_SOLAR) { // Orange/Yellow for Solar mode - RedPwm = LedPwm; - GreenPwm = LedPwm * 2 / 3; - } else { - RedPwm = 0; // Green for Normal/Smart mode - GreenPwm = LedPwm; - } - BluePwm = 0; + if (Mode == MODE_SOLAR) { // Orange for Solar, unless configured otherwise + RedPwm = LedPwm * ColorSolar[0] / 255; + GreenPwm = LedPwm * ColorSolar[1] / 255; + BluePwm = LedPwm * ColorSolar[2] / 255; + } else if (Mode == MODE_SMART) { // Green for Smart, unless configured otherwise + RedPwm = LedPwm * ColorNormal[0] / 255; + GreenPwm = LedPwm * ColorNormal[1] / 255; + BluePwm = LedPwm * ColorNormal[2] / 255; + } else { // Green for Normal, unless configured otherwise + RedPwm = LedPwm * ColorNormal[0] / 255; + GreenPwm = LedPwm * ColorNormal[1] / 255; + BluePwm = LedPwm * ColorNormal[2] / 255; + } } ledcWrite(RED_CHANNEL, RedPwm); @@ -2845,6 +2858,36 @@ void mqtt_receive_callback(const String topic, const String payload) { ColorOff[1] = G; ColorOff[2] = B; } + } else if (topic == MQTTprefix + "/Set/ColorNormal") { + int32_t R, G, B; + int n = sscanf(payload.c_str(), "%d:%d:%d", &R, &G, &B); + + // R,G,B is between 0..255 + if (n == 3 && (R >= 0 && R < 256) && (G >= 0 && G < 256) && (B >= 0 && B < 256)) { + ColorNormal[0] = R; + ColorNormal[1] = G; + ColorNormal[2] = B; + } + } else if (topic == MQTTprefix + "/Set/ColorSmart") { + int32_t R, G, B; + int n = sscanf(payload.c_str(), "%d:%d:%d", &R, &G, &B); + + // R,G,B is between 0..255 + if (n == 3 && (R >= 0 && R < 256) && (G >= 0 && G < 256) && (B >= 0 && B < 256)) { + ColorSmart[0] = R; + ColorSmart[1] = G; + ColorSmart[2] = B; + } + } else if (topic == MQTTprefix + "/Set/ColorSolar") { + int32_t R, G, B; + int n = sscanf(payload.c_str(), "%d:%d:%d", &R, &G, &B); + + // R,G,B is between 0..255 + if (n == 3 && (R >= 0 && R < 256) && (G >= 0 && G < 256) && (B >= 0 && B < 256)) { + ColorSolar[0] = R; + ColorSolar[1] = G; + ColorSolar[2] = B; + } } // Make sure MQTT updates directly to prevent debounces @@ -3082,6 +3125,9 @@ void mqttPublishData() { MQTTclient.publish(MQTTprefix + "/OCPPConnection", (OcppWsClient && OcppWsClient->isConnected()) ? "Connected" : "Disconnected", false, 0); #endif //ENABLE_OCPP MQTTclient.publish(MQTTprefix + "/LEDColorOff", String(ColorOff[0])+","+String(ColorOff[1])+","+String(ColorOff[2]), true, 0); + MQTTclient.publish(MQTTprefix + "/LEDColorNormal", String(ColorNormal[0])+","+String(ColorNormal[1])+","+String(ColorNormal[2]), true, 0); + MQTTclient.publish(MQTTprefix + "/LEDColorSmart", String(ColorSmart[0])+","+String(ColorSmart[1])+","+String(ColorSmart[2]), true, 0); + MQTTclient.publish(MQTTprefix + "/LEDColorSolar", String(ColorSolar[0])+","+String(ColorSolar[1])+","+String(ColorSolar[2]), true, 0); } #endif @@ -4689,7 +4735,7 @@ static void fn_http_server(struct mg_connection *c, int ev, void *ev_data) { boolean evConnected = pilot != PILOT_12V; //when access bit = 1, p.ex. in OFF mode, the STATEs are no longer updated - DynamicJsonDocument doc(1600); // https://arduinojson.org/v6/assistant/ + DynamicJsonDocument doc(3072); // https://arduinojson.org/v6/assistant/ doc["version"] = String(VERSION); doc["serialnr"] = serialnr; doc["mode"] = mode; @@ -4832,9 +4878,18 @@ static void fn_http_server(struct mg_connection *c, int ev, void *ev_data) { doc["backlight"]["timer"] = BacklightTimer; doc["backlight"]["status"] = backlight; - doc["color_off"]["R"] = ColorOff[0]; - doc["color_off"]["G"] = ColorOff[1]; - doc["color_off"]["B"] = ColorOff[2]; + doc["color"]["off"]["R"] = ColorOff[0]; + doc["color"]["off"]["G"] = ColorOff[1]; + doc["color"]["off"]["B"] = ColorOff[2]; + doc["color"]["normal"]["R"] = ColorNormal[0]; + doc["color"]["normal"]["G"] = ColorNormal[1]; + doc["color"]["normal"]["B"] = ColorNormal[2]; + doc["color"]["smart"]["R"] = ColorSmart[0]; + doc["color"]["smart"]["G"] = ColorSmart[1]; + doc["color"]["smart"]["B"] = ColorSmart[2]; + doc["color"]["solar"]["R"] = ColorSolar[0]; + doc["color"]["solar"]["G"] = ColorSolar[1]; + doc["color"]["solar"]["B"] = ColorSolar[2]; String json; serializeJson(doc, json); @@ -5176,12 +5231,80 @@ static void fn_http_server(struct mg_connection *c, int ev, void *ev_data) { ColorOff[0] = R; ColorOff[1] = G; ColorOff[2] = B; - doc["color_off"]["R"] = ColorOff[0]; - doc["color_off"]["G"] = ColorOff[1]; - doc["color_off"]["B"] = ColorOff[2]; + doc["color"]["off"]["R"] = ColorOff[0]; + doc["color"]["off"]["G"] = ColorOff[1]; + doc["color"]["off"]["B"] = ColorOff[2]; + } + } + + String json; + serializeJson(doc, json); + mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\r\n", json.c_str()); // Yes. Respond JSON + + } else if (mg_http_match_uri(hm, "/color_normal") && !memcmp("POST", hm->method.buf, hm->method.len)) { + DynamicJsonDocument doc(200); + + if (request->hasParam("R") && request->hasParam("G") && request->hasParam("B")) { + int32_t R = request->getParam("R")->value().toInt(); + int32_t G = request->getParam("G")->value().toInt(); + int32_t B = request->getParam("B")->value().toInt(); + + // R,G,B is between 0..255 + if ((R >= 0 && R < 256) && (G >= 0 && G < 256) && (B >= 0 && B < 256)) { + ColorNormal[0] = R; + ColorNormal[1] = G; + ColorNormal[2] = B; + doc["color"]["normal"]["R"] = ColorNormal[0]; + doc["color"]["normal"]["G"] = ColorNormal[1]; + doc["color"]["normal"]["B"] = ColorNormal[2]; } } + String json; + serializeJson(doc, json); + mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\r\n", json.c_str()); // Yes. Respond JSON + + } else if (mg_http_match_uri(hm, "/color_smart") && !memcmp("POST", hm->method.buf, hm->method.len)) { + DynamicJsonDocument doc(200); + + if (request->hasParam("R") && request->hasParam("G") && request->hasParam("B")) { + int32_t R = request->getParam("R")->value().toInt(); + int32_t G = request->getParam("G")->value().toInt(); + int32_t B = request->getParam("B")->value().toInt(); + + // R,G,B is between 0..255 + if ((R >= 0 && R < 256) && (G >= 0 && G < 256) && (B >= 0 && B < 256)) { + ColorSmart[0] = R; + ColorSmart[1] = G; + ColorSmart[2] = B; + doc["color"]["smart"]["R"] = ColorSmart[0]; + doc["color"]["smart"]["G"] = ColorSmart[1]; + doc["color"]["smart"]["B"] = ColorSmart[2]; + } + } + + String json; + serializeJson(doc, json); + mg_http_reply(c, 200, "Content-Type: application/json\r\n", "%s\r\n", json.c_str()); // Yes. Respond JSON + + } else if (mg_http_match_uri(hm, "/color_solar") && !memcmp("POST", hm->method.buf, hm->method.len)) { + DynamicJsonDocument doc(200); + + if (request->hasParam("R") && request->hasParam("G") && request->hasParam("B")) { + int32_t R = request->getParam("R")->value().toInt(); + int32_t G = request->getParam("G")->value().toInt(); + int32_t B = request->getParam("B")->value().toInt(); + + // R,G,B is between 0..255 + if ((R >= 0 && R < 256) && (G >= 0 && G < 256) && (B >= 0 && B < 256)) { + ColorSolar[0] = R; + ColorSolar[1] = G; + ColorSolar[2] = B; + doc["color"]["solar"]["R"] = ColorSolar[0]; + doc["color"]["solar"]["G"] = ColorSolar[1]; + doc["color"]["solar"]["B"] = ColorSolar[2]; + } + } String json; serializeJson(doc, json); diff --git a/docs/REST_API.md b/docs/REST_API.md index 0e778a63..b6f47a2e 100644 --- a/docs/REST_API.md +++ b/docs/REST_API.md @@ -137,11 +137,42 @@ to your curl POST command. -d '' * R, G, B +  Sets the color of the connected switch while the EVSE is in Off mode (and overrides the default setting (0, 0, 0).
  R, G and B must be send all together otherwise the data won't be registered. ``` curl -X POST 'http://ipaddress/color_off?R=0&G=0&B=255' -d '' ``` +# POST: /color_normal + +* R, G, B + +  Sets the color of the connected switch while the EVSE is in Normal mode (and overrides the default green setting (0, 255, 0). +
  R, G and B must be send all together otherwise the data won't be registered. +``` + curl -X POST 'http://ipaddress/color_normal?R=0&G=0&B=255' -d '' +``` + +# POST: /color_smart + +* R, G, B + +  Sets the color of the connected switch while the EVSE is in Smart mode (and overrides the default green setting (0, 255, 0). +
  R, G and B must be send all together otherwise the data won't be registered. +``` + curl -X POST 'http://ipaddress/color_smart?R=0&G=0&B=255' -d '' +``` + +# POST: /color_solar + +* R, G, B + +  Sets the color of the connected switch while the EVSE is in Solar mode (and overrides the default yellow setting (255, 170, 0). +
  R, G and B must be send all together otherwise the data won't be registered. +``` + curl -X POST 'http://ipaddress/color_solar?R=0&G=0&B=255' -d '' +``` + # POST: /currents * battery_current diff --git a/docs/configuration.md b/docs/configuration.md index 09b0a93f..ba294205 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -240,6 +240,9 @@ Valid topics you can publish to are: /Set/HomeBatteryCurrent /Set/RequiredEVCCID /Set/ColorOff +/Set/ColorNormal +/Set/ColorSmart +/Set/ColorSolar ``` Your MainsMeter can be fed with: ```