arduino-sketches

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 13  →  ?path2? @ 21
/arduinoEpeverSolarController/arduinoEpeverSolarController.ino
@@ -84,57 +84,59 @@
// and then the load can be toggled using this sketch. //
///////////////////////////////////////////////////////////////////////////
 
#include <ModbusMaster.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#include <ESPmDNS.h>
#endif
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <ArduinoOTA.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP_EEPROM.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <EEPROM.h>
#endif
 
///////////////////////////////////////////////////////////////////////////
// configuration //
///////////////////////////////////////////////////////////////////////////
// Whether to send data over the serial port.
#define SERIAL_DATA 1
// RS-485 module pin DE maps to D2 GPIO on ESP.
#define MAX485_DE D2
// RS-485 module pin RE maps to D1 GPIO on ESP.
#define MAX485_RE D1
 
const char* STA_SSID = "";
const char* STA_PASSWORD = "";
const char* MQTT_SERVER = "";
const int MQTT_PORT = 1883;
const char* MQTT_CLIENT_ID = "EpEver Solar Monitor";
const char* MQTT_TOPIC_PUB = "epever-40a/talk";
const char* MQTT_TOPIC_SUB = "epever-40a/hear";
// seconds to wait for MQTT message to be delivered and processed
const int MQTT_SUBSCRIBE_WAIT = 10;
#define STA_SSID ""
#define STA_PASSWORD ""
#define MQTT_SERVER ""
#define MQTT_PORT 1883
#define MQTT_CLIENT_ID "EpEver Solar Monitor"
#define MQTT_TOPIC_PUB "epever-40a/talk"
#define MQTT_TOPIC_SUB "epever-40a/hear"
// Seconds to wait for MQTT message to be delivered and processed.
#define MQTT_SUBSCRIBE_WAIT 10
 
// The OTA hostname.
const char* OTA_HOSTNAME = "";
//#define OTA_HOSTNAME
// The OTA port on which updates take place.
const unsigned int OTA_PORT = 8266;
//#define OTA_PORT 8266
// The authentication password to use for OTA updates.
// This should be set to the unsalted MD5 hash of the plaintext password.
const char* OTA_PASSWORD_HASH = "";
//#define OTA_PASSWORD_HASH
 
// Whether to use deep sleep or not (requires hardware modifications).
const bool USE_DEEP_SLEEP = true;
//#define USE_DEEP_SLEEP 1
// the minimal amount that the ESP should sleep for.
const int MIN_SLEEP_SECONDS = 60;
#define MIN_SLEEP_SECONDS 60
 
///////////////////////////////////////////////////////////////////////////
// general variable declarations //
// general variable declarations and libraries //
///////////////////////////////////////////////////////////////////////////
#include <ModbusMaster.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#include <ESPmDNS.h>
#endif
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <ArduinoOTA.h>
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP_EEPROM.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <EEPROM.h>
#endif
 
