From 9807aa9818f160cda19db6ee3a34ea0eee6c5ffb Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 27 Nov 2021 12:29:27 +0100 Subject: [PATCH 01/57] BME680 and BMP280 code merged --- include/HomieSettings.h | 4 +-- platformio.ini | 6 ++++ src/main.cpp | 75 ++++++++++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 3e1667a..84c7270 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -12,7 +12,7 @@ #ifndef HOMIE_SETTINGS #define HOMIE_SETTINGS -#define HOMIE_FIRMWARE_NAME "Vindriktning" -#define HOMIE_FIRMWARE_VERSION "1.2.1" +#define HOMIE_FIRMWARE_NAME "RoomSensor" +#define HOMIE_FIRMWARE_VERSION "2.0.0" #endif diff --git a/platformio.ini b/platformio.ini index 06e0c4a..cf25f93 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,10 +13,16 @@ platform = espressif8266 board = d1_mini framework = arduino build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +; build_flag needs define the Bosch sensor... +; -D BMP280 +;or +; -D BME680 + ; the latest development branch (convention V3.0.x) lib_deps = https://github.com/homieiot/homie-esp8266.git#develop EspSoftwareSerial NeoPixel + adafruit/Adafruit BMP280 Library @ ^2.4.2 adafruit/Adafruit BME680 Library @ ^2.0.1 upload_port = /dev/ttyUSB1 \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5aac240..9b99898 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,15 @@ #include #include #include +#ifdef BME680 #include "Adafruit_BME680.h" +#else +#ifdef BMP280 +#include "Adafruit_BMP280.h" +#else +#error "Decition, which BMx??? is used missing" +#endif +#endif /****************************************************************************** * DEFINES @@ -93,18 +101,37 @@ HomieNode particle(NODE_PARTICLE, "particle", "number"); /**< Measuret in micro HomieNode temperatureNode(NODE_TEMPERATUR, "Room Temperature", "number"); HomieNode pressureNode(NODE_PRESSURE, "Pressure", "number"); HomieNode altitudeNode(NODE_ALTITUDE, "Altitude", "number"); +#ifdef BME680 HomieNode gasNode(NODE_GAS, "Gas", "number"); HomieNode humidityNode(NODE_HUMIDITY, "Humidity", "number"); +#endif /****************************** Output control ***********************/ HomieNode ledStripNode /* to rule them all */("led", "RGB led", "color"); /************************** Settings ******************************/ -HomieSetting i2cEnable("i2c", "BME280 sensor present"); +HomieSetting i2cEnable("i2c", +#ifdef BME680 +"BME680 sensor present" +#else +#ifdef BMP280 +"BMP280 sensor present" +#else +"No I2C sensor specified in the project" +#endif +#endif + +); HomieSetting rgbTemp("rgbTemp", "Show temperatur via red (>20 °C) and blue (< 20°C)"); static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX); -Adafruit_BME680 bme(&Wire); // connected via I2C +#ifdef BME680 +Adafruit_BME680 bmx(&Wire); // connected via I2C +#else +#ifdef BMP280 +Adafruit_BMP280 bmx; // connected via I2C +#endif +#endif Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); @@ -199,21 +226,25 @@ void onHomieEvent(const HomieEvent &event) } void bmpPublishValues() { +#ifdef BME680 // Tell BME680 to begin measurement. - unsigned long endTime = bme.beginReading(); + unsigned long endTime = bmx.beginReading(); if (endTime == 0) { log(MQTT_LEVEL_ERROR, F("BME680 not accessable"), MQTT_LOG_I2READ); return; } - temperatureNode.setProperty(NODE_TEMPERATUR).send(String(bme.readTemperature())); - pressureNode.setProperty(NODE_PRESSURE).send(String(bme.readPressure() / 100.0F)); - altitudeNode.setProperty(NODE_ALTITUDE).send(String(bme.readAltitude(SEALEVELPRESSURE_HPA))); - gasNode.setProperty(NODE_GAS).send(String((bme.gas_resistance / 1000.0))); - - humidityNode.setProperty(NODE_HUMIDITY).send(String(bme.humidity)); +#endif + // Publish the values + temperatureNode.setProperty(NODE_TEMPERATUR).send(String(bmx.readTemperature())); + pressureNode.setProperty(NODE_PRESSURE).send(String(bmx.readPressure() / 100.0F)); + altitudeNode.setProperty(NODE_ALTITUDE).send(String(bmx.readAltitude(SEALEVELPRESSURE_HPA))); +#ifdef BME680 + gasNode.setProperty(NODE_GAS).send(String((bmx.gas_resistance / 1000.0))); + humidityNode.setProperty(NODE_HUMIDITY).send(String(bmx.humidity)); +#endif if ( (rgbTemp.get()) && (!mSomethingReceived) ) { - if (bme.readTemperature() < TEMPBORDER) { + if (bmx.readTemperature() < TEMPBORDER) { strip.setPixelColor(0, strip.Color(0,0,255)); } else { strip.setPixelColor(0, strip.Color(255,0,0)); @@ -327,12 +358,14 @@ void setup() altitudeNode.advertise(NODE_ALTITUDE).setName("Altitude") .setDatatype("float") .setUnit("m"); +#ifdef BME680 gasNode.advertise(NODE_GAS).setName("Gas") .setDatatype("float") .setUnit(" KOhms"); humidityNode.advertise(NODE_HUMIDITY).setName("Humidity") .setDatatype("float") .setUnit("%"); +#endif ledStripNode.advertise(NODE_AMBIENT).setName("All Leds") .setDatatype("color").setFormat("rgb") .settable(ledHandler); @@ -350,13 +383,23 @@ void setup() strip.fill(strip.Color(0,128,0)); strip.show(); /* Extracted from library's example */ - mFailedI2Cinitialization = !bme.begin(); + mFailedI2Cinitialization = !bmx.begin(); if (!mFailedI2Cinitialization) { - bme.setTemperatureOversampling(BME680_OS_8X); - bme.setHumidityOversampling(BME680_OS_2X); - bme.setPressureOversampling(BME680_OS_4X); - bme.setIIRFilterSize(BME680_FILTER_SIZE_3); - bme.setGasHeater(320, 150); // 320*C for 150 ms +#ifdef BME680 + bmx.setTemperatureOversampling(BME680_OS_8X); + bmx.setHumidityOversampling(BME680_OS_2X); + bmx.setPressureOversampling(BME680_OS_4X); + bmx.setIIRFilterSize(BME680_FILTER_SIZE_3); + bmx.setGasHeater(320, 150); // 320*C for 150 ms +#endif +#ifdef BMP280 + /* Default settings from datasheet. */ + bmx.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ + Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ + Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ + Adafruit_BMP280::FILTER_X16, /* Filtering. */ + Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ +#endif } else { printf("Faild to initialize I2C bus\r\n"); } From 8e24c171ec5807e4f15b7155ee05cab54cd66e8d Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 27 Nov 2021 12:30:39 +0100 Subject: [PATCH 02/57] Spelling corrected --- src/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9b99898..c2340cc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -98,7 +98,7 @@ bool mFailedI2Cinitialization = false; /******************************* Sensor data **************************/ HomieNode particle(NODE_PARTICLE, "particle", "number"); /**< Measuret in micro gram per quibik meter air volume */ -HomieNode temperatureNode(NODE_TEMPERATUR, "Room Temperature", "number"); +HomieNode temperaturNode(NODE_TEMPERATUR, "Room Temperature", "number"); HomieNode pressureNode(NODE_PRESSURE, "Pressure", "number"); HomieNode altitudeNode(NODE_ALTITUDE, "Altitude", "number"); #ifdef BME680 @@ -122,7 +122,7 @@ HomieSetting i2cEnable("i2c", #endif ); -HomieSetting rgbTemp("rgbTemp", "Show temperatur via red (>20 °C) and blue (< 20°C)"); +HomieSetting rgbTemp("rgbTemp", "Show temperature via red (>20 °C) and blue (< 20°C)"); static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX); #ifdef BME680 @@ -230,12 +230,12 @@ void bmpPublishValues() { // Tell BME680 to begin measurement. unsigned long endTime = bmx.beginReading(); if (endTime == 0) { - log(MQTT_LEVEL_ERROR, F("BME680 not accessable"), MQTT_LOG_I2READ); + log(MQTT_LEVEL_ERROR, F("BME680 not accessible"), MQTT_LOG_I2READ); return; } #endif // Publish the values - temperatureNode.setProperty(NODE_TEMPERATUR).send(String(bmx.readTemperature())); + temperaturNode.setProperty(NODE_TEMPERATUR).send(String(bmx.readTemperature())); pressureNode.setProperty(NODE_PRESSURE).send(String(bmx.readPressure() / 100.0F)); altitudeNode.setProperty(NODE_ALTITUDE).send(String(bmx.readAltitude(SEALEVELPRESSURE_HPA))); #ifdef BME680 @@ -349,7 +349,7 @@ void setup() Homie.setup(); particle.advertise(NODE_PARTICLE).setName("Particle").setDatatype(NUMBER_TYPE).setUnit("micro gram per quibik"); - temperatureNode.advertise(NODE_TEMPERATUR).setName("Degrees") + temperaturNode.advertise(NODE_TEMPERATUR).setName("Degrees") .setDatatype("float") .setUnit("ºC"); pressureNode.advertise(NODE_PRESSURE).setName("Pressure") @@ -401,7 +401,7 @@ void setup() Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ #endif } else { - printf("Faild to initialize I2C bus\r\n"); + printf("Failed to initialize I2C bus\r\n"); } } strip.fill(strip.Color(0,0,0)); From 595fbbc3dab125dc8a710581d316bea2f84b3370 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 27 Nov 2021 12:32:03 +0100 Subject: [PATCH 03/57] Continue with BME680 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index cf25f93..6580e7c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,7 @@ platform = espressif8266 board = d1_mini framework = arduino -build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 ; build_flag needs define the Bosch sensor... ; -D BMP280 ;or From 7567a4ef0730ec411464f5bbf4f9e9d0672cda77 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 27 Nov 2021 14:56:19 +0100 Subject: [PATCH 04/57] Automatic mode is set; instead of ON --- src/main.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c2340cc..34f0faf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -299,23 +299,30 @@ void loopHandler() bool ledHandler(const HomieRange& range, const String& value) { if (range.isRange) return false; // only one switch is present - mSomethingReceived = true; // Stop animation - - int sep1 = value.indexOf(','); - int sep2 = value.indexOf(',', sep1 + 1); - if ((sep1 > 0) && (sep2 > 0)) { - int red = value.substring(0,sep1).toInt(); /* OpenHAB hue (0-360°) */ - int green = value.substring(sep1 + 1, sep2).toInt(); /* OpenHAB saturation (0-100%) */ - int blue = value.substring(sep2 + 1, value.length()).toInt(); /* brightness (0-100%) */ - - uint8_t r = (red * 255) / 250; - uint8_t g = (green *255) / 250; - uint8_t b = (blue *255) / 250; - uint32_t c = strip.Color(r,g,b); - strip.fill(c); - strip.show(); - ledStripNode.setProperty(NODE_AMBIENT).send(String(r) + "," + String(g) + "," + String(b)); + Homie.getLogger() << "Received: " << (value) << endl; + if (value.equals("250,250,250")) { + mSomethingReceived = false; // enable animation again + ledStripNode.setProperty(NODE_AMBIENT).send(value); return true; + } else { + mSomethingReceived = true; // Stop animation + + int sep1 = value.indexOf(','); + int sep2 = value.indexOf(',', sep1 + 1); + if ((sep1 > 0) && (sep2 > 0)) { + int red = value.substring(0,sep1).toInt(); + int green = value.substring(sep1 + 1, sep2).toInt(); + int blue = value.substring(sep2 + 1, value.length()).toInt(); + + uint8_t r = (red * 255) / 250; + uint8_t g = (green *255) / 250; + uint8_t b = (blue *255) / 250; + uint32_t c = strip.Color(r,g,b); + strip.fill(c); + strip.show(); + ledStripNode.setProperty(NODE_AMBIENT).send(value); + return true; + } } return false; } From 49312a203dcb6f503f2bda18004c3418f8ba5714 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 27 Nov 2021 15:22:05 +0100 Subject: [PATCH 05/57] Spelling --- Readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index c0d492a..d8024e8 100644 --- a/Readme.md +++ b/Readme.md @@ -3,7 +3,7 @@ located in IKEAs Vindriktning after this upgrade it will measure: * air quality -* temperatur +* temperature * pressure * altitude @@ -40,7 +40,7 @@ VCC | GND The following pins are used: * GPIO4 PM1006 particle sensor -* GPIO2 WS2812 stripe out of three LEDs, replacing the orignal LEDs at front +* GPIO2 WS2812 stripe out of three LEDs, replacing the original LEDs at front * GPIO15 Red LED (optional) * GPIO12 Green LED (optional) * GPIO13 Blue LED (optional) @@ -55,4 +55,4 @@ The following pins are used: * some wire # Sources -* [https://github.com/amkuipers/witty Witty pinout] \ No newline at end of file +* [https://github.com/amkuipers/witty Witty pinout] From d910d0b94580f436e3506c0c6f4539e877be934e Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 4 Dec 2021 18:46:17 +0100 Subject: [PATCH 06/57] More documentation --- Readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index c0d492a..f3afe06 100644 --- a/Readme.md +++ b/Readme.md @@ -55,4 +55,6 @@ The following pins are used: * some wire # Sources -* [https://github.com/amkuipers/witty Witty pinout] \ No newline at end of file +For the Witty board +* [https://github.com/amkuipers/witty Witty pinout] +* [https://arduino.ua/products_pictures/large_AOC361-5.jpg Schematics] From afff1275daacda4b44429f852206866550839b6b Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 4 Dec 2021 23:09:07 +0100 Subject: [PATCH 07/57] Documentation --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index f3afe06..fd347ad 100644 --- a/Readme.md +++ b/Readme.md @@ -39,10 +39,10 @@ VCC | GND ``` The following pins are used: -* GPIO4 PM1006 particle sensor +* GPIO4 PM1006 particle sensor PIN REST on Vindriktning board * GPIO2 WS2812 stripe out of three LEDs, replacing the orignal LEDs at front * GPIO15 Red LED (optional) -* GPIO12 Green LED (optional) +* GPIO12 Green LED (optional) Used as 3.3V Supply for the I2C sensor * GPIO13 Blue LED (optional) * GPIO13 VCC of I2C (3.3 V) * GPIO14 I2C clock From 1e15d85d6f306abb2193ada2c7aa00d8bce05672 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 4 Dec 2021 23:09:54 +0100 Subject: [PATCH 08/57] Set LED to RED, if no configuration is available --- src/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 34f0faf..3ac5b73 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,10 +33,10 @@ ******************************************************************************/ #define GPIO_WS2812 D4 /**< GPIO2 */ -#define SENSOR_PM1006_RX D2 /**< GPIO4 */ +#define SENSOR_PM1006_RX D2 /**< GPIO4 */ #define SENSOR_PM1006_TX -1 /**< Unused */ #define WITTY_RGB_R D8 /**< GPIO15 */ -#define WITTY_RGB_G D6 /**< GPIO12 */ +#define WITTY_RGB_G D6 /**< GPIO12 Used as 3.3V Power supply for the I2C Sensor */ #define WITTY_RGB_B D7 /**< GPIO13 */ #define PM1006_BIT_RATE 9600 #define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ @@ -418,6 +418,8 @@ void setup() strip.show(); digitalWrite(WITTY_RGB_B, HIGH); } else { + digitalWrite(WITTY_RGB_R, HIGH); + digitalWrite(WITTY_RGB_G, LOW); strip.fill(strip.Color(128,0,0)); for (int i=0;i < (PIXEL_COUNT / 2); i++) { strip.setPixelColor(0, strip.Color(0,0,128)); From c39ebc8e544ecf72d61d8dcd7ecd5b1b0c1054d6 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 4 Dec 2021 23:24:30 +0100 Subject: [PATCH 09/57] Serial debugging enabled --- src/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 3ac5b73..600955e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -242,7 +242,9 @@ void bmpPublishValues() { gasNode.setProperty(NODE_GAS).send(String((bmx.gas_resistance / 1000.0))); humidityNode.setProperty(NODE_HUMIDITY).send(String(bmx.humidity)); #endif - + log(MQTT_LEVEL_DEBUG, String("Temp" + String(bmx.readTemperature()) + "\tPressure:" + + String(bmx.readPressure() / 100.0F) + "\t Altitude:"+ + String(bmx.readAltitude(SEALEVELPRESSURE_HPA))), MQTT_LOG_I2READ); if ( (rgbTemp.get()) && (!mSomethingReceived) ) { if (bmx.readTemperature() < TEMPBORDER) { strip.setPixelColor(0, strip.Color(0,0,255)); @@ -466,4 +468,5 @@ void log(int level, String message, int statusCode) Homie.getMqttClient().publish(logTopic, 2, false, buffer.c_str()); delete logTopic; } + Homie.getLogger() << (level) << "@" << (statusCode) << " " << (message) << endl; } From b2db51d9a986d6615e2a8172e3dd2d7f03489d43 Mon Sep 17 00:00:00 2001 From: Ollo Date: Mon, 6 Dec 2021 20:18:23 +0100 Subject: [PATCH 10/57] Spelling improved --- Readme.md | 2 +- host/Readme.md | 2 +- host/spelling.sh | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 0a4693f..358ebbf 100644 --- a/Readme.md +++ b/Readme.md @@ -40,7 +40,7 @@ VCC | GND The following pins are used: * GPIO4 PM1006 particle sensor PIN REST on Vindriktning board -* GPIO2 WS2812 stripe out of three LEDs, replacing the orignal LEDs at front +* GPIO2 WS2812 stripe out of three LEDs, replacing the original LEDs at front * GPIO15 Red LED (optional) * GPIO12 Green LED (optional) Used as 3.3V Supply for the I2C sensor * GPIO13 Blue LED (optional) diff --git a/host/Readme.md b/host/Readme.md index 5303e87..e94a0ac 100644 --- a/host/Readme.md +++ b/host/Readme.md @@ -27,7 +27,7 @@ usage: ota_updater.py [-h] -l BROKER_HOST -p BROKER_PORT [-u BROKER_USERNAME] [-d BROKER_PASSWORD] [-t BASE_TOPIC] -i DEVICE_ID firmware -ota firmware update scirpt for ESP8226 implemenation of the Homie mqtt IoT +ota firmware update script for ESP8226 implementation of the Homie mqtt IoT convention. positional arguments: diff --git a/host/spelling.sh b/host/spelling.sh index ec98d73..fa2ecfd 100755 --- a/host/spelling.sh +++ b/host/spelling.sh @@ -7,5 +7,6 @@ if [ $? -ne 0 ]; then fi codespell -w ../src/* codespell -w ../include/* -codespell ../Readme.md +codespell -w ../*.md +codespell -w *.md exit 0 From 1c35094cfa3382bd61f4fe4d4846b6192b96838e Mon Sep 17 00:00:00 2001 From: Ollo Date: Mon, 6 Dec 2021 20:28:34 +0100 Subject: [PATCH 11/57] Wait until power is stable for BME680 --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 600955e..f4b8323 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -391,6 +391,10 @@ void setup() if (i2cEnable.get()) { strip.fill(strip.Color(0,128,0)); strip.show(); +#ifdef BME680 + printf("Wait 1 second...\r\n"); + delay(1000); +#endif /* Extracted from library's example */ mFailedI2Cinitialization = !bmx.begin(); if (!mFailedI2Cinitialization) { From f3d439cbc38576ac6c90e332c53bacb476017287 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 14:32:29 +0100 Subject: [PATCH 12/57] Button is published on MQTT, too --- include/HomieSettings.h | 2 +- platformio.ini | 2 +- src/main.cpp | 41 ++++++++++++++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 84c7270..69b47e7 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,6 +13,6 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.0.0" +#define HOMIE_FIRMWARE_VERSION "2.1.0" #endif diff --git a/platformio.ini b/platformio.ini index 6580e7c..b9c1666 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,4 +25,4 @@ lib_deps = https://github.com/homieiot/homie-esp8266.git#develop adafruit/Adafruit BMP280 Library @ ^2.4.2 adafruit/Adafruit BME680 Library @ ^2.0.1 -upload_port = /dev/ttyUSB1 \ No newline at end of file +upload_port = /dev/ttyUSB0 \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f4b8323..2b2f1a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,6 +50,10 @@ #define SEALEVELPRESSURE_HPA (1013.25) +#define BUTTON_MAX_CYCLE 10000U /**< Action: Reset configuration */ +#define BUTTON_MIN_ACTION_CYCLE 20U /**< Minimum cycle to react on the button (e.g. 1 second) */ +#define BUTTON_CHECK_INTERVALL 50U /**< Check every 50 ms the button state */ + #define LOG_TOPIC "log\0" #define MQTT_LEVEL_ERROR 1 #define MQTT_LEVEL_WARNING 10 @@ -78,6 +82,7 @@ #define NODE_GAS "gas" #define NODE_HUMIDITY "humidity" #define NODE_AMBIENT "ambient" +#define NODE_BUTTON "button" /****************************************************************************** * TYPE DEFS ******************************************************************************/ @@ -95,6 +100,7 @@ void log(int level, String message, int code); bool mConfigured = false; bool mConnected = false; bool mFailedI2Cinitialization = false; +long mLastButtonAction = 0; /******************************* Sensor data **************************/ HomieNode particle(NODE_PARTICLE, "particle", "number"); /**< Measuret in micro gram per quibik meter air volume */ @@ -105,6 +111,7 @@ HomieNode altitudeNode(NODE_ALTITUDE, "Altitude", "number"); HomieNode gasNode(NODE_GAS, "Gas", "number"); HomieNode humidityNode(NODE_HUMIDITY, "Humidity", "number"); #endif +HomieNode buttonNode(NODE_BUTTON, "Button", "number"); /****************************** Output control ***********************/ HomieNode ledStripNode /* to rule them all */("led", "RGB led", "color"); @@ -289,7 +296,10 @@ void loopHandler() if (i2cEnable.get() && (!mFailedI2Cinitialization)) { bmpPublishValues(); } - + + buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); + mButtonPressed=0U; + lastRead = millis(); } // Feed the dog -> ESP stay alive @@ -378,7 +388,8 @@ void setup() ledStripNode.advertise(NODE_AMBIENT).setName("All Leds") .setDatatype("color").setFormat("rgb") .settable(ledHandler); - + buttonNode.advertise(NODE_BUTTON).setName("Button pressed") + .setDatatype("integer"); strip.begin(); /* activate I2C for BOSCH sensor */ @@ -439,19 +450,35 @@ void loop() Homie.loop(); /* use the pin, receiving the soft serial additionally as button */ if (digitalRead(GPIO_BUTTON) == LOW) { - mButtonPressed++; - } else { - mButtonPressed=0U; + if ((millis() - mLastButtonAction) > BUTTON_CHECK_INTERVALL) { + mButtonPressed++; + } + if (mButtonPressed > BUTTON_MIN_ACTION_CYCLE) { + digitalWrite(WITTY_RGB_R, HIGH); + digitalWrite(WITTY_RGB_G, LOW); + digitalWrite(WITTY_RGB_B, LOW); + strip.fill(strip.Color(0,0,0)); + strip.setPixelColor(0, strip.Color((mButtonPressed % 100),0,0)); + strip.setPixelColor(1, strip.Color((mButtonPressed / 100),0,0)); + strip.setPixelColor(2, strip.Color((mButtonPressed / 100),0,0)); + strip.show(); + } } - if (mButtonPressed > 10000U) { - mButtonPressed=0U; + if (mButtonPressed > BUTTON_MAX_CYCLE) { + mButtonPressed = (BUTTON_MAX_CYCLE -1); if (SPIFFS.exists("/homie/config.json")) { + strip.fill(strip.Color(0,128,0)); + strip.show(); printf("Resetting config\r\n"); SPIFFS.remove("/homie/config.json"); SPIFFS.end(); + delay(50); + Homie.reboot(); } else { printf("No config present\r\n"); + strip.fill(strip.Color(0,0,128)); + strip.show(); } } } From e52300b792886ff7efbd4f1dd320ef03ed69ce41 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 14:45:34 +0100 Subject: [PATCH 13/57] Update Button via MQTT --- src/main.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2b2f1a8..448424c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,8 +51,8 @@ #define SEALEVELPRESSURE_HPA (1013.25) #define BUTTON_MAX_CYCLE 10000U /**< Action: Reset configuration */ -#define BUTTON_MIN_ACTION_CYCLE 20U /**< Minimum cycle to react on the button (e.g. 1 second) */ -#define BUTTON_CHECK_INTERVALL 50U /**< Check every 50 ms the button state */ +#define BUTTON_MIN_ACTION_CYCLE 50U /**< Minimum cycle to react on the button (e.g. 5 second) */ +#define BUTTON_CHECK_INTERVALL 100U /**< Check every 100 ms the button state */ #define LOG_TOPIC "log\0" #define MQTT_LEVEL_ERROR 1 @@ -297,11 +297,18 @@ void loopHandler() bmpPublishValues(); } - buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); - mButtonPressed=0U; - + /* Clean cycles buttons */ + if (mButtonPressed <= BUTTON_MIN_ACTION_CYCLE) { + buttonNode.setProperty(NODE_BUTTON).send("0"); + } lastRead = millis(); } + + /* if the user sees something via the LEDs, inform MQTT, too */ + if (mButtonPressed > BUTTON_MIN_ACTION_CYCLE) { + buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); + } + // Feed the dog -> ESP stay alive ESP.wdtFeed(); } @@ -463,6 +470,8 @@ void loop() strip.setPixelColor(2, strip.Color((mButtonPressed / 100),0,0)); strip.show(); } + } else { + mButtonPressed=0U; } if (mButtonPressed > BUTTON_MAX_CYCLE) { From 3e89b3e040f880dfe3e80e51e76e6699ab3bcc61 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 14:48:26 +0100 Subject: [PATCH 14/57] Tweak offset --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 448424c..6d0b74a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,7 @@ #define SEALEVELPRESSURE_HPA (1013.25) #define BUTTON_MAX_CYCLE 10000U /**< Action: Reset configuration */ -#define BUTTON_MIN_ACTION_CYCLE 50U /**< Minimum cycle to react on the button (e.g. 5 second) */ +#define BUTTON_MIN_ACTION_CYCLE 55U /**< Minimum cycle to react on the button (e.g. 5 second) */ #define BUTTON_CHECK_INTERVALL 100U /**< Check every 100 ms the button state */ #define LOG_TOPIC "log\0" From fd8277b70297f69f63dab662f583ff0477abe6d9 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 16:00:45 +0100 Subject: [PATCH 15/57] Don't manipulate the green LED during runtime, as it is the powersource for the I2C sensor --- src/main.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6d0b74a..3b58099 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,7 @@ #define PM1006_BIT_RATE 9600 #define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ +#define I2C_MAX_INIT 10 #define SEALEVELPRESSURE_HPA (1013.25) @@ -353,7 +354,7 @@ bool ledHandler(const HomieRange& range, const String& value) { *****************************************************************************/ void setup() -{ +{ SPIFFS.begin(); Serial.begin(115200); Serial.setTimeout(2000); @@ -407,8 +408,6 @@ void setup() if (mConfigured) { if (i2cEnable.get()) { - strip.fill(strip.Color(0,128,0)); - strip.show(); #ifdef BME680 printf("Wait 1 second...\r\n"); delay(1000); @@ -416,6 +415,8 @@ void setup() /* Extracted from library's example */ mFailedI2Cinitialization = !bmx.begin(); if (!mFailedI2Cinitialization) { + strip.fill(strip.Color(0,64,0)); + strip.show(); #ifdef BME680 bmx.setTemperatureOversampling(BME680_OS_8X); bmx.setHumidityOversampling(BME680_OS_2X); @@ -443,7 +444,6 @@ void setup() digitalWrite(WITTY_RGB_B, HIGH); } else { digitalWrite(WITTY_RGB_R, HIGH); - digitalWrite(WITTY_RGB_G, LOW); strip.fill(strip.Color(128,0,0)); for (int i=0;i < (PIXEL_COUNT / 2); i++) { strip.setPixelColor(0, strip.Color(0,0,128)); @@ -462,7 +462,6 @@ void loop() } if (mButtonPressed > BUTTON_MIN_ACTION_CYCLE) { digitalWrite(WITTY_RGB_R, HIGH); - digitalWrite(WITTY_RGB_G, LOW); digitalWrite(WITTY_RGB_B, LOW); strip.fill(strip.Color(0,0,0)); strip.setPixelColor(0, strip.Color((mButtonPressed % 100),0,0)); From e3fe70dff2c776d4c65593e0cb934acdefcee0a8 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 16:28:53 +0100 Subject: [PATCH 16/57] Removed unnecessary DEFINE --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 3b58099..63bcc1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,7 +47,6 @@ #define PM1006_BIT_RATE 9600 #define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ -#define I2C_MAX_INIT 10 #define SEALEVELPRESSURE_HPA (1013.25) From 6af6a6ac76f21e9d044ffeb923865a8375640b62 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 16:47:40 +0100 Subject: [PATCH 17/57] Use red led to visualize button presses --- src/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 63bcc1d..4075751 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -209,6 +209,7 @@ void onHomieEvent(const HomieEvent &event) digitalWrite(WITTY_RGB_R, LOW); if (!i2cEnable.get()) { /** keep green LED activated to power I2C sensor */ digitalWrite(WITTY_RGB_G, LOW); + log(MQTT_LEVEL_INFO, F("I2C powersupply deactivated"), MQTT_LOG_I2CINIT); } digitalWrite(WITTY_RGB_B, LOW); strip.fill(strip.Color(0,0,128)); @@ -227,6 +228,9 @@ void onHomieEvent(const HomieEvent &event) case HomieEventType::OTA_SUCCESSFUL: ESP.restart(); break; + case HomieEventType::WIFI_CONNECTED: + digitalWrite(WITTY_RGB_B, HIGH); + break; default: break; } @@ -440,7 +444,6 @@ void setup() strip.setPixelColor(0, strip.Color(0,0,128)); } strip.show(); - digitalWrite(WITTY_RGB_B, HIGH); } else { digitalWrite(WITTY_RGB_R, HIGH); strip.fill(strip.Color(128,0,0)); @@ -470,6 +473,7 @@ void loop() } } else { mButtonPressed=0U; + digitalWrite(WITTY_RGB_R, LOW); } if (mButtonPressed > BUTTON_MAX_CYCLE) { From 5ece74b0e659607330be1786bc0bfb41df9270ae Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 17:07:20 +0100 Subject: [PATCH 18/57] Activate I2C after powering the sensor --- src/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4075751..c8ab44e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -403,8 +403,6 @@ void setup() .setDatatype("integer"); strip.begin(); - /* activate I2C for BOSCH sensor */ - Wire.begin(SENSOR_I2C_SDI, SENSOR_I2C_SCK); mConfigured = Homie.isConfigured(); digitalWrite(WITTY_RGB_G, HIGH); @@ -415,6 +413,10 @@ void setup() printf("Wait 1 second...\r\n"); delay(1000); #endif + /* activate I2C for BOSCH sensor */ + Wire.begin(SENSOR_I2C_SDI, SENSOR_I2C_SCK); + printf("Wait 50 milliseconds...\r\n"); + delay(50); /* Extracted from library's example */ mFailedI2Cinitialization = !bmx.begin(); if (!mFailedI2Cinitialization) { From dadee863b8f9fb77eac41334fd5fa9263a7aae9f Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 12 Dec 2021 17:45:45 +0100 Subject: [PATCH 19/57] GPIO and Arduino-Pins are never the same --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c8ab44e..d5bb3bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,8 +42,8 @@ #define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ #define PIXEL_COUNT 3 #define GPIO_BUTTON SENSOR_PM1006_RX /**< Button and software serial share one pin on Witty board */ -#define SENSOR_I2C_SCK D1 /**< GPIO14 - I2C clock pin */ -#define SENSOR_I2C_SDI D5 /**< GPIO5 - I2C data pin */ +#define SENSOR_I2C_SCK D5 /**< GPIO14 - I2C clock pin */ +#define SENSOR_I2C_SDI D1 /**< GPIO5 - I2C data pin */ #define PM1006_BIT_RATE 9600 #define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ From db10de101cc2327b4ccefa4a9deffd3182e83cc3 Mon Sep 17 00:00:00 2001 From: Ollo Date: Wed, 15 Dec 2021 17:02:36 +0100 Subject: [PATCH 20/57] Reduced brightness to 50% --- src/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d5bb3bb..cdf904a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -258,9 +258,9 @@ void bmpPublishValues() { String(bmx.readAltitude(SEALEVELPRESSURE_HPA))), MQTT_LOG_I2READ); if ( (rgbTemp.get()) && (!mSomethingReceived) ) { if (bmx.readTemperature() < TEMPBORDER) { - strip.setPixelColor(0, strip.Color(0,0,255)); + strip.setPixelColor(0, strip.Color(0,0,127)); } else { - strip.setPixelColor(0, strip.Color(255,0,0)); + strip.setPixelColor(0, strip.Color(127,0,0)); } strip.show(); } @@ -286,11 +286,11 @@ void loopHandler() particle.setProperty(NODE_PARTICLE).send(String(pM25)); if (!mSomethingReceived) { if (pM25 < 35) { - strip.fill(strip.Color(0, 255, 0)); /* green */ + strip.fill(strip.Color(0, 127, 0)); /* green */ } else if (pM25 < 85) { - strip.fill(strip.Color(255, 127, 0)); /* orange */ + strip.fill(strip.Color(127, 64, 0)); /* orange */ } else { - strip.fill(strip.Color(255, 0, 0)); /* red */ + strip.fill(strip.Color(127, 0, 0)); /* red */ } strip.show(); } From d6e34a8e75791352ecb8a6d58dc14a8f5776ab01 Mon Sep 17 00:00:00 2001 From: Ollo Date: Wed, 15 Dec 2021 17:22:10 +0100 Subject: [PATCH 21/57] Brightness can be configured --- include/HomieSettings.h | 2 +- src/main.cpp | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 69b47e7..f12788f 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,6 +13,6 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.1.0" +#define HOMIE_FIRMWARE_VERSION "2.2.0" #endif diff --git a/src/main.cpp b/src/main.cpp index cdf904a..f3016bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,6 +74,8 @@ strcat(topic, "/"); \ strcat(topic, test); +#define PERCENT2FACTOR(b, a) ((b * a.get()) / 100) + #define NUMBER_TYPE "Number" #define NODE_PARTICLE "particle" #define NODE_TEMPERATUR "temp" @@ -130,6 +132,7 @@ HomieSetting i2cEnable("i2c", ); HomieSetting rgbTemp("rgbTemp", "Show temperature via red (>20 °C) and blue (< 20°C)"); +HomieSetting rgbDim("rgbDim", "Factor (1 to 200%) of the status LEDs"); static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX); #ifdef BME680 @@ -258,9 +261,9 @@ void bmpPublishValues() { String(bmx.readAltitude(SEALEVELPRESSURE_HPA))), MQTT_LOG_I2READ); if ( (rgbTemp.get()) && (!mSomethingReceived) ) { if (bmx.readTemperature() < TEMPBORDER) { - strip.setPixelColor(0, strip.Color(0,0,127)); + strip.setPixelColor(0, strip.Color(0,0,PERCENT2FACTOR(127, rgbDim))); } else { - strip.setPixelColor(0, strip.Color(127,0,0)); + strip.setPixelColor(0, strip.Color(PERCENT2FACTOR(127, rgbDim),0,0)); } strip.show(); } @@ -286,11 +289,11 @@ void loopHandler() particle.setProperty(NODE_PARTICLE).send(String(pM25)); if (!mSomethingReceived) { if (pM25 < 35) { - strip.fill(strip.Color(0, 127, 0)); /* green */ + strip.fill(strip.Color(0, PERCENT2FACTOR(127, rgbDim), 0)); /* green */ } else if (pM25 < 85) { - strip.fill(strip.Color(127, 64, 0)); /* orange */ + strip.fill(strip.Color(PERCENT2FACTOR(127, rgbDim), PERCENT2FACTOR(64, rgbDim), 0)); /* orange */ } else { - strip.fill(strip.Color(127, 0, 0)); /* red */ + strip.fill(strip.Color(PERCENT2FACTOR(127, rgbDim), 0, 0)); /* red */ } strip.show(); } @@ -373,6 +376,9 @@ void setup() Homie.onEvent(onHomieEvent); i2cEnable.setDefaultValue(false); rgbTemp.setDefaultValue(false); + rgbDim.setDefaultValue(100).setValidator([] (long candidate) { + return (candidate > 1) && (candidate <= 200); + }); memset(serialRxBuf, 0, 80); pmSerial.begin(PM1006_BIT_RATE); @@ -420,7 +426,7 @@ void setup() /* Extracted from library's example */ mFailedI2Cinitialization = !bmx.begin(); if (!mFailedI2Cinitialization) { - strip.fill(strip.Color(0,64,0)); + strip.fill(strip.Color(0,PERCENT2FACTOR(64, rgbDim),0)); strip.show(); #ifdef BME680 bmx.setTemperatureOversampling(BME680_OS_8X); @@ -443,7 +449,7 @@ void setup() } strip.fill(strip.Color(0,0,0)); for (int i=0;i < (PIXEL_COUNT / 2); i++) { - strip.setPixelColor(0, strip.Color(0,0,128)); + strip.setPixelColor(0, strip.Color(0,0,128 * rgbDim.get())); } strip.show(); } else { @@ -481,7 +487,7 @@ void loop() if (mButtonPressed > BUTTON_MAX_CYCLE) { mButtonPressed = (BUTTON_MAX_CYCLE -1); if (SPIFFS.exists("/homie/config.json")) { - strip.fill(strip.Color(0,128,0)); + strip.fill(strip.Color(0,PERCENT2FACTOR(127, rgbDim),0)); strip.show(); printf("Resetting config\r\n"); SPIFFS.remove("/homie/config.json"); From 21ba43bbf9cd591f54331a0667ddafcd29599630 Mon Sep 17 00:00:00 2001 From: Ollo Date: Wed, 15 Dec 2021 20:18:22 +0100 Subject: [PATCH 22/57] twice the same define... deleted second one --- src/main.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f3016bc..f480dc1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,9 +45,6 @@ #define SENSOR_I2C_SCK D5 /**< GPIO14 - I2C clock pin */ #define SENSOR_I2C_SDI D1 /**< GPIO5 - I2C data pin */ -#define PM1006_BIT_RATE 9600 -#define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ - #define SEALEVELPRESSURE_HPA (1013.25) #define BUTTON_MAX_CYCLE 10000U /**< Action: Reset configuration */ From c0aa9c8da15728f92f9d679f7ea0cf2db2dd1e5d Mon Sep 17 00:00:00 2001 From: Ollo Date: Wed, 15 Dec 2021 20:21:14 +0100 Subject: [PATCH 23/57] Reduce cycle time --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index f480dc1..6edcf81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,7 +39,7 @@ #define WITTY_RGB_G D6 /**< GPIO12 Used as 3.3V Power supply for the I2C Sensor */ #define WITTY_RGB_B D7 /**< GPIO13 */ #define PM1006_BIT_RATE 9600 -#define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ +#define PM1006_MQTT_UPDATE 30000 /**< Check the sensor every 30 seconds; New measurement is done every 20seconds by the PM1006 sensor */ #define PIXEL_COUNT 3 #define GPIO_BUTTON SENSOR_PM1006_RX /**< Button and software serial share one pin on Witty board */ #define SENSOR_I2C_SCK D5 /**< GPIO14 - I2C clock pin */ From 33ef6bc21b12db229263df41d169caf57d37c58d Mon Sep 17 00:00:00 2001 From: Ollo Date: Tue, 21 Dec 2021 13:18:46 +0100 Subject: [PATCH 24/57] Do not publish invalid PM2.5 values --- src/main.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 6edcf81..df5cf6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,6 +51,8 @@ #define BUTTON_MIN_ACTION_CYCLE 55U /**< Minimum cycle to react on the button (e.g. 5 second) */ #define BUTTON_CHECK_INTERVALL 100U /**< Check every 100 ms the button state */ +#define PM_MAX 1001 /**< According datasheet https://en.gassensor.com.cn/ParticulateMatterSensor/info_itemid_105.html 1000 is the maximum */ + #define LOG_TOPIC "log\0" #define MQTT_LEVEL_ERROR 1 #define MQTT_LEVEL_WARNING 10 @@ -188,7 +190,12 @@ int getSensorData() { // Header und Prüfsumme checken if (serialRxBuf[0] == 0x16 && serialRxBuf[1] == 0x11 && serialRxBuf[2] == 0x0B /* && checksum == 0 */) { - return (serialRxBuf[5] << 8 | serialRxBuf[6]); + int pmValue = (serialRxBuf[5] << 8 | serialRxBuf[6]); + if (pmValue > PM_MAX) { + return (-1); + } else { + return pmValue; + } } else { From c93c76ab5221837b5fa97d7d1843f3aadc45aabb Mon Sep 17 00:00:00 2001 From: Ollo Date: Thu, 23 Dec 2021 14:00:18 +0100 Subject: [PATCH 25/57] Manual merge from standalone; Added mMeasureIndex --- include/HomieSettings.h | 2 +- src/main.cpp | 40 +++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index f12788f..433486a 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,6 +13,6 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.2.0" +#define HOMIE_FIRMWARE_VERSION "2.2.1" #endif diff --git a/src/main.cpp b/src/main.cpp index df5cf6a..4c5901d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -84,6 +84,7 @@ #define NODE_HUMIDITY "humidity" #define NODE_AMBIENT "ambient" #define NODE_BUTTON "button" +#define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */ /****************************************************************************** * TYPE DEFS ******************************************************************************/ @@ -145,13 +146,15 @@ Adafruit_BMP280 bmx; // connected via I2C Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); // Variablen -uint8_t serialRxBuf[80]; +uint8_t serialRxBuf[SERIAL_RCEVBUF_MAX]; uint8_t rxBufIdx = 0; -int spm25 = 0; +int mParticle_pM25 = 0; int last = 0; unsigned int mButtonPressed = 0; bool mSomethingReceived = false; +uint32_t mMeasureIndex = 0; + /****************************************************************************** * LOCAL FUNCTIONS *****************************************************************************/ @@ -222,8 +225,17 @@ void onHomieEvent(const HomieEvent &event) strip.fill(strip.Color(0,0,128)); strip.show(); if (mFailedI2Cinitialization) { - log(MQTT_LEVEL_DEBUG, F("Could not find a valid BME680 sensor, check wiring or " - "try a different address!"), MQTT_LOG_I2CINIT); + log(MQTT_LEVEL_DEBUG, +#ifdef BME680 + "Could not find a valid BME680 sensor, check wiring or try a different address!" +#else +#ifdef BMP280 + "Could not find a valid BMP280 sensor, check wiring or try a different address!" +#else + "no I2C sensor defined" +#endif +#endif + , MQTT_LOG_I2CINIT); } else { log(MQTT_LEVEL_INFO, F("BME680 sensor found"), MQTT_LOG_I2CINIT); } @@ -248,7 +260,7 @@ void bmpPublishValues() { // Tell BME680 to begin measurement. unsigned long endTime = bmx.beginReading(); if (endTime == 0) { - log(MQTT_LEVEL_ERROR, F("BME680 not accessible"), MQTT_LOG_I2READ); + log(MQTT_LEVEL_ERROR, "BMX not accessible", MQTT_LOG_I2READ); return; } #endif @@ -288,13 +300,13 @@ void loopHandler() { static long lastRead = 0; if ((millis() - lastRead) > PM1006_MQTT_UPDATE) { - int pM25 = getSensorData(); - if (pM25 >= 0) { - particle.setProperty(NODE_PARTICLE).send(String(pM25)); + mParticle_pM25 = getSensorData(); + if (mParticle_pM25 >= 0) { + particle.setProperty(NODE_PARTICLE).send(String(mParticle_pM25)); if (!mSomethingReceived) { - if (pM25 < 35) { + if (mParticle_pM25 < 35) { strip.fill(strip.Color(0, PERCENT2FACTOR(127, rgbDim), 0)); /* green */ - } else if (pM25 < 85) { + } else if (mParticle_pM25 < 85) { strip.fill(strip.Color(PERCENT2FACTOR(127, rgbDim), PERCENT2FACTOR(64, rgbDim), 0)); /* orange */ } else { strip.fill(strip.Color(PERCENT2FACTOR(127, rgbDim), 0, 0)); /* red */ @@ -308,6 +320,8 @@ void loopHandler() bmpPublishValues(); } + mMeasureIndex++; + /* Clean cycles buttons */ if (mButtonPressed <= BUTTON_MIN_ACTION_CYCLE) { buttonNode.setProperty(NODE_BUTTON).send("0"); @@ -383,7 +397,7 @@ void setup() rgbDim.setDefaultValue(100).setValidator([] (long candidate) { return (candidate > 1) && (candidate <= 200); }); - memset(serialRxBuf, 0, 80); + memset(serialRxBuf, 0, SERIAL_RCEVBUF_MAX); pmSerial.begin(PM1006_BIT_RATE); Homie.setup(); @@ -447,6 +461,7 @@ void setup() Adafruit_BMP280::FILTER_X16, /* Filtering. */ Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ #endif + printf("Sensor found on I2C bus\r\n"); } else { printf("Failed to initialize I2C bus\r\n"); } @@ -488,8 +503,7 @@ void loop() digitalWrite(WITTY_RGB_R, LOW); } - if (mButtonPressed > BUTTON_MAX_CYCLE) { - mButtonPressed = (BUTTON_MAX_CYCLE -1); + if (mButtonPressed > BUTTON_MAX_CYCLE) { if (SPIFFS.exists("/homie/config.json")) { strip.fill(strip.Color(0,PERCENT2FACTOR(127, rgbDim),0)); strip.show(); From 210222799a57380de229b5d3eb21d3e42f934d47 Mon Sep 17 00:00:00 2001 From: Ollo Date: Thu, 23 Dec 2021 14:34:47 +0100 Subject: [PATCH 26/57] Prepared sleeping --- include/HomieSettings.h | 2 +- src/main.cpp | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 433486a..3501a0e 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,6 +13,6 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.2.1" +#define HOMIE_FIRMWARE_VERSION "2.3.0" #endif diff --git a/src/main.cpp b/src/main.cpp index 4c5901d..8dbc064 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,7 @@ #include #ifdef BME680 #include "Adafruit_BME680.h" -#else +#else #ifdef BMP280 #include "Adafruit_BMP280.h" #else @@ -51,6 +51,7 @@ #define BUTTON_MIN_ACTION_CYCLE 55U /**< Minimum cycle to react on the button (e.g. 5 second) */ #define BUTTON_CHECK_INTERVALL 100U /**< Check every 100 ms the button state */ +#define MIN_MEASURED_CYCLES 2 #define PM_MAX 1001 /**< According datasheet https://en.gassensor.com.cn/ParticulateMatterSensor/info_itemid_105.html 1000 is the maximum */ #define LOG_TOPIC "log\0" @@ -101,6 +102,7 @@ void log(int level, String message, int code); bool mConfigured = false; bool mConnected = false; +bool mOTAactive = false; /**< Stop sleeping, if OTA is running */ bool mFailedI2Cinitialization = false; long mLastButtonAction = 0; @@ -133,6 +135,7 @@ HomieSetting i2cEnable("i2c", ); HomieSetting rgbTemp("rgbTemp", "Show temperature via red (>20 °C) and blue (< 20°C)"); HomieSetting rgbDim("rgbDim", "Factor (1 to 200%) of the status LEDs"); +HomieSetting deepsleep("deepsleep", "Amount of seconds to sleep (default 0 - always online, maximum 4294 - 71 minutes)"); static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX); #ifdef BME680 @@ -214,6 +217,15 @@ void onHomieEvent(const HomieEvent &event) { switch (event.type) { + case HomieEventType::READY_TO_SLEEP: + if (mOTAactive) { + Homie.getLogger() << "Skip sleeping, as OTA was started" << endl; + return; + } else if (deepsleep.get() > 0) { + long sleepInSeconds = deepsleep.get(); + Homie.doDeepSleep(sleepInSeconds * 1000000, RF_NO_CAL); + } + break; case HomieEventType::MQTT_READY: mConnected=true; digitalWrite(WITTY_RGB_R, LOW); @@ -240,9 +252,8 @@ void onHomieEvent(const HomieEvent &event) log(MQTT_LEVEL_INFO, F("BME680 sensor found"), MQTT_LOG_I2CINIT); } break; - case HomieEventType::READY_TO_SLEEP: - break; case HomieEventType::OTA_STARTED: + mOTAactive = true; break; case HomieEventType::OTA_SUCCESSFUL: ESP.restart(); @@ -327,6 +338,13 @@ void loopHandler() buttonNode.setProperty(NODE_BUTTON).send("0"); } lastRead = millis(); + + /* If nothing needs to be done, sleep and the time is ready for sleeping */ + if (mMeasureIndex > MIN_MEASURED_CYCLES && (deepsleep.get() > 0) ) { + Homie.prepareToSleep(); + delay(100); + } + } /* if the user sees something via the LEDs, inform MQTT, too */ @@ -397,6 +415,9 @@ void setup() rgbDim.setDefaultValue(100).setValidator([] (long candidate) { return (candidate > 1) && (candidate <= 200); }); + deepsleep.setDefaultValue(0).setValidator([] (long candidate) { + return ((candidate >= 0) && (candidate < 4294)); /* between 0 (deactivated) and 71 minutes */ + }); memset(serialRxBuf, 0, SERIAL_RCEVBUF_MAX); pmSerial.begin(PM1006_BIT_RATE); From 02a5095bf6138dd3c1f18fdea6684e841dd8fd98 Mon Sep 17 00:00:00 2001 From: Ollo Date: Thu, 23 Dec 2021 15:29:49 +0100 Subject: [PATCH 27/57] keep the RGB status, during sleeping --- src/main.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8dbc064..4f18485 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -234,8 +234,12 @@ void onHomieEvent(const HomieEvent &event) log(MQTT_LEVEL_INFO, F("I2C powersupply deactivated"), MQTT_LOG_I2CINIT); } digitalWrite(WITTY_RGB_B, LOW); - strip.fill(strip.Color(0,0,128)); - strip.show(); + /* Update LED only, if not sleeping */ + if (deepsleep.get() <= 0) { + strip.fill(strip.Color(0,0,PERCENT2FACTOR(127, rgbDim))); + strip.show(); + } + if (mFailedI2Cinitialization) { log(MQTT_LEVEL_DEBUG, #ifdef BME680 @@ -487,11 +491,14 @@ void setup() printf("Failed to initialize I2C bus\r\n"); } } - strip.fill(strip.Color(0,0,0)); - for (int i=0;i < (PIXEL_COUNT / 2); i++) { - strip.setPixelColor(0, strip.Color(0,0,128 * rgbDim.get())); + /* Nothing when sleeping */ + if (deepsleep.get() <= 0) { + strip.fill(strip.Color(0,0,0)); + for (int i=0;i < (PIXEL_COUNT / 2); i++) { + strip.setPixelColor(0, strip.Color(0,0,128 * rgbDim.get())); + } + strip.show(); } - strip.show(); } else { digitalWrite(WITTY_RGB_R, HIGH); strip.fill(strip.Color(128,0,0)); From f8279c219623f9ec8ddba8e58feae1e99e2bdb03 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 20:44:08 +0200 Subject: [PATCH 28/57] Imported library from https://github.com/KinDR007/VictronMPPT-ESPHOME --- include/HomieSettings.h | 5 +- include/victron.h | 108 +++++++ src/main.cpp | 9 +- src/victron.cpp | 633 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 753 insertions(+), 2 deletions(-) create mode 100644 include/victron.h create mode 100644 src/victron.cpp diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 3501a0e..a544a92 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,6 +13,9 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.3.0" +#define HOMIE_FIRMWARE_VERSION "2.4.0" + + +#define SERIAL_BAUDRATE 19200 #endif diff --git a/include/victron.h b/include/victron.h new file mode 100644 index 0000000..9a06321 --- /dev/null +++ b/include/victron.h @@ -0,0 +1,108 @@ +/** + * @file victron.h + * @author Icefest + * @brief Wrapper for Victron MPPT + * @version 0.1 + * + * Inspired by: + * https://github.com/KinDR007/VictronMPPT-ESPHOME/blob/main/components/victron/victron.h + */ + +#ifndef VICTRON_MPPT +#define VICTRON_MPPT + +#include +#include + +namespace victron { + +class VictronComponent { + public: + VictronComponent(int initialstate); + VictronComponent(); + ~VictronComponent(); + void loop(void); + uint32_t getPanelVoltageSensor(void); + uint32_t getPanelPowerSensor(void); + uint32_t getBatteryVoltageSensor(void); + uint32_t getBatteryVoltage2Sensor(void); + uint32_t getBatteryVoltage3Sensor(void); + uint32_t getBatteryCurrentSensor(void); + uint32_t getBatteryCurrent_2Sensor(void); + uint32_t getBatteryCurrent_3Sensor(void); + uint32_t getLoadCurrentSensor(void); + + std::string getFirmwareVersion(void); + std::string getFirmware_version_24bit_textSensor(void); + std::string getSerialNumber(void); + + protected: + void handle_value_(); + +private: + bool publishing_; + int state_; + std::string label_; + std::string value_; + uint32_t last_transmission_; + uint32_t last_publish_; + uint32_t throttle_; + + void log(String tag, String message); + + + /* All Settings */ + + int max_power_yesterday_sensor_ = 0; + int max_power_today_sensor_ = 0; + float yield_total_sensor_ = 0; + float yield_yesterday_sensor_ = 0; + float yield_today_sensor_ = 0; + int panel_voltage_sensor_ = 0; + int panel_power_sensor_ = 0; + int battery_voltage_sensor_ = 0; + int battery_voltage_2_sensor_ = 0; + int battery_voltage_3_sensor_ = 0; + int auxiliary_battery_voltage_sensor_ = 0; + int midpoint_voltage_of_the_battery_bank_sensor_ = 0; + int midpoint_deviation_of_the_battery_bank_sensor_ = 0; + int battery_current_sensor_ = 0; + int battery_current_2_sensor_ = 0; + int battery_current_3_sensor_ = 0; + int ac_out_voltage_sensor_ = 0; + int ac_out_current_sensor_ = 0; + int ac_out_apparent_power_sensor_ = 0; + int load_current_sensor_ = 0; + int day_number_sensor_ = 0; + int device_mode_sensor_ = 0; + int charging_mode_id_sensor_ = 0; + int error_code_sensor_ = 0; + int warning_code_sensor_ = 0; + int tracking_mode_id_sensor_ = 0; + int device_mode_id_sensor_ = 0; + int dc_monitor_mode_id_sensor_ = 0; + int off_reason_bitmask_sensor_ = 0; + + + bool load_state_binary_sensor_; + + std::string alarm_condition_active_text_sensor_; + + std::string charging_mode_text_sensor_; + std::string error_text_sensor_; + std::string warning_text_sensor_; + std::string tracking_mode_text_sensor_; + std::string device_mode_text_sensor_; + std::string firmware_version_text_sensor_; + std::string firmware_version_24bit_text_sensor_; + std::string device_type_text_sensor_; + std::string serial_number_text_sensor_; + std::string hardware_revision_text_sensor_; + std::string dc_monitor_mode_text_sensor_; + std::string off_reason_text_sensor_; + +}; + +} // namespace victron + +#endif /* End of VICTRON_MPPT */ \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4f18485..f97c869 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef BME680 #include "Adafruit_BME680.h" #else @@ -148,6 +149,8 @@ Adafruit_BMP280 bmx; // connected via I2C Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); +victron::VictronComponent mppt(0); + // Variablen uint8_t serialRxBuf[SERIAL_RCEVBUF_MAX]; uint8_t rxBufIdx = 0; @@ -356,6 +359,9 @@ void loopHandler() buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); } + // Read victron MPPT + mppt.loop(); + // Feed the dog -> ESP stay alive ESP.wdtFeed(); } @@ -402,8 +408,9 @@ bool ledHandler(const HomieRange& range, const String& value) { void setup() { SPIFFS.begin(); - Serial.begin(115200); + Serial.begin(SERIAL_BAUDRATE); Serial.setTimeout(2000); + pinMode(WITTY_RGB_R, OUTPUT); pinMode(WITTY_RGB_G, OUTPUT); pinMode(WITTY_RGB_B, OUTPUT); diff --git a/src/victron.cpp b/src/victron.cpp new file mode 100644 index 0000000..f87ccf4 --- /dev/null +++ b/src/victron.cpp @@ -0,0 +1,633 @@ +/** + * @file victron.cpp + * @author Icefest + * @brief Wrapper for Victron MPPT + * @version 0.1 + * + * Inspired by: + * https://github.com/KinDR007/VictronMPPT-ESPHOME/blob/main/components/victron/victron.cpp + */ + +#include "victron.h" + +namespace victron { + + static const char *const TAG = "victron"; + + static const uint8_t OFF_REASONS_SIZE = 16; + static const char *const OFF_REASONS[OFF_REASONS_SIZE] = { + "No input power", // 0000 0000 0000 0001 + "Switched off (power switch)", // 0000 0000 0000 0010 + "Switched off (device mode register)", // 0000 0000 0000 0100 + "Remote input", // 0000 0000 0000 1000 + "Protection active", // 0000 0000 0001 0000 + "Paygo", // 0000 0000 0010 0000 + "BMS", // 0000 0000 0100 0000 + "Engine shutdown detection", // 0000 0000 1000 0000 + "Analysing input voltage", // 0000 0001 0000 0000 + "Unknown: Bit 10", // 0000 0010 0000 0000 + "Unknown: Bit 11", // 0000 0100 0000 0000 + "Unknown: Bit 12", // 0000 1000 0000 0000 + "Unknown: Bit 13", // 0001 0000 0000 0000 + "Unknown: Bit 14", // 0010 0000 0000 0000 + "Unknown: Bit 15", // 0100 0000 0000 0000 + "Unknown: Bit 16", // 1000 0000 0000 0000 + }; + + + static std::string tracking_mode_text(int value) { + switch (value) { + case 0: + return "Off"; + case 1: + return "Limited"; + case 2: + return "Active"; + default: + return "Unknown"; + } + } + + static std::string error_code_text(int value) { + switch (value) { + case 0: + return "No error"; + case 2: + return "Battery voltage too high"; + case 17: + return "Charger temperature too high"; + case 18: + return "Charger over current"; + case 19: + return "Charger current reversed"; + case 20: + return "Bulk time limit exceeded"; + case 21: + return "Current sensor issue"; + case 26: + return "Terminals overheated"; + case 28: + return "Converter issue"; + case 33: + return "Input voltage too high (solar panel)"; + case 34: + return "Input current too high (solar panel)"; + case 38: + return "Input shutdown (excessive battery voltage)"; + case 39: + return "Input shutdown (due to current flow during off mode)"; + case 65: + return "Lost communication with one of devices"; + case 66: + return "Synchronised charging device configuration issue"; + case 67: + return "BMS connection lost"; + case 68: + return "Network misconfigured"; + case 116: + return "Factory calibration data lost"; + case 117: + return "Invalid/incompatible firmware"; + case 119: + return "User settings invalid"; + default: + return "Unknown"; + } + } + + + + static std::string charging_mode_text(int value) { + switch (value) { + case 0: + return "Off"; + case 1: + return "Low power"; + case 2: + return "Fault"; + case 3: + return "Bulk"; + case 4: + return "Absorption"; + case 5: + return "Float"; + case 6: + return "Storage"; + case 7: + return "Equalize (manual)"; + case 9: + return "Inverting"; + case 11: + return "Power supply"; + case 245: + return "Starting-up"; + case 246: + return "Repeated absorption"; + case 247: + return "Auto equalize / Recondition"; + case 248: + return "BatterySafe"; + case 252: + return "External control"; + default: + return "Unknown"; + } + } + + + + static std::string device_type_text(int value) + { + switch (value) { + case 0x203: + return "BMV-700"; + case 0x204: + return "BMV-702"; + case 0x205: + return "BMV-700H"; + case 0x0300: + return "BlueSolar MPPT 70|15"; + case 0xA040: + return "BlueSolar MPPT 75|50"; + case 0xA041: + return "BlueSolar MPPT 150|35"; + case 0xA042: + return "BlueSolar MPPT 75|15"; + case 0xA043: + return "BlueSolar MPPT 100|15"; + case 0xA044: + return "BlueSolar MPPT 100|30"; + case 0xA045: + return "BlueSolar MPPT 100|50"; + case 0xA046: + return "BlueSolar MPPT 150|70"; + case 0xA047: + return "BlueSolar MPPT 150|100"; + case 0xA049: + return "BlueSolar MPPT 100|50 rev2"; + case 0xA04A: + return "BlueSolar MPPT 100|30 rev2"; + case 0xA04B: + return "BlueSolar MPPT 150|35 rev2"; + case 0xA04C: + return "BlueSolar MPPT 75|10"; + case 0xA04D: + return "BlueSolar MPPT 150|45"; + case 0xA04E: + return "BlueSolar MPPT 150|60"; + case 0xA04F: + return "BlueSolar MPPT 150|85"; + case 0xA050: + return "SmartSolar MPPT 250|100"; + case 0xA051: + return "SmartSolar MPPT 150|100"; + case 0xA052: + return "SmartSolar MPPT 150|85"; + case 0xA053: + return "SmartSolar MPPT 75|15"; + case 0xA075: + return "SmartSolar MPPT 75|15 rev2"; + case 0xA054: + return "SmartSolar MPPT 75|10"; + case 0xA074: + return "SmartSolar MPPT 75|10 rev2"; + case 0xA055: + return "SmartSolar MPPT 100|15"; + case 0xA056: + return "SmartSolar MPPT 100|30"; + case 0xA073: + return "SmartSolar MPPT 150|45 rev3"; + case 0xA057: + return "SmartSolar MPPT 100|50"; + case 0xA058: + return "SmartSolar MPPT 150|35"; + case 0xA059: + return "SmartSolar MPPT 150|100 rev2"; + case 0xA05A: + return "SmartSolar MPPT 150|85 rev2"; + case 0xA05B: + return "SmartSolar MPPT 250|70"; + case 0xA05C: + return "SmartSolar MPPT 250|85"; + case 0xA05D: + return "SmartSolar MPPT 250|60"; + case 0xA05E: + return "SmartSolar MPPT 250|45"; + case 0xA05F: + return "SmartSolar MPPT 100|20"; + case 0xA060: + return "SmartSolar MPPT 100|20 48V"; + case 0xA061: + return "SmartSolar MPPT 150|45"; + case 0xA062: + return "SmartSolar MPPT 150|60"; + case 0xA063: + return "SmartSolar MPPT 150|70"; + case 0xA064: + return "SmartSolar MPPT 250|85 rev2"; + case 0xA065: + return "SmartSolar MPPT 250|100 rev2"; + case 0xA066: + return "BlueSolar MPPT 100|20"; + case 0xA067: + return "BlueSolar MPPT 100|20 48V"; + case 0xA068: + return "SmartSolar MPPT 250|60 rev2"; + case 0xA069: + return "SmartSolar MPPT 250|70 rev2"; + case 0xA06A: + return "SmartSolar MPPT 150|45 rev2"; + case 0xA06B: + return "SmartSolar MPPT 150|60 rev2"; + case 0xA06C: + return "SmartSolar MPPT 150|70 rev2"; + case 0xA06D: + return "SmartSolar MPPT 150|85 rev3"; + case 0xA06E: + return "SmartSolar MPPT 150|100 rev3"; + case 0xA06F: + return "BlueSolar MPPT 150|45 rev2"; + case 0xA070: + return "BlueSolar MPPT 150|60 rev2"; + case 0xA071: + return "BlueSolar MPPT 150|70 rev2"; + case 0xA07D: + return "BlueSolar MPPT 75|15 rev3"; + case 0xA102: + return "SmartSolar MPPT VE.Can 150/70"; + case 0xA103: + return "SmartSolar MPPT VE.Can 150/45"; + case 0xA104: + return "SmartSolar MPPT VE.Can 150/60"; + case 0xA105: + return "SmartSolar MPPT VE.Can 150/85"; + case 0xA106: + return "SmartSolar MPPT VE.Can 150/100"; + case 0xA107: + return "SmartSolar MPPT VE.Can 250/45"; + case 0xA108: + return "SmartSolar MPPT VE.Can 250/60"; + case 0xA109: + return "SmartSolar MPPT VE.Can 250/70"; + case 0xA10A: + return "SmartSolar MPPT VE.Can 250/85"; + case 0xA10B: + return "SmartSolar MPPT VE.Can 250/100"; + case 0xA10C: + return "SmartSolar MPPT VE.Can 150/70 rev2"; + case 0xA10D: + return "SmartSolar MPPT VE.Can 150/85 rev2"; + case 0xA10E: + return "SmartSolar MPPT VE.Can 150/100 rev2"; + case 0xA10F: + return "BlueSolar MPPT VE.Can 150/100"; + case 0xA112: + return "BlueSolar MPPT VE.Can 250/70"; + case 0xA113: + return "BlueSolar MPPT VE.Can 250/100"; + case 0xA114: + return "SmartSolar MPPT VE.Can 250/70 rev2"; + case 0xA115: + return "SmartSolar MPPT VE.Can 250/100 rev2"; + case 0xA116: + return "SmartSolar MPPT VE.Can 250/85 rev2"; + case 0xA201: + return "Phoenix Inverter 12V 250VA 230V"; + case 0xA202: + return "Phoenix Inverter 24V 250VA 230V"; + case 0xA204: + return "Phoenix Inverter 48V 250VA 230V"; + case 0xA211: + return "Phoenix Inverter 12V 375VA 230V"; + case 0xA212: + return "Phoenix Inverter 24V 375VA 230V"; + case 0xA214: + return "Phoenix Inverter 48V 375VA 230V"; + case 0xA221: + return "Phoenix Inverter 12V 500VA 230V"; + case 0xA222: + return "Phoenix Inverter 24V 500VA 230V"; + case 0xA224: + return "Phoenix Inverter 48V 500VA 230V"; + case 0xA231: + return "Phoenix Inverter 12V 250VA 230V"; + case 0xA232: + return "Phoenix Inverter 24V 250VA 230V"; + case 0xA234: + return "Phoenix Inverter 48V 250VA 230V"; + case 0xA239: + return "Phoenix Inverter 12V 250VA 120V"; + case 0xA23A: + return "Phoenix Inverter 24V 250VA 120V"; + case 0xA23C: + return "Phoenix Inverter 48V 250VA 120V"; + case 0xA241: + return "Phoenix Inverter 12V 375VA 230V"; + case 0xA242: + return "Phoenix Inverter 24V 375VA 230V"; + case 0xA244: + return "Phoenix Inverter 48V 375VA 230V"; + case 0xA249: + return "Phoenix Inverter 12V 375VA 120V"; + case 0xA24A: + return "Phoenix Inverter 24V 375VA 120V"; + case 0xA24C: + return "Phoenix Inverter 48V 375VA 120V"; + case 0xA251: + return "Phoenix Inverter 12V 500VA 230V"; + case 0xA252: + return "Phoenix Inverter 24V 500VA 230V"; + case 0xA254: + return "Phoenix Inverter 48V 500VA 230V"; + case 0xA259: + return "Phoenix Inverter 12V 500VA 120V"; + case 0xA25A: + return "Phoenix Inverter 24V 500VA 120V"; + case 0xA25C: + return "Phoenix Inverter 48V 500VA 120V"; + case 0xA261: + return "Phoenix Inverter 12V 800VA 230V"; + case 0xA262: + return "Phoenix Inverter 24V 800VA 230V"; + case 0xA264: + return "Phoenix Inverter 48V 800VA 230V"; + case 0xA269: + return "Phoenix Inverter 12V 800VA 120V"; + case 0xA26A: + return "Phoenix Inverter 24V 800VA 120V"; + case 0xA26C: + return "Phoenix Inverter 48V 800VA 120V"; + case 0xA271: + return "Phoenix Inverter 12V 1200VA 230V"; + case 0xA272: + return "Phoenix Inverter 24V 1200VA 230V"; + case 0xA274: + return "Phoenix Inverter 48V 1200VA 230V"; + case 0xA279: + case 0xA2F9: + return "Phoenix Inverter 12V 1200VA 120V"; + case 0xA27A: + return "Phoenix Inverter 24V 1200VA 120V"; + case 0xA27C: + return "Phoenix Inverter 48V 1200VA 120V"; + case 0xA281: + return "Phoenix Inverter 12V 1600VA 230V"; + case 0xA282: + return "Phoenix Inverter 24V 1600VA 230V"; + case 0xA284: + return "Phoenix Inverter 48V 1600VA 230V"; + case 0xA291: + return "Phoenix Inverter 12V 2000VA 230V"; + case 0xA292: + return "Phoenix Inverter 24V 2000VA 230V"; + case 0xA294: + return "Phoenix Inverter 48V 2000VA 230V"; + case 0xA2A1: + return "Phoenix Inverter 12V 3000VA 230V"; + case 0xA2A2: + return "Phoenix Inverter 24V 3000VA 230V"; + case 0xA2A4: + return "Phoenix Inverter 48V 3000VA 230V"; + case 0xA30A: + return "Blue Smart IP65 Charger 12|25"; + case 0xA332: + return "Blue Smart IP22 Charger 24|8"; + case 0xA334: + return "Blue Smart IP22 Charger 24|12"; + case 0xA336: + return "Blue Smart IP22 Charger 24|16"; + case 0xA340: + return "Phoenix Smart IP43 Charger 12|50 (1+1)"; + case 0xA341: + return "Phoenix Smart IP43 Charger 12|50 (3)"; + case 0xA342: + return "Phoenix Smart IP43 Charger 24|25 (1+1)"; + case 0xA343: + return "Phoenix Smart IP43 Charger 24|25 (3)"; + case 0xA344: + return "Phoenix Smart IP43 Charger 12|30 (1+1)"; + case 0xA345: + return "Phoenix Smart IP43 Charger 12|30 (3)"; + case 0xA346: + return "Phoenix Smart IP43 Charger 24|16 (1+1)"; + case 0xA347: + return "Phoenix Smart IP43 Charger 24|16 (3)"; + case 0xA381: + return "BMV-712 Smart"; + case 0xA382: + return "BMV-710H Smart"; + case 0xA383: + return "BMV-712 Smart Rev2"; + case 0xA389: + return "SmartShunt 500A/50mV"; + case 0xA38A: + return "SmartShunt 1000A/50mV"; + case 0xA38B: + return "SmartShunt 2000A/50mV"; + case 0xA442: + return "Multi RS Solar 48V 6000VA 230V"; + default: + return "Unknown"; + } + } + + VictronComponent::VictronComponent() + { + this->state_ = 0; + } + + VictronComponent::~VictronComponent() + { + + } + + VictronComponent::VictronComponent(int initialstate) + { + this->state_ = initialstate; + } + + void VictronComponent::log(String tag, String message) + { + Serial << tag << " : " << message << endl; + Serial.flush(); + } + + void VictronComponent::loop() + { + const uint32_t now = millis(); + if ((state_ > 0) && (now - last_transmission_ >= 200)) { + // last transmission too long ago. Reset RX index. + log(TAG, "Last transmission too long ago"); + state_ = 0; + } + + if (!Serial.available()) + return; + + last_transmission_ = now; + while (Serial.available()) { + uint8_t c; + c = Serial.read(); + if (state_ == 0) { + if (c == '\r' || c == '\n') { + continue; + } + label_.clear(); + value_.clear(); + state_ = 1; + } + if (state_ == 1) { + // Start of a ve.direct hex frame + if (c == ':') { + state_ = 3; + continue; + } + if (c == '\t') { + state_ = 2; + } else { + label_.push_back(c); + } + continue; + } + if (state_ == 2) { + if (label_ == "Checksum") { + state_ = 0; + // The checksum is used as end of frame indicator + if (now - this->last_publish_ >= this->throttle_) { + this->last_publish_ = now; + this->publishing_ = true; + } else { + this->publishing_ = false; + } + continue; + } + if (c == '\r' || c == '\n') { + if (this->publishing_) { + handle_value_(); + } + state_ = 0; + } else { + value_.push_back(c); + } + } + // Discard ve.direct hex frame + if (state_ == 3) { + if (c == '\r' || c == '\n') { + state_ = 0; + } + } + } + } + + void VictronComponent::handle_value_() + { + int value; + + if (label_ == "V") { + battery_voltage_sensor_ = atoi(value_.c_str()); /* mV */ + return; + } + + if (label_ == "VPV") { + // mV to V + panel_voltage_sensor_ = atoi(value_.c_str()); /* mV */ + return; + } + + if (label_ == "PPV") { + panel_power_sensor_ = atoi(value_.c_str()); + return; + } + + if (label_ == "I") { + // mA to A + battery_current_sensor_ = atoi(value_.c_str()); /* mA */ + return; + } + + if (label_ == "IL") { + load_current_sensor_ = atoi(value_.c_str()); /* mA */ + return; + } + + if (label_ == "LOAD") { + load_state_binary_sensor_= (value_ == "ON" || value_ == "On"); + return; + } + + if (label_ == "Alarm") { + alarm_condition_active_text_sensor_ = value_; + return; + } + + if (label_ == "H19") { + yield_total_sensor_ = (atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + return; + } + + if (label_ == "H20") { + yield_today_sensor_ = (atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + return; + } + + if (label_ == "H21") { + max_power_today_sensor_ = (atoi(value_.c_str())); // NOLINT(cert-err34-c) + return; + } + + if (label_ == "H22") { + yield_yesterday_sensor_ = (atoi(value_.c_str()) * 10.0f); // NOLINT(cert-err34-c) + return; + } + + if (label_ == "H23") { + max_power_yesterday_sensor_ = atoi(value_.c_str()); + return; + } + + if (label_ == "ERR") { + value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + error_code_sensor_ = value; + error_text_sensor_ = error_code_text(value); + return; + } + + if (label_ == "CS") { + value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + charging_mode_id_sensor_ = value; + charging_mode_text_sensor_ = charging_mode_text(value); + return; + } + + + if (label_ == "FW") { + firmware_version_text_sensor_ = value_.insert(value_.size() - 2, "."); + return; + } + + + if (label_ == "PID") { + device_type_text_sensor_ = device_type_text(strtol(value_.c_str(), nullptr, 0)); + return; + } + + if (label_ == "SER#") { + serial_number_text_sensor_ = value_; + return; + } + + if (label_ == "HSDS") { + day_number_sensor_ = atoi(value_.c_str()); + return; + } + + if (label_ == "MPPT") { + value = atoi(value_.c_str()); // NOLINT(cert-err34-c) + tracking_mode_id_sensor_ = value; + tracking_mode_text_sensor_ = tracking_mode_text(value); + return; + } + + Serial << TAG << " : Unhandled property:" << label_.c_str() << " : " << value_.c_str() << endl; + } +} From f2465f3c7a8ea3868ef29caf8475e7bf7ffeb277 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 20:56:41 +0200 Subject: [PATCH 29/57] Reduced variables to needed --- include/victron.h | 141 +++++++++++++++++----------------------------- src/victron.cpp | 29 ++-------- 2 files changed, 57 insertions(+), 113 deletions(-) diff --git a/include/victron.h b/include/victron.h index 9a06321..ec05330 100644 --- a/include/victron.h +++ b/include/victron.h @@ -14,94 +14,59 @@ #include #include -namespace victron { - -class VictronComponent { - public: - VictronComponent(int initialstate); - VictronComponent(); - ~VictronComponent(); - void loop(void); - uint32_t getPanelVoltageSensor(void); - uint32_t getPanelPowerSensor(void); - uint32_t getBatteryVoltageSensor(void); - uint32_t getBatteryVoltage2Sensor(void); - uint32_t getBatteryVoltage3Sensor(void); - uint32_t getBatteryCurrentSensor(void); - uint32_t getBatteryCurrent_2Sensor(void); - uint32_t getBatteryCurrent_3Sensor(void); - uint32_t getLoadCurrentSensor(void); - - std::string getFirmwareVersion(void); - std::string getFirmware_version_24bit_textSensor(void); - std::string getSerialNumber(void); - - protected: - void handle_value_(); - -private: - bool publishing_; - int state_; - std::string label_; - std::string value_; - uint32_t last_transmission_; - uint32_t last_publish_; - uint32_t throttle_; - - void log(String tag, String message); - - - /* All Settings */ - - int max_power_yesterday_sensor_ = 0; - int max_power_today_sensor_ = 0; - float yield_total_sensor_ = 0; - float yield_yesterday_sensor_ = 0; - float yield_today_sensor_ = 0; - int panel_voltage_sensor_ = 0; - int panel_power_sensor_ = 0; - int battery_voltage_sensor_ = 0; - int battery_voltage_2_sensor_ = 0; - int battery_voltage_3_sensor_ = 0; - int auxiliary_battery_voltage_sensor_ = 0; - int midpoint_voltage_of_the_battery_bank_sensor_ = 0; - int midpoint_deviation_of_the_battery_bank_sensor_ = 0; - int battery_current_sensor_ = 0; - int battery_current_2_sensor_ = 0; - int battery_current_3_sensor_ = 0; - int ac_out_voltage_sensor_ = 0; - int ac_out_current_sensor_ = 0; - int ac_out_apparent_power_sensor_ = 0; - int load_current_sensor_ = 0; - int day_number_sensor_ = 0; - int device_mode_sensor_ = 0; - int charging_mode_id_sensor_ = 0; - int error_code_sensor_ = 0; - int warning_code_sensor_ = 0; - int tracking_mode_id_sensor_ = 0; - int device_mode_id_sensor_ = 0; - int dc_monitor_mode_id_sensor_ = 0; - int off_reason_bitmask_sensor_ = 0; - - - bool load_state_binary_sensor_; - - std::string alarm_condition_active_text_sensor_; - - std::string charging_mode_text_sensor_; - std::string error_text_sensor_; - std::string warning_text_sensor_; - std::string tracking_mode_text_sensor_; - std::string device_mode_text_sensor_; - std::string firmware_version_text_sensor_; - std::string firmware_version_24bit_text_sensor_; - std::string device_type_text_sensor_; - std::string serial_number_text_sensor_; - std::string hardware_revision_text_sensor_; - std::string dc_monitor_mode_text_sensor_; - std::string off_reason_text_sensor_; - -}; +namespace victron +{ + + class VictronComponent + { + public: + VictronComponent(int initialstate); + VictronComponent(); + ~VictronComponent(); + void loop(void); + + private: + void handle_value_(); + void log(String tag, String message); + /* States during serial parsing */ + bool publishing_; + int state_; + std::string label_; + std::string value_; + uint32_t last_transmission_; + uint32_t last_publish_; + uint32_t throttle_; + + + /* All Settings */1 + int max_power_yesterday_sensor_ = 0; + int max_power_today_sensor_ = 0; + float yield_total_sensor_ = 0; + float yield_yesterday_sensor_ = 0; + float yield_today_sensor_ = 0; + int panel_voltage_sensor_ = 0; + int panel_power_sensor_ = 0; + int battery_voltage_sensor_ = 0; + int battery_current_sensor_ = 0; + int load_current_sensor_ = 0; + int day_number_sensor_ = 0; + int charging_mode_id_sensor_ = 0; + int error_code_sensor_ = 0; + int tracking_mode_id_sensor_ = 0; + + + bool load_state_binary_sensor_; + + std::string alarm_condition_active_text_sensor_; + + std::string charging_mode_text_sensor_; + std::string error_text_sensor_; + std::string tracking_mode_text_sensor_; + std::string firmware_version_text_sensor_; + std::string device_type_text_sensor_; + std::string serial_number_text_sensor_; + + }; } // namespace victron diff --git a/src/victron.cpp b/src/victron.cpp index f87ccf4..881df44 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -14,28 +14,7 @@ namespace victron { static const char *const TAG = "victron"; - static const uint8_t OFF_REASONS_SIZE = 16; - static const char *const OFF_REASONS[OFF_REASONS_SIZE] = { - "No input power", // 0000 0000 0000 0001 - "Switched off (power switch)", // 0000 0000 0000 0010 - "Switched off (device mode register)", // 0000 0000 0000 0100 - "Remote input", // 0000 0000 0000 1000 - "Protection active", // 0000 0000 0001 0000 - "Paygo", // 0000 0000 0010 0000 - "BMS", // 0000 0000 0100 0000 - "Engine shutdown detection", // 0000 0000 1000 0000 - "Analysing input voltage", // 0000 0001 0000 0000 - "Unknown: Bit 10", // 0000 0010 0000 0000 - "Unknown: Bit 11", // 0000 0100 0000 0000 - "Unknown: Bit 12", // 0000 1000 0000 0000 - "Unknown: Bit 13", // 0001 0000 0000 0000 - "Unknown: Bit 14", // 0010 0000 0000 0000 - "Unknown: Bit 15", // 0100 0000 0000 0000 - "Unknown: Bit 16", // 1000 0000 0000 0000 - }; - - - static std::string tracking_mode_text(int value) { + std::string tracking_mode_text(int value) { switch (value) { case 0: return "Off"; @@ -48,7 +27,7 @@ namespace victron { } } - static std::string error_code_text(int value) { + std::string error_code_text(int value) { switch (value) { case 0: return "No error"; @@ -97,7 +76,7 @@ namespace victron { - static std::string charging_mode_text(int value) { + std::string charging_mode_text(int value) { switch (value) { case 0: return "Off"; @@ -136,7 +115,7 @@ namespace victron { - static std::string device_type_text(int value) + std::string device_type_text(int value) { switch (value) { case 0x203: From 3befbc0d5b1f133e8a50f140974937f0a9391698 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 21:02:50 +0200 Subject: [PATCH 30/57] Reduced string variables mad the project compileable --- include/victron.h | 6 ++---- src/victron.cpp | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/victron.h b/include/victron.h index ec05330..839a14f 100644 --- a/include/victron.h +++ b/include/victron.h @@ -38,7 +38,7 @@ namespace victron uint32_t throttle_; - /* All Settings */1 + /* All Settings */ int max_power_yesterday_sensor_ = 0; int max_power_today_sensor_ = 0; float yield_total_sensor_ = 0; @@ -59,11 +59,9 @@ namespace victron std::string alarm_condition_active_text_sensor_; - std::string charging_mode_text_sensor_; std::string error_text_sensor_; - std::string tracking_mode_text_sensor_; std::string firmware_version_text_sensor_; - std::string device_type_text_sensor_; + long device_type_text_sensor_; std::string serial_number_text_sensor_; }; diff --git a/src/victron.cpp b/src/victron.cpp index 881df44..5cb7b80 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -574,7 +574,6 @@ namespace victron { if (label_ == "CS") { value = atoi(value_.c_str()); // NOLINT(cert-err34-c) charging_mode_id_sensor_ = value; - charging_mode_text_sensor_ = charging_mode_text(value); return; } @@ -586,7 +585,7 @@ namespace victron { if (label_ == "PID") { - device_type_text_sensor_ = device_type_text(strtol(value_.c_str(), nullptr, 0)); + device_type_text_sensor_ = strtol(value_.c_str(), nullptr, 0); return; } @@ -603,7 +602,6 @@ namespace victron { if (label_ == "MPPT") { value = atoi(value_.c_str()); // NOLINT(cert-err34-c) tracking_mode_id_sensor_ = value; - tracking_mode_text_sensor_ = tracking_mode_text(value); return; } From 0ec51ac1d596fe2e9c4bb20ca8920a9a98beec18 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 21:36:04 +0200 Subject: [PATCH 31/57] Victron data is written to serial console --- include/victron.h | 6 +++++- src/main.cpp | 1 + src/victron.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/include/victron.h b/include/victron.h index 839a14f..99eba3d 100644 --- a/include/victron.h +++ b/include/victron.h @@ -24,10 +24,15 @@ namespace victron VictronComponent(); ~VictronComponent(); void loop(void); + void dump_config(void); private: void handle_value_(); void log(String tag, String message); + void logTextSensor(String tag, String message, std::string text); + void logBinarySensor(String tag, String message, bool flag); + void logSensor(String tag, String message, int number); + /* States during serial parsing */ bool publishing_; int state_; @@ -59,7 +64,6 @@ namespace victron std::string alarm_condition_active_text_sensor_; - std::string error_text_sensor_; std::string firmware_version_text_sensor_; long device_type_text_sensor_; std::string serial_number_text_sensor_; diff --git a/src/main.cpp b/src/main.cpp index f97c869..1f210e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -352,6 +352,7 @@ void loopHandler() delay(100); } + mppt.dump_config(); } /* if the user sees something via the LEDs, inform MQTT, too */ diff --git a/src/victron.cpp b/src/victron.cpp index 5cb7b80..114d9c6 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -26,7 +26,7 @@ namespace victron { return "Unknown"; } } - + std::string error_code_text(int value) { switch (value) { case 0: @@ -115,7 +115,7 @@ namespace victron { - std::string device_type_text(int value) + std::string device_type_text(long value) { switch (value) { case 0x203: @@ -431,6 +431,24 @@ namespace victron { Serial.flush(); } + void VictronComponent::logTextSensor(String tag, String message, std::string text) + { + Serial << tag << " : " << message << " : " << text.c_str() << endl; + Serial.flush(); + } + + void VictronComponent::logBinarySensor(String tag, String message, bool flag) + { + Serial << tag << " : " << message << " : " << flag << endl; + Serial.flush(); + } + + void VictronComponent::logSensor(String tag, String message, int number) + { + Serial << tag << " : " << message << " : " << number << endl; + Serial.flush(); + } + void VictronComponent::loop() { const uint32_t now = millis(); @@ -567,7 +585,6 @@ namespace victron { if (label_ == "ERR") { value = atoi(value_.c_str()); // NOLINT(cert-err34-c) error_code_sensor_ = value; - error_text_sensor_ = error_code_text(value); return; } @@ -607,4 +624,36 @@ namespace victron { Serial << TAG << " : Unhandled property:" << label_.c_str() << " : " << value_.c_str() << endl; } + + + void VictronComponent::dump_config(void) + { + if (this->last_publish_ <= 0) + { + return; /* No data -> no log */ + } + + log(TAG, "Victron:"); + logBinarySensor(" ", "Load state", load_state_binary_sensor_); + logSensor(" ", "Max Power Yesterday", max_power_yesterday_sensor_); + logSensor(" ", "Max Power Today", max_power_today_sensor_); + logSensor(" ", "Yield Total", yield_total_sensor_); + logSensor(" ", "Yield Yesterday", yield_yesterday_sensor_); + logSensor(" ", "Yield Today", yield_today_sensor_); + logSensor(" ", "Panel Voltage", panel_voltage_sensor_); + logSensor(" ", "Panel Power", panel_power_sensor_); + logSensor(" ", "Battery Voltage", battery_voltage_sensor_); + logSensor(" ", "Battery Current", battery_current_sensor_); + logSensor(" ", "Load Current", load_current_sensor_); + logSensor(" ", "Day Number", day_number_sensor_); + logSensor(" ", "Charging Mode ID", charging_mode_id_sensor_); + logSensor(" ", "Error Code", error_code_sensor_); + logSensor(" ", "Tracking Mode ID", tracking_mode_id_sensor_); + logTextSensor(" ", "Error Text", error_code_text(error_code_sensor_)); + logTextSensor(" ", "Tracking Mode", tracking_mode_text(tracking_mode_id_sensor_)); + logTextSensor(" ", "Charging Mode", charging_mode_text(charging_mode_id_sensor_)); + logTextSensor(" ", "Firmware Version", firmware_version_text_sensor_); + logTextSensor(" ", "Device Type", device_type_text(device_type_text_sensor_)); + logTextSensor(" ", "Alarm Condition Active", alarm_condition_active_text_sensor_); + } } From f3f276606fb4444ae3188806d73e07b0378b42b2 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 22:20:57 +0200 Subject: [PATCH 32/57] Add VICTRON compiler flag --- include/HomieSettings.h | 2 +- platformio.ini | 3 ++- src/main.cpp | 24 ++++++++++++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index a544a92..33dcd58 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,7 +13,7 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.4.0" +#define HOMIE_FIRMWARE_VERSION "2.4.1" #define SERIAL_BAUDRATE 19200 diff --git a/platformio.ini b/platformio.ini index b9c1666..fba63e4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,11 +12,12 @@ platform = espressif8266 board = d1_mini framework = arduino -build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 +build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 -D VICTRON ; build_flag needs define the Bosch sensor... ; -D BMP280 ;or ; -D BME680 +; Optinal Paramter to read Victron MPPT ; the latest development branch (convention V3.0.x) lib_deps = https://github.com/homieiot/homie-esp8266.git#develop diff --git a/src/main.cpp b/src/main.cpp index 1f210e0..d97f5bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,9 @@ #include #include #include +#ifdef VICTRON #include +#endif #ifdef BME680 #include "Adafruit_BME680.h" #else @@ -86,6 +88,8 @@ #define NODE_HUMIDITY "humidity" #define NODE_AMBIENT "ambient" #define NODE_BUTTON "button" +#define NODE_MPPT "mppt" +#define NODE_SOLAR "solar" #define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */ /****************************************************************************** * TYPE DEFS @@ -118,6 +122,11 @@ HomieNode humidityNode(NODE_HUMIDITY, "Humidity", "number"); #endif HomieNode buttonNode(NODE_BUTTON, "Button", "number"); +#ifdef VICTRON +HomieNode mpptNode(NODE_MPPT, "MPPT", "json"); +HomieNode solarNode(NODE_SOLAR, "Solar", "number"); +#endif + /****************************** Output control ***********************/ HomieNode ledStripNode /* to rule them all */("led", "RGB led", "color"); @@ -149,7 +158,9 @@ Adafruit_BMP280 bmx; // connected via I2C Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); +#ifdef VICTRON victron::VictronComponent mppt(0); +#endif // Variablen uint8_t serialRxBuf[SERIAL_RCEVBUF_MAX]; @@ -351,8 +362,10 @@ void loopHandler() Homie.prepareToSleep(); delay(100); } - +#ifdef VICTRON mppt.dump_config(); + mpptNode.setProperty(NODE_MPPT).send(mppt.toJson()); +#endif } /* if the user sees something via the LEDs, inform MQTT, too */ @@ -360,8 +373,10 @@ void loopHandler() buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); } +#ifdef VICTRON // Read victron MPPT mppt.loop(); +#endif // Feed the dog -> ESP stay alive ESP.wdtFeed(); @@ -458,7 +473,12 @@ void setup() .settable(ledHandler); buttonNode.advertise(NODE_BUTTON).setName("Button pressed") .setDatatype("integer"); - +#if VICTRON + mpptNode.advertise(NODE_MPPT).setName("MPPT") + .setDatatype("json"); + solarNode.advertise(NODE_SOLAR).setName("Solar") + .setDatatype("integer"); +#endif strip.begin(); mConfigured = Homie.isConfigured(); From 2e40134444ae6f8584df77a1921d32f1c267628c Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 22:21:46 +0200 Subject: [PATCH 33/57] Added toJson function and extracted text switch-case to seperate header --- host/VictronDummyData.txt | 36 ++++ include/VictronTexts.h | 399 ++++++++++++++++++++++++++++++++++ include/victron.h | 1 + src/victron.cpp | 443 ++++---------------------------------- 4 files changed, 481 insertions(+), 398 deletions(-) create mode 100644 host/VictronDummyData.txt create mode 100644 include/VictronTexts.h diff --git a/host/VictronDummyData.txt b/host/VictronDummyData.txt new file mode 100644 index 0000000..82b6e74 --- /dev/null +++ b/host/VictronDummyData.txt @@ -0,0 +1,36 @@ +SER# HQ2202K3VD9 +V 26310 +I 0 +VPV 0 +PPV 0 +CS 0 +MPPT 0 +ERR 0 +LOAD ON +IL 0 +H19 0 +H20 0 +H21 0 +H22 0 +H23 0 +HSDS 0 +Checksum f +PID 0xA04C +FW 159 +SER# HQ2202K3VD9 +V 26310 +I 0 +VPV 0 +PPV 0 +CS 0 +MPPT 0 +ERR 0 +LOAD ON +IL 0 +H19 0 +H20 0 +H21 0 +H22 0 +H23 0 +HSDS 0 +Checksum f diff --git a/include/VictronTexts.h b/include/VictronTexts.h new file mode 100644 index 0000000..47d9b15 --- /dev/null +++ b/include/VictronTexts.h @@ -0,0 +1,399 @@ +#pragma once + + + + std::string tracking_mode_text(int value) { + switch (value) { + case 0: + return "Off"; + case 1: + return "Limited"; + case 2: + return "Active"; + default: + return "Unknown"; + } + } + + std::string error_code_text(int value) { + switch (value) { + case 0: + return "No error"; + case 2: + return "Battery voltage too high"; + case 17: + return "Charger temperature too high"; + case 18: + return "Charger over current"; + case 19: + return "Charger current reversed"; + case 20: + return "Bulk time limit exceeded"; + case 21: + return "Current sensor issue"; + case 26: + return "Terminals overheated"; + case 28: + return "Converter issue"; + case 33: + return "Input voltage too high (solar panel)"; + case 34: + return "Input current too high (solar panel)"; + case 38: + return "Input shutdown (excessive battery voltage)"; + case 39: + return "Input shutdown (due to current flow during off mode)"; + case 65: + return "Lost communication with one of devices"; + case 66: + return "Synchronised charging device configuration issue"; + case 67: + return "BMS connection lost"; + case 68: + return "Network misconfigured"; + case 116: + return "Factory calibration data lost"; + case 117: + return "Invalid/incompatible firmware"; + case 119: + return "User settings invalid"; + default: + return "Unknown"; + } + } + + + + std::string charging_mode_text(int value) { + switch (value) { + case 0: + return "Off"; + case 1: + return "Low power"; + case 2: + return "Fault"; + case 3: + return "Bulk"; + case 4: + return "Absorption"; + case 5: + return "Float"; + case 6: + return "Storage"; + case 7: + return "Equalize (manual)"; + case 9: + return "Inverting"; + case 11: + return "Power supply"; + case 245: + return "Starting-up"; + case 246: + return "Repeated absorption"; + case 247: + return "Auto equalize / Recondition"; + case 248: + return "BatterySafe"; + case 252: + return "External control"; + default: + return "Unknown"; + } + } + + + + std::string device_type_text(long value) + { + switch (value) { + case 0x203: + return "BMV-700"; + case 0x204: + return "BMV-702"; + case 0x205: + return "BMV-700H"; + case 0x0300: + return "BlueSolar MPPT 70|15"; + case 0xA040: + return "BlueSolar MPPT 75|50"; + case 0xA041: + return "BlueSolar MPPT 150|35"; + case 0xA042: + return "BlueSolar MPPT 75|15"; + case 0xA043: + return "BlueSolar MPPT 100|15"; + case 0xA044: + return "BlueSolar MPPT 100|30"; + case 0xA045: + return "BlueSolar MPPT 100|50"; + case 0xA046: + return "BlueSolar MPPT 150|70"; + case 0xA047: + return "BlueSolar MPPT 150|100"; + case 0xA049: + return "BlueSolar MPPT 100|50 rev2"; + case 0xA04A: + return "BlueSolar MPPT 100|30 rev2"; + case 0xA04B: + return "BlueSolar MPPT 150|35 rev2"; + case 0xA04C: + return "BlueSolar MPPT 75|10"; + case 0xA04D: + return "BlueSolar MPPT 150|45"; + case 0xA04E: + return "BlueSolar MPPT 150|60"; + case 0xA04F: + return "BlueSolar MPPT 150|85"; + case 0xA050: + return "SmartSolar MPPT 250|100"; + case 0xA051: + return "SmartSolar MPPT 150|100"; + case 0xA052: + return "SmartSolar MPPT 150|85"; + case 0xA053: + return "SmartSolar MPPT 75|15"; + case 0xA075: + return "SmartSolar MPPT 75|15 rev2"; + case 0xA054: + return "SmartSolar MPPT 75|10"; + case 0xA074: + return "SmartSolar MPPT 75|10 rev2"; + case 0xA055: + return "SmartSolar MPPT 100|15"; + case 0xA056: + return "SmartSolar MPPT 100|30"; + case 0xA073: + return "SmartSolar MPPT 150|45 rev3"; + case 0xA057: + return "SmartSolar MPPT 100|50"; + case 0xA058: + return "SmartSolar MPPT 150|35"; + case 0xA059: + return "SmartSolar MPPT 150|100 rev2"; + case 0xA05A: + return "SmartSolar MPPT 150|85 rev2"; + case 0xA05B: + return "SmartSolar MPPT 250|70"; + case 0xA05C: + return "SmartSolar MPPT 250|85"; + case 0xA05D: + return "SmartSolar MPPT 250|60"; + case 0xA05E: + return "SmartSolar MPPT 250|45"; + case 0xA05F: + return "SmartSolar MPPT 100|20"; + case 0xA060: + return "SmartSolar MPPT 100|20 48V"; + case 0xA061: + return "SmartSolar MPPT 150|45"; + case 0xA062: + return "SmartSolar MPPT 150|60"; + case 0xA063: + return "SmartSolar MPPT 150|70"; + case 0xA064: + return "SmartSolar MPPT 250|85 rev2"; + case 0xA065: + return "SmartSolar MPPT 250|100 rev2"; + case 0xA066: + return "BlueSolar MPPT 100|20"; + case 0xA067: + return "BlueSolar MPPT 100|20 48V"; + case 0xA068: + return "SmartSolar MPPT 250|60 rev2"; + case 0xA069: + return "SmartSolar MPPT 250|70 rev2"; + case 0xA06A: + return "SmartSolar MPPT 150|45 rev2"; + case 0xA06B: + return "SmartSolar MPPT 150|60 rev2"; + case 0xA06C: + return "SmartSolar MPPT 150|70 rev2"; + case 0xA06D: + return "SmartSolar MPPT 150|85 rev3"; + case 0xA06E: + return "SmartSolar MPPT 150|100 rev3"; + case 0xA06F: + return "BlueSolar MPPT 150|45 rev2"; + case 0xA070: + return "BlueSolar MPPT 150|60 rev2"; + case 0xA071: + return "BlueSolar MPPT 150|70 rev2"; + case 0xA07D: + return "BlueSolar MPPT 75|15 rev3"; + case 0xA102: + return "SmartSolar MPPT VE.Can 150/70"; + case 0xA103: + return "SmartSolar MPPT VE.Can 150/45"; + case 0xA104: + return "SmartSolar MPPT VE.Can 150/60"; + case 0xA105: + return "SmartSolar MPPT VE.Can 150/85"; + case 0xA106: + return "SmartSolar MPPT VE.Can 150/100"; + case 0xA107: + return "SmartSolar MPPT VE.Can 250/45"; + case 0xA108: + return "SmartSolar MPPT VE.Can 250/60"; + case 0xA109: + return "SmartSolar MPPT VE.Can 250/70"; + case 0xA10A: + return "SmartSolar MPPT VE.Can 250/85"; + case 0xA10B: + return "SmartSolar MPPT VE.Can 250/100"; + case 0xA10C: + return "SmartSolar MPPT VE.Can 150/70 rev2"; + case 0xA10D: + return "SmartSolar MPPT VE.Can 150/85 rev2"; + case 0xA10E: + return "SmartSolar MPPT VE.Can 150/100 rev2"; + case 0xA10F: + return "BlueSolar MPPT VE.Can 150/100"; + case 0xA112: + return "BlueSolar MPPT VE.Can 250/70"; + case 0xA113: + return "BlueSolar MPPT VE.Can 250/100"; + case 0xA114: + return "SmartSolar MPPT VE.Can 250/70 rev2"; + case 0xA115: + return "SmartSolar MPPT VE.Can 250/100 rev2"; + case 0xA116: + return "SmartSolar MPPT VE.Can 250/85 rev2"; + case 0xA201: + return "Phoenix Inverter 12V 250VA 230V"; + case 0xA202: + return "Phoenix Inverter 24V 250VA 230V"; + case 0xA204: + return "Phoenix Inverter 48V 250VA 230V"; + case 0xA211: + return "Phoenix Inverter 12V 375VA 230V"; + case 0xA212: + return "Phoenix Inverter 24V 375VA 230V"; + case 0xA214: + return "Phoenix Inverter 48V 375VA 230V"; + case 0xA221: + return "Phoenix Inverter 12V 500VA 230V"; + case 0xA222: + return "Phoenix Inverter 24V 500VA 230V"; + case 0xA224: + return "Phoenix Inverter 48V 500VA 230V"; + case 0xA231: + return "Phoenix Inverter 12V 250VA 230V"; + case 0xA232: + return "Phoenix Inverter 24V 250VA 230V"; + case 0xA234: + return "Phoenix Inverter 48V 250VA 230V"; + case 0xA239: + return "Phoenix Inverter 12V 250VA 120V"; + case 0xA23A: + return "Phoenix Inverter 24V 250VA 120V"; + case 0xA23C: + return "Phoenix Inverter 48V 250VA 120V"; + case 0xA241: + return "Phoenix Inverter 12V 375VA 230V"; + case 0xA242: + return "Phoenix Inverter 24V 375VA 230V"; + case 0xA244: + return "Phoenix Inverter 48V 375VA 230V"; + case 0xA249: + return "Phoenix Inverter 12V 375VA 120V"; + case 0xA24A: + return "Phoenix Inverter 24V 375VA 120V"; + case 0xA24C: + return "Phoenix Inverter 48V 375VA 120V"; + case 0xA251: + return "Phoenix Inverter 12V 500VA 230V"; + case 0xA252: + return "Phoenix Inverter 24V 500VA 230V"; + case 0xA254: + return "Phoenix Inverter 48V 500VA 230V"; + case 0xA259: + return "Phoenix Inverter 12V 500VA 120V"; + case 0xA25A: + return "Phoenix Inverter 24V 500VA 120V"; + case 0xA25C: + return "Phoenix Inverter 48V 500VA 120V"; + case 0xA261: + return "Phoenix Inverter 12V 800VA 230V"; + case 0xA262: + return "Phoenix Inverter 24V 800VA 230V"; + case 0xA264: + return "Phoenix Inverter 48V 800VA 230V"; + case 0xA269: + return "Phoenix Inverter 12V 800VA 120V"; + case 0xA26A: + return "Phoenix Inverter 24V 800VA 120V"; + case 0xA26C: + return "Phoenix Inverter 48V 800VA 120V"; + case 0xA271: + return "Phoenix Inverter 12V 1200VA 230V"; + case 0xA272: + return "Phoenix Inverter 24V 1200VA 230V"; + case 0xA274: + return "Phoenix Inverter 48V 1200VA 230V"; + case 0xA279: + case 0xA2F9: + return "Phoenix Inverter 12V 1200VA 120V"; + case 0xA27A: + return "Phoenix Inverter 24V 1200VA 120V"; + case 0xA27C: + return "Phoenix Inverter 48V 1200VA 120V"; + case 0xA281: + return "Phoenix Inverter 12V 1600VA 230V"; + case 0xA282: + return "Phoenix Inverter 24V 1600VA 230V"; + case 0xA284: + return "Phoenix Inverter 48V 1600VA 230V"; + case 0xA291: + return "Phoenix Inverter 12V 2000VA 230V"; + case 0xA292: + return "Phoenix Inverter 24V 2000VA 230V"; + case 0xA294: + return "Phoenix Inverter 48V 2000VA 230V"; + case 0xA2A1: + return "Phoenix Inverter 12V 3000VA 230V"; + case 0xA2A2: + return "Phoenix Inverter 24V 3000VA 230V"; + case 0xA2A4: + return "Phoenix Inverter 48V 3000VA 230V"; + case 0xA30A: + return "Blue Smart IP65 Charger 12|25"; + case 0xA332: + return "Blue Smart IP22 Charger 24|8"; + case 0xA334: + return "Blue Smart IP22 Charger 24|12"; + case 0xA336: + return "Blue Smart IP22 Charger 24|16"; + case 0xA340: + return "Phoenix Smart IP43 Charger 12|50 (1+1)"; + case 0xA341: + return "Phoenix Smart IP43 Charger 12|50 (3)"; + case 0xA342: + return "Phoenix Smart IP43 Charger 24|25 (1+1)"; + case 0xA343: + return "Phoenix Smart IP43 Charger 24|25 (3)"; + case 0xA344: + return "Phoenix Smart IP43 Charger 12|30 (1+1)"; + case 0xA345: + return "Phoenix Smart IP43 Charger 12|30 (3)"; + case 0xA346: + return "Phoenix Smart IP43 Charger 24|16 (1+1)"; + case 0xA347: + return "Phoenix Smart IP43 Charger 24|16 (3)"; + case 0xA381: + return "BMV-712 Smart"; + case 0xA382: + return "BMV-710H Smart"; + case 0xA383: + return "BMV-712 Smart Rev2"; + case 0xA389: + return "SmartShunt 500A/50mV"; + case 0xA38A: + return "SmartShunt 1000A/50mV"; + case 0xA38B: + return "SmartShunt 2000A/50mV"; + case 0xA442: + return "Multi RS Solar 48V 6000VA 230V"; + default: + return "Unknown"; + } + } \ No newline at end of file diff --git a/include/victron.h b/include/victron.h index 99eba3d..e900d1e 100644 --- a/include/victron.h +++ b/include/victron.h @@ -25,6 +25,7 @@ namespace victron ~VictronComponent(); void loop(void); void dump_config(void); + String toJson(void); private: void handle_value_(); diff --git a/src/victron.cpp b/src/victron.cpp index 114d9c6..73aafc9 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -14,402 +14,6 @@ namespace victron { static const char *const TAG = "victron"; - std::string tracking_mode_text(int value) { - switch (value) { - case 0: - return "Off"; - case 1: - return "Limited"; - case 2: - return "Active"; - default: - return "Unknown"; - } - } - - std::string error_code_text(int value) { - switch (value) { - case 0: - return "No error"; - case 2: - return "Battery voltage too high"; - case 17: - return "Charger temperature too high"; - case 18: - return "Charger over current"; - case 19: - return "Charger current reversed"; - case 20: - return "Bulk time limit exceeded"; - case 21: - return "Current sensor issue"; - case 26: - return "Terminals overheated"; - case 28: - return "Converter issue"; - case 33: - return "Input voltage too high (solar panel)"; - case 34: - return "Input current too high (solar panel)"; - case 38: - return "Input shutdown (excessive battery voltage)"; - case 39: - return "Input shutdown (due to current flow during off mode)"; - case 65: - return "Lost communication with one of devices"; - case 66: - return "Synchronised charging device configuration issue"; - case 67: - return "BMS connection lost"; - case 68: - return "Network misconfigured"; - case 116: - return "Factory calibration data lost"; - case 117: - return "Invalid/incompatible firmware"; - case 119: - return "User settings invalid"; - default: - return "Unknown"; - } - } - - - - std::string charging_mode_text(int value) { - switch (value) { - case 0: - return "Off"; - case 1: - return "Low power"; - case 2: - return "Fault"; - case 3: - return "Bulk"; - case 4: - return "Absorption"; - case 5: - return "Float"; - case 6: - return "Storage"; - case 7: - return "Equalize (manual)"; - case 9: - return "Inverting"; - case 11: - return "Power supply"; - case 245: - return "Starting-up"; - case 246: - return "Repeated absorption"; - case 247: - return "Auto equalize / Recondition"; - case 248: - return "BatterySafe"; - case 252: - return "External control"; - default: - return "Unknown"; - } - } - - - - std::string device_type_text(long value) - { - switch (value) { - case 0x203: - return "BMV-700"; - case 0x204: - return "BMV-702"; - case 0x205: - return "BMV-700H"; - case 0x0300: - return "BlueSolar MPPT 70|15"; - case 0xA040: - return "BlueSolar MPPT 75|50"; - case 0xA041: - return "BlueSolar MPPT 150|35"; - case 0xA042: - return "BlueSolar MPPT 75|15"; - case 0xA043: - return "BlueSolar MPPT 100|15"; - case 0xA044: - return "BlueSolar MPPT 100|30"; - case 0xA045: - return "BlueSolar MPPT 100|50"; - case 0xA046: - return "BlueSolar MPPT 150|70"; - case 0xA047: - return "BlueSolar MPPT 150|100"; - case 0xA049: - return "BlueSolar MPPT 100|50 rev2"; - case 0xA04A: - return "BlueSolar MPPT 100|30 rev2"; - case 0xA04B: - return "BlueSolar MPPT 150|35 rev2"; - case 0xA04C: - return "BlueSolar MPPT 75|10"; - case 0xA04D: - return "BlueSolar MPPT 150|45"; - case 0xA04E: - return "BlueSolar MPPT 150|60"; - case 0xA04F: - return "BlueSolar MPPT 150|85"; - case 0xA050: - return "SmartSolar MPPT 250|100"; - case 0xA051: - return "SmartSolar MPPT 150|100"; - case 0xA052: - return "SmartSolar MPPT 150|85"; - case 0xA053: - return "SmartSolar MPPT 75|15"; - case 0xA075: - return "SmartSolar MPPT 75|15 rev2"; - case 0xA054: - return "SmartSolar MPPT 75|10"; - case 0xA074: - return "SmartSolar MPPT 75|10 rev2"; - case 0xA055: - return "SmartSolar MPPT 100|15"; - case 0xA056: - return "SmartSolar MPPT 100|30"; - case 0xA073: - return "SmartSolar MPPT 150|45 rev3"; - case 0xA057: - return "SmartSolar MPPT 100|50"; - case 0xA058: - return "SmartSolar MPPT 150|35"; - case 0xA059: - return "SmartSolar MPPT 150|100 rev2"; - case 0xA05A: - return "SmartSolar MPPT 150|85 rev2"; - case 0xA05B: - return "SmartSolar MPPT 250|70"; - case 0xA05C: - return "SmartSolar MPPT 250|85"; - case 0xA05D: - return "SmartSolar MPPT 250|60"; - case 0xA05E: - return "SmartSolar MPPT 250|45"; - case 0xA05F: - return "SmartSolar MPPT 100|20"; - case 0xA060: - return "SmartSolar MPPT 100|20 48V"; - case 0xA061: - return "SmartSolar MPPT 150|45"; - case 0xA062: - return "SmartSolar MPPT 150|60"; - case 0xA063: - return "SmartSolar MPPT 150|70"; - case 0xA064: - return "SmartSolar MPPT 250|85 rev2"; - case 0xA065: - return "SmartSolar MPPT 250|100 rev2"; - case 0xA066: - return "BlueSolar MPPT 100|20"; - case 0xA067: - return "BlueSolar MPPT 100|20 48V"; - case 0xA068: - return "SmartSolar MPPT 250|60 rev2"; - case 0xA069: - return "SmartSolar MPPT 250|70 rev2"; - case 0xA06A: - return "SmartSolar MPPT 150|45 rev2"; - case 0xA06B: - return "SmartSolar MPPT 150|60 rev2"; - case 0xA06C: - return "SmartSolar MPPT 150|70 rev2"; - case 0xA06D: - return "SmartSolar MPPT 150|85 rev3"; - case 0xA06E: - return "SmartSolar MPPT 150|100 rev3"; - case 0xA06F: - return "BlueSolar MPPT 150|45 rev2"; - case 0xA070: - return "BlueSolar MPPT 150|60 rev2"; - case 0xA071: - return "BlueSolar MPPT 150|70 rev2"; - case 0xA07D: - return "BlueSolar MPPT 75|15 rev3"; - case 0xA102: - return "SmartSolar MPPT VE.Can 150/70"; - case 0xA103: - return "SmartSolar MPPT VE.Can 150/45"; - case 0xA104: - return "SmartSolar MPPT VE.Can 150/60"; - case 0xA105: - return "SmartSolar MPPT VE.Can 150/85"; - case 0xA106: - return "SmartSolar MPPT VE.Can 150/100"; - case 0xA107: - return "SmartSolar MPPT VE.Can 250/45"; - case 0xA108: - return "SmartSolar MPPT VE.Can 250/60"; - case 0xA109: - return "SmartSolar MPPT VE.Can 250/70"; - case 0xA10A: - return "SmartSolar MPPT VE.Can 250/85"; - case 0xA10B: - return "SmartSolar MPPT VE.Can 250/100"; - case 0xA10C: - return "SmartSolar MPPT VE.Can 150/70 rev2"; - case 0xA10D: - return "SmartSolar MPPT VE.Can 150/85 rev2"; - case 0xA10E: - return "SmartSolar MPPT VE.Can 150/100 rev2"; - case 0xA10F: - return "BlueSolar MPPT VE.Can 150/100"; - case 0xA112: - return "BlueSolar MPPT VE.Can 250/70"; - case 0xA113: - return "BlueSolar MPPT VE.Can 250/100"; - case 0xA114: - return "SmartSolar MPPT VE.Can 250/70 rev2"; - case 0xA115: - return "SmartSolar MPPT VE.Can 250/100 rev2"; - case 0xA116: - return "SmartSolar MPPT VE.Can 250/85 rev2"; - case 0xA201: - return "Phoenix Inverter 12V 250VA 230V"; - case 0xA202: - return "Phoenix Inverter 24V 250VA 230V"; - case 0xA204: - return "Phoenix Inverter 48V 250VA 230V"; - case 0xA211: - return "Phoenix Inverter 12V 375VA 230V"; - case 0xA212: - return "Phoenix Inverter 24V 375VA 230V"; - case 0xA214: - return "Phoenix Inverter 48V 375VA 230V"; - case 0xA221: - return "Phoenix Inverter 12V 500VA 230V"; - case 0xA222: - return "Phoenix Inverter 24V 500VA 230V"; - case 0xA224: - return "Phoenix Inverter 48V 500VA 230V"; - case 0xA231: - return "Phoenix Inverter 12V 250VA 230V"; - case 0xA232: - return "Phoenix Inverter 24V 250VA 230V"; - case 0xA234: - return "Phoenix Inverter 48V 250VA 230V"; - case 0xA239: - return "Phoenix Inverter 12V 250VA 120V"; - case 0xA23A: - return "Phoenix Inverter 24V 250VA 120V"; - case 0xA23C: - return "Phoenix Inverter 48V 250VA 120V"; - case 0xA241: - return "Phoenix Inverter 12V 375VA 230V"; - case 0xA242: - return "Phoenix Inverter 24V 375VA 230V"; - case 0xA244: - return "Phoenix Inverter 48V 375VA 230V"; - case 0xA249: - return "Phoenix Inverter 12V 375VA 120V"; - case 0xA24A: - return "Phoenix Inverter 24V 375VA 120V"; - case 0xA24C: - return "Phoenix Inverter 48V 375VA 120V"; - case 0xA251: - return "Phoenix Inverter 12V 500VA 230V"; - case 0xA252: - return "Phoenix Inverter 24V 500VA 230V"; - case 0xA254: - return "Phoenix Inverter 48V 500VA 230V"; - case 0xA259: - return "Phoenix Inverter 12V 500VA 120V"; - case 0xA25A: - return "Phoenix Inverter 24V 500VA 120V"; - case 0xA25C: - return "Phoenix Inverter 48V 500VA 120V"; - case 0xA261: - return "Phoenix Inverter 12V 800VA 230V"; - case 0xA262: - return "Phoenix Inverter 24V 800VA 230V"; - case 0xA264: - return "Phoenix Inverter 48V 800VA 230V"; - case 0xA269: - return "Phoenix Inverter 12V 800VA 120V"; - case 0xA26A: - return "Phoenix Inverter 24V 800VA 120V"; - case 0xA26C: - return "Phoenix Inverter 48V 800VA 120V"; - case 0xA271: - return "Phoenix Inverter 12V 1200VA 230V"; - case 0xA272: - return "Phoenix Inverter 24V 1200VA 230V"; - case 0xA274: - return "Phoenix Inverter 48V 1200VA 230V"; - case 0xA279: - case 0xA2F9: - return "Phoenix Inverter 12V 1200VA 120V"; - case 0xA27A: - return "Phoenix Inverter 24V 1200VA 120V"; - case 0xA27C: - return "Phoenix Inverter 48V 1200VA 120V"; - case 0xA281: - return "Phoenix Inverter 12V 1600VA 230V"; - case 0xA282: - return "Phoenix Inverter 24V 1600VA 230V"; - case 0xA284: - return "Phoenix Inverter 48V 1600VA 230V"; - case 0xA291: - return "Phoenix Inverter 12V 2000VA 230V"; - case 0xA292: - return "Phoenix Inverter 24V 2000VA 230V"; - case 0xA294: - return "Phoenix Inverter 48V 2000VA 230V"; - case 0xA2A1: - return "Phoenix Inverter 12V 3000VA 230V"; - case 0xA2A2: - return "Phoenix Inverter 24V 3000VA 230V"; - case 0xA2A4: - return "Phoenix Inverter 48V 3000VA 230V"; - case 0xA30A: - return "Blue Smart IP65 Charger 12|25"; - case 0xA332: - return "Blue Smart IP22 Charger 24|8"; - case 0xA334: - return "Blue Smart IP22 Charger 24|12"; - case 0xA336: - return "Blue Smart IP22 Charger 24|16"; - case 0xA340: - return "Phoenix Smart IP43 Charger 12|50 (1+1)"; - case 0xA341: - return "Phoenix Smart IP43 Charger 12|50 (3)"; - case 0xA342: - return "Phoenix Smart IP43 Charger 24|25 (1+1)"; - case 0xA343: - return "Phoenix Smart IP43 Charger 24|25 (3)"; - case 0xA344: - return "Phoenix Smart IP43 Charger 12|30 (1+1)"; - case 0xA345: - return "Phoenix Smart IP43 Charger 12|30 (3)"; - case 0xA346: - return "Phoenix Smart IP43 Charger 24|16 (1+1)"; - case 0xA347: - return "Phoenix Smart IP43 Charger 24|16 (3)"; - case 0xA381: - return "BMV-712 Smart"; - case 0xA382: - return "BMV-710H Smart"; - case 0xA383: - return "BMV-712 Smart Rev2"; - case 0xA389: - return "SmartShunt 500A/50mV"; - case 0xA38A: - return "SmartShunt 1000A/50mV"; - case 0xA38B: - return "SmartShunt 2000A/50mV"; - case 0xA442: - return "Multi RS Solar 48V 6000VA 230V"; - default: - return "Unknown"; - } - } - VictronComponent::VictronComponent() { this->state_ = 0; @@ -649,11 +253,54 @@ namespace victron { logSensor(" ", "Charging Mode ID", charging_mode_id_sensor_); logSensor(" ", "Error Code", error_code_sensor_); logSensor(" ", "Tracking Mode ID", tracking_mode_id_sensor_); + logTextSensor(" ", "Firmware Version", firmware_version_text_sensor_); + logTextSensor(" ", "Alarm Condition Active", alarm_condition_active_text_sensor_); + /** + * Linking .pio/build/nodemcuv2/firmware.elf + .pio/build/nodemcuv2/libFrameworkArduino.a(core_esp8266_postmortem.cpp.o): in function `__wrap_system_restart_local': + core_esp8266_postmortem.cpp:(.text.__wrap_system_restart_local+0x2): dangerous relocation: j: cannot encode: (.text.postmortem_report+0x88) + + logTextSensor(" ", "Error Text", error_code_text(error_code_sensor_)); logTextSensor(" ", "Tracking Mode", tracking_mode_text(tracking_mode_id_sensor_)); logTextSensor(" ", "Charging Mode", charging_mode_text(charging_mode_id_sensor_)); - logTextSensor(" ", "Firmware Version", firmware_version_text_sensor_); logTextSensor(" ", "Device Type", device_type_text(device_type_text_sensor_)); - logTextSensor(" ", "Alarm Condition Active", alarm_condition_active_text_sensor_); + */ + } + + String VictronComponent::toJson(void) + { + String buffer; + if (this->last_publish_ <= 0) + { + return buffer; + } + else + { + StaticJsonDocument<200> doc; + //FIXME doc["LoadState"] = load_state_binary_sensor_; + // doc["MaxPowerYesterday"] = max_power_yesterday_sensor_; + // doc["MaxPowerToday"] = max_power_today_sensor_; + // doc["YieldTotal"] = yield_total_sensor_; + // doc["YieldYesterday"] = yield_yesterday_sensor_; + // doc["YieldToday"] = yield_today_sensor_; + // doc["PanelVoltage"] = panel_voltage_sensor_; + // doc["PanelPower"] = panel_power_sensor_; + doc["BatVoltage"] = battery_voltage_sensor_; + // doc["BatCurrent"] = battery_current_sensor_; + // doc["LoadCurrent"] = load_current_sensor_; + // doc["DayNumber"] = day_number_sensor_; + // doc["ChargingModeID"] = charging_mode_id_sensor_; + // doc["ErrorCode"] = error_code_sensor_; + // doc["TrackingModeID"] = tracking_mode_id_sensor_; + //FIXME doc["ErrorText"] = error_code_text(error_code_sensor_).c_str(); + //FIXME doc["TrackingMode"] = tracking_mode_text(tracking_mode_id_sensor_).c_str(); + //FIXME doc["ChargingMode"] = charging_mode_text(charging_mode_id_sensor_).c_str(); + //FIXME doc["FirmwareVersion"] = firmware_version_text_sensor_.c_str(); + //FIXME doc["DeviceType"] = device_type_text(device_type_text_sensor_).c_str(); + //FIXME doc["AlarmConditionActive"] = alarm_condition_active_text_sensor_.c_str(); + serializeJson(doc, buffer); + return buffer; + } } } From 72c1345e89dd3bd5b04a52e09b19421bf50c9866 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 10 May 2025 22:39:38 +0200 Subject: [PATCH 34/57] Refactored Logging into new module: MqttLog --- include/MqttLog.h | 31 +++++++++++++++++++++++++++++++ include/victron.h | 1 - src/MqttLog.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/main.cpp | 40 ++-------------------------------------- src/victron.cpp | 25 ++++++++++--------------- 5 files changed, 80 insertions(+), 54 deletions(-) create mode 100644 include/MqttLog.h create mode 100644 src/MqttLog.cpp diff --git a/include/MqttLog.h b/include/MqttLog.h new file mode 100644 index 0000000..a4a1cf6 --- /dev/null +++ b/include/MqttLog.h @@ -0,0 +1,31 @@ +/** + * @file MqttLog.h + * @author Ollo + * @brief Wrapper for Logger to Mqtt + * @version 0.1 + * + */ + +#ifndef MQTT_LOGGER +#define MQTT_LOGGER + +#include + +#define LOG_TOPIC "log\0" +#define MQTT_LEVEL_ERROR 1 +#define MQTT_LEVEL_WARNING 10 +#define MQTT_LEVEL_INFO 20 +#define MQTT_LEVEL_DEBUG 90 + +#define MQTT_LOG_PM1006 10 +#define MQTT_LOG_I2CINIT 100 +#define MQTT_LOG_I2READ 101 +#define MQTT_LOG_RGB 200 + +#define MQTT_LOG_VICTRON 400 + +extern bool mConnected; + +void log(int level, String message, int statusCode); + +#endif /* end of MQTT_LOGGER */ \ No newline at end of file diff --git a/include/victron.h b/include/victron.h index e900d1e..b864b76 100644 --- a/include/victron.h +++ b/include/victron.h @@ -29,7 +29,6 @@ namespace victron private: void handle_value_(); - void log(String tag, String message); void logTextSensor(String tag, String message, std::string text); void logBinarySensor(String tag, String message, bool flag); void logSensor(String tag, String message, int number); diff --git a/src/MqttLog.cpp b/src/MqttLog.cpp new file mode 100644 index 0000000..21abbd8 --- /dev/null +++ b/src/MqttLog.cpp @@ -0,0 +1,37 @@ +/** + * @file MqttLog.cpp + * @author Ollo + * @brief Wrapper for Logger to Mqtt + * @version 0.1 + * + */ + +#include "MqttLog.h" + +bool mConnected = false; + +#define getTopic(test, topic) \ + char *topic = new char[strlen(Homie.getConfiguration().mqtt.baseTopic) + strlen(Homie.getConfiguration().deviceId) + 1 + strlen(test) + 1]; \ + strcpy(topic, Homie.getConfiguration().mqtt.baseTopic); \ + strcat(topic, Homie.getConfiguration().deviceId); \ + strcat(topic, "/"); \ + strcat(topic, test); + + +void log(int level, String message, int statusCode) +{ + String buffer; + StaticJsonDocument<200> doc; + doc["level"] = level; + doc["message"] = message; + doc["statusCode"] = statusCode; + serializeJson(doc, buffer); + if (mConnected) + { + getTopic(LOG_TOPIC, logTopic) + + Homie.getMqttClient().publish(logTopic, 2, false, buffer.c_str()); + delete logTopic; + } + Homie.getLogger() << (level) << "@" << (statusCode) << " " << (message) << endl; +} diff --git a/src/main.cpp b/src/main.cpp index d97f5bf..3a2e9c0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include #include #include "HomieSettings.h" +#include "MqttLog.h" #include #include #include @@ -57,26 +58,8 @@ #define MIN_MEASURED_CYCLES 2 #define PM_MAX 1001 /**< According datasheet https://en.gassensor.com.cn/ParticulateMatterSensor/info_itemid_105.html 1000 is the maximum */ -#define LOG_TOPIC "log\0" -#define MQTT_LEVEL_ERROR 1 -#define MQTT_LEVEL_WARNING 10 -#define MQTT_LEVEL_INFO 20 -#define MQTT_LEVEL_DEBUG 90 - -#define MQTT_LOG_PM1006 10 -#define MQTT_LOG_I2CINIT 100 -#define MQTT_LOG_I2READ 101 -#define MQTT_LOG_RGB 200 - #define TEMPBORDER 20 -#define getTopic(test, topic) \ - char *topic = new char[strlen(Homie.getConfiguration().mqtt.baseTopic) + strlen(Homie.getConfiguration().deviceId) + 1 + strlen(test) + 1]; \ - strcpy(topic, Homie.getConfiguration().mqtt.baseTopic); \ - strcat(topic, Homie.getConfiguration().deviceId); \ - strcat(topic, "/"); \ - strcat(topic, test); - #define PERCENT2FACTOR(b, a) ((b * a.get()) / 100) #define NUMBER_TYPE "Number" @@ -106,7 +89,7 @@ void log(int level, String message, int code); ******************************************************************************/ bool mConfigured = false; -bool mConnected = false; + bool mOTAactive = false; /**< Stop sleeping, if OTA is running */ bool mFailedI2Cinitialization = false; long mLastButtonAction = 0; @@ -575,22 +558,3 @@ void loop() } } } - - -void log(int level, String message, int statusCode) -{ - String buffer; - StaticJsonDocument<200> doc; - doc["level"] = level; - doc["message"] = message; - doc["statusCode"] = statusCode; - serializeJson(doc, buffer); - if (mConnected) - { - getTopic(LOG_TOPIC, logTopic) - - Homie.getMqttClient().publish(logTopic, 2, false, buffer.c_str()); - delete logTopic; - } - Homie.getLogger() << (level) << "@" << (statusCode) << " " << (message) << endl; -} diff --git a/src/victron.cpp b/src/victron.cpp index 73aafc9..159de5f 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -9,6 +9,7 @@ */ #include "victron.h" +#include "MqttLog.h" namespace victron { @@ -29,28 +30,22 @@ namespace victron { this->state_ = initialstate; } - void VictronComponent::log(String tag, String message) - { - Serial << tag << " : " << message << endl; - Serial.flush(); - } - void VictronComponent::logTextSensor(String tag, String message, std::string text) { - Serial << tag << " : " << message << " : " << text.c_str() << endl; - Serial.flush(); + String complete = message + " : " + String(text.c_str()); + log(MQTT_LEVEL_INFO, complete, MQTT_LOG_VICTRON); } void VictronComponent::logBinarySensor(String tag, String message, bool flag) { - Serial << tag << " : " << message << " : " << flag << endl; - Serial.flush(); + String complete = message + " : " + String(flag); + log(MQTT_LEVEL_INFO, complete, MQTT_LOG_VICTRON); } void VictronComponent::logSensor(String tag, String message, int number) { - Serial << tag << " : " << message << " : " << number << endl; - Serial.flush(); + String complete = message + " : " + String(number); + log(MQTT_LEVEL_INFO, complete, MQTT_LOG_VICTRON); } void VictronComponent::loop() @@ -58,7 +53,7 @@ namespace victron { const uint32_t now = millis(); if ((state_ > 0) && (now - last_transmission_ >= 200)) { // last transmission too long ago. Reset RX index. - log(TAG, "Last transmission too long ago"); + log(MQTT_LEVEL_INFO, "Last transmission too long ago", MQTT_LOG_VICTRON); state_ = 0; } @@ -226,7 +221,8 @@ namespace victron { return; } - Serial << TAG << " : Unhandled property:" << label_.c_str() << " : " << value_.c_str() << endl; + String message= "Unhandled property:" + String(label_.c_str()) + " : " + String(value_.c_str()); + log(MQTT_LEVEL_ERROR, message, MQTT_LOG_VICTRON); } @@ -237,7 +233,6 @@ namespace victron { return; /* No data -> no log */ } - log(TAG, "Victron:"); logBinarySensor(" ", "Load state", load_state_binary_sensor_); logSensor(" ", "Max Power Yesterday", max_power_yesterday_sensor_); logSensor(" ", "Max Power Today", max_power_today_sensor_); From 8f9cc56809eba52bed3c3f33c3919f1422f0feaf Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 00:05:31 +0200 Subject: [PATCH 35/57] Read serial event directly in Arduino-Loop --- host/VictronDummyData.txt | 73 ++++++++++++++++++++------------------- src/main.cpp | 10 +++--- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/host/VictronDummyData.txt b/host/VictronDummyData.txt index 82b6e74..e960aa7 100644 --- a/host/VictronDummyData.txt +++ b/host/VictronDummyData.txt @@ -1,36 +1,37 @@ -SER# HQ2202K3VD9 -V 26310 -I 0 -VPV 0 -PPV 0 -CS 0 -MPPT 0 -ERR 0 -LOAD ON -IL 0 -H19 0 -H20 0 -H21 0 -H22 0 -H23 0 -HSDS 0 -Checksum f -PID 0xA04C -FW 159 -SER# HQ2202K3VD9 -V 26310 -I 0 -VPV 0 -PPV 0 -CS 0 -MPPT 0 -ERR 0 -LOAD ON -IL 0 -H19 0 -H20 0 -H21 0 -H22 0 -H23 0 -HSDS 0 -Checksum f +SER# HQ2202K3VD9 +V 26310 +I 0 +VPV 0 +PPV 0 +CS 0 +MPPT 0 +ERR 0 +LOAD ON +IL 0 +H19 0 +H20 0 +H21 0 +H22 0 +H23 0 +HSDS 0 +Checksum f +PID 0xA04C +FW 159 +SER# HQ2202K3VD9 +V 26310 +I 0 +VPV 0 +PPV 0 +CS 0 +MPPT 0 +ERR 0 +LOAD ON +IL 0 +H19 0 +H20 0 +H21 0 +H22 0 +H23 0 +HSDS 0 +Checksum f + diff --git a/src/main.cpp b/src/main.cpp index 3a2e9c0..7f0c9ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -356,11 +356,6 @@ void loopHandler() buttonNode.setProperty(NODE_BUTTON).send(String(mButtonPressed)); } -#ifdef VICTRON - // Read victron MPPT - mppt.loop(); -#endif - // Feed the dog -> ESP stay alive ESP.wdtFeed(); } @@ -557,4 +552,9 @@ void loop() strip.show(); } } + +#ifdef VICTRON + // Read victron MPPT + mppt.loop(); +#endif } From 34982f9f4501787f51734ebd7cd03ec16e16fe6e Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 00:09:46 +0200 Subject: [PATCH 36/57] Uniq numbers in the dump --- host/VictronDummyData.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/host/VictronDummyData.txt b/host/VictronDummyData.txt index e960aa7..352b51f 100644 --- a/host/VictronDummyData.txt +++ b/host/VictronDummyData.txt @@ -19,19 +19,19 @@ PID 0xA04C FW 159 SER# HQ2202K3VD9 V 26310 -I 0 -VPV 0 -PPV 0 -CS 0 -MPPT 0 -ERR 0 +I 1 +VPV 2 +PPV 3 +CS 4 +MPPT 5 +ERR 6 LOAD ON -IL 0 -H19 0 -H20 0 -H21 0 -H22 0 -H23 0 -HSDS 0 +IL 7 +H19 8 +H20 9 +H21 10 +H22 11 +H23 12 +HSDS 13 Checksum f From 10d439d189c34bf84b462126f52187c2013d1866 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 00:21:02 +0200 Subject: [PATCH 37/57] Show Battery voltage --- include/victron.h | 4 ++++ src/main.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/include/victron.h b/include/victron.h index b864b76..abe604f 100644 --- a/include/victron.h +++ b/include/victron.h @@ -27,6 +27,10 @@ namespace victron void dump_config(void); String toJson(void); + int getBatteryVoltage() { + return battery_voltage_sensor_; + } + private: void handle_value_(); void logTextSensor(String tag, String message, std::string text); diff --git a/src/main.cpp b/src/main.cpp index 7f0c9ec..e9f071b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -73,6 +73,7 @@ #define NODE_BUTTON "button" #define NODE_MPPT "mppt" #define NODE_SOLAR "solar" +#define NODE_SOLAR_BATTERY "battery" #define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */ /****************************************************************************** * TYPE DEFS @@ -348,6 +349,8 @@ void loopHandler() #ifdef VICTRON mppt.dump_config(); mpptNode.setProperty(NODE_MPPT).send(mppt.toJson()); + solarNode.setProperty(NODE_SOLAR_BATTERY).send(String(mppt.getBatteryVoltage())); + #endif } @@ -456,6 +459,9 @@ void setup() .setDatatype("json"); solarNode.advertise(NODE_SOLAR).setName("Solar") .setDatatype("integer"); + + solarNode.advertise(NODE_SOLAR_BATTERY).setName("Solar") + .setDatatype("integer").setUnit("mV"); #endif strip.begin(); From 5235a3141a5dcb1d5cac60628e72a3d60293b052 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 10:39:29 +0200 Subject: [PATCH 38/57] Ignore configuration files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 89cc49c..9b8093f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch +**/config*.json \ No newline at end of file From 8e1792bb582ef1597075853ae17e2854bc757b4f Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 10:50:39 +0200 Subject: [PATCH 39/57] Added documentation for Victron --- Readme.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Readme.md b/Readme.md index 358ebbf..db34d03 100644 --- a/Readme.md +++ b/Readme.md @@ -23,6 +23,7 @@ Upload this new generated filesystem with: Can be found at ```~/.platformio/penv/bin/pio``` # Hardware +## Core ESP8266 version ESP12 was used. The prototype was based on the Witty board @@ -47,14 +48,32 @@ The following pins are used: * GPIO13 VCC of I2C (3.3 V) * GPIO14 I2C clock * GPIO5 I2C data pin +* RXD Victron MPPT + +## Victron + +An *ADUM 1201* should be used for galvanic isolation. +The following wiring will be setup: +``` +Ve.Direct | Purpose | connect | ADUM1201 #2 | ADUM1201 #1 | connect | ESP8266 +1 | GND | <-> | GND2 | GND1 | <-> | GND +2 | RX | <-> | VOB | VIB | | +3 | TX | <-> | VIA | VOA | <-> | RX +4 | 5V | <-> | VDD2 | VDD1 | <-> | 3V3 +``` # Bill of materials +## Core * IKEA Vindriktning * ESP8266 (e.g. Witty board) * BMP280 sensor * some wire +## Victron +* ADUM 1201 + # Sources For the Witty board * [https://github.com/amkuipers/witty Witty pinout] * [https://arduino.ua/products_pictures/large_AOC361-5.jpg Schematics] +* [https://github.com/KinDR007/VictronMPPT-ESPHOME/ Victron MPPT ESP8266 Library] \ No newline at end of file From c4fd54057fe37d795746a0f9fd70f6b4888526f4 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 21:05:07 +0200 Subject: [PATCH 40/57] First lines are simulated --- host/simulateMPPT75-10.py | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 host/simulateMPPT75-10.py diff --git a/host/simulateMPPT75-10.py b/host/simulateMPPT75-10.py new file mode 100755 index 0000000..71675e3 --- /dev/null +++ b/host/simulateMPPT75-10.py @@ -0,0 +1,48 @@ +#!/usr/bin/python3 +import serial +import time +import argparse +import re +import random +from termcolor import colored +from time import localtime, strftime, gmtime +from datetime import datetime, timezone + +parser = argparse.ArgumentParser() +parser.add_argument('-d', '--device', help='ttyUSB device. By default, /dev/ttyUSB0 is used.') +args = parser.parse_args() + +if (args.device): + serialDevice=args.device +else: + serialDevice="/dev/ttyUSB0" + +with serial.Serial(serialDevice, 19200, timeout=1) as ser: + print(ser.name) # check which port was really used + + lastUpdate=0 + + # some dummy values + battery_volt=12000 + + # Main Loop + while (True): + s=ser.readline() + now=int(time.time()) + updateSerial=((now - lastUpdate) > 2) + + if ((s is not None) and (len(s) > 0)): + print(colored(strftime("%Y-%m-%d %H:%M:%S", gmtime()) + " " + str(s.decode('utf-8', errors='ignore')).rstrip(), "green")) + + if (updateSerial): + lastUpdate=int(time.time()) + # Send the status string + outStr="SER#\tHQ2202K3VD9\nV\t{0:d}\nChecksum f\r\n".format(battery_volt) + # write a string + ser.write(outStr.encode(encoding='UTF-8')) + print(colored(outStr.rstrip(), "white")) + time.sleep(0.2) + + ser.close() # close port + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 From 2059403f38c8b50e6eb7c2fe8a394b88732c842b Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 21:15:16 +0200 Subject: [PATCH 41/57] Enhanced simulation with dynamic values --- host/simulateMPPT75-10.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/host/simulateMPPT75-10.py b/host/simulateMPPT75-10.py index 71675e3..b7fae2a 100755 --- a/host/simulateMPPT75-10.py +++ b/host/simulateMPPT75-10.py @@ -24,6 +24,9 @@ # some dummy values battery_volt=12000 + battery_current = 1 + panel_volt = 13000 + panel_power = 2 # Main Loop while (True): @@ -37,11 +40,16 @@ if (updateSerial): lastUpdate=int(time.time()) # Send the status string - outStr="SER#\tHQ2202K3VD9\nV\t{0:d}\nChecksum f\r\n".format(battery_volt) + outStr="SER#\tHQ2202K3VD9\nV\t{0:d}\nI\t{1:d}\nVPV\t{2:d}\nPPV\t{3:d}\nChecksum f\r\n".format(battery_volt, battery_current, panel_volt, panel_power) + # Other values + # CS\t{4:d}\nMPPT\t{5:d}\nERR\t{6:d}\nLOAD\t{7}\nIL\t{8:d}\nH19\t{9:d}\nH20\t{10:d}\nH21\t{11:d}\nH22\t{12:d}\nH23\t{13:d}\nHSDS\t{14:d}\n + # write a string ser.write(outStr.encode(encoding='UTF-8')) print(colored(outStr.rstrip(), "white")) time.sleep(0.2) + panel_volt = panel_volt + 1 + panel_power = panel_power + 1 ser.close() # close port From 4e1a24cf7257a39cb9310dd9cf20a100c051fab2 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 11 May 2025 21:28:30 +0200 Subject: [PATCH 42/57] Seperate properties for battery voltage, solar panel voltage and solar panel power --- include/HomieSettings.h | 2 +- include/victron.h | 12 ++++++++++++ src/main.cpp | 22 +++++++++++++++++----- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 33dcd58..e1ec399 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,7 +13,7 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.4.1" +#define HOMIE_FIRMWARE_VERSION "2.4.2" #define SERIAL_BAUDRATE 19200 diff --git a/include/victron.h b/include/victron.h index abe604f..759135e 100644 --- a/include/victron.h +++ b/include/victron.h @@ -31,6 +31,18 @@ namespace victron return battery_voltage_sensor_; } + int getPanelVoltage() { + return panel_voltage_sensor_; + } + + int getPanelPower() { + return panel_power_sensor_; + } + + bool hasData() { + return (battery_voltage_sensor_ > 0); + } + private: void handle_value_(); void logTextSensor(String tag, String message, std::string text); diff --git a/src/main.cpp b/src/main.cpp index e9f071b..5442fbc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -73,7 +73,9 @@ #define NODE_BUTTON "button" #define NODE_MPPT "mppt" #define NODE_SOLAR "solar" -#define NODE_SOLAR_BATTERY "battery" +#define NODE_SOLAR_BATTERYVOLT "batteryV" +#define NODE_SOLAR_PANELPOWER "panelP" +#define NODE_SOLAR_PANELVOLT "panelV" #define SERIAL_RCEVBUF_MAX 80 /**< Maximum 80 characters can be received from the PM1006 sensor */ /****************************************************************************** * TYPE DEFS @@ -342,15 +344,21 @@ void loopHandler() lastRead = millis(); /* If nothing needs to be done, sleep and the time is ready for sleeping */ - if (mMeasureIndex > MIN_MEASURED_CYCLES && (deepsleep.get() > 0) ) { + if ((mMeasureIndex > MIN_MEASURED_CYCLES) && (deepsleep.get() > 0) +#ifdef VICTRON + && (mppt.hasData()) +#endif + ) { Homie.prepareToSleep(); delay(100); } #ifdef VICTRON mppt.dump_config(); mpptNode.setProperty(NODE_MPPT).send(mppt.toJson()); - solarNode.setProperty(NODE_SOLAR_BATTERY).send(String(mppt.getBatteryVoltage())); - + solarNode.setProperty(NODE_SOLAR_BATTERYVOLT).send(String(mppt.getBatteryVoltage())); + solarNode.setProperty(NODE_SOLAR_PANELVOLT).send(String(mppt.getPanelVoltage())); + solarNode.setProperty(NODE_SOLAR_PANELPOWER).send(String(mppt.getPanelPower())); + #endif } @@ -460,7 +468,11 @@ void setup() solarNode.advertise(NODE_SOLAR).setName("Solar") .setDatatype("integer"); - solarNode.advertise(NODE_SOLAR_BATTERY).setName("Solar") + solarNode.advertise(NODE_SOLAR_BATTERYVOLT).setName("Solar") + .setDatatype("integer").setUnit("mV"); + solarNode.advertise(NODE_SOLAR_PANELPOWER).setName("Panel") + .setDatatype("integer").setUnit("W"); + solarNode.advertise(NODE_SOLAR_PANELVOLT).setName("Panel") .setDatatype("integer").setUnit("mV"); #endif strip.begin(); From 721d7c0430ca44e7c94ffaa20b950ce1fae09ddb Mon Sep 17 00:00:00 2001 From: Ollo Date: Mon, 12 May 2025 18:56:59 +0200 Subject: [PATCH 43/57] Wait until established MPPT communication before sleeping again --- include/HomieSettings.h | 2 +- src/main.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index e1ec399..070ab19 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,7 +13,7 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.4.2" +#define HOMIE_FIRMWARE_VERSION "2.4.3" #define SERIAL_BAUDRATE 19200 diff --git a/src/main.cpp b/src/main.cpp index 5442fbc..6d90030 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -145,6 +145,7 @@ Adafruit_BMP280 bmx; // connected via I2C Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); #ifdef VICTRON +HomieSetting deepsleepMppt("dsleepMppt", "Deep sleep only after MPPT comminication (default 0 / false: sleep without any info from Victron)"); victron::VictronComponent mppt(0); #endif @@ -346,7 +347,7 @@ void loopHandler() /* If nothing needs to be done, sleep and the time is ready for sleeping */ if ((mMeasureIndex > MIN_MEASURED_CYCLES) && (deepsleep.get() > 0) #ifdef VICTRON - && (mppt.hasData()) + && (mppt.hasData() || (deepsleepMppt.get() == 0)) #endif ) { Homie.prepareToSleep(); @@ -427,7 +428,11 @@ void setup() Homie.setLoopFunction(loopHandler); Homie.onEvent(onHomieEvent); i2cEnable.setDefaultValue(false); + deepsleepMppt.setDefaultValue(false); +#if VICTRON rgbTemp.setDefaultValue(false); +#endif + rgbDim.setDefaultValue(100).setValidator([] (long candidate) { return (candidate > 1) && (candidate <= 200); }); From 101c59b37cbf63f6b797152914032eed7e6e091a Mon Sep 17 00:00:00 2001 From: Ollo Date: Mon, 12 May 2025 19:04:56 +0200 Subject: [PATCH 44/57] Dump all settings of MPPT --- src/victron.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/victron.cpp b/src/victron.cpp index 159de5f..3413e8c 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -10,6 +10,7 @@ #include "victron.h" #include "MqttLog.h" +#include "VictronTexts.h" namespace victron { @@ -249,18 +250,11 @@ namespace victron { logSensor(" ", "Error Code", error_code_sensor_); logSensor(" ", "Tracking Mode ID", tracking_mode_id_sensor_); logTextSensor(" ", "Firmware Version", firmware_version_text_sensor_); - logTextSensor(" ", "Alarm Condition Active", alarm_condition_active_text_sensor_); - /** - * Linking .pio/build/nodemcuv2/firmware.elf - .pio/build/nodemcuv2/libFrameworkArduino.a(core_esp8266_postmortem.cpp.o): in function `__wrap_system_restart_local': - core_esp8266_postmortem.cpp:(.text.__wrap_system_restart_local+0x2): dangerous relocation: j: cannot encode: (.text.postmortem_report+0x88) - - + logTextSensor(" ", "Alarm Condition Active", alarm_condition_active_text_sensor_); logTextSensor(" ", "Error Text", error_code_text(error_code_sensor_)); logTextSensor(" ", "Tracking Mode", tracking_mode_text(tracking_mode_id_sensor_)); logTextSensor(" ", "Charging Mode", charging_mode_text(charging_mode_id_sensor_)); logTextSensor(" ", "Device Type", device_type_text(device_type_text_sensor_)); - */ } String VictronComponent::toJson(void) From 3698d1693f97168d2494c343b388ba367170e78f Mon Sep 17 00:00:00 2001 From: Ollo Date: Mon, 12 May 2025 20:13:14 +0200 Subject: [PATCH 45/57] publish complete serial state as one json object and removed dump config --- include/victron.h | 1 - src/main.cpp | 1 - src/victron.cpp | 85 +++++++++++++++++------------------------------ 3 files changed, 31 insertions(+), 56 deletions(-) diff --git a/include/victron.h b/include/victron.h index 759135e..107915f 100644 --- a/include/victron.h +++ b/include/victron.h @@ -24,7 +24,6 @@ namespace victron VictronComponent(); ~VictronComponent(); void loop(void); - void dump_config(void); String toJson(void); int getBatteryVoltage() { diff --git a/src/main.cpp b/src/main.cpp index 6d90030..b1fb121 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -354,7 +354,6 @@ void loopHandler() delay(100); } #ifdef VICTRON - mppt.dump_config(); mpptNode.setProperty(NODE_MPPT).send(mppt.toJson()); solarNode.setProperty(NODE_SOLAR_BATTERYVOLT).send(String(mppt.getBatteryVoltage())); solarNode.setProperty(NODE_SOLAR_PANELVOLT).send(String(mppt.getPanelVoltage())); diff --git a/src/victron.cpp b/src/victron.cpp index 3413e8c..d7d3a69 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -226,37 +226,6 @@ namespace victron { log(MQTT_LEVEL_ERROR, message, MQTT_LOG_VICTRON); } - - void VictronComponent::dump_config(void) - { - if (this->last_publish_ <= 0) - { - return; /* No data -> no log */ - } - - logBinarySensor(" ", "Load state", load_state_binary_sensor_); - logSensor(" ", "Max Power Yesterday", max_power_yesterday_sensor_); - logSensor(" ", "Max Power Today", max_power_today_sensor_); - logSensor(" ", "Yield Total", yield_total_sensor_); - logSensor(" ", "Yield Yesterday", yield_yesterday_sensor_); - logSensor(" ", "Yield Today", yield_today_sensor_); - logSensor(" ", "Panel Voltage", panel_voltage_sensor_); - logSensor(" ", "Panel Power", panel_power_sensor_); - logSensor(" ", "Battery Voltage", battery_voltage_sensor_); - logSensor(" ", "Battery Current", battery_current_sensor_); - logSensor(" ", "Load Current", load_current_sensor_); - logSensor(" ", "Day Number", day_number_sensor_); - logSensor(" ", "Charging Mode ID", charging_mode_id_sensor_); - logSensor(" ", "Error Code", error_code_sensor_); - logSensor(" ", "Tracking Mode ID", tracking_mode_id_sensor_); - logTextSensor(" ", "Firmware Version", firmware_version_text_sensor_); - logTextSensor(" ", "Alarm Condition Active", alarm_condition_active_text_sensor_); - logTextSensor(" ", "Error Text", error_code_text(error_code_sensor_)); - logTextSensor(" ", "Tracking Mode", tracking_mode_text(tracking_mode_id_sensor_)); - logTextSensor(" ", "Charging Mode", charging_mode_text(charging_mode_id_sensor_)); - logTextSensor(" ", "Device Type", device_type_text(device_type_text_sensor_)); - } - String VictronComponent::toJson(void) { String buffer; @@ -266,29 +235,37 @@ namespace victron { } else { - StaticJsonDocument<200> doc; - //FIXME doc["LoadState"] = load_state_binary_sensor_; - // doc["MaxPowerYesterday"] = max_power_yesterday_sensor_; - // doc["MaxPowerToday"] = max_power_today_sensor_; - // doc["YieldTotal"] = yield_total_sensor_; - // doc["YieldYesterday"] = yield_yesterday_sensor_; - // doc["YieldToday"] = yield_today_sensor_; - // doc["PanelVoltage"] = panel_voltage_sensor_; - // doc["PanelPower"] = panel_power_sensor_; - doc["BatVoltage"] = battery_voltage_sensor_; - // doc["BatCurrent"] = battery_current_sensor_; - // doc["LoadCurrent"] = load_current_sensor_; - // doc["DayNumber"] = day_number_sensor_; - // doc["ChargingModeID"] = charging_mode_id_sensor_; - // doc["ErrorCode"] = error_code_sensor_; - // doc["TrackingModeID"] = tracking_mode_id_sensor_; - //FIXME doc["ErrorText"] = error_code_text(error_code_sensor_).c_str(); - //FIXME doc["TrackingMode"] = tracking_mode_text(tracking_mode_id_sensor_).c_str(); - //FIXME doc["ChargingMode"] = charging_mode_text(charging_mode_id_sensor_).c_str(); - //FIXME doc["FirmwareVersion"] = firmware_version_text_sensor_.c_str(); - //FIXME doc["DeviceType"] = device_type_text(device_type_text_sensor_).c_str(); - //FIXME doc["AlarmConditionActive"] = alarm_condition_active_text_sensor_.c_str(); - serializeJson(doc, buffer); + buffer += "{ "; + buffer += "\"load\":" + String(load_state_binary_sensor_) + ",\n"; + buffer += "\"MaxPower\":{\n"; + buffer += "\"yesterday\":" + String(max_power_yesterday_sensor_) + ",\n"; + buffer += "\"today\":" + String(max_power_today_sensor_) + "\n"; + buffer += "},\n"; + buffer += "\"Yield\":{\n"; + buffer += "\"Total\":" + String(yield_total_sensor_) + ",\n"; + buffer += "\"Yesterday\":" + String(yield_yesterday_sensor_) + ",\n"; + buffer += "\"Today\":" + String(yield_today_sensor_) + "\n"; + buffer += "},\n"; + buffer += "\"Panel\":{\n"; + buffer += "\"Voltage\":" + String(panel_voltage_sensor_) + ",\n"; + buffer += "\"Power\":" + String(panel_power_sensor_) + "\n"; + buffer += "},\n"; + buffer += "\"Bat\":{\n"; + buffer += "\"Voltage\":" + String(battery_voltage_sensor_) + ",\n"; + buffer += "\"Current\":" + String(battery_current_sensor_) + "\n"; + buffer += "},\n"; + buffer += "\"LoadCurrent\":" + String(load_current_sensor_) + ",\n"; + buffer += "\"DayNumber\":" + String(day_number_sensor_) + ",\n"; + buffer += "\"ChargingModeID\":" + String(charging_mode_id_sensor_) + ",\n"; + buffer += "\"ErrorCode\":" + String(error_code_sensor_) + ",\n"; + buffer += "\"TrackingModeID\":" + String(tracking_mode_id_sensor_) + ",\n"; + buffer += "\"ErrorText\": \"" + String(error_code_text(error_code_sensor_).c_str()) + "\",\n"; + buffer += "\"TrackingMode\": \"" + String(tracking_mode_text(tracking_mode_id_sensor_).c_str()) + "\",\n"; + buffer += "\"ChargingMode\": \"" + String(charging_mode_text(charging_mode_id_sensor_).c_str()) + "\",\n"; + buffer += "\"FirmwareVersion\": \"" + String(firmware_version_text_sensor_.c_str()) + "\",\n"; + buffer += "\"DeviceType\": \"" + String(device_type_text(device_type_text_sensor_).c_str() ) + "\",\n"; + buffer += "\"AlarmConditionActive\": \"" + String(alarm_condition_active_text_sensor_.c_str()) + "\"\n"; + buffer += "}"; return buffer; } } From a0b214e9953eee5942c2b76dc9c7aaf671c19954 Mon Sep 17 00:00:00 2001 From: Ollo Date: Thu, 15 May 2025 21:45:45 +0200 Subject: [PATCH 46/57] Real device needs some time (compared to simulation) --- include/HomieSettings.h | 2 +- include/victron.h | 3 ++- src/victron.cpp | 27 +++++++++++++++------------ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 070ab19..e2e621d 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,7 +13,7 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.4.3" +#define HOMIE_FIRMWARE_VERSION "2.4.4" #define SERIAL_BAUDRATE 19200 diff --git a/include/victron.h b/include/victron.h index 107915f..ba2843b 100644 --- a/include/victron.h +++ b/include/victron.h @@ -14,6 +14,8 @@ #include #include +#define VICTRON_THROTTLE 100 + namespace victron { @@ -55,7 +57,6 @@ namespace victron std::string value_; uint32_t last_transmission_; uint32_t last_publish_; - uint32_t throttle_; /* All Settings */ diff --git a/src/victron.cpp b/src/victron.cpp index d7d3a69..51264eb 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -16,11 +16,6 @@ namespace victron { static const char *const TAG = "victron"; - VictronComponent::VictronComponent() - { - this->state_ = 0; - } - VictronComponent::~VictronComponent() { @@ -86,26 +81,27 @@ namespace victron { } continue; } - if (state_ == 2) { - if (label_ == "Checksum") { + if (state_ == 2) + { + if (label_ == "Checksum") { state_ = 0; // The checksum is used as end of frame indicator - if (now - this->last_publish_ >= this->throttle_) { + if ((now - this->last_publish_) >= VICTRON_THROTTLE) { this->last_publish_ = now; this->publishing_ = true; } else { this->publishing_ = false; } continue; - } - if (c == '\r' || c == '\n') { + } + if (c == '\r' || c == '\n') { if (this->publishing_) { handle_value_(); } state_ = 0; - } else { + } else { value_.push_back(c); - } + } } // Discard ve.direct hex frame if (state_ == 3) { @@ -231,11 +227,18 @@ namespace victron { String buffer; if (this->last_publish_ <= 0) { + buffer += "{ "; + buffer += "\"mode\": \"nodata\",\n"; + buffer += "\"state\":" + String(state_) + ",\n"; + buffer += "\"transmission\":" + String(last_transmission_) + ",\n"; + buffer += "\"publish\":" + String(last_publish_) + "\n"; + buffer += "}"; return buffer; } else { buffer += "{ "; + buffer += "\"mode\": \"newdata\",\n"; buffer += "\"load\":" + String(load_state_binary_sensor_) + ",\n"; buffer += "\"MaxPower\":{\n"; buffer += "\"yesterday\":" + String(max_power_yesterday_sensor_) + ",\n"; From 09464148b128302440019f20402ac237d4e2fc3b Mon Sep 17 00:00:00 2001 From: Ollo Date: Thu, 15 May 2025 21:46:12 +0200 Subject: [PATCH 47/57] Simulate Firmware, too --- host/simulateMPPT75-10.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/host/simulateMPPT75-10.py b/host/simulateMPPT75-10.py index b7fae2a..28f256e 100755 --- a/host/simulateMPPT75-10.py +++ b/host/simulateMPPT75-10.py @@ -40,7 +40,8 @@ if (updateSerial): lastUpdate=int(time.time()) # Send the status string - outStr="SER#\tHQ2202K3VD9\nV\t{0:d}\nI\t{1:d}\nVPV\t{2:d}\nPPV\t{3:d}\nChecksum f\r\n".format(battery_volt, battery_current, panel_volt, panel_power) + + outStr="FW\t159\nSER#\tHQ2202K3VD9\nV\t{0:d}\nI\t{1:d}\nVPV\t{2:d}\nPPV\t{3:d}\nChecksum f\r\n".format(battery_volt, battery_current, panel_volt, panel_power) # Other values # CS\t{4:d}\nMPPT\t{5:d}\nERR\t{6:d}\nLOAD\t{7}\nIL\t{8:d}\nH19\t{9:d}\nH20\t{10:d}\nH21\t{11:d}\nH22\t{12:d}\nH23\t{13:d}\nHSDS\t{14:d}\n From 5bf48493be655c00fd6c673b316e825b22613e28 Mon Sep 17 00:00:00 2001 From: Ollo Date: Thu, 15 May 2025 22:12:00 +0200 Subject: [PATCH 48/57] Return Volt instead of milliVolt --- include/victron.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/victron.h b/include/victron.h index ba2843b..d3034ab 100644 --- a/include/victron.h +++ b/include/victron.h @@ -29,11 +29,11 @@ namespace victron String toJson(void); int getBatteryVoltage() { - return battery_voltage_sensor_; + return (battery_voltage_sensor_ / 1000); } int getPanelVoltage() { - return panel_voltage_sensor_; + return (panel_voltage_sensor_ / 1000); } int getPanelPower() { From fde1c860f1f38449475845c0d0753d12326f1f30 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 24 May 2025 16:44:31 +0200 Subject: [PATCH 49/57] Debug interface introduced into victron module --- include/victron.h | 5 +++++ src/victron.cpp | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/victron.h b/include/victron.h index d3034ab..7913fd5 100644 --- a/include/victron.h +++ b/include/victron.h @@ -16,6 +16,8 @@ #define VICTRON_THROTTLE 100 +typedef void (*debug_serialcommunication) (std::string); + namespace victron { @@ -23,6 +25,7 @@ namespace victron { public: VictronComponent(int initialstate); + VictronComponent(int initialstate, debug_serialcommunication debugFunction); VictronComponent(); ~VictronComponent(); void loop(void); @@ -55,9 +58,11 @@ namespace victron int state_; std::string label_; std::string value_; + std::string complete_line_; uint32_t last_transmission_; uint32_t last_publish_; + debug_serialcommunication fdebugSerial = NULL; /* All Settings */ int max_power_yesterday_sensor_ = 0; diff --git a/src/victron.cpp b/src/victron.cpp index 51264eb..5776d7a 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -26,6 +26,12 @@ namespace victron { this->state_ = initialstate; } + VictronComponent::VictronComponent(int initialstate, debug_serialcommunication debugFunction) + { + this->state_ = initialstate; + this->fdebugSerial = debugFunction; + } + void VictronComponent::logTextSensor(String tag, String message, std::string text) { String complete = message + " : " + String(text.c_str()); @@ -60,8 +66,20 @@ namespace victron { while (Serial.available()) { uint8_t c; c = Serial.read(); + + if (fdebugSerial) /* debugging enabled */ + { + /* always store the incoming data */ + complete_line_.push_back(c); + } + if (state_ == 0) { if (c == '\r' || c == '\n') { + if ( (fdebugSerial) /* debugging enabled */ && (complete_line_.length() > 0) ) + { + fdebugSerial(complete_line_); + complete_line_.clear(); + } continue; } label_.clear(); From 90770267aea30d8d540b54b8211be5f47824b5d6 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 24 May 2025 16:57:15 +0200 Subject: [PATCH 50/57] Removed serial number --- include/victron.h | 3 --- src/victron.cpp | 5 ----- 2 files changed, 8 deletions(-) diff --git a/include/victron.h b/include/victron.h index 7913fd5..364c2e4 100644 --- a/include/victron.h +++ b/include/victron.h @@ -84,11 +84,8 @@ namespace victron bool load_state_binary_sensor_; std::string alarm_condition_active_text_sensor_; - std::string firmware_version_text_sensor_; long device_type_text_sensor_; - std::string serial_number_text_sensor_; - }; } // namespace victron diff --git a/src/victron.cpp b/src/victron.cpp index 5776d7a..3f6cd40 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -220,11 +220,6 @@ namespace victron { return; } - if (label_ == "SER#") { - serial_number_text_sensor_ = value_; - return; - } - if (label_ == "HSDS") { day_number_sensor_ = atoi(value_.c_str()); return; From e0087c20c498a94c8e8106a41648243dca385fe4 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 24 May 2025 17:15:06 +0200 Subject: [PATCH 51/57] Integrated Callback: publish data via MQTT (deactivate all internal strings in order to compile the project on an ESP8266) --- include/victron.h | 5 ++--- src/main.cpp | 12 ++++++++++++ src/victron.cpp | 9 +++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/victron.h b/include/victron.h index 364c2e4..610b60a 100644 --- a/include/victron.h +++ b/include/victron.h @@ -25,7 +25,6 @@ namespace victron { public: VictronComponent(int initialstate); - VictronComponent(int initialstate, debug_serialcommunication debugFunction); VictronComponent(); ~VictronComponent(); void loop(void); @@ -47,6 +46,8 @@ namespace victron return (battery_voltage_sensor_ > 0); } + void activateDebugging(debug_serialcommunication debugFunction); + private: void handle_value_(); void logTextSensor(String tag, String message, std::string text); @@ -83,8 +84,6 @@ namespace victron bool load_state_binary_sensor_; - std::string alarm_condition_active_text_sensor_; - std::string firmware_version_text_sensor_; long device_type_text_sensor_; }; diff --git a/src/main.cpp b/src/main.cpp index b1fb121..227099b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -163,6 +163,16 @@ uint32_t mMeasureIndex = 0; * LOCAL FUNCTIONS *****************************************************************************/ +/** + * @brief Log Victron communication plain to MQTT + * + * @param uartLine one complete line, received on VC.Direct Bus + */ +void mqttLog_callback(std::string uartLine) +{ + log(MQTT_LEVEL_DEBUG, String(uartLine.c_str()), MQTT_LOG_VICTRON); +} + /** * @brief Get the Sensor Data from software serial * @@ -229,6 +239,7 @@ void onHomieEvent(const HomieEvent &event) break; case HomieEventType::MQTT_READY: mConnected=true; + mppt.activateDebugging(mqttLog_callback); digitalWrite(WITTY_RGB_R, LOW); if (!i2cEnable.get()) { /** keep green LED activated to power I2C sensor */ digitalWrite(WITTY_RGB_G, LOW); @@ -301,6 +312,7 @@ void bmpPublishValues() { } } + /** * @brief Main loop, triggered by the Homie API * All logic needs to be done here. diff --git a/src/victron.cpp b/src/victron.cpp index 3f6cd40..44c269f 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -26,9 +26,8 @@ namespace victron { this->state_ = initialstate; } - VictronComponent::VictronComponent(int initialstate, debug_serialcommunication debugFunction) + void VictronComponent::activateDebugging(debug_serialcommunication debugFunction) { - this->state_ = initialstate; this->fdebugSerial = debugFunction; } @@ -167,7 +166,7 @@ namespace victron { } if (label_ == "Alarm") { - alarm_condition_active_text_sensor_ = value_; + /* Skip Alarm */ return; } @@ -210,7 +209,7 @@ namespace victron { if (label_ == "FW") { - firmware_version_text_sensor_ = value_.insert(value_.size() - 2, "."); + /* Skip firmware */ return; } @@ -278,9 +277,7 @@ namespace victron { buffer += "\"ErrorText\": \"" + String(error_code_text(error_code_sensor_).c_str()) + "\",\n"; buffer += "\"TrackingMode\": \"" + String(tracking_mode_text(tracking_mode_id_sensor_).c_str()) + "\",\n"; buffer += "\"ChargingMode\": \"" + String(charging_mode_text(charging_mode_id_sensor_).c_str()) + "\",\n"; - buffer += "\"FirmwareVersion\": \"" + String(firmware_version_text_sensor_.c_str()) + "\",\n"; buffer += "\"DeviceType\": \"" + String(device_type_text(device_type_text_sensor_).c_str() ) + "\",\n"; - buffer += "\"AlarmConditionActive\": \"" + String(alarm_condition_active_text_sensor_.c_str()) + "\"\n"; buffer += "}"; return buffer; } From f0ff44551fe162ee66530e15688d6356c625614e Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 24 May 2025 18:42:54 +0200 Subject: [PATCH 52/57] Changed to python3! --- host/upload-via-mqtt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/upload-via-mqtt.sh b/host/upload-via-mqtt.sh index 949eda2..5789b13 100755 --- a/host/upload-via-mqtt.sh +++ b/host/upload-via-mqtt.sh @@ -20,6 +20,6 @@ fi echo "Waiting for $homieId ..." mosquitto_sub -h $mqttHost -t "${mqttPrefix}${homieId}/#" -R -C 1 -python ota_updater.py -l $mqttHost -t "$mqttPrefix" -i "$homieId" $firmwareFile +python3 ota_updater.py -l $mqttHost -t "$mqttPrefix" -i "$homieId" $firmwareFile exit 0 From 391ea174792a0b5d82fbda79b10fde7c08ea7b0e Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 24 May 2025 18:43:28 +0200 Subject: [PATCH 53/57] =?UTF-8?q?Increased=20firmware=20version=C2=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/HomieSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index e2e621d..2421cc0 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -13,7 +13,7 @@ #define HOMIE_SETTINGS #define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.4.4" +#define HOMIE_FIRMWARE_VERSION "2.4.5" #define SERIAL_BAUDRATE 19200 From d03ca97efb59f2e7f389554b9a17d9ff5e12cfb1 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sat, 24 May 2025 18:50:41 +0200 Subject: [PATCH 54/57] print controller uptime with each log message --- src/MqttLog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MqttLog.cpp b/src/MqttLog.cpp index 21abbd8..0db3e16 100644 --- a/src/MqttLog.cpp +++ b/src/MqttLog.cpp @@ -23,6 +23,7 @@ void log(int level, String message, int statusCode) String buffer; StaticJsonDocument<200> doc; doc["level"] = level; + doc["uptime"] = String(millis()); doc["message"] = message; doc["statusCode"] = statusCode; serializeJson(doc, buffer); From 897fc7881e72155d206e529fd47a8cc177e1e3c8 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 27 Jul 2025 13:20:48 +0200 Subject: [PATCH 55/57] Display current flashed version in Firmware name --- include/HomieSettings.h | 15 +++++++++++++-- platformio.ini | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/HomieSettings.h b/include/HomieSettings.h index 2421cc0..5f67333 100644 --- a/include/HomieSettings.h +++ b/include/HomieSettings.h @@ -12,9 +12,20 @@ #ifndef HOMIE_SETTINGS #define HOMIE_SETTINGS -#define HOMIE_FIRMWARE_NAME "RoomSensor" -#define HOMIE_FIRMWARE_VERSION "2.4.5" +#if BME680 +#define FIRMWARE_FEATURE1 "_Bme680" +#else +#define FIRMWARE_FEATURE1 "" +#endif +#if VICTRON +#define FIRMWARE_FEATURE2 "_Victron" +#else +#define FIRMWARE_FEATURE2 "" +#endif + +#define HOMIE_FIRMWARE_NAME "RoomSensor" FIRMWARE_FEATURE1 FIRMWARE_FEATURE2 +#define HOMIE_FIRMWARE_VERSION "2.4.5" #define SERIAL_BAUDRATE 19200 diff --git a/platformio.ini b/platformio.ini index fba63e4..47c33bf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -17,7 +17,7 @@ build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 -D VICTRON ; -D BMP280 ;or ; -D BME680 -; Optinal Paramter to read Victron MPPT +; Optinal Paramter to read Victron MPPT: -D VICTRON ; the latest development branch (convention V3.0.x) lib_deps = https://github.com/homieiot/homie-esp8266.git#develop From 32f55d97a156551dd7b51a0d7760373d1df66d90 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 27 Jul 2025 13:28:59 +0200 Subject: [PATCH 56/57] skip optional VICTRON code --- src/main.cpp | 6 ++++-- src/victron.cpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 227099b..5b9b136 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,7 +239,9 @@ void onHomieEvent(const HomieEvent &event) break; case HomieEventType::MQTT_READY: mConnected=true; +#ifdef VICTRON mppt.activateDebugging(mqttLog_callback); +#endif digitalWrite(WITTY_RGB_R, LOW); if (!i2cEnable.get()) { /** keep green LED activated to power I2C sensor */ digitalWrite(WITTY_RGB_G, LOW); @@ -439,10 +441,10 @@ void setup() Homie.setLoopFunction(loopHandler); Homie.onEvent(onHomieEvent); i2cEnable.setDefaultValue(false); - deepsleepMppt.setDefaultValue(false); #if VICTRON - rgbTemp.setDefaultValue(false); + deepsleepMppt.setDefaultValue(false); #endif + rgbTemp.setDefaultValue(false); rgbDim.setDefaultValue(100).setValidator([] (long candidate) { return (candidate > 1) && (candidate <= 200); diff --git a/src/victron.cpp b/src/victron.cpp index 44c269f..5887341 100644 --- a/src/victron.cpp +++ b/src/victron.cpp @@ -8,6 +8,7 @@ * https://github.com/KinDR007/VictronMPPT-ESPHOME/blob/main/components/victron/victron.cpp */ +#ifdef VICTRON #include "victron.h" #include "MqttLog.h" #include "VictronTexts.h" @@ -283,3 +284,4 @@ namespace victron { } } } +#endif /* VICTRON */ From 86b95fc048636bbfd353abf8fd5ee908a74fa9b4 Mon Sep 17 00:00:00 2001 From: Ollo Date: Sun, 27 Jul 2025 13:29:10 +0200 Subject: [PATCH 57/57] deactivate VICTRON device --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 47c33bf..236f19d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,7 +12,7 @@ platform = espressif8266 board = d1_mini framework = arduino -build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 -D VICTRON +build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -D BME680 ; build_flag needs define the Bosch sensor... ; -D BMP280 ;or