diff --git a/BUILDS.md b/BUILDS.md index 5939ba1d6..6512304ab 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -80,7 +80,7 @@ m = minimal, l = lite, t = tasmota, k = knx, s = sensors, i = ir, d = display | USE_DDSU666 | - | - | - / x | - | x | - | - | | USE_SOLAX_X1 | - | - | - / - | - | - | - | - | | USE_LE01MR | - | - | - / - | - | - | - | - | -| USE_BL0940 | - | x | x / - | x | x | - | - | +| USE_BL09XX | - | x | x / x | x | x | - | - | | USE_TELEINFO | - | - | - / - | - | - | - | - | | USE_IEM3000 | - | - | - / - | - | - | - | - | | USE_WE517 | - | - | - / - | - | - | - | - | diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 766f31d6a..69ed9612e 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 358390bc9..1fde089d9 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -709,6 +709,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index be7396a92..4809e6ccf 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 2e94554d1..0cc13b3db 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index d18aa9bce..37b10413d 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 2caab6abc..dbcfb9a6f 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index c5d98d79e..9f8144dd0 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index bd63fc53f..dbdca0efe 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -709,7 +709,8 @@ #define D_SENSOR_CSE7761_TX "CSE7761 TX" #define D_SENSOR_CSE7761_RX "CSE7761 RX" #define D_SENSOR_CSE7766_TX "CSE7766 TX" -#define D_SENSOR_CSE7766_RX "CSE7766 RX" +#define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 TX" #define D_SENSOR_PN532_RX "PN532 RX" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index 86e0fb7d2..7703bfcee 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index efd02b2f4..9ebd39c51 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 3da61ccc6..5f1c511ab 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 413e70a26..7b3335658 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -764,6 +764,7 @@ #define D_SENSOR_LE01MR_RX "LE-01MR - RX" #define D_SENSOR_LE01MR_TX "LE-01MR - TX" #define D_SENSOR_BL0940_RX "BL0940 - RX" +#define D_SENSOR_BL0939_RX "BL0939 - RX" #define D_SENSOR_CC1101_GDO0 "CC1101 - GDO0" #define D_SENSOR_CC1101_GDO2 "CC1101 - GDO2" #define D_SENSOR_HRXL_RX "HRXL - RX" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index d427966cd..4ebb63250 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 56015b023..56e0a5faf 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 7f9b79727..be85b7f5b 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 83a9d88c3..e0822795f 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 1775cbd75..32b4c9ace 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index b1058e60d..6ea846aea 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index b6fb1bc35..b34629afb 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 3ac233b00..bb38d0625 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index c026d53b6..2c4b4bb29 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 5d2d969b4..547b14a43 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 3be6240c2..829dc18cd 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index d1e855bec..f60e26634 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index c9a64adac..30332b22b 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 2074f04f7..f9aebfe20 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -710,6 +710,7 @@ #define D_SENSOR_CSE7761_RX "CSE7761 Rx" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_PN532_TX "PN532 Tx" #define D_SENSOR_PN532_RX "PN532 Rx" #define D_SENSOR_SM16716_CLK "SM16716 CLK" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index fd68aeb96..64545b496 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -780,7 +780,7 @@ //#define USE_LE01MR // Add support for F&F LE-01MR Modbus energy monitor (+1k code) #define LE01MR_SPEED 9600 // LE-01MR modbus baudrate (default: 9600) #define LE01MR_ADDR 1 // LE-01MR modbus address (default: 0x01) -#define USE_BL0940 // Add support for BL0940 Energy monitor as used in Blitzwolf SHP-10 (+1k6 code) +#define USE_BL09XX // Add support for various BL09XX Energy monitor as used in Blitzwolf SHP-10 or Sonoff Dual R3 v2 (+1k6 code) //#define USE_TELEINFO // Add support for Teleinfo via serial RX interface (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM) //#define USE_IEM3000 // Add support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code) #define IEM3000_SPEED 19200 // iEM3000-Modbus RS485 serial speed (default: 19200 baud) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index a4311ea74..e696f9cc8 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -567,8 +567,8 @@ void ResponseAppendFeatures(void) #if defined(USE_I2C) && defined(USE_MCP9808) feature6 |= 0x00002000; // xsns_72_mcp9808.ino #endif -#if defined(USE_ENERGY_SENSOR) && defined(USE_BL0940) - feature6 |= 0x00004000; // xnrg_14_bl0940.ino +#if defined(USE_ENERGY_SENSOR) && (defined(USE_BL0940) || defined(USE_BL09XX)) + feature6 |= 0x00004000; // xnrg_14_bl09xx.ino #endif #ifdef USE_TELEGRAM feature6 |= 0x00008000; // xdrv_40_telegram.ino diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index c7c315cbb..4d34f22e3 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -876,7 +876,7 @@ #undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code) #undef USE_SOLAX_X1 // Disable support for Solax X1 series Modbus log info (+3k1 code) #undef USE_LE01MR // Disable support for F&F LE-01MR Modbus energy meter (+2k code) -#undef USE_BL0940 // Disable support for BL0940 Energy monitor as used in Blitzwolf SHP-10 (+1k6 code) +#undef USE_BL09XX // Add support for various BL09XX Energy monitor as used in Blitzwolf SHP-10 or Sonoff Dual R3 v2 (+1k6 code) #undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry #undef USE_IEM3000 // Disable support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code) #undef USE_WE517 // Disable support for Orno WE517-Modbus energy monitor (+1k code) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index e38041af6..e8ba6c5f2 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -172,6 +172,7 @@ enum UserSelectablePins { GPIO_MCP2515_CS, // MCP2515 Chip Select GPIO_HRG15_TX, GPIO_HRG15_RX, // Hydreon RG-15 rain sensor serial interface GPIO_VINDRIKTNING_RX, // IKEA VINDRIKTNING Serial interface + GPIO_BL0939_RX, // BL0939 Serial interface (Dual R3 v2) GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -363,7 +364,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_INTERRUPT "|" D_SENSOR_MCP2515_CS "|" D_SENSOR_HRG15_TX "|" D_SENSOR_HRG15_RX "|" - D_SENSOR_VINDRIKTNING_RX + D_SENSOR_VINDRIKTNING_RX "|" + D_SENSOR_BL0939_RX ; const char kSensorNamesFixed[] PROGMEM = @@ -694,7 +696,8 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_LE01MR_TX), // F7F LE-01MR energy meter tx pin AGPIO(GPIO_LE01MR_RX), // F7F LE-01MR energy meter rx pin #endif // IFDEF:USE_LE01MR -#ifdef USE_BL0940 +#if defined(USE_BL0940) || defined(USE_BL09XX) + AGPIO(GPIO_BL0939_RX), // BL0939 Serial interface (Dual R3 v2) AGPIO(GPIO_BL0940_RX), // BL0940 Serial interface #endif #ifdef USE_IEM3000 diff --git a/tasmota/xnrg_14_bl0940.ino b/tasmota/xnrg_14_bl0940.ino deleted file mode 100644 index ecd30c543..000000000 --- a/tasmota/xnrg_14_bl0940.ino +++ /dev/null @@ -1,326 +0,0 @@ -/* - xnrg_14_bl0940.ino - BL0940 energy sensor support for Tasmota - - Copyright (C) 2021 Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifdef USE_ENERGY_SENSOR -#ifdef USE_BL0940 -/*********************************************************************************************\ - * BL0940 - Energy (Blitzwolf SHP10) - * - * Template {"NAME":"BW-SHP10","GPIO":[0,148,0,207,158,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} - * - * Based on datasheet from http://www.belling.com.cn/media/file_object/bel_product/BL0940/datasheet/BL0940_V1.1_en.pdf -\*********************************************************************************************/ - -#define XNRG_14 14 - -#define BL0940_PREF 1430 -#define BL0940_UREF 33000 -#define BL0940_IREF 2750 - -#define BL0940_PULSES_NOT_INITIALIZED -1 - -#define BL0940_BUFFER_SIZE 36 - -#define BL0940_WRITE_COMMAND 0xA0 // 0xA8 according to documentation -#define BL0940_REG_I_FAST_RMS_CTRL 0x10 -#define BL0940_REG_MODE 0x18 -#define BL0940_REG_SOFT_RESET 0x19 -#define BL0940_REG_USR_WRPROT 0x1A -#define BL0940_REG_TPS_CTRL 0x1B - -#define BL0940_READ_COMMAND 0x50 // 0x58 according to documentation -#define BL0940_FULL_PACKET 0xAA - -#define BL0940_PACKET_HEADER 0x55 // 0x58 according to documentation - -#include - -TasmotaSerial *Bl0940Serial = nullptr; - -struct BL0940 { - long voltage = 0; - long current = 0; - long power = 0; - long power_cycle_first = 0; - long cf_pulses = 0; - long cf_pulses_last_time = BL0940_PULSES_NOT_INITIALIZED; - float temperature; - - int byte_counter = 0; - uint16_t tps1 = 0; - uint8_t *rx_buffer = nullptr; - bool received = false; -} Bl0940; - -const uint8_t bl0940_init[5][6] = { - { BL0940_WRITE_COMMAND, BL0940_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38 }, // Reset to default - { BL0940_WRITE_COMMAND, BL0940_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0 }, // Enable User Operation Write - { BL0940_WRITE_COMMAND, BL0940_REG_MODE, 0x00, 0x10, 0x00, 0x37 }, // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS - { BL0940_WRITE_COMMAND, BL0940_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE }, // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS - { BL0940_WRITE_COMMAND, BL0940_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B }}; // 0x181C = Half cycle, Fast RMS threshold 6172 - -void Bl0940Received(void) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 - // 55 F2 03 00 00 00 00 7E 02 00 D4 B0 72 AC 01 00 00 00 00 02 01 00 00 00 00 00 00 00 BA 01 00 FE 03 00 83 - // 55 88 02 00 49 00 00 FE 02 00 AF EF 71 D2 01 00 EB FF FF 49 01 00 00 00 00 02 00 00 CF 01 00 FE 03 00 9F - // 55 B9 33 00 DE 45 00 94 02 00 CF E4 70 63 02 00 6C 4C 00 13 01 00 09 00 00 00 00 00 E4 01 00 FE 03 00 72 - // Hd IFRms--- Current- Reserved Voltage- Reserved Power--- Reserved CF------ Reserved TPS1---- TPS2---- Ck - - uint16_t tps1 = Bl0940.rx_buffer[29] << 8 | Bl0940.rx_buffer[28]; // TPS1 unsigned - if ((Bl0940.rx_buffer[0] != BL0940_PACKET_HEADER) || // Bad header - (Bl0940.tps1 && ((tps1 < (Bl0940.tps1 -10)) || (tps1 > (Bl0940.tps1 +10)))) // Invalid temperature change - ) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Invalid data")); - return; - } - - Bl0940.tps1 = tps1; - float t = ((170.0f/448.0f)*(((float)Bl0940.tps1/2.0f)-32.0f))-45.0f; - Bl0940.temperature = ConvertTemp(t); - - Bl0940.voltage = Bl0940.rx_buffer[12] << 16 | Bl0940.rx_buffer[11] << 8 | Bl0940.rx_buffer[10]; // V_RMS unsigned - Bl0940.current = Bl0940.rx_buffer[6] << 16 | Bl0940.rx_buffer[5] << 8 | Bl0940.rx_buffer[4]; // I_RMS unsigned - int32_t power = Bl0940.rx_buffer[18] << 24 | Bl0940.rx_buffer[17] << 16 | Bl0940.rx_buffer[16] << 8; // WATT signed - Bl0940.power = abs(power) >> 8; // WATT unsigned - int32_t cf_cnt = Bl0940.rx_buffer[24] << 24 | Bl0940.rx_buffer[23] << 16 | Bl0940.rx_buffer[22] << 8; // CF_CNT signed - Bl0940.cf_pulses = abs(cf_cnt) >> 8; - - AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: U %d, I %d, P %d, C %d, T %d"), - Bl0940.voltage, Bl0940.current, Bl0940.power, Bl0940.cf_pulses, Bl0940.tps1); - - if (Energy.power_on) { // Powered on - Energy.voltage[0] = (float)Bl0940.voltage / Settings->energy_voltage_calibration; - if (power && (Bl0940.power > Settings->energy_power_calibration)) { // We need at least 1W - Energy.active_power[0] = (float)Bl0940.power / Settings->energy_power_calibration; - Energy.current[0] = (float)Bl0940.current / (Settings->energy_current_calibration * 100); - } else { - Energy.active_power[0] = 0; - Energy.current[0] = 0; - } - } else { // Powered off -// Bl0940.power_cycle_first = 0; - Energy.voltage[0] = 0; - Energy.active_power[0] = 0; - Energy.current[0] = 0; - } -} - -void Bl0940SerialInput(void) { - while (Bl0940Serial->available()) { - yield(); - uint8_t serial_in_byte = Bl0940Serial->read(); - if (!Bl0940.received && (BL0940_PACKET_HEADER == serial_in_byte)) { - Bl0940.received = true; - Bl0940.byte_counter = 0; - } - if (Bl0940.received) { - Bl0940.rx_buffer[Bl0940.byte_counter++] = serial_in_byte; - if (BL0940_BUFFER_SIZE == Bl0940.byte_counter) { - - AddLogBuffer(LOG_LEVEL_DEBUG_MORE, Bl0940.rx_buffer, BL0940_BUFFER_SIZE -1); - - uint8_t checksum = BL0940_READ_COMMAND; - for (uint32_t i = 0; i < BL0940_BUFFER_SIZE -2; i++) { checksum += Bl0940.rx_buffer[i]; } - checksum ^= 0xFF; - if (checksum == Bl0940.rx_buffer[34]) { - Energy.data_valid[0] = 0; - Bl0940Received(); - Bl0940.received = false; - return; - } else { - do { // Sync buffer with data (issue #1907 and #3425) - memmove(Bl0940.rx_buffer, Bl0940.rx_buffer +1, BL0940_BUFFER_SIZE -1); - Bl0940.byte_counter--; - } while ((Bl0940.byte_counter > 1) && (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0])); - if (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0]) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE)); - Bl0940.received = false; - Bl0940.byte_counter = 0; - } - } - } - } - } -} - -/********************************************************************************************/ - -void Bl0940EverySecond(void) { - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { - Bl0940.voltage = 0; - Bl0940.current = 0; - Bl0940.power = 0; - } else { -/* - // Calculate energy by using active power - if (Energy.active_power[0]) { - Energy.kWhtoday_delta += (Energy.active_power[0] * 1000) / 36; - EnergyUpdateToday(); - } -*/ - // Calculate energy by using active energy pulse count - if (BL0940_PULSES_NOT_INITIALIZED == Bl0940.cf_pulses_last_time) { - Bl0940.cf_pulses_last_time = Bl0940.cf_pulses; // Init after restart - } else { - uint32_t cf_pulses = 0; - if (Bl0940.cf_pulses < Bl0940.cf_pulses_last_time) { // Rolled over after 0xFFFFFF (16777215) pulses - cf_pulses = (0x1000000 - Bl0940.cf_pulses_last_time) + Bl0940.cf_pulses; - } else { - cf_pulses = Bl0940.cf_pulses - Bl0940.cf_pulses_last_time; - } - if (cf_pulses && Energy.active_power[0]) { - uint32_t watt256 = (1638400 * 256) / Settings->energy_power_calibration; - uint32_t delta = (cf_pulses * watt256) / 36; - if (delta <= (4000 * 1000 / 36)) { // max load for SHP10: 4.00kW (3.68kW) - Bl0940.cf_pulses_last_time = Bl0940.cf_pulses; - Energy.kWhtoday_delta += delta; - } else { - AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Overload")); - Bl0940.cf_pulses_last_time = BL0940_PULSES_NOT_INITIALIZED; - } - EnergyUpdateToday(); - } - } - - } - -// AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Poll")); - - Bl0940Serial->flush(); - Bl0940Serial->write(BL0940_READ_COMMAND); - Bl0940Serial->write(BL0940_FULL_PACKET); -} - -void Bl0940SnsInit(void) { - // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions - Bl0940Serial = new TasmotaSerial(Pin(GPIO_BL0940_RX), Pin(GPIO_TXD), 1); - if (Bl0940Serial->begin(4800, 1)) { - if (Bl0940Serial->hardwareSerial()) { - ClaimSerial(); - } - if (HLW_UREF_PULSE == Settings->energy_voltage_calibration) { - Settings->energy_voltage_calibration = BL0940_UREF; - Settings->energy_current_calibration = BL0940_IREF; - Settings->energy_power_calibration = BL0940_PREF; - } - Energy.use_overtemp = true; // Use global temperature for overtemp detection - - for (uint32_t i = 0; i < 5; i++) { - for (uint32_t j = 0; j < 6; j++) { - Bl0940Serial->write(bl0940_init[i][j]); -// Bl0940Serial->write(pgm_read_byte(bl0940_init + (6 * i) + j)); // Wrong byte order! - } - delay(1); - } - - } else { - TasmotaGlobal.energy_driver = ENERGY_NONE; - } -} - -void Bl0940DrvInit(void) { - if (PinUsed(GPIO_BL0940_RX) && PinUsed(GPIO_TXD)) { - Bl0940.rx_buffer = (uint8_t*)(malloc(BL0940_BUFFER_SIZE)); - if (Bl0940.rx_buffer != nullptr) { - TasmotaGlobal.energy_driver = XNRG_14; - } - } -} - -bool Bl0940Command(void) { - bool serviced = true; - - uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 - - if (CMND_POWERSET == Energy.command_code) { - if (XdrvMailbox.data_len && Bl0940.power) { - Settings->energy_power_calibration = (Bl0940.power * 100) / value; - } - } - else if (CMND_VOLTAGESET == Energy.command_code) { - if (XdrvMailbox.data_len && Bl0940.voltage) { - Settings->energy_voltage_calibration = (Bl0940.voltage * 100) / value; - } - } - else if (CMND_CURRENTSET == Energy.command_code) { - if (XdrvMailbox.data_len && Bl0940.current) { - Settings->energy_current_calibration = Bl0940.current / value; - } - } - else serviced = false; // Unknown command - - return serviced; -} - -void Bl0940Show(bool json) { - if (json) { - ResponseAppend_P(JSON_SNS_F_TEMP, "BL0940", Settings->flag2.temperature_resolution, &Bl0940.temperature); - if (0 == TasmotaGlobal.tele_period) { -#ifdef USE_DOMOTICZ - DomoticzFloatSensor(DZ_TEMP, Bl0940.temperature); -#endif // USE_DOMOTICZ -#ifdef USE_KNX - KnxSensor(KNX_TEMPERATURE, Bl0940.temperature); -#endif // USE_KNX - } -#ifdef USE_WEBSERVER - } else { - WSContentSend_Temp("", Bl0940.temperature); -#endif // USE_WEBSERVER - - } -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xnrg14(uint8_t function) { - bool result = false; - - switch (function) { - case FUNC_LOOP: - if (Bl0940Serial) { Bl0940SerialInput(); } - break; - case FUNC_EVERY_SECOND: - Bl0940EverySecond(); - break; - case FUNC_JSON_APPEND: - Bl0940Show(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - Bl0940Show(0); - break; -#endif // USE_WEBSERVER - case FUNC_COMMAND: - result = Bl0940Command(); - break; - case FUNC_INIT: - Bl0940SnsInit(); - break; - case FUNC_PRE_INIT: - Bl0940DrvInit(); - break; - } - return result; -} - -#endif // USE_BL0940 -#endif // USE_ENERGY_SENSOR diff --git a/tasmota/xnrg_14_bl09xx.ino b/tasmota/xnrg_14_bl09xx.ino new file mode 100644 index 000000000..a21f820f8 --- /dev/null +++ b/tasmota/xnrg_14_bl09xx.ino @@ -0,0 +1,388 @@ +/* + xnrg_14_bl09xx.ino - BL09XX energy sensor support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ENERGY_SENSOR +#if defined(USE_BL0940) || defined(USE_BL09XX) +#ifdef USE_BL0940 +#warning **** USE_BL0940 is obsolete. Please replace with USE_BLE09XX **** +#endif +/*********************************************************************************************\ + * Support the following Shangai Belling energy sensors: + * + * BL09XX - Energy (as in Blitzwolf SHP10 + * Template {"NAME":"BW-SHP10","GPIO":[0,148,0,207,158,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} + * Based on datasheet from http://www.belling.com.cn/media/file_object/bel_product/BL09XX/datasheet/BL09XX_V1.1_en.pdf + * + * BL0939 - Energy (as in Sonoff Dual R3 v2) + * {"NAME":"Sonoff Dual R3 v2","GPIO":[32,0,0,0,0,0,0,0,0,576,225,0,0,0,0,0,0,0,0,0,0,3200,8128,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1} + * Based on datasheet from https://www.belling.com.cn/product_info.html?id=368 + * See https://github.com/arendst/Tasmota/discussions/10793 + \*********************************************************************************************/ + +#define XNRG_14 14 + +#define BL09XX_PREF 713 // =(4046*1*0,51*1000)/(1,218*1,218*(390*5+0,51)) = 713,105 +#define BL09XX_UREF 17159 // =(79931*0,51*1000)/(1,218*(390*5+0,51)) = 17158,92 +#define BL09XX_IREF 266013 // =(324004*1)/1,218 = 266013,14 + +#define BL09XX_PULSES_NOT_INITIALIZED -1 + +#define BL09XX_BUFFER_SIZE 36 + +#define BL0939_MODEL 39 +#define BL0940_MODEL 40 + +#define BL0939_ADDRESS 0x05 +#define BL0940_ADDRESS 0x00 + +#define BL09XX_WRITE_COMMAND 0xA0 // 0xA8 according to documentation +#define BL09XX_REG_I_FAST_RMS_CTRL 0x10 +#define BL09XX_REG_MODE 0x18 +#define BL09XX_REG_SOFT_RESET 0x19 +#define BL09XX_REG_USR_WRPROT 0x1A +#define BL09XX_REG_TPS_CTRL 0x1B + +#define BL09XX_READ_COMMAND 0x50 // 0x58 according to documentation +#define BL09XX_FULL_PACKET 0xAA + +#define BL09XX_PACKET_HEADER 0x55 // 0x58 according to documentation + +#include + +TasmotaSerial *Bl09XXSerial = nullptr; + +struct BL09XX { + long voltage = 0; + long current[2] = { 0, }; + long power[2] = { 0, }; + long power_cycle_first = 0; + long cf_pulses[2] = { 0, }; + long cf_pulses_last_time[2] = { BL09XX_PULSES_NOT_INITIALIZED, BL09XX_PULSES_NOT_INITIALIZED}; + float temperature; + uint8_t address; + uint8_t model; + int byte_counter = 0; + uint16_t tps1 = 0; + uint8_t *rx_buffer = nullptr; + bool received = false; +} Bl09XX; + +const uint8_t bl09xx_init[5][6] = { + { BL09XX_WRITE_COMMAND, BL09XX_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38 }, // Reset to default + { BL09XX_WRITE_COMMAND, BL09XX_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0 }, // Enable User Operation Write + { BL09XX_WRITE_COMMAND, BL09XX_REG_MODE, 0x00, 0x10, 0x00, 0x37 }, // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS + { BL09XX_WRITE_COMMAND, BL09XX_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE }, // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS + { BL09XX_WRITE_COMMAND, BL09XX_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B }}; // 0x181C = Half cycle, Fast RMS threshold 6172 + +void Bl09XXReceived(void) { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 + // Sample from BL0940 (single channel) + // 55 F2 03 00 00 00 00 7E 02 00 D4 B0 72 AC 01 00 00 00 00 02 01 00 00 00 00 00 00 00 BA 01 00 FE 03 00 83 + // 55 88 02 00 49 00 00 FE 02 00 AF EF 71 D2 01 00 EB FF FF 49 01 00 00 00 00 02 00 00 CF 01 00 FE 03 00 9F + // 55 B9 33 00 DE 45 00 94 02 00 CF E4 70 63 02 00 6C 4C 00 13 01 00 09 00 00 00 00 00 E4 01 00 FE 03 00 72 + // Hd IFRms--- Current- Reserved Voltage- Reserved Power--- Reserved CF------ Reserved TPS1---- TPS2---- Ck + // Sample from BL0939 (dual channel) + // 55 82 03 00 00 00 00 1E 15 01 65 80 3E E5 C6 00 00 00 00 50 B1 00 00 00 00 00 00 00 F9 01 00 FE 03 00 D2 = U 4096101, I 0/70942, P 0/45392, C 0/0, T 505 + // 55 E6 02 00 00 00 00 37 15 01 0F 83 3E F4 C7 00 00 00 00 69 B1 00 00 00 00 01 00 00 FA 01 00 FE 03 00 7E = U 4096783, I 0/70967, P 0/45417, C 0/1, T 506 + // 55 29 03 00 00 00 00 27 15 01 3A 86 3E AF C8 00 00 00 00 67 B1 00 00 00 00 01 00 00 FA 01 00 FE 03 00 62 = U 4097594, I 0/70951, P 0/45415, C 0/1, T 506 + // 55 04 03 00 00 00 00 D6 14 01 7D 8E 3E 25 C7 00 00 00 00 53 B1 00 00 00 00 01 00 00 F9 01 00 FE 03 00 2E = U 4099709, I 0/70870, P 0/45395, C 0/1, T 505 + // Hd IFRms-A- CurrentA CurrentB Voltage- IFRms-B- PowerA-- PowerB-- CF-A---- CF-B---- TPS1---- TPS2---- Ck + + uint16_t tps1 = Bl09XX.rx_buffer[29] << 8 | Bl09XX.rx_buffer[28]; // TPS1 unsigned + if ((Bl09XX.rx_buffer[0] != BL09XX_PACKET_HEADER) || // Bad header + (Bl09XX.tps1 && ((tps1 < (Bl09XX.tps1 -10)) || (tps1 > (Bl09XX.tps1 +10)))) // Invalid temperature change + ) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Invalid data")); + return; + } + + Bl09XX.tps1 = tps1; + float t = ((170.0f/448.0f)*(((float)Bl09XX.tps1/2.0f)-32.0f))-45.0f; + Bl09XX.temperature = ConvertTemp(t); + + Bl09XX.voltage = Bl09XX.rx_buffer[12] << 16 | Bl09XX.rx_buffer[11] << 8 | Bl09XX.rx_buffer[10]; // V_RMS unsigned + + int32_t tmp; + Bl09XX.current[0] = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // IA_RMS unsigned + tmp = Bl09XX.rx_buffer[18] << 24 | Bl09XX.rx_buffer[17] << 16 | Bl09XX.rx_buffer[16] << 8; // WATT_A signed + Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned + tmp = Bl09XX.rx_buffer[24] << 24 | Bl09XX.rx_buffer[23] << 16 | Bl09XX.rx_buffer[22] << 8; // CFA_CNT signed + Bl09XX.cf_pulses[0] = abs(tmp >> 8); // CFA_CNT unsigned + + if (Energy.phase_count > 1) { + Bl09XX.current[1] = Bl09XX.rx_buffer[9] << 16 | Bl09XX.rx_buffer[8] << 8 | Bl09XX.rx_buffer[7]; // IB_RMS unsigned + tmp = Bl09XX.rx_buffer[21] << 24 | Bl09XX.rx_buffer[20] << 16 | Bl09XX.rx_buffer[19] << 8; // WATT_B signed + Bl09XX.power[1] = abs(tmp >> 8); // WATT_B unsigned + tmp = Bl09XX.rx_buffer[27] << 24 | Bl09XX.rx_buffer[26] << 16 | Bl09XX.rx_buffer[25] << 8; // CFB_CNT signed + Bl09XX.cf_pulses[1] = abs(tmp >> 8); // CFB_CNT unsigned + } + + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d/%d, P %d/%d, C %d/%d, T %d"), + // Bl09XX.voltage, Bl09XX.current[0], Bl09XX.current[1], Bl09XX.power[0], Bl09XX.power[1], Bl09XX.cf_pulses[0], Bl09XX.cf_pulses[1], Bl09XX.tps1); + + if (Energy.power_on) { // Powered on + Energy.voltage[0] = (float)Bl09XX.voltage / Settings->energy_voltage_calibration; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Voltage %f, Temp %f"), Energy.voltage[0], Bl09XX.temperature); + for ( int chan = 0 ; chan < Energy.phase_count ; chan++ ) { + if (Bl09XX.power[chan] > Settings->energy_power_calibration) { // We need at least 1W + Energy.active_power[chan] = (float)Bl09XX.power[chan] / Settings->energy_power_calibration; + Energy.current[chan] = (float)Bl09XX.current[chan] / Settings->energy_current_calibration; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Chan[%d] I %f, P %f"), chan, Energy.current[chan], Energy.active_power[chan]); + } else { + Energy.active_power[chan] = 0; + Energy.current[chan] = 0; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Chan[%d] I zero, P zero"), chan); + } + } + } else { // Powered off + // Bl09XX.power_cycle_first = 0; + Energy.voltage[0] = 0; + Energy.active_power[0] = Energy.active_power[1] = 0; + Energy.current[0] = Energy.current[1] = 0; + } +} + +void Bl09XXSerialInput(void) { + while (Bl09XXSerial->available()) { + yield(); + uint8_t serial_in_byte = Bl09XXSerial->read(); + if (!Bl09XX.received && (BL09XX_PACKET_HEADER == serial_in_byte)) { + Bl09XX.received = true; + Bl09XX.byte_counter = 0; + } + if (Bl09XX.received) { + Bl09XX.rx_buffer[Bl09XX.byte_counter++] = serial_in_byte; + if (BL09XX_BUFFER_SIZE == Bl09XX.byte_counter) { + + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, Bl09XX.rx_buffer, BL09XX_BUFFER_SIZE -1); + + uint8_t checksum = BL09XX_READ_COMMAND | Bl09XX.address; + for (uint32_t i = 0; i < BL09XX_BUFFER_SIZE -2; i++) { checksum += Bl09XX.rx_buffer[i]; } + checksum ^= 0xFF; + if (checksum == Bl09XX.rx_buffer[34]) { + Energy.data_valid[0] = 0; + Bl09XXReceived(); + Bl09XX.received = false; + return; + } else { + //AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE "received 0x%02X instead of 0x%02X"), Bl09XX.rx_buffer[34], checksum); + do { // Sync buffer with data (issue #1907 and #3425) + memmove(Bl09XX.rx_buffer, Bl09XX.rx_buffer +1, BL09XX_BUFFER_SIZE -1); + Bl09XX.byte_counter--; + } while ((Bl09XX.byte_counter > 1) && (BL09XX_PACKET_HEADER != Bl09XX.rx_buffer[0])); + if (BL09XX_PACKET_HEADER != Bl09XX.rx_buffer[0]) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE)); + Bl09XX.received = false; + Bl09XX.byte_counter = 0; + } + } + } + } + } +} + +/********************************************************************************************/ + +void Bl09XXEverySecond(void) { + if (Energy.data_valid[0] > ENERGY_WATCHDOG) { + Bl09XX.voltage = 0; + memset(Bl09XX.current,0,sizeof(Bl09XX.current)); + memset(Bl09XX.power,0,sizeof(Bl09XX.power)); + } else { +/* + // Calculate energy by using active power + if (Energy.active_power[0]) { + Energy.kWhtoday_delta += (Energy.active_power[0] * 1000) / 36; + EnergyUpdateToday(); + } +*/ + // Calculate energy by using active energy pulse count + bool update_today = false; + for (int chan = 0 ; chan < Energy.phase_count ; chan++ ) { + if (BL09XX_PULSES_NOT_INITIALIZED == Bl09XX.cf_pulses_last_time[chan]) { + Bl09XX.cf_pulses_last_time[chan] = Bl09XX.cf_pulses[chan]; // Init after restart + } else { + uint32_t cf_pulses = 0; + if (Bl09XX.cf_pulses[chan] < Bl09XX.cf_pulses_last_time[chan]) { // Rolled over after 0xFFFFFF (16777215) pulses + cf_pulses = (0x1000000 - Bl09XX.cf_pulses_last_time[chan]) + Bl09XX.cf_pulses[chan]; + } else { + cf_pulses = Bl09XX.cf_pulses[chan] - Bl09XX.cf_pulses_last_time[chan]; + } + if (cf_pulses && Energy.active_power[chan]) { + uint32_t watt256 = (1638400 * 256) / Settings->energy_power_calibration; + uint32_t delta = (cf_pulses * watt256) / 36; + if (delta <= (4000 * 1000 / 36)) { // max load for SHP10: 4.00kW (3.68kW) + Bl09XX.cf_pulses_last_time[chan] = Bl09XX.cf_pulses[chan]; + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Overload [%d] %d"), chan, delta); + Bl09XX.cf_pulses_last_time[chan] = BL09XX_PULSES_NOT_INITIALIZED; + } + update_today = true; + } + } + } + if (update_today) + EnergyUpdateToday(); + } + +// AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Poll")); + + Bl09XXSerial->flush(); + Bl09XXSerial->write(BL09XX_READ_COMMAND | Bl09XX.address); + Bl09XXSerial->write(BL09XX_FULL_PACKET); +} + +void Bl09XXSnsInit(void) { + // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions + if (XNRG_14 != TasmotaGlobal.energy_driver) return; + int rx_pin = Pin((BL0939_MODEL == Bl09XX.model) ? GPIO_BL0939_RX : GPIO_BL0940_RX); + Bl09XXSerial = new TasmotaSerial(rx_pin, Pin(GPIO_TXD), 1); + if (Bl09XXSerial->begin(4800, 1)) { + if (Bl09XXSerial->hardwareSerial()) { + ClaimSerial(); + } + if (HLW_UREF_PULSE == Settings->energy_voltage_calibration) { + Settings->energy_voltage_calibration = BL09XX_UREF; + Settings->energy_current_calibration = BL09XX_IREF; + Settings->energy_power_calibration = BL09XX_PREF; + } + Energy.use_overtemp = true; // Use global temperature for overtemp detection + + for (uint32_t i = 0; i < 5; i++) { + Bl09XXSerial->write(bl09xx_init[i][0] | Bl09XX.address); + for (uint32_t j = 1; j < 6; j++) { + Bl09XXSerial->write(bl09xx_init[i][j]); +// Bl09XXSerial->write(pgm_read_byte(bl09xx_init + (6 * i) + j)); // Wrong byte order! + } + delay(1); + } + + } else { + TasmotaGlobal.energy_driver = ENERGY_NONE; + } +} + +void Bl09XXDrvInit(void) { + if (PinUsed(GPIO_BL0939_RX) && PinUsed(GPIO_TXD)) { + Bl09XX.model = BL0939_MODEL; + Bl09XX.address = BL0939_ADDRESS; + } else if (PinUsed(GPIO_BL0940_RX) && PinUsed(GPIO_TXD)) { + Bl09XX.model = BL0940_MODEL; + Bl09XX.address = BL0940_ADDRESS; + } + if (Bl09XX.model) { + Bl09XX.rx_buffer = (uint8_t*)(malloc(BL09XX_BUFFER_SIZE)); + if (Bl09XX.rx_buffer != nullptr) { + TasmotaGlobal.energy_driver = XNRG_14; + Energy.voltage_common = true; // Use common voltage + Energy.frequency_common = true; // Use common frequency + Energy.use_overtemp = true; // Use global temperature for overtemp detection + if (BL0939_MODEL == Bl09XX.model) { + Energy.phase_count = 2; // Handle two channels as two phases + AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: BL0939 driver enabled, TX:%d, RX:%d"), Pin(GPIO_TXD), Pin(GPIO_BL0939_RX)); + } else { + Energy.phase_count = 1; // Handle 1 channel + AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: BL0940 driver enabled, TX:%d, RX:%d"), Pin(GPIO_TXD), Pin(GPIO_BL0940_RX)); + } + } + } +} + +bool Bl09XXCommand(void) { + bool serviced = true; + + uint32_t channel = (2 == XdrvMailbox.index) && (Energy.phase_count > 1) ? 1 : 0; + uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 + + if (CMND_POWERSET == Energy.command_code) { + if (XdrvMailbox.data_len && Bl09XX.power[channel]) { + Settings->energy_power_calibration = (Bl09XX.power[channel] * 100) / value; + } + } + else if (CMND_VOLTAGESET == Energy.command_code) { + if (XdrvMailbox.data_len && Bl09XX.voltage) { + Settings->energy_voltage_calibration = (Bl09XX.voltage * 100) / value; + } + } + else if (CMND_CURRENTSET == Energy.command_code) { + if (XdrvMailbox.data_len && Bl09XX.current[channel]) { + Settings->energy_current_calibration = Bl09XX.current[channel] / value; + } + } + else serviced = false; // Unknown command + + return serviced; +} + +void Bl09XXShow(bool json) { + if (json) { + ResponseAppend_P(JSON_SNS_F_TEMP, "BL09XX", Settings->flag2.temperature_resolution, &Bl09XX.temperature); + if (0 == TasmotaGlobal.tele_period) { +#ifdef USE_DOMOTICZ + DomoticzFloatSensor(DZ_TEMP, Bl09XX.temperature); +#endif // USE_DOMOTICZ +#ifdef USE_KNX + KnxSensor(KNX_TEMPERATURE, Bl09XX.temperature); +#endif // USE_KNX + } +#ifdef USE_WEBSERVER + } else { + WSContentSend_Temp("", Bl09XX.temperature); +#endif // USE_WEBSERVER + + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xnrg14(uint8_t function) { + bool result = false; + + switch (function) { + case FUNC_LOOP: + if (Bl09XXSerial) { Bl09XXSerialInput(); } + break; + case FUNC_EVERY_SECOND: + Bl09XXEverySecond(); + break; + case FUNC_JSON_APPEND: + Bl09XXShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + Bl09XXShow(0); + break; +#endif // USE_WEBSERVER + case FUNC_COMMAND: + result = Bl09XXCommand(); + break; + case FUNC_INIT: + Bl09XXSnsInit(); + break; + case FUNC_PRE_INIT: + Bl09XXDrvInit(); + break; + } + return result; +} + +#endif // USE_BL09XX +#endif // USE_ENERGY_SENSOR diff --git a/tools/decode-status.py b/tools/decode-status.py index e406bd6e0..7b4c4a777 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -238,7 +238,7 @@ a_features = [[ "USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080", "USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING", "USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075", - "USE_VEML7700","USE_MCP9808","USE_BL0940","USE_TELEGRAM", + "USE_VEML7700","USE_MCP9808","USE_BL09XX","USE_TELEGRAM", "USE_HP303B","USE_TCP_BRIDGE","USE_TELEINFO","USE_LMT01", "USE_PROMETHEUS","USE_IEM3000","USE_DYP","USE_I2S_AUDIO", "USE_MLX90640","USE_VL53L1X","USE_MIEL_HVAC","USE_WE517",