ModbusMaster node;
WiFiClient wifi_client;
PubSubClient mqtt_client(wifi_client);
@@ -375,11 +377,8 @@
while (!mqtt_client.connected()) {
Serial.print("MQTT Reconnecting: ");
 
// Create a client ID
String clientId = MQTT_CLIENT_ID;
 
// Attempt to connect
if (mqtt_client.connect(clientId.c_str())) {
if (mqtt_client.connect(MQTT_CLIENT_ID)) {
Serial.println("success");
 
Serial.print("Subscribing MQTT: ");
@@ -484,8 +483,7 @@
}
}
 
//////////////////////////
/////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Arduino functions //
///////////////////////////////////////////////////////////////////////////
void setup() {
@@ -508,9 +506,9 @@
node.begin(1, Serial);
 
// Connect D0 to RST to wake up
if (USE_DEEP_SLEEP) {
pinMode(D0, WAKEUP_PULLUP);
}
#ifdef USE_DEEP_SLEEP
pinMode(D0, WAKEUP_PULLUP);
#endif
 
// variable handling
EEPROM.begin(16);
@@ -531,22 +529,15 @@
void loop() {
uint8_t i, result;
 
// flash the led
for (i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, LOW);
delay(200);
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
}
// Turn on LED
digitalWrite(LED_BUILTIN, HIGH);
 
// clear old data
//
// Clear old data
memset(rtc.buf, 0, sizeof(rtc.buf));
memset(live.buf, 0, sizeof(live.buf));
memset(stats.buf, 0, sizeof(stats.buf));
 
// Read registers for clock
//
node.clearResponseBuffer();
result = node.readHoldingRegisters(RTC_CLOCK, RTC_CLOCK_CNT);
if (result == node.ku8MBSuccess) {
@@ -559,8 +550,7 @@
Serial.println(result, HEX);
}
 
// read LIVE-Data
//
// Read LIVE-Data
node.clearResponseBuffer();
result = node.readInputRegisters(LIVE_DATA, LIVE_DATA_CNT);
 
@@ -574,13 +564,12 @@
}
 
// Statistical Data
//
node.clearResponseBuffer();
result = node.readInputRegisters(STATISTICS, STATISTICS_CNT);
if (result == node.ku8MBSuccess) {
 
for (i = 0; i < STATISTICS_CNT; i++) stats.buf[i] = node.getResponseBuffer(i);
 
for (i = 0; i < STATISTICS_CNT; i++) {
stats.buf[i] = node.getResponseBuffer(i);
}
} else {
Serial.print("Miss read statistics, ret val:");
Serial.println(result, HEX);
@@ -587,13 +576,10 @@
}
 
// Battery SOC
//
node.clearResponseBuffer();
result = node.readInputRegisters(BATTERY_SOC, 1);
if (result == node.ku8MBSuccess) {
 
batterySOC = node.getResponseBuffer(0);
 
} else {
Serial.print("Miss read batterySOC, ret val:");
Serial.println(result, HEX);
@@ -600,14 +586,11 @@
}
 
// Battery Net Current = Icharge - Iload
//
node.clearResponseBuffer();
result = node.readInputRegisters(BATTERY_CURRENT_L, 2);
if (result == node.ku8MBSuccess) {
 
batteryCurrent = node.getResponseBuffer(0);
batteryCurrent |= node.getResponseBuffer(1) << 16;
 
} else {
Serial.print("Miss read batteryCurrent, ret val:");
Serial.println(result, HEX);
@@ -614,13 +597,10 @@
}
 
// State of the Load Switch
//
node.clearResponseBuffer();
result = node.readCoils(LOAD_STATE, 1);
if (result == node.ku8MBSuccess) {
 
loadState = node.getResponseBuffer(0);
 
} else {
Serial.print("Miss read loadState, ret val:");
Serial.println(result, HEX);
@@ -627,11 +607,9 @@
}
 
// Read Status Flags
//
node.clearResponseBuffer();
result = node.readInputRegisters(0x3200, 2);
if (result == node.ku8MBSuccess) {
 
uint16_t temp = node.getResponseBuffer(0);
Serial.print("Batt Flags : ");
Serial.println(temp);
@@ -641,7 +619,6 @@
status_batt.resistance = (temp >> 8) & 0b1;
status_batt.rated_volt = (temp >> 15) & 0b1;
 
 
temp = node.getResponseBuffer(1);
Serial.print("Chrg Flags : ");
Serial.println(temp, HEX);
@@ -659,8 +636,6 @@
Serial.println(charger_mode);
//Serial.print( "charger_oper : "); Serial.println( charger_operation );
//Serial.print( "charger_state : "); Serial.println( charger_state );
 
 
} else {
Serial.print("Miss read ChargeState, ret val:");
Serial.println(result, HEX);
@@ -667,7 +642,7 @@
}
 
// Print out to serial
//
#ifdef SERIAL_DATA
Serial.printf("\n\nTime: 20%02d-%02d-%02d %02d:%02d:%02d \n", rtc.r.y, rtc.r.M, rtc.r.d, rtc.r.h, rtc.r.m, rtc.r.s);
Serial.print("\nLive-Data: Volt Amp Watt ");
Serial.printf("\n Panel: %7.3f %7.3f %7.3f ", live.l.pV / 100.f, live.l.pI / 100.f, live.l.pP / 100.0f);
@@ -693,10 +668,9 @@
Serial.printf("\n charger.charging: %s ", charger_charging_status[charger_mode]);
Serial.println();
Serial.println();
#endif
 
// Go Online to publish via mqtt
//
// get wifi going
// Start WiFi connection.
digitalWrite(LED_BUILTIN, LOW);
WiFi.mode(WIFI_STA);
WiFi.begin(STA_SSID, STA_PASSWORD);
@@ -712,17 +686,23 @@
Serial.println(WiFi.localIP());
 
// Port defaults to 8266
#ifdef OTA_PORT
ArduinoOTA.setPort(OTA_PORT);
#endif
 
// Hostname defaults to esp8266-[ChipID]
#ifdef OTA_HOSTNAME
if (strlen(OTA_HOSTNAME) != 0) {
ArduinoOTA.setHostname(OTA_HOSTNAME);
}
#endif
 
// No authentication by default
#ifdef OTA_PASSWORD_HASH
if (strlen(OTA_PASSWORD_HASH) != 0) {
ArduinoOTA.setPasswordHash(OTA_PASSWORD_HASH);
}
#endif
 
ArduinoOTA.onStart([]() {
String type;
@@ -757,8 +737,7 @@
});
ArduinoOTA.begin();
 
// establish/keep mqtt connection
//
// Establish/keep mqtt connection
mqtt_client.setServer(MQTT_SERVER, MQTT_PORT);
mqtt_client.setCallback(mqtt_callback);
mqtt_reconnect();
@@ -775,7 +754,7 @@
controllerStatusPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "status").c_str(), tmpJsonPayloadBuffer);
 
