ESPHome  2024.9.0
bl0906.cpp
Go to the documentation of this file.
1 #include "bl0906.h"
2 #include "constants.h"
3 
4 #include "esphome/core/log.h"
5 
6 namespace esphome {
7 namespace bl0906 {
8 
9 static const char *const TAG = "bl0906";
10 
11 constexpr uint32_t to_uint32_t(ube24_t input) { return input.h << 16 | input.m << 8 | input.l; }
12 
13 constexpr int32_t to_int32_t(sbe24_t input) { return input.h << 16 | input.m << 8 | input.l; }
14 
15 // The SUM byte is (Addr+Data_L+Data_M+Data_H)&0xFF negated;
16 constexpr uint8_t bl0906_checksum(const uint8_t address, const DataPacket *data) {
17  return (address + data->l + data->m + data->h) ^ 0xFF;
18 }
19 
20 void BL0906::loop() {
21  if (this->current_channel_ == UINT8_MAX) {
22  return;
23  }
24 
25  while (this->available())
26  this->flush();
27 
28  if (this->current_channel_ == 0) {
29  // Temperature
30  this->read_data_(BL0906_TEMPERATURE, BL0906_TREF, this->temperature_sensor_);
31  } else if (this->current_channel_ == 1) {
32  this->read_data_(BL0906_I_1_RMS, BL0906_IREF, this->current_1_sensor_);
33  this->read_data_(BL0906_WATT_1, BL0906_PREF, this->power_1_sensor_);
34  this->read_data_(BL0906_CF_1_CNT, BL0906_EREF, this->energy_1_sensor_);
35  } else if (this->current_channel_ == 2) {
36  this->read_data_(BL0906_I_2_RMS, BL0906_IREF, this->current_2_sensor_);
37  this->read_data_(BL0906_WATT_2, BL0906_PREF, this->power_2_sensor_);
38  this->read_data_(BL0906_CF_2_CNT, BL0906_EREF, this->energy_2_sensor_);
39  } else if (this->current_channel_ == 3) {
40  this->read_data_(BL0906_I_3_RMS, BL0906_IREF, this->current_3_sensor_);
41  this->read_data_(BL0906_WATT_3, BL0906_PREF, this->power_3_sensor_);
42  this->read_data_(BL0906_CF_3_CNT, BL0906_EREF, this->energy_3_sensor_);
43  } else if (this->current_channel_ == 4) {
44  this->read_data_(BL0906_I_4_RMS, BL0906_IREF, this->current_4_sensor_);
45  this->read_data_(BL0906_WATT_4, BL0906_PREF, this->power_4_sensor_);
46  this->read_data_(BL0906_CF_4_CNT, BL0906_EREF, this->energy_4_sensor_);
47  } else if (this->current_channel_ == 5) {
48  this->read_data_(BL0906_I_5_RMS, BL0906_IREF, this->current_5_sensor_);
49  this->read_data_(BL0906_WATT_5, BL0906_PREF, this->power_5_sensor_);
50  this->read_data_(BL0906_CF_5_CNT, BL0906_EREF, this->energy_5_sensor_);
51  } else if (this->current_channel_ == 6) {
52  this->read_data_(BL0906_I_6_RMS, BL0906_IREF, this->current_6_sensor_);
53  this->read_data_(BL0906_WATT_6, BL0906_PREF, this->power_6_sensor_);
54  this->read_data_(BL0906_CF_6_CNT, BL0906_EREF, this->energy_6_sensor_);
55  } else if (this->current_channel_ == UINT8_MAX - 2) {
56  // Frequency
57  this->read_data_(BL0906_FREQUENCY, BL0906_FREF, frequency_sensor_);
58  // Voltage
59  this->read_data_(BL0906_V_RMS, BL0906_UREF, voltage_sensor_);
60  } else if (this->current_channel_ == UINT8_MAX - 1) {
61  // Total power
62  this->read_data_(BL0906_WATT_SUM, BL0906_WATT, this->total_power_sensor_);
63  // Total Energy
64  this->read_data_(BL0906_CF_SUM_CNT, BL0906_CF, this->total_energy_sensor_);
65  } else {
66  this->current_channel_ = UINT8_MAX - 2; // Go to frequency and voltage
67  return;
68  }
69  this->current_channel_++;
70  this->handle_actions_();
71 }
72 
73 void BL0906::setup() {
74  while (this->available())
75  this->flush();
76  this->write_array(USR_WRPROT_WITABLE, sizeof(USR_WRPROT_WITABLE));
77  // Calibration (1: register address; 2: value before calibration; 3: value after calibration)
78  this->bias_correction_(BL0906_RMSOS_1, 0.01600, 0); // Calibration current_1
79  this->bias_correction_(BL0906_RMSOS_2, 0.01500, 0);
80  this->bias_correction_(BL0906_RMSOS_3, 0.01400, 0);
81  this->bias_correction_(BL0906_RMSOS_4, 0.01300, 0);
82  this->bias_correction_(BL0906_RMSOS_5, 0.01200, 0);
83  this->bias_correction_(BL0906_RMSOS_6, 0.01200, 0); // Calibration current_6
84 
85  this->write_array(USR_WRPROT_ONLYREAD, sizeof(USR_WRPROT_ONLYREAD));
86 }
87 
88 void BL0906::update() { this->current_channel_ = 0; }
89 
91  this->action_queue_.push_back(function);
92  return this->action_queue_.size();
93 }
94 
96  if (this->action_queue_.empty()) {
97  return;
98  }
99  ActionCallbackFuncPtr ptr_func = nullptr;
100  for (int i = 0; i < this->action_queue_.size(); i++) {
101  ptr_func = this->action_queue_[i];
102  if (ptr_func) {
103  ESP_LOGI(TAG, "HandleActionCallback[%d]...", i);
104  (this->*ptr_func)();
105  }
106  }
107 
108  while (this->available()) {
109  this->read();
110  }
111 
112  this->action_queue_.clear();
113 }
114 
115 // Reset energy
117  this->write_array(BL0906_INIT[0], 6);
118  delay(1);
119  this->flush();
120 
121  ESP_LOGW(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_INIT[0][0], BL0906_INIT[0][1], BL0906_INIT[0][2],
122  BL0906_INIT[0][3], BL0906_INIT[0][4], BL0906_INIT[0][5]);
123 }
124 
125 // Read data
126 void BL0906::read_data_(const uint8_t address, const float reference, sensor::Sensor *sensor) {
127  if (sensor == nullptr) {
128  return;
129  }
130  DataPacket buffer;
131  ube24_t data_u24;
132  sbe24_t data_s24;
133  float value = 0;
134 
135  bool signed_result = reference == BL0906_TREF || reference == BL0906_WATT || reference == BL0906_PREF;
136 
137  this->write_byte(BL0906_READ_COMMAND);
138  this->write_byte(address);
139  if (this->read_array((uint8_t *) &buffer, sizeof(buffer) - 1)) {
140  if (bl0906_checksum(address, &buffer) == buffer.checksum) {
141  if (signed_result) {
142  data_s24.l = buffer.l;
143  data_s24.m = buffer.m;
144  data_s24.h = buffer.h;
145  } else {
146  data_u24.l = buffer.l;
147  data_u24.m = buffer.m;
148  data_u24.h = buffer.h;
149  }
150  } else {
151  ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
152  while (read() >= 0)
153  ;
154  return;
155  }
156  }
157  // Power
158  if (reference == BL0906_PREF) {
159  value = (float) to_int32_t(data_s24) * reference;
160  }
161 
162  // Total power
163  if (reference == BL0906_WATT) {
164  value = (float) to_int32_t(data_s24) * reference;
165  }
166 
167  // Voltage, current, power, total power
168  if (reference == BL0906_UREF || reference == BL0906_IREF || reference == BL0906_EREF || reference == BL0906_CF) {
169  value = (float) to_uint32_t(data_u24) * reference;
170  }
171 
172  // Frequency
173  if (reference == BL0906_FREF) {
174  value = reference / (float) to_uint32_t(data_u24);
175  }
176  // Chip temperature
177  if (reference == BL0906_TREF) {
178  value = (float) to_int32_t(data_s24);
179  value = (value - 64) * 12.5 / 59 - 40;
180  }
181  sensor->publish_state(value);
182 }
183 
184 // RMS offset correction
185 void BL0906::bias_correction_(uint8_t address, float measurements, float correction) {
186  DataPacket data;
187  float ki = 12875 * 1 * (5.1 + 5.1) * 1000 / 2000 / 1.097; // Current coefficient
188  float i_rms0 = measurements * ki;
189  float i_rms = correction * ki;
190  int32_t value = (i_rms * i_rms - i_rms0 * i_rms0) / 256;
191  data.l = value << 24 >> 24;
192  data.m = value << 16 >> 24;
193  if (value < 0) {
194  data.h = (value << 8 >> 24) | 0b10000000;
195  }
196  data.address = bl0906_checksum(address, &data);
197  ESP_LOGV(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_WRITE_COMMAND, address, data.l, data.m, data.h, data.address);
198  this->write_byte(BL0906_WRITE_COMMAND);
199  this->write_byte(address);
200  this->write_byte(data.l);
201  this->write_byte(data.m);
202  this->write_byte(data.h);
203  this->write_byte(data.address);
204 }
205 
206 void BL0906::dump_config() {
207  ESP_LOGCONFIG(TAG, "BL0906:");
208  LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
209 
210  LOG_SENSOR(" ", "Current1", this->current_1_sensor_);
211  LOG_SENSOR(" ", "Current2", this->current_2_sensor_);
212  LOG_SENSOR(" ", "Current3", this->current_3_sensor_);
213  LOG_SENSOR(" ", "Current4", this->current_4_sensor_);
214  LOG_SENSOR(" ", "Current5", this->current_5_sensor_);
215  LOG_SENSOR(" ", "Current6", this->current_6_sensor_);
216 
217  LOG_SENSOR(" ", "Power1", this->power_1_sensor_);
218  LOG_SENSOR(" ", "Power2", this->power_2_sensor_);
219  LOG_SENSOR(" ", "Power3", this->power_3_sensor_);
220  LOG_SENSOR(" ", "Power4", this->power_4_sensor_);
221  LOG_SENSOR(" ", "Power5", this->power_5_sensor_);
222  LOG_SENSOR(" ", "Power6", this->power_6_sensor_);
223 
224  LOG_SENSOR(" ", "Energy1", this->energy_1_sensor_);
225  LOG_SENSOR(" ", "Energy2", this->energy_2_sensor_);
226  LOG_SENSOR(" ", "Energy3", this->energy_3_sensor_);
227  LOG_SENSOR(" ", "Energy4", this->energy_4_sensor_);
228  LOG_SENSOR(" ", "Energy5", this->energy_5_sensor_);
229  LOG_SENSOR(" ", "Energy6", this->energy_6_sensor_);
230 
231  LOG_SENSOR(" ", "Total Power", this->total_power_sensor_);
232  LOG_SENSOR(" ", "Total Energy", this->total_energy_sensor_);
233  LOG_SENSOR(" ", "Frequency", this->frequency_sensor_);
234  LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
235 }
236 
237 } // namespace bl0906
238 } // namespace esphome
ube24_t i_rms
Definition: bl0940.h:21
virtual void loop()
This method will be called repeatedly.
Definition: component.cpp:50
optional< std::array< uint8_t, N > > read_array()
Definition: uart.h:33
void write_array(const uint8_t *data, size_t len)
Definition: uart.h:21
void write_byte(uint8_t data)
Definition: uart.h:19
void bias_correction_(uint8_t address, float measurements, float correction)
Definition: bl0906.cpp:185
const uint8_t BL0906_INIT[2][6]
Definition: constants.h:115
size_t enqueue_action_(ActionCallbackFuncPtr function)
Definition: bl0906.cpp:90
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
void read_data_(uint8_t address, float reference, sensor::Sensor *sensor)
Definition: bl0906.cpp:126
uint8_t current_channel_
Definition: bl0906.h:82
constexpr int32_t to_int32_t(sbe24_t input)
Definition: bl0906.cpp:13
constexpr uint32_t to_uint32_t(ube24_t input)
Definition: bl0906.cpp:11
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
uint8_t address
Definition: bl0906.h:211
void(BL0906::*)() ActionCallbackFuncPtr
Definition: bl0906.h:39
Base-class for all sensors.
Definition: sensor.h:57
constexpr uint8_t bl0906_checksum(const uint8_t address, const DataPacket *data)
Definition: bl0906.cpp:16
esphome::sensor::Sensor * sensor
Definition: statsd.h:37
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26