diff --git a/tasmota/xnrg_14_bl09xx.ino b/tasmota/xnrg_14_bl09xx.ino index 0549f2dfd..bca55c513 100644 --- a/tasmota/xnrg_14_bl09xx.ino +++ b/tasmota/xnrg_14_bl09xx.ino @@ -51,20 +51,6 @@ #define BL0942_UREF 15187 #define BL0942_IREF 251213 -#define BL09XX_PULSES_NOT_INITIALIZED -1 - -#define BL0939_BUFFER_SIZE 35 -#define BL0940_BUFFER_SIZE 35 -#define BL0942_BUFFER_SIZE 23 - -#define BL0939_MODEL 39 -#define BL0940_MODEL 40 -#define BL0942_MODEL 42 - -#define BL0939_ADDRESS 0x05 -#define BL0940_ADDRESS 0x00 -#define BL0942_ADDRESS 0x08 - #define BL09XX_WRITE_COMMAND 0xA0 // 0xA8 according to documentation #define BL09XX_REG_I_FAST_RMS_CTRL 0x10 #define BL09XX_REG_MODE 0x18 @@ -81,13 +67,26 @@ TasmotaSerial *Bl09XXSerial = nullptr; +enum Bl09xxModel { BL0939_MODEL, BL0940_MODEL, BL0942_MODEL, BL09XX_MODEL }; // Model index number starting from 0 +const uint32_t bl09xx_pref[] = { BL0939_PREF, BL0940_PREF, BL0942_PREF }; // Power reference constant +const uint32_t bl09xx_uref[] = { BL0939_UREF, BL0940_UREF, BL0942_UREF }; // Voltage reference constant +const uint32_t bl09xx_iref[] = { BL0939_IREF, BL0940_IREF, BL0942_IREF }; // Current reference constant +const uint8_t bl09xx_type[] = { 39, 40, 42 }; // Device name BL09xx +const uint8_t bl09xx_phase_count[] = { 2, 1, 1 }; // Supported phase/channel count +const uint8_t bl09xx_address[] = { 0x05, 0x00, 0x08 }; // Device address +const uint8_t bl09xx_buffer_size[] = { 35, 35, 23 }; // Serial receive buffer size +const uint8_t bl09xx_init[5][4] = { + { BL09XX_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A }, // Reset to default + { BL09XX_REG_USR_WRPROT, 0x55, 0x00, 0x00 }, // Enable User Operation Write + { BL09XX_REG_MODE, 0x00, 0x10, 0x00 }, // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS + { BL09XX_REG_TPS_CTRL, 0xFF, 0x47, 0x00 }, // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS + { BL09XX_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00 } // 0x181C = Half cycle, Fast RMS threshold 6172 +}; + 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}; + uint32_t voltage = 0; + uint32_t current[2] = { 0, }; + uint32_t power[2] = { 0, }; float temperature; uint16_t tps1 = 0; uint8_t *rx_buffer = nullptr; @@ -99,15 +98,6 @@ struct BL09XX { bool received = false; } Bl09XX; -const uint8_t bl09xx_init[5][4] = { - { BL09XX_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A }, // Reset to default - { BL09XX_REG_USR_WRPROT, 0x55, 0x00, 0x00 }, // Enable User Operation Write - { BL09XX_REG_MODE, 0x00, 0x10, 0x00 }, // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS - { BL09XX_REG_TPS_CTRL, 0xFF, 0x47, 0x00 }, // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS - { BL09XX_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00 } // 0x181C = Half cycle, Fast RMS threshold 6172 -}; - - bool Bl09XXDecode3940(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) @@ -136,26 +126,20 @@ bool Bl09XXDecode3940(void) { 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 + Bl09XX.voltage = Bl09XX.rx_buffer[12] << 16 | Bl09XX.rx_buffer[11] << 8 | Bl09XX.rx_buffer[10]; // V_RMS unsigned + Bl09XX.current[0] = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // IA_RMS unsigned + int32_t 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 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 + 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 } #ifdef DEBUG_BL09XX - 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); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d/%d, P %d/%d, T %d"), + Bl09XX.voltage, Bl09XX.current[0], Bl09XX.current[1], Bl09XX.power[0], Bl09XX.power[1], Bl09XX.tps1); #endif return true; @@ -185,18 +169,14 @@ bool Bl09XXDecode42(void) { return false; } - Bl09XX.voltage = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // V_RMS unsigned - - int32_t tmp; - Bl09XX.current[0] = Bl09XX.rx_buffer[3] << 16 | Bl09XX.rx_buffer[2] << 8 | Bl09XX.rx_buffer[1]; // IA_RMS unsigned - tmp = Bl09XX.rx_buffer[12] << 24 | Bl09XX.rx_buffer[11] << 16 | Bl09XX.rx_buffer[10] << 8; // WATT_A signed - Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned - tmp = Bl09XX.rx_buffer[15] << 24 | Bl09XX.rx_buffer[14] << 16 | Bl09XX.rx_buffer[13] << 8; // CFA_CNT signed - Bl09XX.cf_pulses[0] = abs(tmp >> 8); // CFA_CNT unsigned + Bl09XX.voltage = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // V_RMS unsigned + Bl09XX.current[0] = Bl09XX.rx_buffer[3] << 16 | Bl09XX.rx_buffer[2] << 8 | Bl09XX.rx_buffer[1]; // IA_RMS unsigned + int32_t tmp = Bl09XX.rx_buffer[12] << 24 | Bl09XX.rx_buffer[11] << 16 | Bl09XX.rx_buffer[10] << 8; // WATT_A signed + Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned #ifdef DEBUG_BL09XX - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d, P %d, C %d"), - Bl09XX.voltage, Bl09XX.current[0], Bl09XX.power[0], Bl09XX.cf_pulses[0]); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d, P %d"), + Bl09XX.voltage, Bl09XX.current[0], Bl09XX.power[0]); #endif return true; @@ -207,7 +187,7 @@ void Bl09XXUpdateEnergy() { 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 (uint32_t chan = 0; chan < Energy.phase_count; chan++) { - if (Bl09XX.power[chan] > Settings->energy_power_calibration) { // We need at least 1W + 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; #ifdef DEBUG_BL09XX @@ -222,12 +202,12 @@ void Bl09XXUpdateEnergy() { } } } 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(); @@ -249,12 +229,12 @@ void Bl09XXSerialInput(void) { if (checksum == Bl09XX.rx_buffer[Bl09XX.buffer_size -1]) { Energy.data_valid[0] = 0; bool ok; - if (BL0942_MODEL == Bl09XX.model) + if (BL0942_MODEL == Bl09XX.model) { ok = Bl09XXDecode42(); - else + } else { ok = Bl09XXDecode3940(); - if (ok) - Bl09XXUpdateEnergy(); + } + if (ok) { Bl09XXUpdateEnergy(); } Bl09XX.received = false; return; } else { @@ -304,24 +284,9 @@ void Bl09XXInit(void) { ClaimSerial(); } if (HLW_UREF_PULSE == Settings->energy_voltage_calibration) { - switch (Bl09XX.model) { - case BL0939_MODEL: - Settings->energy_voltage_calibration = BL0939_UREF; - Settings->energy_current_calibration = BL0939_IREF; - Settings->energy_power_calibration = BL0939_PREF; - break; - case BL0940_MODEL: - Settings->energy_voltage_calibration = BL0940_UREF; - Settings->energy_current_calibration = BL0940_IREF; - Settings->energy_power_calibration = BL0940_PREF; - break; - case BL0942_MODEL: - default: - Settings->energy_voltage_calibration = BL0942_UREF; - Settings->energy_current_calibration = BL0942_IREF; - Settings->energy_power_calibration = BL0942_PREF; - break; - } + Settings->energy_voltage_calibration = bl09xx_uref[Bl09XX.model]; + Settings->energy_current_calibration = bl09xx_iref[Bl09XX.model]; + Settings->energy_power_calibration = bl09xx_pref[Bl09XX.model]; } if ((BL0940_MODEL == Bl09XX.model) && (Settings->energy_current_calibration < (BL0940_IREF / 20))) { Settings->energy_current_calibration *= 100; @@ -329,7 +294,7 @@ void Bl09XXInit(void) { if (BL0942_MODEL != Bl09XX.model) { #ifdef DEBUG_BL09XX - AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Send Init string for model BL09%02d"), Bl09XX.model); + AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Send Init string")); #endif Energy.use_overtemp = true; // Use global temperature for overtemp detection for (uint32_t i = 0; i < 5; i++) { @@ -352,32 +317,32 @@ void Bl09XXInit(void) { } void Bl09XXPreInit(void) { - if (PinUsed(GPIO_BL0939_RX) && PinUsed(GPIO_TXD)) { - Bl09XX.model = BL0939_MODEL; - Bl09XX.address = BL0939_ADDRESS; - Bl09XX.buffer_size = BL0939_BUFFER_SIZE; - Bl09XX.rx_pin = Pin(GPIO_BL0939_RX); - } else if (PinUsed(GPIO_BL0940_RX) && PinUsed(GPIO_TXD)) { - Bl09XX.model = BL0940_MODEL; - Bl09XX.address = BL0940_ADDRESS; - Bl09XX.buffer_size = BL0940_BUFFER_SIZE; - Bl09XX.rx_pin = Pin(GPIO_BL0940_RX); - } - else if (PinUsed(GPIO_BL0942_RX) && PinUsed(GPIO_TXD)) { - Bl09XX.model = BL0942_MODEL; - Bl09XX.address = BL0942_ADDRESS; - Bl09XX.buffer_size = BL0942_BUFFER_SIZE; - Bl09XX.rx_pin = Pin(GPIO_BL0942_RX); - } - if (Bl09XX.model) { - Bl09XX.rx_buffer = (uint8_t*)(malloc(Bl09XX.buffer_size)); - if (Bl09XX.rx_buffer != nullptr) { - Energy.voltage_common = true; // Use common voltage - Energy.frequency_common = true; // Use common frequency - Energy.use_overtemp = true; // Use global temperature for overtemp detection - Energy.phase_count = (BL0939_MODEL == Bl09XX.model) ? 2 : 1; // Handle two channels as two phases - TasmotaGlobal.energy_driver = XNRG_14; - AddLog(LOG_LEVEL_DEBUG,PSTR("BL9: Enabling BL09%02d"), Bl09XX.model); + if (PinUsed(GPIO_TXD)) { + Bl09XX.model = BL09XX_MODEL; + if (PinUsed(GPIO_BL0939_RX)) { + Bl09XX.model = BL0939_MODEL; + Bl09XX.rx_pin = Pin(GPIO_BL0939_RX); + } + else if (PinUsed(GPIO_BL0940_RX)) { + Bl09XX.model = BL0940_MODEL; + Bl09XX.rx_pin = Pin(GPIO_BL0940_RX); + } + else if (PinUsed(GPIO_BL0942_RX)) { + Bl09XX.model = BL0942_MODEL; + Bl09XX.rx_pin = Pin(GPIO_BL0942_RX); + } + if (Bl09XX.model != BL09XX_MODEL) { + Bl09XX.address = bl09xx_address[Bl09XX.model]; + Bl09XX.buffer_size = bl09xx_buffer_size[Bl09XX.model]; + Bl09XX.rx_buffer = (uint8_t*)(malloc(Bl09XX.buffer_size)); + if (Bl09XX.rx_buffer != nullptr) { + Energy.voltage_common = true; // Use common voltage + Energy.frequency_common = true; // Use common frequency + Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy.phase_count = bl09xx_phase_count[Bl09XX.model]; // Handle two channels as two phases + TasmotaGlobal.energy_driver = XNRG_14; + AddLog(LOG_LEVEL_DEBUG,PSTR("BL9: Enabling BL09%02d"), bl09xx_type[Bl09XX.model]); + } } } }