// wait for MQTT subscription processing
// Wait for MQTT subscription processing
Serial.println("Waiting for MQTT and OTA events.");
unsigned int now = millis();
while (millis() - now < MQTT_SUBSCRIBE_WAIT * 1000) {
@@ -789,12 +768,10 @@
}
Serial.println("Done waiting for MQTT and OTA events.");
 
// publish via mqtt
//
// Publish to MQTT
Serial.print("Publishing to MQTT: ");
 
// panel
//
// Panel
epeverMetricsPayload["solar"]["panel"]["V"] = String(live.l.pV / 100.f, 2);
epeverMetricsPayload["solar"]["panel"]["I"] = String(live.l.pI / 100.f, 2);
epeverMetricsPayload["solar"]["panel"]["P"] = String(live.l.pP / 100.f, 2);
@@ -805,8 +782,7 @@
epeverMetricsPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "panel").c_str(), tmpJsonPayloadBuffer);
 
// battery
//
// Battery
epeverMetricsPayload["solar"]["battery"]["V"] = String(live.l.bV / 100.f, 2);
epeverMetricsPayload["solar"]["battery"]["I"] = String(live.l.bI / 100.f, 2);
epeverMetricsPayload["solar"]["battery"]["P"] = String(live.l.bP / 100.f, 2);
@@ -821,8 +797,7 @@
epeverMetricsPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "battery").c_str(), tmpJsonPayloadBuffer);
 
// load
//
// Load
epeverMetricsPayload["solar"]["load"]["V"] = String(live.l.lV / 100.f, 2);
epeverMetricsPayload["solar"]["load"]["I"] = String(live.l.lI / 100.f, 2);
epeverMetricsPayload["solar"]["load"]["P"] = String(live.l.lP / 100.f, 2);
@@ -840,8 +815,7 @@
epeverMetricsPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "load").c_str(), tmpJsonPayloadBuffer);
 
// energy
//
// Energy
epeverMetricsPayload["solar"]["energy"]["consumed_day"] = String(stats.s.consEnerDay / 100.f, 3);
epeverMetricsPayload["solar"]["energy"]["consumed_all"] = String(stats.s.consEnerTotal / 100.f, 3);
epeverMetricsPayload["solar"]["energy"]["generated_day"] = String(stats.s.genEnerDay / 100.f, 3);
@@ -851,8 +825,7 @@
epeverMetricsPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "energy").c_str(), tmpJsonPayloadBuffer);
 
// extra
//
// Extra
epeverMetricsPayload["solar"]["extra"]["CO2"]["t"] = String(stats.s.c02Reduction / 100.f, 2);
//epever_serialize_s( "solar/status/charger_input", charger_input_status[ charger_input ]
epeverMetricsPayload["solar"]["extra"]["charger_mode"] = charger_charging_status[charger_mode];
@@ -865,8 +838,7 @@
epeverMetricsPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "extra").c_str(), tmpJsonPayloadBuffer);
 
// settings
//
// Settings
epeverMetricsPayload["solar"]["monitor"]["settings"]["sleep"].set(sleepSeconds);
 
serializeJson(epeverMetricsPayload, tmpJsonPayloadBuffer);
@@ -880,7 +852,7 @@
controllerStatusPayload.clear();
mqtt_client.publish((String(MQTT_TOPIC_PUB) + "/" + "status").c_str(), tmpJsonPayloadBuffer);
 
// ensure all messages are sent
// Ensure all messages are sent
mqtt_client.unsubscribe(MQTT_TOPIC_SUB);
mqtt_client.disconnect();
while (mqtt_client.state() != -1) {
@@ -895,14 +867,18 @@
digitalWrite(MAX485_RE, 0);
digitalWrite(MAX485_DE, 0);
 
// DeepSleep n microseconds
//
Serial.print("\nDeepSleep for ");
// Sleep
Serial.print("\nSleep for ");
Serial.print(sleepSeconds);
Serial.println(" Seconds");
digitalWrite(LED_BUILTIN, LOW);
#ifdef USE_DEEP_SLEEP
if (USE_DEEP_SLEEP) {
ESP.deepSleep(sleepSeconds * 1000000);
} else {
delay(sleepSeconds * 1000);
}
#else
delay(sleepSeconds * 1000);
#endif
}