ESPHome 2025.5.0
Loading...
Searching...
No Matches
bl0940.cpp
Go to the documentation of this file.
1#include "bl0940.h"
2#include "esphome/core/log.h"
3#include <cinttypes>
4
5namespace esphome {
6namespace bl0940 {
7
8static const char *const TAG = "bl0940";
9
10static const uint8_t BL0940_READ_COMMAND = 0x50; // 0x58 according to documentation
11static const uint8_t BL0940_FULL_PACKET = 0xAA;
12static const uint8_t BL0940_PACKET_HEADER = 0x55; // 0x58 according to documentation
13
14static const uint8_t BL0940_WRITE_COMMAND = 0xA0; // 0xA8 according to documentation
15static const uint8_t BL0940_REG_I_FAST_RMS_CTRL = 0x10;
16static const uint8_t BL0940_REG_MODE = 0x18;
17static const uint8_t BL0940_REG_SOFT_RESET = 0x19;
18static const uint8_t BL0940_REG_USR_WRPROT = 0x1A;
19static const uint8_t BL0940_REG_TPS_CTRL = 0x1B;
20
21const uint8_t BL0940_INIT[5][6] = {
22 // Reset to default
23 {BL0940_WRITE_COMMAND, BL0940_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x38},
24 // Enable User Operation Write
25 {BL0940_WRITE_COMMAND, BL0940_REG_USR_WRPROT, 0x55, 0x00, 0x00, 0xF0},
26 // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
27 {BL0940_WRITE_COMMAND, BL0940_REG_MODE, 0x00, 0x10, 0x00, 0x37},
28 // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
29 {BL0940_WRITE_COMMAND, BL0940_REG_TPS_CTRL, 0xFF, 0x47, 0x00, 0xFE},
30 // 0x181C = Half cycle, Fast RMS threshold 6172
31 {BL0940_WRITE_COMMAND, BL0940_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00, 0x1B}};
32
34 DataPacket buffer;
35 if (!this->available()) {
36 return;
37 }
38 if (read_array((uint8_t *) &buffer, sizeof(buffer))) {
39 if (validate_checksum(&buffer)) {
40 received_package_(&buffer);
41 }
42 } else {
43 ESP_LOGW(TAG, "Junk on wire. Throwing away partial message");
44 while (read() >= 0)
45 ;
46 }
47}
48
50 uint8_t checksum = BL0940_READ_COMMAND;
51 // Whole package but checksum
52 for (uint32_t i = 0; i < sizeof(data->raw) - 1; i++) {
53 checksum += data->raw[i];
54 }
55 checksum ^= 0xFF;
56 if (checksum != data->checksum) {
57 ESP_LOGW(TAG, "BL0940 invalid checksum! 0x%02X != 0x%02X", checksum, data->checksum);
58 }
59 return checksum == data->checksum;
60}
61
63 this->flush();
64 this->write_byte(BL0940_READ_COMMAND);
65 this->write_byte(BL0940_FULL_PACKET);
66}
67
69 for (auto *i : BL0940_INIT) {
70 this->write_array(i, 6);
71 delay(1);
72 }
73 this->flush();
74}
75
77 auto tb = (float) (temperature.h << 8 | temperature.l);
78 float converted_temp = ((float) 170 / 448) * (tb / 2 - 32) - 45;
79 if (sensor != nullptr) {
80 if (sensor->has_state() && std::abs(converted_temp - sensor->get_state()) > max_temperature_diff_) {
81 ESP_LOGD(TAG, "Invalid temperature change. Sensor: '%s', Old temperature: %f, New temperature: %f",
82 sensor->get_name().c_str(), sensor->get_state(), converted_temp);
83 return 0.0f;
84 }
85 sensor->publish_state(converted_temp);
86 }
87 return converted_temp;
88}
89
90void BL0940::received_package_(const DataPacket *data) const {
91 // Bad header
92 if (data->frame_header != BL0940_PACKET_HEADER) {
93 ESP_LOGI(TAG, "Invalid data. Header mismatch: %d", data->frame_header);
94 return;
95 }
96
97 float v_rms = (float) to_uint32_t(data->v_rms) / voltage_reference_;
98 float i_rms = (float) to_uint32_t(data->i_rms) / current_reference_;
99 float watt = (float) to_int32_t(data->watt) / power_reference_;
100 uint32_t cf_cnt = to_uint32_t(data->cf_cnt);
101 float total_energy_consumption = (float) cf_cnt / energy_reference_;
102
105
106 if (voltage_sensor_ != nullptr) {
108 }
109 if (current_sensor_ != nullptr) {
111 }
112 if (power_sensor_ != nullptr) {
114 }
115 if (energy_sensor_ != nullptr) {
116 energy_sensor_->publish_state(total_energy_consumption);
117 }
118
119 ESP_LOGV(TAG, "BL0940: U %fV, I %fA, P %fW, Cnt %" PRId32 ", ∫P %fkWh, T1 %f°C, T2 %f°C", v_rms, i_rms, watt, cf_cnt,
120 total_energy_consumption, tps1, tps2);
121}
122
123void BL0940::dump_config() { // NOLINT(readability-function-cognitive-complexity)
124 ESP_LOGCONFIG(TAG, "BL0940:");
125 LOG_SENSOR("", "Voltage", this->voltage_sensor_);
126 LOG_SENSOR("", "Current", this->current_sensor_);
127 LOG_SENSOR("", "Power", this->power_sensor_);
128 LOG_SENSOR("", "Energy", this->energy_sensor_);
129 LOG_SENSOR("", "Internal temperature", this->internal_temperature_sensor_);
130 LOG_SENSOR("", "External temperature", this->external_temperature_sensor_);
131}
132
133uint32_t BL0940::to_uint32_t(ube24_t input) { return input.h << 16 | input.m << 8 | input.l; }
134
135int32_t BL0940::to_int32_t(sbe24_t input) { return input.h << 16 | input.m << 8 | input.l; }
136
137} // namespace bl0940
138} // namespace esphome
uint8_t checksum
Definition bl0906.h:3
ube16_t tps1
Definition bl0939.h:12
ube24_t v_rms
Definition bl0939.h:6
ube16_t tps2
Definition bl0939.h:14
ube24_t i_rms
Definition bl0940.h:4
ube24_t cf_cnt
Definition bl0940.h:10
sbe24_t watt
Definition bl0940.h:8
const StringRef & get_name() const
constexpr const char * c_str() const
Definition string_ref.h:68
sensor::Sensor * external_temperature_sensor_
Definition bl0940.h:85
sensor::Sensor * current_sensor_
Definition bl0940.h:79
sensor::Sensor * internal_temperature_sensor_
Definition bl0940.h:84
static bool validate_checksum(const DataPacket *data)
Definition bl0940.cpp:49
float max_temperature_diff_
Definition bl0940.h:88
static int32_t to_int32_t(sbe24_t input)
Definition bl0940.cpp:135
void dump_config() override
Definition bl0940.cpp:123
sensor::Sensor * voltage_sensor_
Definition bl0940.h:78
sensor::Sensor * energy_sensor_
Definition bl0940.h:83
void update() override
Definition bl0940.cpp:62
void setup() override
Definition bl0940.cpp:68
static uint32_t to_uint32_t(ube24_t input)
Definition bl0940.cpp:133
float update_temp_(sensor::Sensor *sensor, ube16_t packed_temperature) const
Definition bl0940.cpp:76
void received_package_(const DataPacket *data) const
Definition bl0940.cpp:90
sensor::Sensor * power_sensor_
Definition bl0940.h:82
void loop() override
Definition bl0940.cpp:33
Base-class for all sensors.
Definition sensor.h:57
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:39
float get_state() const
Getter-syntax for .state.
Definition sensor.cpp:86
bool has_state() const
Return whether this sensor has gotten a full state (that passed through all filters) yet.
Definition sensor.cpp:97
optional< std::array< uint8_t, N > > read_array()
Definition uart.h:33
void write_byte(uint8_t data)
Definition uart.h:19
void write_array(const uint8_t *data, size_t len)
Definition uart.h:21
const uint8_t BL0940_INIT[5][6]
Definition bl0940.cpp:21
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint16_t temperature
Definition sun_gtil2.cpp:12