ESPHome  2024.5.1
ade7880.h
Go to the documentation of this file.
1 #pragma once
2 
3 // This component was developed using knowledge gathered by a number
4 // of people who reverse-engineered the Shelly 3EM:
5 //
6 // @AndreKR on GitHub
7 // Axel (@Axel830 on GitHub)
8 // Marko (@goodkiller on GitHub)
9 // MichaĆ«l Piron (@michaelpiron on GitHub)
10 // Theo Arends (@arendst on GitHub)
11 
12 #include "esphome/core/component.h"
13 #include "esphome/core/hal.h"
16 
17 #include "ade7880_registers.h"
18 
19 namespace esphome {
20 namespace ade7880 {
21 
23  void set_current(sensor::Sensor *sens) { this->current = sens; }
24 
26 
29 };
30 
31 struct PowerChannel {
32  void set_current(sensor::Sensor *sens) { this->current = sens; }
33  void set_voltage(sensor::Sensor *sens) { this->voltage = sens; }
34  void set_active_power(sensor::Sensor *sens) { this->active_power = sens; }
35  void set_apparent_power(sensor::Sensor *sens) { this->apparent_power = sens; }
36  void set_power_factor(sensor::Sensor *sens) { this->power_factor = sens; }
37  void set_forward_active_energy(sensor::Sensor *sens) { this->forward_active_energy = sens; }
38  void set_reverse_active_energy(sensor::Sensor *sens) { this->reverse_active_energy = sens; }
39 
41  void set_voltage_gain_calibration(int32_t val) { this->voltage_gain_calibration = val; }
42  void set_power_gain_calibration(int32_t val) { this->power_gain_calibration = val; }
43  void set_phase_angle_calibration(int32_t val) { this->phase_angle_calibration = val; }
44 
46  sensor::Sensor *voltage{nullptr};
47  sensor::Sensor *active_power{nullptr};
48  sensor::Sensor *apparent_power{nullptr};
49  sensor::Sensor *power_factor{nullptr};
50  sensor::Sensor *forward_active_energy{nullptr};
51  sensor::Sensor *reverse_active_energy{nullptr};
53  int32_t voltage_gain_calibration{0};
54  int32_t power_gain_calibration{0};
55  uint16_t phase_angle_calibration{0};
56  float forward_active_energy_total{0};
57  float reverse_active_energy_total{0};
58 };
59 
60 // Store data in a class that doesn't use multiple-inheritance (no vtables in flash!)
61 struct ADE7880Store {
62  volatile bool reset_done{false};
63  bool reset_pending{false};
65 
66  static void gpio_intr(ADE7880Store *arg);
67 };
68 
69 class ADE7880 : public i2c::I2CDevice, public PollingComponent {
70  public:
71  void set_irq0_pin(InternalGPIOPin *pin) { this->irq0_pin_ = pin; }
72  void set_irq1_pin(InternalGPIOPin *pin) { this->irq1_pin_ = pin; }
73  void set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; }
74  void set_frequency(float frequency) { this->frequency_ = frequency; }
75  void set_channel_n(NeutralChannel *channel) { this->channel_n_ = channel; }
76  void set_channel_a(PowerChannel *channel) { this->channel_a_ = channel; }
77  void set_channel_b(PowerChannel *channel) { this->channel_b_ = channel; }
78  void set_channel_c(PowerChannel *channel) { this->channel_c_ = channel; }
79 
80  void setup() override;
81 
82  void loop() override;
83 
84  void update() override;
85 
86  void dump_config() override;
87 
88  float get_setup_priority() const override { return setup_priority::DATA; }
89 
90  protected:
91  ADE7880Store store_{};
92  InternalGPIOPin *irq0_pin_{nullptr};
93  InternalGPIOPin *irq1_pin_{nullptr};
94  InternalGPIOPin *reset_pin_{nullptr};
95  float frequency_;
96  NeutralChannel *channel_n_{nullptr};
97  PowerChannel *channel_a_{nullptr};
98  PowerChannel *channel_b_{nullptr};
99  PowerChannel *channel_c_{nullptr};
100 
101  void calibrate_s10zp_reading_(uint16_t a_register, int16_t calibration);
102  void calibrate_s24zpse_reading_(uint16_t a_register, int32_t calibration);
103 
104  void init_device_();
105 
106  // each of these functions allow the caller to pass in a lambda (or any other callable)
107  // which modifies the value read from the register before it is passed to the sensor
108  // the callable will be passed a 'float' value and is expected to return a 'float'
109  template<typename F> void update_sensor_from_s24zp_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
110  template<typename F> void update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
111  template<typename F> void update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f);
112 
113  void reset_device_();
114 
115  uint8_t read_u8_register16_(uint16_t a_register);
116  int16_t read_s16_register16_(uint16_t a_register);
117  uint16_t read_u16_register16_(uint16_t a_register);
118  int32_t read_s24zp_register16_(uint16_t a_register);
119  int32_t read_s32_register16_(uint16_t a_register);
120  uint32_t read_u32_register16_(uint16_t a_register);
121 
122  void write_u8_register16_(uint16_t a_register, uint8_t value);
123  void write_s10zp_register16_(uint16_t a_register, int16_t value);
124  void write_u16_register16_(uint16_t a_register, uint16_t value);
125  void write_s24zpse_register16_(uint16_t a_register, int32_t value);
126  void write_s32_register16_(uint16_t a_register, int32_t value);
127  void write_u32_register16_(uint16_t a_register, uint32_t value);
128 };
129 
130 } // namespace ade7880
131 } // namespace esphome
void setup()
void loop()
ISRInternalGPIOPin irq1_pin
Definition: ade7880.h:64
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
float get_setup_priority() const override
Definition: ade7880.h:88
Copy of GPIOPin that is safe to use from ISRs (with no virtual functions)
Definition: gpio.h:84
void set_power_gain_calibration(int32_t val)
Definition: ade7880.h:42
void set_channel_a(PowerChannel *channel)
Definition: ade7880.h:76
void set_reset_pin(InternalGPIOPin *pin)
Definition: ade7880.h:73
void set_channel_n(NeutralChannel *channel)
Definition: ade7880.h:75
mopeka_std_values val[4]
This class simplifies creating components that periodically check a state.
Definition: component.h:283
void set_current(sensor::Sensor *sens)
Definition: ade7880.h:32
void set_voltage_gain_calibration(int32_t val)
Definition: ade7880.h:41
void set_voltage(sensor::Sensor *sens)
Definition: ade7880.h:33
void set_current_gain_calibration(int32_t val)
Definition: ade7880.h:25
void set_channel_b(PowerChannel *channel)
Definition: ade7880.h:77
void set_irq1_pin(InternalGPIOPin *pin)
Definition: ade7880.h:72
void set_reverse_active_energy(sensor::Sensor *sens)
Definition: ade7880.h:38
void set_current_gain_calibration(int32_t val)
Definition: ade7880.h:40
void set_power_factor(sensor::Sensor *sens)
Definition: ade7880.h:36
void set_apparent_power(sensor::Sensor *sens)
Definition: ade7880.h:35
uint16_le_t frequency
Definition: bl0942.h:21
void set_active_power(sensor::Sensor *sens)
Definition: ade7880.h:34
void set_channel_c(PowerChannel *channel)
Definition: ade7880.h:78
sensor::Sensor * current
Definition: ade7880.h:27
void set_frequency(float frequency)
Definition: ade7880.h:74
void set_irq0_pin(InternalGPIOPin *pin)
Definition: ade7880.h:71
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
Base-class for all sensors.
Definition: sensor.h:57
void set_phase_angle_calibration(int32_t val)
Definition: ade7880.h:43
void set_forward_active_energy(sensor::Sensor *sens)
Definition: ade7880.h:37
void set_current(sensor::Sensor *sens)
Definition: ade7880.h:23
This Class provides the methods to read/write bytes from/to an i2c device.
Definition: i2c.h:133