2024-09-25 17:05:16 +01:00
|
|
|
/*
|
|
|
|
xnrg_24_bl0906.ino - BL0906 energy sensor support for Tasmota
|
|
|
|
|
|
|
|
SPDX-FileCopyrightText: 2024 Theo Arends
|
|
|
|
|
|
|
|
SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef ESP32
|
|
|
|
#ifdef USE_ENERGY_SENSOR
|
|
|
|
#ifdef USE_BL0906
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Support the following Shangai Belling energy sensors:
|
|
|
|
*
|
|
|
|
* BL0906 - Energy (as in Athom 6CH Energy Meter EM6)
|
|
|
|
* Based on athom-tech https://github.com/athom-tech/esp32-configs/tree/main/components/bl0906
|
|
|
|
* See https://github.com/arendst/Tasmota/discussions/22167
|
|
|
|
*
|
|
|
|
* {"NAME":"Athom EM2","GPIO":[0,0,0,0,0,0,0,3200,11329,1,544,0,0,0,0,0,0,0,1,0,0,0],"FLAG":0,"BASE":1}
|
|
|
|
* {"NAME":"Athom EM6","GPIO":[0,0,0,0,0,0,0,3200,11333,1,544,0,0,0,0,0,0,0,1,0,0,0],"FLAG":0,"BASE":1}
|
|
|
|
*
|
|
|
|
* Optional commands:
|
|
|
|
* EnergyCols <phases>` - Change default 4 column GUI display to <phases> columns
|
|
|
|
* VoltRes 1 - Change none to 1 decimal display
|
2024-09-26 16:20:34 +01:00
|
|
|
* FreqRes 1 - Change none to 1 decimal display
|
2024-09-25 17:05:16 +01:00
|
|
|
* WattRes 2 - Change none to 2 decimals display
|
2024-09-26 16:20:34 +01:00
|
|
|
* SetOption21 1 - Display Voltage
|
2024-09-25 17:05:16 +01:00
|
|
|
* SetOption129 1 - Display energy for each phase instead of single sum
|
|
|
|
* SetOption150 1 - Display no common voltage/frequency
|
2024-09-27 17:08:22 +01:00
|
|
|
* EnergyExportActive 1 - Enable display of Export Active energy based on negative Active Power
|
2024-09-25 17:05:16 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
#define XNRG_24 24
|
|
|
|
|
|
|
|
#ifndef BL0906_UPDATE
|
2024-09-26 16:20:34 +01:00
|
|
|
#define BL0906_UPDATE 2 // Update every 2 seconds (Must be lower than ENERGY_WATCHDOG)
|
2024-09-25 17:05:16 +01:00
|
|
|
#endif
|
|
|
|
//#define DEBUG_BL0906
|
|
|
|
|
|
|
|
// Total power conversion
|
|
|
|
static const float BL0906_WATT = 16 * 1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) /
|
|
|
|
(40.41259 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000);
|
|
|
|
// Total Energy conversion
|
|
|
|
static const float BL0906_CF = 16 * 4194304 * 0.032768 * 16 /
|
|
|
|
(3600000 * 16 *
|
|
|
|
(40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 /
|
|
|
|
(1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000))));
|
|
|
|
// Frequency conversion
|
|
|
|
static const float BL0906_FREF = 10000000;
|
|
|
|
// Temperature conversion
|
|
|
|
static const float BL0906_TREF = 12.5 / 59 - 40; // Celsius
|
|
|
|
// Current conversion
|
|
|
|
static const float BL0906_IREF = 1.097 / (12875 * 1 * (5.1 + 5.1) * 1000 / 2000);
|
|
|
|
// Voltage conversion
|
|
|
|
static const float BL0906_UREF = 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) / (13162 * 1 * 100 * 1000);
|
|
|
|
// Power conversion
|
|
|
|
static const float BL0906_PREF = 1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000) /
|
|
|
|
(40.41259 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000);
|
|
|
|
// Energy conversion
|
|
|
|
static const float BL0906_EREF = 4194304 * 0.032768 * 16 /
|
|
|
|
(3600000 * 16 *
|
|
|
|
(40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 /
|
|
|
|
(1.097 * 1.097 * (20000 + 20000 + 20000 + 20000 + 20000))));
|
|
|
|
// Current coefficient
|
|
|
|
static const float BL0906_KI = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097;
|
|
|
|
// Power coefficient
|
|
|
|
static const float BL0906_KP = 40.4125 * ((5.1 + 5.1) * 1000 / 2000) * 1 * 100 * 1 * 1000 / 1.097 / 1.097 /
|
|
|
|
(20000 + 20000 + 20000 + 20000 + 20000);
|
|
|
|
|
|
|
|
// Register address
|
|
|
|
// Voltage
|
|
|
|
static const uint8_t BL0906_V_RMS = 0x16;
|
|
|
|
|
|
|
|
// Total power
|
|
|
|
static const uint8_t BL0906_WATT_SUM = 0X2C;
|
|
|
|
|
|
|
|
// Current1~6
|
|
|
|
static const uint8_t BL0906_I_1_RMS = 0x0D; // current_1
|
|
|
|
static const uint8_t BL0906_I_2_RMS = 0x0E;
|
|
|
|
static const uint8_t BL0906_I_3_RMS = 0x0F;
|
|
|
|
static const uint8_t BL0906_I_4_RMS = 0x10;
|
|
|
|
static const uint8_t BL0906_I_5_RMS = 0x13;
|
|
|
|
static const uint8_t BL0906_I_6_RMS = 0x14; // current_6
|
|
|
|
|
|
|
|
// Power1~6
|
|
|
|
static const uint8_t BL0906_WATT_1 = 0X23; // power_1
|
|
|
|
static const uint8_t BL0906_WATT_2 = 0X24;
|
|
|
|
static const uint8_t BL0906_WATT_3 = 0X25;
|
|
|
|
static const uint8_t BL0906_WATT_4 = 0X26;
|
|
|
|
static const uint8_t BL0906_WATT_5 = 0X29;
|
|
|
|
static const uint8_t BL0906_WATT_6 = 0X2A; // power_6
|
|
|
|
|
|
|
|
// Active pulse count, unsigned
|
|
|
|
static const uint8_t BL0906_CF_1_CNT = 0X30; // Channel_1
|
|
|
|
static const uint8_t BL0906_CF_2_CNT = 0X31;
|
|
|
|
static const uint8_t BL0906_CF_3_CNT = 0X32;
|
|
|
|
static const uint8_t BL0906_CF_4_CNT = 0X33;
|
|
|
|
static const uint8_t BL0906_CF_5_CNT = 0X36;
|
|
|
|
static const uint8_t BL0906_CF_6_CNT = 0X37; // Channel_6
|
|
|
|
|
|
|
|
// Total active pulse count, unsigned
|
|
|
|
static const uint8_t BL0906_CF_SUM_CNT = 0X39;
|
|
|
|
|
|
|
|
// Voltage frequency cycle
|
|
|
|
static const uint8_t BL0906_FREQUENCY = 0X4E;
|
|
|
|
|
|
|
|
// Internal temperature
|
|
|
|
static const uint8_t BL0906_TEMPERATURE = 0X5E;
|
|
|
|
|
|
|
|
// Calibration register
|
|
|
|
// RMS gain adjustment register
|
|
|
|
static const uint8_t BL0906_RMSGN_1 = 0x6D; // Channel_1
|
|
|
|
static const uint8_t BL0906_RMSGN_2 = 0x6E;
|
|
|
|
static const uint8_t BL0906_RMSGN_3 = 0x6F;
|
|
|
|
static const uint8_t BL0906_RMSGN_4 = 0x70;
|
|
|
|
static const uint8_t BL0906_RMSGN_5 = 0x73;
|
|
|
|
static const uint8_t BL0906_RMSGN_6 = 0x74; // Channel_6
|
|
|
|
|
|
|
|
// RMS offset correction register
|
|
|
|
static const uint8_t BL0906_RMSOS_1 = 0x78; // Channel_1
|
|
|
|
static const uint8_t BL0906_RMSOS_2 = 0x79;
|
|
|
|
static const uint8_t BL0906_RMSOS_3 = 0x7A;
|
|
|
|
static const uint8_t BL0906_RMSOS_4 = 0x7B;
|
|
|
|
static const uint8_t BL0906_RMSOS_5 = 0x7E;
|
|
|
|
static const uint8_t BL0906_RMSOS_6 = 0x7F; // Channel_6
|
|
|
|
|
|
|
|
// Active power gain adjustment register
|
|
|
|
static const uint8_t BL0906_WATTGN_1 = 0xB7; // Channel_1
|
|
|
|
static const uint8_t BL0906_WATTGN_2 = 0xB8;
|
|
|
|
static const uint8_t BL0906_WATTGN_3 = 0xB9;
|
|
|
|
static const uint8_t BL0906_WATTGN_4 = 0xBA;
|
|
|
|
static const uint8_t BL0906_WATTGN_5 = 0xBD;
|
|
|
|
static const uint8_t BL0906_WATTGN_6 = 0xBE; // Channel_6
|
|
|
|
|
|
|
|
// Commands
|
|
|
|
static const uint8_t BL0906_READ_COMMAND = 0x35;
|
|
|
|
static const uint8_t BL0906_WRITE_COMMAND = 0xCA;
|
|
|
|
|
|
|
|
// User write protection setting register,
|
|
|
|
// You must first write 0x5555 to the write protection setting register before writing to other registers.
|
|
|
|
static const uint8_t BL0906_USR_WRPROT = 0x9E;
|
|
|
|
// Enable User Operation Write
|
|
|
|
static const uint8_t BL0906_WRPROT_WRITABLE[6] = {BL0906_WRITE_COMMAND, BL0906_USR_WRPROT, 0x55, 0x55, 0x00, 0xB7};
|
|
|
|
// Disable User Operation Write
|
|
|
|
static const uint8_t BL0906_WRPROT_ONLYREAD[6] = {BL0906_WRITE_COMMAND, BL0906_USR_WRPROT, 0x00, 0x00, 0x00, 0x61};
|
|
|
|
|
|
|
|
// Reset Register
|
|
|
|
static const uint8_t BL0906_SOFT_RESET = 0x9F;
|
|
|
|
// Reset to default
|
|
|
|
static const uint8_t BL0906_INIT[6] = {BL0906_WRITE_COMMAND, BL0906_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x52};
|
|
|
|
|
|
|
|
typedef struct Bl0906DataPacket {
|
|
|
|
uint8_t l{0};
|
|
|
|
uint8_t m{0};
|
|
|
|
uint8_t h{0};
|
|
|
|
uint8_t checksum;
|
|
|
|
uint8_t address;
|
|
|
|
} Bl0906DataPacket;
|
|
|
|
|
|
|
|
typedef struct Bl0906ube24_t {
|
|
|
|
uint8_t l{0};
|
|
|
|
uint8_t m{0};
|
|
|
|
uint8_t h{0};
|
|
|
|
} Bl0906ube24_t;
|
|
|
|
|
|
|
|
typedef struct Bl0906sbe24_t {
|
|
|
|
uint8_t l{0};
|
|
|
|
uint8_t m{0};
|
|
|
|
int8_t h{0};
|
|
|
|
} Bl0906sbe24_t;
|
|
|
|
|
|
|
|
#include <TasmotaSerial.h>
|
|
|
|
TasmotaSerial *Bl0906Serial = nullptr;
|
|
|
|
|
|
|
|
struct BL0906 {
|
|
|
|
float temperature;
|
|
|
|
uint16_t baudrate;
|
|
|
|
uint8_t current_channel = 0;
|
|
|
|
uint8_t model = 0;
|
|
|
|
uint8_t rx_pin;
|
|
|
|
} Bl0906;
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
|
|
|
bool Bl0906_check_read_timeout(size_t len) {
|
|
|
|
if (Bl0906Serial->available() >= int(len)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
uint32_t start_time = millis();
|
|
|
|
while (Bl0906Serial->available() < int(len)) {
|
|
|
|
if (millis() - start_time > 100) {
|
|
|
|
#ifdef DEBUG_BL0906
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: Timeout at %u/%u"), Bl0906Serial->available(), len);
|
|
|
|
#endif // DEBUG_BL0906
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Bl0906ReadArray(uint8_t *data, size_t len) {
|
|
|
|
if (!Bl0906_check_read_timeout(len)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Bl0906Serial->read(data, len);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
|
|
|
uint32_t Bl0906_to_uint32_t(Bl0906ube24_t input);
|
|
|
|
uint32_t Bl0906_to_uint32_t(Bl0906ube24_t input) {
|
|
|
|
return input.h << 16 | input.m << 8 | input.l;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t Bl0906_to_int32_t(Bl0906sbe24_t input);
|
|
|
|
int32_t Bl0906_to_int32_t(Bl0906sbe24_t input) {
|
|
|
|
return input.h << 16 | input.m << 8 | input.l;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
|
|
|
// The SUM byte is (Addr+Data_L+Data_M+Data_H)&0xFF negated;
|
|
|
|
uint8_t Bl0906Checksum(const uint8_t address, const Bl0906DataPacket *data); // Pre-declare to fix compile error on Bl0906DataPacket
|
|
|
|
uint8_t Bl0906Checksum(const uint8_t address, const Bl0906DataPacket *data) {
|
|
|
|
return (address + data->l + data->m + data->h) ^ 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
// RMS offset correction
|
|
|
|
void Bl0906BiasCorrection(uint8_t address, float measurements, float correction) {
|
|
|
|
Bl0906DataPacket data;
|
|
|
|
float ki = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097; // Current coefficient
|
|
|
|
float i_rms0 = measurements * ki;
|
|
|
|
float i_rms = correction * ki;
|
|
|
|
int32_t value = (i_rms * i_rms - i_rms0 * i_rms0) / 256;
|
|
|
|
data.l = value << 24 >> 24;
|
|
|
|
data.m = value << 16 >> 24;
|
|
|
|
if (value < 0) {
|
|
|
|
data.h = (value << 8 >> 24) | 0b10000000;
|
|
|
|
}
|
|
|
|
data.address = Bl0906Checksum(address, &data);
|
|
|
|
#ifdef DEBUG_BL0906
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: BiasCorrection %02X %02X %02X %02X %02X %02X"), BL0906_WRITE_COMMAND, address, data.l, data.m, data.h, data.address);
|
|
|
|
#endif // DEBUG_BL0906
|
|
|
|
Bl0906Serial->write(BL0906_WRITE_COMMAND);
|
|
|
|
Bl0906Serial->write(address);
|
|
|
|
Bl0906Serial->write(data.l);
|
|
|
|
Bl0906Serial->write(data.m);
|
|
|
|
Bl0906Serial->write(data.h);
|
|
|
|
Bl0906Serial->write(data.address);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
// Gain adjustment
|
|
|
|
void Bl0906GainCorrection(const uint8_t address, const float measurements, const float Correction, const float coefficient) {
|
|
|
|
Bl0906DataPacket data;
|
|
|
|
float I_RMS0 = measurements * coefficient;
|
|
|
|
float I_RMS = Correction * coefficient;
|
|
|
|
float rms_gn = int((I_RMS / I_RMS0 - 1) * 65536);
|
|
|
|
int16_t value;
|
|
|
|
if (rms_gn <= -32767) {
|
|
|
|
value = -32767;
|
|
|
|
} else {
|
|
|
|
value = int(rms_gn);
|
|
|
|
}
|
|
|
|
data.h = 0xFF;
|
|
|
|
data.m = value >> 8;
|
|
|
|
data.l = value << 8 >> 8;
|
|
|
|
data.address = Bl0906Checksum(address, &data);
|
|
|
|
#ifdef DEBUG_BL0906
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: GainCorrection %02X %02X %02X %02X %02X %02X"), BL0906_WRITE_COMMAND, address, data.l, data.m, data.h, data.address);
|
|
|
|
#endif // DEBUG_BL0906
|
|
|
|
Bl0906Serial->write(BL0906_WRITE_COMMAND);
|
|
|
|
Bl0906Serial->write(address);
|
|
|
|
Bl0906Serial->write(data.l);
|
|
|
|
Bl0906Serial->write(data.m);
|
|
|
|
Bl0906Serial->write(data.h);
|
|
|
|
Bl0906Serial->write(data.address);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
void Bl0906Setup(void) {
|
|
|
|
while (Bl0906Serial->available()) {
|
|
|
|
Bl0906Serial->flush();
|
|
|
|
}
|
|
|
|
Bl0906Serial->write(BL0906_WRPROT_WRITABLE, sizeof(BL0906_WRPROT_WRITABLE));
|
|
|
|
// Calibration (1: register address; 2: value before calibration; 3: value after calibration)
|
|
|
|
Bl0906BiasCorrection(BL0906_RMSOS_1, 0.01600, 0); // Calibration current_1
|
|
|
|
Bl0906BiasCorrection(BL0906_RMSOS_2, 0.01500, 0);
|
|
|
|
Bl0906BiasCorrection(BL0906_RMSOS_3, 0.01400, 0);
|
|
|
|
Bl0906BiasCorrection(BL0906_RMSOS_4, 0.01300, 0);
|
|
|
|
Bl0906BiasCorrection(BL0906_RMSOS_5, 0.01200, 0);
|
|
|
|
Bl0906BiasCorrection(BL0906_RMSOS_6, 0.01200, 0); // Calibration current_6
|
|
|
|
/*
|
|
|
|
Bl0906GainCorrection(BL0906_RMSGN_1, 2.15000, 2.148, BL0906_KI); //RMS gain adjustment current_1
|
|
|
|
Bl0906GainCorrection(BL0906_RMSGN_2, 2.15100, 2.148, BL0906_KI);
|
|
|
|
Bl0906GainCorrection(BL0906_RMSGN_3, 2.15200, 2.148, BL0906_KI);
|
|
|
|
Bl0906GainCorrection(BL0906_RMSGN_4, 2.14500, 2.148, BL0906_KI);
|
|
|
|
Bl0906GainCorrection(BL0906_RMSGN_5, 2.14600, 2.148, BL0906_KI);
|
|
|
|
Bl0906GainCorrection(BL0906_RMSGN_6, 2.14600, 2.148, BL0906_KI); //RMS gain adjustment current_6
|
|
|
|
|
|
|
|
Bl0906GainCorrection(BL0906_WATTGN_1, 15.13427, 14.5, BL0906_KP); //Active power gain adjustment power_1
|
|
|
|
Bl0906GainCorrection(BL0906_WATTGN_2, 15.23937, 14.5, BL0906_KP);
|
|
|
|
Bl0906GainCorrection(BL0906_WATTGN_3, 15.44956, 14.5, BL0906_KP);
|
|
|
|
Bl0906GainCorrection(BL0906_WATTGN_4, 16.57646, 14.5, BL0906_KP);
|
|
|
|
Bl0906GainCorrection(BL0906_WATTGN_5, 15.27440, 14.5, BL0906_KP);
|
|
|
|
Bl0906GainCorrection(BL0906_WATTGN_6, 31.75744, 14.5, BL0906_KP); //Active power gain adjustment power_6
|
|
|
|
*/
|
|
|
|
Bl0906Serial->write(BL0906_WRPROT_ONLYREAD, sizeof(BL0906_WRPROT_ONLYREAD));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset energy
|
|
|
|
void Bl0906ResetEnergy(void) {
|
|
|
|
Bl0906Serial->write(BL0906_INIT, sizeof(BL0906_INIT));
|
|
|
|
delay(1);
|
|
|
|
Bl0906Serial->flush(); // Flush send buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read data
|
|
|
|
void Bl0906ReadData(const uint8_t address, const float reference, float *sensor) {
|
|
|
|
if (sensor == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bl0906Serial->write(BL0906_READ_COMMAND);
|
|
|
|
Bl0906Serial->write(address);
|
|
|
|
Bl0906DataPacket buffer;
|
|
|
|
if (Bl0906ReadArray((uint8_t *) &buffer, sizeof(buffer) - 1)) {
|
|
|
|
if (Bl0906Checksum(address, &buffer) == buffer.checksum) {
|
|
|
|
|
|
|
|
Bl0906ube24_t data_u24;
|
|
|
|
Bl0906sbe24_t data_s24;
|
|
|
|
bool signed_result = reference == BL0906_TREF || reference == BL0906_WATT || reference == BL0906_PREF;
|
|
|
|
if (signed_result) {
|
|
|
|
data_s24.l = buffer.l;
|
|
|
|
data_s24.m = buffer.m;
|
|
|
|
data_s24.h = buffer.h;
|
|
|
|
} else {
|
|
|
|
data_u24.l = buffer.l;
|
|
|
|
data_u24.m = buffer.m;
|
|
|
|
data_u24.h = buffer.h;
|
|
|
|
}
|
|
|
|
|
|
|
|
float value = 0;
|
|
|
|
// Power
|
|
|
|
if (reference == BL0906_PREF) {
|
|
|
|
value = (float) Bl0906_to_int32_t(data_s24) * reference;
|
|
|
|
}
|
|
|
|
// Total power
|
|
|
|
if (reference == BL0906_WATT) {
|
|
|
|
value = (float) Bl0906_to_int32_t(data_s24) * reference;
|
|
|
|
}
|
|
|
|
// Voltage, current, power, total power
|
|
|
|
if (reference == BL0906_UREF || reference == BL0906_IREF || reference == BL0906_EREF || reference == BL0906_CF) {
|
|
|
|
value = (float) Bl0906_to_uint32_t(data_u24) * reference;
|
|
|
|
}
|
|
|
|
// Frequency
|
|
|
|
if (reference == BL0906_FREF) {
|
|
|
|
value = reference / (float) Bl0906_to_uint32_t(data_u24);
|
|
|
|
}
|
|
|
|
// Chip temperature
|
|
|
|
if (reference == BL0906_TREF) {
|
|
|
|
value = (float) Bl0906_to_int32_t(data_s24);
|
|
|
|
value = (value - 64) * 12.5 / 59 - 40; // Celsius
|
|
|
|
// value = (value - 64) * reference;
|
|
|
|
value = ConvertTemp(value);
|
|
|
|
}
|
|
|
|
*sensor = value;
|
|
|
|
} else {
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: CRC error"));
|
|
|
|
while (Bl0906Serial->read() >= 0); // Flush receive buffer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
|
|
|
void Bl0906Loop(void) {
|
|
|
|
if (UINT8_MAX == Bl0906.current_channel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-09-26 16:20:34 +01:00
|
|
|
while (Bl0906Serial->available()) {
|
2024-09-25 17:05:16 +01:00
|
|
|
Bl0906Serial->flush();
|
2024-09-26 16:20:34 +01:00
|
|
|
}
|
2024-09-25 17:05:16 +01:00
|
|
|
if (0 == Bl0906.current_channel) {
|
2024-09-26 16:20:34 +01:00
|
|
|
#ifdef DEBUG_BL0906
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: Start polling"));
|
|
|
|
#endif // DEBUG_BL0906
|
2024-09-25 17:05:16 +01:00
|
|
|
// Temperature
|
|
|
|
Bl0906ReadData(BL0906_TEMPERATURE, BL0906_TREF, &Bl0906.temperature);
|
|
|
|
} else if (1 == Bl0906.current_channel) {
|
|
|
|
Bl0906ReadData(BL0906_I_1_RMS, BL0906_IREF, &Energy->current[0]);
|
|
|
|
Bl0906ReadData(BL0906_WATT_1, BL0906_PREF, &Energy->active_power[0]);
|
|
|
|
Bl0906ReadData(BL0906_CF_1_CNT, BL0906_EREF, &Energy->import_active[0]);
|
2024-09-26 16:20:34 +01:00
|
|
|
Energy->data_valid[0] = 0;
|
2024-09-25 17:05:16 +01:00
|
|
|
} else if (2 == Bl0906.current_channel) {
|
|
|
|
Bl0906ReadData(BL0906_I_2_RMS, BL0906_IREF, &Energy->current[1]);
|
|
|
|
Bl0906ReadData(BL0906_WATT_2, BL0906_PREF, &Energy->active_power[1]);
|
|
|
|
Bl0906ReadData(BL0906_CF_2_CNT, BL0906_EREF, &Energy->import_active[1]);
|
2024-09-26 16:20:34 +01:00
|
|
|
Energy->data_valid[1] = 0;
|
2024-09-25 17:05:16 +01:00
|
|
|
} else if (3 == Bl0906.current_channel) {
|
|
|
|
Bl0906ReadData(BL0906_I_3_RMS, BL0906_IREF, &Energy->current[2]);
|
|
|
|
Bl0906ReadData(BL0906_WATT_3, BL0906_PREF, &Energy->active_power[2]);
|
|
|
|
Bl0906ReadData(BL0906_CF_3_CNT, BL0906_EREF, &Energy->import_active[2]);
|
2024-09-26 16:20:34 +01:00
|
|
|
Energy->data_valid[2] = 0;
|
2024-09-25 17:05:16 +01:00
|
|
|
} else if (4 == Bl0906.current_channel) {
|
|
|
|
Bl0906ReadData(BL0906_I_4_RMS, BL0906_IREF, &Energy->current[3]);
|
|
|
|
Bl0906ReadData(BL0906_WATT_4, BL0906_PREF, &Energy->active_power[3]);
|
|
|
|
Bl0906ReadData(BL0906_CF_4_CNT, BL0906_EREF, &Energy->import_active[3]);
|
2024-09-26 16:20:34 +01:00
|
|
|
Energy->data_valid[3] = 0;
|
2024-09-25 17:05:16 +01:00
|
|
|
} else if (5 == Bl0906.current_channel) {
|
|
|
|
Bl0906ReadData(BL0906_I_5_RMS, BL0906_IREF, &Energy->current[4]);
|
|
|
|
Bl0906ReadData(BL0906_WATT_5, BL0906_PREF, &Energy->active_power[4]);
|
|
|
|
Bl0906ReadData(BL0906_CF_5_CNT, BL0906_EREF, &Energy->import_active[4]);
|
2024-09-26 16:20:34 +01:00
|
|
|
Energy->data_valid[4] = 0;
|
2024-09-25 17:05:16 +01:00
|
|
|
} else if (6 == Bl0906.current_channel) {
|
|
|
|
Bl0906ReadData(BL0906_I_6_RMS, BL0906_IREF, &Energy->current[5]);
|
|
|
|
Bl0906ReadData(BL0906_WATT_6, BL0906_PREF, &Energy->active_power[5]);
|
|
|
|
Bl0906ReadData(BL0906_CF_6_CNT, BL0906_EREF, &Energy->import_active[5]);
|
2024-09-26 16:20:34 +01:00
|
|
|
Energy->data_valid[5] = 0;
|
2024-09-25 17:05:16 +01:00
|
|
|
} else if (8 == Bl0906.current_channel) {
|
|
|
|
// Frequency
|
|
|
|
Bl0906ReadData(BL0906_FREQUENCY, BL0906_FREF, &Energy->frequency[0]);
|
|
|
|
// Voltage
|
|
|
|
Bl0906ReadData(BL0906_V_RMS, BL0906_UREF, &Energy->voltage[0]);
|
|
|
|
} else if (9 == Bl0906.current_channel) {
|
|
|
|
// Total power
|
|
|
|
// Bl0906ReadData(BL0906_WATT_SUM, BL0906_WATT, this->total_power_sensor_);
|
|
|
|
// Total Energy
|
|
|
|
// Bl0906ReadData(BL0906_CF_SUM_CNT, BL0906_CF, &Energy->total[0]);
|
|
|
|
|
|
|
|
EnergyUpdateTotal();
|
|
|
|
} else {
|
|
|
|
Bl0906.current_channel = UINT8_MAX - 1; // Stop
|
2024-09-26 16:20:34 +01:00
|
|
|
#ifdef DEBUG_BL0906
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: Stop polling"));
|
|
|
|
#endif // DEBUG_BL0906
|
2024-09-25 17:05:16 +01:00
|
|
|
}
|
|
|
|
if (Bl0906.current_channel == Energy->phase_count) {
|
|
|
|
Bl0906.current_channel = 7; // Skip next phases and go to frequency and voltage
|
|
|
|
}
|
|
|
|
|
|
|
|
Bl0906.current_channel++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
while (Bl0906Serial->available()) {
|
|
|
|
Bl0906Serial->read();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
while (Bl0906Serial->read() >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bl0906EverySecond(void) {
|
|
|
|
if (!(TasmotaGlobal.uptime % BL0906_UPDATE)) { // Every BL0906_UPDATE seconds an update
|
|
|
|
if (UINT8_MAX == Bl0906.current_channel) {
|
|
|
|
Bl0906.current_channel = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bl0906Show(bool json) {
|
|
|
|
if (json) {
|
2024-09-29 13:30:54 +01:00
|
|
|
ResponseAppend_P(JSON_SNS_F_TEMP, "BL0906", Settings->flag2.temperature_resolution, &Bl0906.temperature);
|
2024-09-25 17:05:16 +01:00
|
|
|
if (0 == TasmotaGlobal.tele_period) {
|
|
|
|
#ifdef USE_DOMOTICZ
|
|
|
|
DomoticzFloatSensor(DZ_TEMP, Bl0906.temperature);
|
|
|
|
#endif // USE_DOMOTICZ
|
|
|
|
#ifdef USE_KNX
|
|
|
|
KnxSensor(KNX_TEMPERATURE, Bl0906.temperature);
|
|
|
|
#endif // USE_KNX
|
|
|
|
}
|
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
} else {
|
|
|
|
WSContentSend_Temp("", Bl0906.temperature);
|
|
|
|
#endif // USE_WEBSERVER
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bl0906Init(void) {
|
|
|
|
// Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions
|
|
|
|
Bl0906Serial = new TasmotaSerial(Bl0906.rx_pin, Pin(GPIO_TXD), 1);
|
|
|
|
if (Bl0906Serial->begin(Bl0906.baudrate)) {
|
|
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6: Serial UART%d"), Bl0906Serial->getUart());
|
|
|
|
Bl0906Setup();
|
|
|
|
// Bl0906ResetEnergy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Bl0906PreInit(void) {
|
|
|
|
if (PinUsed(GPIO_TXD) && PinUsed(GPIO_BL0906_RX, GPIO_ANY)) {
|
|
|
|
Bl0906.rx_pin = Pin(GPIO_BL0906_RX, GPIO_ANY);
|
|
|
|
uint32_t option = GetPin(Bl0906.rx_pin) - AGPIO(GPIO_BL0906_RX); // 0 .. 5
|
|
|
|
Bl0906.baudrate = 19200;
|
|
|
|
|
|
|
|
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 = option +1; // Handle 1 to 6 channels as phases
|
|
|
|
|
|
|
|
TasmotaGlobal.energy_driver = XNRG_24;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Interface
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
bool Xnrg24(uint32_t function) {
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
switch (function) {
|
|
|
|
case FUNC_LOOP:
|
|
|
|
if (Bl0906Serial) { Bl0906Loop(); }
|
|
|
|
break;
|
|
|
|
case FUNC_EVERY_SECOND:
|
|
|
|
Bl0906EverySecond();
|
|
|
|
break;
|
|
|
|
case FUNC_JSON_APPEND:
|
|
|
|
Bl0906Show(1);
|
|
|
|
break;
|
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
case FUNC_WEB_SENSOR:
|
|
|
|
Bl0906Show(0);
|
|
|
|
break;
|
|
|
|
#endif // USE_WEBSERVER
|
|
|
|
case FUNC_INIT:
|
|
|
|
Bl0906Init();
|
|
|
|
break;
|
|
|
|
case FUNC_PRE_INIT:
|
|
|
|
Bl0906PreInit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // USE_BL0906
|
|
|
|
#endif // USE_ENERGY_SENSOR
|
|
|
|
#endif // ESP32
|