Merge branch 'master' into dev-v2.2

This commit is contained in:
Gunnar Skjold
2022-10-13 20:47:48 +02:00
51 changed files with 863 additions and 269 deletions

View File

@@ -65,10 +65,11 @@ ADC_MODE(ADC_VCC);
#include "RemoteDebug.h"
#define BUF_SIZE_COMMON (2048)
#define BUF_SIZE_HAN (1024)
#define BUF_SIZE_HAN (1280)
#include "IEC6205621.h"
#include "IEC6205675.h"
#include "LNG.h"
#include "ams/DataParsers.h"
@@ -118,7 +119,6 @@ DLMSParser *dlmsParser = NULL;
DSMRParser *dsmrParser = NULL;
void setup() {
WiFiConfig wifi;
Serial.begin(115200);
if(!config.getGpioConfig(gpioConfig)) {
@@ -245,7 +245,6 @@ void setup() {
}
Debug.setSerialEnabled(true);
DebugConfig debug;
delay(1);
float vcc = hw.getVcc();
@@ -435,6 +434,10 @@ void loop() {
}
}
if(now > 10000 && now - lastErrorBlink > 3000) {
errorBlink();
}
// Only do normal stuff if we're not booted as AP
if (WiFi.getMode() != WIFI_AP) {
if (WiFi.status() != WL_CONNECTED) {
@@ -505,13 +508,10 @@ void loop() {
MDNS.update();
#endif
if(now > 10000 && now - lastErrorBlink > 3000) {
errorBlink();
}
if (mqttEnabled || config.isMqttChanged()) {
if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) {
MQTT_connect();
config.ackMqttChange();
}
} else if(mqtt != NULL && mqtt->connected()) {
mqttClient->stop();
@@ -589,11 +589,11 @@ void loop() {
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
mqttHandler->publishTemperatures(&config, &hw);
}
debugD("Used %d ms to update temperature", millis()-start);
debugD("Used %ld ms to update temperature", millis()-start);
}
if(now - lastSysupdate > 10000) {
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
mqttHandler->publishSystem(&hw);
mqttHandler->publishSystem(&hw, eapi, &ea);
}
lastSysupdate = now;
}
@@ -723,22 +723,25 @@ void errorBlink() {
if(lastError == 3)
lastError = 0;
lastErrorBlink = millis();
for(;lastError < 3;lastError++) {
switch(lastError) {
while(lastError < 3) {
switch(lastError++) {
case 0:
if(lastErrorBlink - meterState.getLastUpdateMillis() > 30000) {
debugW("No HAN data received last 30s, single blink");
hw.ledBlink(LED_RED, 1); // If no message received from AMS in 30 sec, blink once
return;
}
break;
case 1:
if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) {
debugW("MQTT connection not available, double blink");
hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice
return;
}
break;
case 2:
if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) {
debugW("WiFi not connected, tripe blink");
hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times
return;
}
@@ -825,6 +828,11 @@ bool readHanPort() {
}
if(pos == DATA_PARSE_INCOMPLETE) {
return false;
} else if(pos == DATA_PARSE_UNKNOWN_DATA) {
len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
debugPrint(hanBuffer, 0, len);
len = 0;
return false;
}
if(pos == DATA_PARSE_INTERMEDIATE_SEGMENT) {
@@ -848,20 +856,26 @@ bool readHanPort() {
}
AmsData data;
char* payload = ((char *) (hanBuffer)) + pos;
if(ctx.type == DATA_TAG_DLMS) {
// If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
mqtt->publish(topic.c_str(), toHex(hanBuffer+pos, ctx.length));
mqtt->publish(topic.c_str(), toHex((byte*) payload, ctx.length));
mqtt->loop();
}
debugV("Using application data:");
if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint(hanBuffer+pos, 0, ctx.length);
if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length);
// TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats
data = IEC6205675(((char *) (hanBuffer)) + pos, meterState.getMeterType(), &meterConfig, ctx);
// Rudimentary detector for L&G proprietary format
if(payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) {
data = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug);
} else {
// TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats
data = IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx);
}
} else if(ctx.type == DATA_TAG_DSMR) {
data = IEC6205621(((char *) (hanBuffer)) + pos);
data = IEC6205621(payload);
}
len = 0;
@@ -977,17 +991,34 @@ void debugPrint(byte *buffer, int start, int length) {
Debug.println("");
}
unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT;
unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT;
void WiFi_connect() {
if(millis() - lastWifiRetry < wifiTimeout) {
delay(50);
return;
}
lastWifiRetry = millis();
if (WiFi.status() != WL_CONNECTED) {
if(WiFi.status() == WL_DISCONNECTED) {
if(millis() - lastWifiRetry < WIFI_CONNECTION_TIMEOUT) {
return;
}
}
if(WiFi.getMode() != WIFI_OFF) {
switch(WiFi.status()) {
case WL_NO_SSID_AVAIL:
debugE("WiFi error, no SSID available");
break;
case WL_CONNECT_FAILED:
debugE("WiFi error, connection failed");
break;
case WL_CONNECTION_LOST:
debugE("WiFi error, connection lost");
break;
#if defined(ESP8266)
case WL_WRONG_PASSWORD:
debugE("WiFi error, wrong password");
break;
#endif
default:
debugE("WiFi error, %d", WiFi.status());
break;
}
if(wifiReconnectCount > 3) {
ESP.restart();
return;
@@ -1021,11 +1052,13 @@ void WiFi_connect() {
WiFi.softAPdisconnect(true);
WiFi.enableAP(false);
WiFi.mode(WIFI_OFF);
#if defined(ESP8266)
WiFi.forceSleepBegin();
#endif
yield();
wifiTimeout = 5000;
return;
}
wifiTimeout = WIFI_CONNECTION_TIMEOUT;
lastWifiRetry = millis();
WiFiConfig wifi;
if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) {
@@ -1043,7 +1076,7 @@ void WiFi_connect() {
}
#endif
WiFi.mode(WIFI_STA);
WiFi.setSleep(WIFI_PS_MIN_MODEM);
WiFi.setSleep(WIFI_PS_MAX_MODEM);
#if defined(ESP32)
if(wifi.power >= 195)
WiFi.setTxPower(WIFI_POWER_19_5dBm);
@@ -1113,16 +1146,16 @@ void WiFi_connect() {
void mqttMessageReceived(String &topic, String &payload) {
debugI("Received message for topic %s", topic.c_str() );
if(meterConfig.source == METER_SOURCE_MQTT) {
DataParserContext ctx = {payload.length()/2};
fromHex(hanBuffer, payload, ctx.length);
uint16_t pos = unwrapData(hanBuffer, ctx);
//if(meterConfig.source == METER_SOURCE_MQTT) {
//DataParserContext ctx = {static_cast<uint8_t>(payload.length()/2)};
//fromHex(hanBuffer, payload, ctx.length);
//uint16_t pos = unwrapData(hanBuffer, ctx);
// TODO: Run through DLMS/DMSR parser and apply AmsData
}
//}
}
int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
int16_t ret;
int16_t ret = 0;
bool doRet = false;
uint16_t end = BUF_SIZE_HAN;
uint8_t tag = (*buf);
@@ -1243,7 +1276,6 @@ void MQTT_connect() {
if(Debug.isActive(RemoteDebug::WARNING)) debugW("No MQTT config");
mqttEnabled = false;
ws.setMqttEnabled(false);
config.ackMqttChange();
return;
}
if(mqtt != NULL) {
@@ -1258,20 +1290,19 @@ void MQTT_connect() {
}
mqtt->disconnect();
if(config.isMqttChanged()) {
if(mqttSecureClient != NULL) {
mqttSecureClient->stop();
delete mqttSecureClient;
mqttSecureClient = NULL;
} else {
mqttClient->stop();
}
mqttClient = NULL;
}
yield();
} else {
uint16_t size = 256;
switch(mqttConfig.payloadFormat) {
case 0: // JSON
case 4: // Home Assistant
size = 768;
break;
case 255: // Raw frame
size = 1024;
break;
}
mqtt = new MQTTClient(size);
mqtt = new MQTTClient(1024);
ws.setMqtt(mqtt);
}
@@ -1306,54 +1337,54 @@ void MQTT_connect() {
debugI("MQTT SSL is configured (%dkb free heap)", ESP.getFreeHeap());
if(mqttSecureClient == NULL) {
mqttSecureClient = new WiFiClientSecure();
}
#if defined(ESP8266)
mqttSecureClient->setBufferSizes(512, 512);
#endif
if(LittleFS.begin()) {
File file;
#if defined(ESP8266)
mqttSecureClient->setBufferSizes(512, 512);
#endif
if(LittleFS.begin()) {
File file;
if(LittleFS.exists(FILE_MQTT_CA)) {
debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CA, "r");
#if defined(ESP8266)
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file);
mqttSecureClient->setTrustAnchors(serverTrustedCA);
#elif defined(ESP32)
mqttSecureClient->loadCACert(file, file.size());
#endif
file.close();
if(LittleFS.exists(FILE_MQTT_CA)) {
debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CA, "r");
#if defined(ESP8266)
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file);
mqttSecureClient->setTrustAnchors(serverTrustedCA);
#elif defined(ESP32)
mqttSecureClient->loadCACert(file, file.size());
#endif
file.close();
}
if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) {
#if defined(ESP8266)
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CERT, "r");
BearSSL::X509List *serverCertList = new BearSSL::X509List(file);
file.close();
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_KEY, "r");
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file);
file.close();
debugD("Setting client certificates (%dkb free heap)", ESP.getFreeHeap());
mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey);
#elif defined(ESP32)
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CERT, "r");
mqttSecureClient->loadCertificate(file, file.size());
file.close();
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_KEY, "r");
mqttSecureClient->loadPrivateKey(file, file.size());
file.close();
#endif
}
LittleFS.end();
debugD("MQTT SSL setup complete (%dkb free heap)", ESP.getFreeHeap());
}
if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) {
#if defined(ESP8266)
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CERT, "r");
BearSSL::X509List *serverCertList = new BearSSL::X509List(file);
file.close();
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_KEY, "r");
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file);
file.close();
debugD("Setting client certificates (%dkb free heap)", ESP.getFreeHeap());
mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey);
#elif defined(ESP32)
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CERT, "r");
mqttSecureClient->loadCertificate(file, file.size());
file.close();
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_KEY, "r");
mqttSecureClient->loadPrivateKey(file, file.size());
file.close();
#endif
}
LittleFS.end();
debugD("MQTT SSL setup complete (%dkb free heap)", ESP.getFreeHeap());
}
mqttClient = mqttSecureClient;
} else if(mqttClient == NULL) {
@@ -1369,7 +1400,7 @@ void MQTT_connect() {
#if defined(ESP8266)
if(mqttSecureClient) {
time_t epoch = time(nullptr);
debugD("Setting NTP time %i for secure MQTT connection", epoch);
debugD("Setting NTP time %lld for secure MQTT connection", epoch);
mqttSecureClient->setX509Time(epoch);
}
#endif
@@ -1378,10 +1409,9 @@ void MQTT_connect() {
if ((strlen(mqttConfig.username) == 0 && mqtt->connect(mqttConfig.clientId)) ||
(strlen(mqttConfig.username) > 0 && mqtt->connect(mqttConfig.clientId, mqttConfig.username, mqttConfig.password))) {
if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!");
config.ackMqttChange();
if(mqttHandler != NULL) {
mqttHandler->publishSystem(&hw);
mqttHandler->publishSystem(&hw, eapi, &ea);
}
// Subscribe to the chosen MQTT topic, if set in configuration