ESPHome  2024.3.1
bl0942.cpp
Go to the documentation of this file.
1 #include "bl0942.h"
2 #include "esphome/core/log.h"
3 #include <cinttypes>
4 
5 namespace esphome {
6 namespace bl0942 {
7 
8 static const char *const TAG = "bl0942";
9 
10 static const uint8_t BL0942_READ_COMMAND = 0x58;
11 static const uint8_t BL0942_FULL_PACKET = 0xAA;
12 static const uint8_t BL0942_PACKET_HEADER = 0x55;
13 
14 static const uint8_t BL0942_WRITE_COMMAND = 0xA8;
15 static const uint8_t BL0942_REG_I_FAST_RMS_CTRL = 0x10;
16 static const uint8_t BL0942_REG_MODE = 0x18;
17 static const uint8_t BL0942_REG_SOFT_RESET = 0x19;
18 static const uint8_t BL0942_REG_USR_WRPROT = 0x1A;
19 static const uint8_t BL0942_REG_TPS_CTRL = 0x1B;
20 
21 // TODO: Confirm insialisation works as intended
22 const uint8_t BL0942_INIT[5][6] = {
23  // Reset to default
24  {BL0942_WRITE_COMMAND, BL0942_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38},
25  // Enable User Operation Write
26  {BL0942_WRITE_COMMAND, BL0942_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0},
27  // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
28  {BL0942_WRITE_COMMAND, BL0942_REG_MODE, 0x00, 0x10, 0x00, 0x37},
29  // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
30  {BL0942_WRITE_COMMAND, BL0942_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE},
31  // 0x181C = Half cycle, Fast RMS threshold 6172
32  {BL0942_WRITE_COMMAND, BL0942_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}};
33 
34 void BL0942::loop() {
35  DataPacket buffer;
36  if (!this->available()) {
37  return;
38  }
39  if (read_array((uint8_t *) &buffer, sizeof(buffer))) {
40  if (validate_checksum(&buffer)) {
41  received_package_(&buffer);
42  }
43  } else {
44  ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
45  while (read() >= 0)
46  ;
47  }
48 }
49 
51  uint8_t checksum = BL0942_READ_COMMAND;
52  // Whole package but checksum
53  uint8_t *raw = (uint8_t *) data;
54  for (uint32_t i = 0; i < sizeof(*data) - 1; i++) {
55  checksum += raw[i];
56  }
57  checksum ^= 0xFF;
58  if (checksum != data->checksum) {
59  ESP_LOGW(TAG, "BL0942 invalid checksum! 0x%02X != 0x%02X", checksum, data->checksum);
60  }
61  return checksum == data->checksum;
62 }
63 
65  this->flush();
66  this->write_byte(BL0942_READ_COMMAND);
67  this->write_byte(BL0942_FULL_PACKET);
68 }
69 
70 void BL0942::setup() {
71  for (auto *i : BL0942_INIT) {
72  this->write_array(i, 6);
73  delay(1);
74  }
75  this->flush();
76 }
77 
79  // Bad header
80  if (data->frame_header != BL0942_PACKET_HEADER) {
81  ESP_LOGI(TAG, "Invalid data. Header mismatch: %d", data->frame_header);
82  return;
83  }
84 
85  float v_rms = (uint24_t) data->v_rms / voltage_reference_;
86  float i_rms = (uint24_t) data->i_rms / current_reference_;
87  float watt = (int24_t) data->watt / power_reference_;
88  uint32_t cf_cnt = (uint24_t) data->cf_cnt;
89  float total_energy_consumption = cf_cnt / energy_reference_;
90  float frequency = 1000000.0f / data->frequency;
91 
92  if (voltage_sensor_ != nullptr) {
94  }
95  if (current_sensor_ != nullptr) {
97  }
98  if (power_sensor_ != nullptr) {
100  }
101  if (energy_sensor_ != nullptr) {
102  energy_sensor_->publish_state(total_energy_consumption);
103  }
104  if (frequency_sensor_ != nullptr) {
105  frequency_sensor_->publish_state(frequency);
106  }
107 
108  ESP_LOGV(TAG, "BL0942: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, frequency %fHz, status 0x%08X", v_rms, i_rms,
109  watt, cf_cnt, total_energy_consumption, frequency, data->status);
110 }
111 
112 void BL0942::dump_config() { // NOLINT(readability-function-cognitive-complexity)
113  ESP_LOGCONFIG(TAG, "BL0942:");
114  LOG_SENSOR("", "Voltage", this->voltage_sensor_);
115  LOG_SENSOR("", "Current", this->current_sensor_);
116  LOG_SENSOR("", "Power", this->power_sensor_);
117  LOG_SENSOR("", "Energy", this->energy_sensor_);
118  LOG_SENSOR("", "frequency", this->frequency_sensor_);
119 }
120 
121 } // namespace bl0942
122 } // namespace esphome
ube24_t i_rms
Definition: bl0940.h:21
void setup() override
Definition: bl0942.cpp:70
sensor::Sensor * frequency_sensor_
Definition: bl0942.h:52
24-bit unsigned integer type, transparently converting to 32-bit.
Definition: datatypes.h:32
uint8_t raw[35]
Definition: bl0939.h:19
ube24_t cf_cnt
Definition: bl0940.h:27
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
const uint8_t BL0942_INIT[5][6]
Definition: bl0942.cpp:22
void write_byte(uint8_t data)
Definition: uart.h:19
sensor::Sensor * power_sensor_
Definition: bl0942.h:50
void loop() override
Definition: bl0942.cpp:34
static bool validate_checksum(DataPacket *data)
Definition: bl0942.cpp:50
uint16_le_t frequency
Definition: bl0942.h:23
sensor::Sensor * current_sensor_
Definition: bl0942.h:47
24-bit signed integer type, transparently converting to 32-bit.
Definition: datatypes.h:38
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
void update() override
Definition: bl0942.cpp:64
sensor::Sensor * voltage_sensor_
Definition: bl0942.h:46
uint8_t checksum
Definition: bl0939.h:35
uint16_le_t frequency
Definition: bl0942.h:21
sensor::Sensor * energy_sensor_
Definition: bl0942.h:51
void dump_config() override
Definition: bl0942.cpp:112
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void received_package_(DataPacket *data)
Definition: bl0942.cpp:78
float current_reference_
Definition: bl0942.h:59
sbe24_t watt
Definition: bl0940.h:25
ube24_t v_rms
Definition: bl0939.h:25
float voltage_reference_
Definition: bl0942.h:57
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26