/arduinoEpeverSolarController/arduinoEpeverSolarController.ino |
@@ -79,6 +79,10 @@ |
// "value" : // |
// } // |
// // |
// Note that for the switch to work, the Epever device has to be set to // |
// "manual mode". From the manual, that seems to be setting the load // |
// setting for the first timer to 117 and the second should display 2, n // |
// and then the load can be toggled using this sketch. // |
/////////////////////////////////////////////////////////////////////////// |
|
#include <ModbusMaster.h> |
@@ -130,17 +134,15 @@ |
ModbusMaster node; |
WiFiClient wifi_client; |
PubSubClient mqtt_client(wifi_client); |
int switch_load = 0; |
bool loadState = true; |
// 1 minutes default |
unsigned int sleepSeconds = 60; |
const int EPEVER_METRICS_PAYLOAD_SIZE = 512; |
const int CONTROLLER_STATUS_PAYLOAD_SIZE = 32; |
const int EPEVER_CONTROL_PAYLOAD_SIZE = 256; |
const int JSON_DOCUMENT_SIZE = 512; |
|
StaticJsonDocument<EPEVER_METRICS_PAYLOAD_SIZE> epeverMetricsPayload; |
char tmpJsonPayloadBuffer[EPEVER_METRICS_PAYLOAD_SIZE]; |
JsonObject jsonObject; |
StaticJsonDocument<JSON_DOCUMENT_SIZE> controllerStatusPayload; |
StaticJsonDocument<JSON_DOCUMENT_SIZE> epeverMetricsPayload; |
StaticJsonDocument<JSON_DOCUMENT_SIZE> epeverControlPayload; |
char tmpJsonPayloadBuffer[JSON_DOCUMENT_SIZE]; |
|
/////////////////////////////////////////////////////////////////////////// |
// modbus data definitions // |
@@ -393,10 +395,12 @@ |
// control load on / off here, setting sleep duration |
// |
void mqtt_callback(char* topic, byte* payload, unsigned int length) { |
uint8_t i, result; |
|
Serial.print("Message arrived ["); |
Serial.print(topic); |
Serial.print("] "); |
for (int i = 0; i < length; i++) { |
for (i = 0; i < length; i++) { |
Serial.print((char)payload[i]); |
} |
Serial.println(); |
@@ -410,7 +414,6 @@ |
|
// Parse the payload sent to the MQTT topic as a JSON document. |
Serial.print("Deserializing message: "); |
StaticJsonDocument<EPEVER_CONTROL_PAYLOAD_SIZE> epeverControlPayload; |
DeserializationError error = deserializeJson(epeverControlPayload, payload); |
if (error) { |
Serial.print("failed, error="); |
@@ -421,6 +424,7 @@ |
} |
|
if (!epeverControlPayload.containsKey("action")) { |
epeverControlPayload.clear(); |
return; |
} |
|
@@ -428,15 +432,25 @@ |
// Switch - but i can't seem to switch a coil directly here ?!? |
if (epeverControlPayload["status"] == "on") { |
loadState = true; |
switch_load = 1; |
} |
|
if (epeverControlPayload["status"] == "off") { |
loadState = false; |
switch_load = 1; |
} |
|
return; |
Serial.print("Setting load state:"); |
node.clearResponseBuffer(); |
node.writeSingleCoil(0x0001, 1); |
result = node.writeSingleCoil(0x0002, loadState); |
if(result == node.ku8MBSuccess) { |
Serial.println("success"); |
} |
else |
{ |
Serial.println("failure"); |
Serial.print("Miss write loadState, ret val: "); |
Serial.println(result, HEX); |
} |
} |
|
if (epeverControlPayload["action"] == "settings") { |
@@ -452,6 +466,7 @@ |
Serial.println(sleepSeconds); |
} |
|
epeverControlPayload.clear(); |
return; |
} |
} |
@@ -461,7 +476,10 @@ |
/////////////////////////////////////////////////////////////////////////// |
void setup() { |
// say hello |
Serial.begin(115200); |
Serial1.begin (74880); |
Serial1.println("Serial1 Initialised"); |
|
Serial.begin(115200); // DO NOT CHANGE! |
while (!Serial) { |
; |
} |
@@ -468,21 +486,24 @@ |
Serial.println(); |
Serial.println("Hello World! I'm an EpEver Solar Monitor!"); |
|
// Connect D0 to RST to wake up |
if (USE_DEEP_SLEEP) { |
pinMode(D0, WAKEUP_PULLUP); |
} |
// init modbus in receive mode |
pinMode(MAX485_RE, OUTPUT); |
pinMode(MAX485_DE, OUTPUT); |
digitalWrite(MAX485_RE, 0); |
digitalWrite(MAX485_DE, 0); |
|
// EPEver Device ID 1 |
node.begin(1, Serial); |
|
// modbus callbacks |
node.preTransmission(preTransmission); |
node.postTransmission(postTransmission); |
|
// Connect D0 to RST to wake up |
if (USE_DEEP_SLEEP) { |
pinMode(D0, WAKEUP_PULLUP); |
} |
|
// Initialize the LED_BUILTIN pin as an output, low active |
pinMode(LED_BUILTIN, OUTPUT); |
digitalWrite(LED_BUILTIN, HIGH); |
@@ -725,11 +746,10 @@ |
digitalWrite(LED_BUILTIN, HIGH); |
|
// Once connected, publish an announcement. |
StaticJsonDocument<CONTROLLER_STATUS_PAYLOAD_SIZE> controllerStatusPayload; |
controllerStatusPayload["status"] = "online"; |
char tmpJsonStatusBuffer[CONTROLLER_STATUS_PAYLOAD_SIZE]; |
serializeJson(controllerStatusPayload, tmpJsonStatusBuffer, CONTROLLER_STATUS_PAYLOAD_SIZE); |
mqtt_client.publish(MQTT_TOPIC_PUB, tmpJsonStatusBuffer, CONTROLLER_STATUS_PAYLOAD_SIZE); |
controllerStatusPayload["solar"]["monitor"]["status"] = "online"; |
serializeJson(controllerStatusPayload, tmpJsonPayloadBuffer); |
controllerStatusPayload.clear(); |
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "status").c_str(), tmpJsonPayloadBuffer); |
|
// publish via mqtt |
// |
@@ -817,24 +837,11 @@ |
|
Serial.println("done"); |
|
// Do the Switching of the Load here - doesn't work in callback ?!? |
// |
if (switch_load == 1) { |
switch_load = 0; |
Serial.print("Switching Load "); |
Serial.println((loadState ? "On" : "Off")); |
controllerStatusPayload["solar"]["monitor"]["status"] = "waiting"; |
serializeJson(controllerStatusPayload, tmpJsonPayloadBuffer); |
controllerStatusPayload.clear(); |
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "status").c_str(), tmpJsonPayloadBuffer); |
|
result = node.writeSingleCoil(0x0002, loadState); |
if (result != node.ku8MBSuccess) { |
Serial.print("Miss write loadState, ret val:"); |
Serial.println(result, HEX); |
} |
} |
|
controllerStatusPayload["status"] = "waiting"; |
serializeJson(controllerStatusPayload, tmpJsonStatusBuffer, CONTROLLER_STATUS_PAYLOAD_SIZE); |
mqtt_client.publish(MQTT_TOPIC_PUB, tmpJsonStatusBuffer, CONTROLLER_STATUS_PAYLOAD_SIZE); |
|
// wait for MQTT subscription processing |
Serial.print("Waiting for MQTT and OTA events."); |
unsigned int now = millis(); |
@@ -849,9 +856,10 @@ |
} |
Serial.println("Done waiting for MQTT and OTA events."); |
|
controllerStatusPayload["status"] = "offline"; |
serializeJson(controllerStatusPayload, tmpJsonStatusBuffer, CONTROLLER_STATUS_PAYLOAD_SIZE); |
mqtt_client.publish(MQTT_TOPIC_PUB, tmpJsonStatusBuffer, CONTROLLER_STATUS_PAYLOAD_SIZE); |
controllerStatusPayload["solar"]["monitor"]["status"] = "offline"; |
serializeJson(controllerStatusPayload, tmpJsonPayloadBuffer); |
controllerStatusPayload.clear(); |
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "status").c_str(), tmpJsonPayloadBuffer); |
|
// ensure all messages are sent |
mqtt_client.unsubscribe(MQTT_TOPIC_SUB); |