ESPHome  2024.12.2
bl0940.h
Go to the documentation of this file.
1 #pragma once
2 
6 
7 namespace esphome {
8 namespace bl0940 {
9 
10 static const float BL0940_PREF = 1430;
11 static const float BL0940_UREF = 33000;
12 static const float BL0940_IREF = 275000; // 2750 from tasmota. Seems to generate values 100 times too high
13 
14 // Measured to 297J per click according to power consumption of 5 minutes
15 // Converted to kWh (3.6MJ per kwH). Used to be 256 * 1638.4
16 static const float BL0940_EREF = 3.6e6 / 297;
17 
18 struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
19  uint8_t l;
20  uint8_t m;
21  uint8_t h;
22 } __attribute__((packed));
23 
24 struct ube16_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
25  uint8_t l;
26  uint8_t h;
27 } __attribute__((packed));
28 
29 struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
30  uint8_t l;
31  uint8_t m;
32  int8_t h;
33 } __attribute__((packed));
34 
35 // Caveat: All these values are big endian (low - middle - high)
36 
37 union DataPacket { // NOLINT(altera-struct-pack-align)
38  uint8_t raw[35];
39  struct {
40  uint8_t frame_header; // value of 0x58 according to docs. 0x55 according to Tasmota real world tests. Reality wins.
42  ube24_t i_rms; // 0x04
43  ube24_t RESERVED0; // reserved
44  ube24_t v_rms; // 0x06
45  ube24_t RESERVED1; // reserved
46  sbe24_t watt; // 0x08
47  ube24_t RESERVED2; // reserved
48  ube24_t cf_cnt; // 0x0A
49  ube24_t RESERVED3; // reserved
50  ube16_t tps1; // 0x0c
51  uint8_t RESERVED4; // value of 0x00
52  ube16_t tps2; // 0x0c
53  uint8_t RESERVED5; // value of 0x00
54  uint8_t checksum; // checksum
55  };
56 } __attribute__((packed));
57 
58 class BL0940 : public PollingComponent, public uart::UARTDevice {
59  public:
60  void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
61  void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
62  void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
63  void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
64  void set_internal_temperature_sensor(sensor::Sensor *internal_temperature_sensor) {
65  internal_temperature_sensor_ = internal_temperature_sensor;
66  }
67  void set_external_temperature_sensor(sensor::Sensor *external_temperature_sensor) {
68  external_temperature_sensor_ = external_temperature_sensor;
69  }
70 
71  void loop() override;
72 
73  void update() override;
74  void setup() override;
75  void dump_config() override;
76 
77  protected:
78  sensor::Sensor *voltage_sensor_{nullptr};
79  sensor::Sensor *current_sensor_{nullptr};
80  // NB This may be negative as the circuits is seemingly able to measure
81  // power in both directions
82  sensor::Sensor *power_sensor_{nullptr};
83  sensor::Sensor *energy_sensor_{nullptr};
84  sensor::Sensor *internal_temperature_sensor_{nullptr};
85  sensor::Sensor *external_temperature_sensor_{nullptr};
86 
87  // Max difference between two measurements of the temperature. Used to avoid noise.
88  float max_temperature_diff_{0};
89  // Divide by this to turn into Watt
90  float power_reference_ = BL0940_PREF;
91  // Divide by this to turn into Volt
92  float voltage_reference_ = BL0940_UREF;
93  // Divide by this to turn into Ampere
94  float current_reference_ = BL0940_IREF;
95  // Divide by this to turn into kWh
96  float energy_reference_ = BL0940_EREF;
97 
98  float update_temp_(sensor::Sensor *sensor, ube16_t packed_temperature) const;
99 
100  static uint32_t to_uint32_t(ube24_t input);
101 
102  static int32_t to_int32_t(sbe24_t input);
103 
104  static bool validate_checksum(const DataPacket *data);
105 
106  void received_package_(const DataPacket *data) const;
107 };
108 } // namespace bl0940
109 } // namespace esphome
void setup()
void loop()
void set_voltage_sensor(sensor::Sensor *voltage_sensor)
Definition: bl0940.h:60
uint8_t raw[35]
Definition: bl0940.h:17
void set_power_sensor(sensor::Sensor *power_sensor)
Definition: bl0940.h:62
This class simplifies creating components that periodically check a state.
Definition: component.h:283
void set_external_temperature_sensor(sensor::Sensor *external_temperature_sensor)
Definition: bl0940.h:67
void set_current_sensor(sensor::Sensor *current_sensor)
Definition: bl0940.h:61
void set_energy_sensor(sensor::Sensor *energy_sensor)
Definition: bl0940.h:63
constexpr int32_t to_int32_t(sbe24_t input)
Definition: bl0906.cpp:13
void set_internal_temperature_sensor(sensor::Sensor *internal_temperature_sensor)
Definition: bl0940.h:64
esphome::bl0940::BL0940 __attribute__
constexpr uint32_t to_uint32_t(ube24_t input)
Definition: bl0906.cpp:11
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
Base-class for all sensors.
Definition: sensor.h:57
esphome::sensor::Sensor * sensor
Definition: statsd.h:38