Skip to content

Commit

Permalink
Additional LED color configuration options for Normal, Smart and Sola…
Browse files Browse the repository at this point in the history
…r modes (#132)

* Cheap Tariff Indicator
- Adds MQTT configurable parameter '/Set/CheapTariffIndicator'
- Adds MQTT publication of '/CheapTariffIndicator'
- When 'CheapTariffIndicator' is set to a future unix time (in seconds), the EVSE LED will turn blue, when no EV is connected and access is locked.

* More general mode off LED color implementation:
- Removes MQTT configurable parameter '/Set/CheapTariffIndicator'
- Removes MQTT publication of '/CheapTariffIndicator'
- Adds MQTT configurable parameter '/Set/ColorOff' which takes an RGB value 'R:G:B'
- Adds MQTT publication of '/ColorOff'

* Expanded LED color off-mode implementation:
- Added REST api: curl -X POST 'http://ipaddress/color_off?R=0&G=0&B=255' -d ''
- Added LED color off-mode setting to http://ipaddress/settings
- Add /Set/ColorOff to list of valid MQTT topics to publish to
- Add REST api mods to REST_API manual

* Additional LED color configuration options for Normal, Smart and Solar modes

- Added REST api: curl -X POST 'http://ipaddress/color_normal?R=0&G=0&B=255' -d ''
- Added REST api: curl -X POST 'http://ipaddress/color_smart?R=0&G=0&B=255' -d ''
- Added REST api: curl -X POST 'http://ipaddress/color_solar?R=0&G=0&B=255' -d ''
- Added LED color normal/smart/soloar setting to http://ipaddress/settings
- Increased size of DynamicJsonDocument to fit new parameters
- Add /Set/ColorNormal to list of valid MQTT topics to publish to
- Add /Set/ColorSmart to list of valid MQTT topics to publish to
- Add /Set/ColorSolar to list of valid MQTT topics to publish to
- Add REST api mods to REST_API manual

* Correct mistake in REST API doc
  • Loading branch information
jonesPD authored Oct 14, 2024
1 parent d4116da commit fa788d5
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 23 deletions.
169 changes: 146 additions & 23 deletions SmartEVSE-3/src/evse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
31 changes: 31 additions & 0 deletions docs/REST_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,42 @@ to your curl POST command. -d ''

* R, G, B

&emsp;&emsp;Sets the color of the connected switch while the EVSE is in Off mode (and overrides the default setting (0, 0, 0).
<br>&emsp;&emsp;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

&emsp;&emsp;Sets the color of the connected switch while the EVSE is in Normal mode (and overrides the default green setting (0, 255, 0).
<br>&emsp;&emsp;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

&emsp;&emsp;Sets the color of the connected switch while the EVSE is in Smart mode (and overrides the default green setting (0, 255, 0).
<br>&emsp;&emsp;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

&emsp;&emsp;Sets the color of the connected switch while the EVSE is in Solar mode (and overrides the default yellow setting (255, 170, 0).
<br>&emsp;&emsp;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
Expand Down
3 changes: 3 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
```
Expand Down

0 comments on commit fa788d5

Please sign in to comment.