ESPHome  2024.11.0
bl0939.h
Go to the documentation of this file.
1 #pragma once
2 
6 
7 namespace esphome {
8 namespace bl0939 {
9 
10 // https://datasheet.lcsc.com/lcsc/2108071830_BL-Shanghai-Belling-BL0939_C2841044.pdf
11 // (unfortunately chinese, but the formulas can be easily understood)
12 // Sonoff Dual R3 V2 has the exact same resistor values for the current shunts (RL=1miliOhm)
13 // and for the voltage divider (R1=0.51kOhm, R2=5*390kOhm)
14 // as in the manufacturer's reference circuit, so the same formulas were used here (Vref=1.218V)
15 static const float BL0939_IREF = 324004 * 1 / 1.218;
16 static const float BL0939_UREF = 79931 * 0.51 * 1000 / (1.218 * (5 * 390 + 0.51));
17 static const float BL0939_PREF = 4046 * 1 * 0.51 * 1000 / (1.218 * 1.218 * (5 * 390 + 0.51));
18 static const float BL0939_EREF = 3.6e6 * 4046 * 1 * 0.51 * 1000 / (1638.4 * 256 * 1.218 * 1.218 * (5 * 390 + 0.51));
19 
20 struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
21  uint8_t l;
22  uint8_t m;
23  uint8_t h;
24 } __attribute__((packed));
25 
26 struct ube16_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
27  uint8_t l;
28  uint8_t h;
29 } __attribute__((packed));
30 
31 struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
32  uint8_t l;
33  uint8_t m;
34  int8_t h;
35 } __attribute__((packed));
36 
37 // Caveat: All these values are big endian (low - middle - high)
38 
39 union DataPacket { // NOLINT(altera-struct-pack-align)
40  uint8_t raw[35];
41  struct {
42  uint8_t frame_header; // 0x55 according to docs
53  uint8_t RESERVED1; // value of 0x00
55  uint8_t RESERVED2; // value of 0x00
56  uint8_t checksum; // checksum
57  };
58 } __attribute__((packed));
59 
60 class BL0939 : public PollingComponent, public uart::UARTDevice {
61  public:
62  void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
63  void set_current_sensor_1(sensor::Sensor *current_sensor_1) { current_sensor_1_ = current_sensor_1; }
64  void set_current_sensor_2(sensor::Sensor *current_sensor_2) { current_sensor_2_ = current_sensor_2; }
65  void set_power_sensor_1(sensor::Sensor *power_sensor_1) { power_sensor_1_ = power_sensor_1; }
66  void set_power_sensor_2(sensor::Sensor *power_sensor_2) { power_sensor_2_ = power_sensor_2; }
67  void set_energy_sensor_1(sensor::Sensor *energy_sensor_1) { energy_sensor_1_ = energy_sensor_1; }
68  void set_energy_sensor_2(sensor::Sensor *energy_sensor_2) { energy_sensor_2_ = energy_sensor_2; }
69  void set_energy_sensor_sum(sensor::Sensor *energy_sensor_sum) { energy_sensor_sum_ = energy_sensor_sum; }
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_1_{nullptr};
80  sensor::Sensor *current_sensor_2_{nullptr};
81  // NB This may be negative as the circuits is seemingly able to measure
82  // power in both directions
83  sensor::Sensor *power_sensor_1_{nullptr};
84  sensor::Sensor *power_sensor_2_{nullptr};
85  sensor::Sensor *energy_sensor_1_{nullptr};
86  sensor::Sensor *energy_sensor_2_{nullptr};
87  sensor::Sensor *energy_sensor_sum_{nullptr};
88 
89  // Divide by this to turn into Watt
90  float power_reference_ = BL0939_PREF;
91  // Divide by this to turn into Volt
92  float voltage_reference_ = BL0939_UREF;
93  // Divide by this to turn into Ampere
94  float current_reference_ = BL0939_IREF;
95  // Divide by this to turn into kWh
96  float energy_reference_ = BL0939_EREF;
97 
98  static uint32_t to_uint32_t(ube24_t input);
99 
100  static int32_t to_int32_t(sbe24_t input);
101 
102  static bool validate_checksum(const DataPacket *data);
103 
104  void received_package_(const DataPacket *data) const;
105 };
106 } // namespace bl0939
107 } // namespace esphome
void setup()
void loop()
uint8_t raw[35]
Definition: bl0939.h:19
void set_power_sensor_2(sensor::Sensor *power_sensor_2)
Definition: bl0939.h:66
void set_voltage_sensor(sensor::Sensor *voltage_sensor)
Definition: bl0939.h:62
esphome::bl0939::BL0939 __attribute__
void set_current_sensor_2(sensor::Sensor *current_sensor_2)
Definition: bl0939.h:64
This class simplifies creating components that periodically check a state.
Definition: component.h:283
void set_power_sensor_1(sensor::Sensor *power_sensor_1)
Definition: bl0939.h:65
void set_energy_sensor_2(sensor::Sensor *energy_sensor_2)
Definition: bl0939.h:68
void set_current_sensor_1(sensor::Sensor *current_sensor_1)
Definition: bl0939.h:63
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
Base-class for all sensors.
Definition: sensor.h:57
void set_energy_sensor_1(sensor::Sensor *energy_sensor_1)
Definition: bl0939.h:67
void set_energy_sensor_sum(sensor::Sensor *energy_sensor_sum)
Definition: bl0939.h:69