ESPHome  2024.12.2
hlw8012.cpp
Go to the documentation of this file.
1 #include "hlw8012.h"
2 #include "esphome/core/log.h"
3 
4 namespace esphome {
5 namespace hlw8012 {
6 
7 static const char *const TAG = "hlw8012";
8 
9 // valid for HLW8012 and CSE7759
10 static const uint32_t HLW8012_CLOCK_FREQUENCY = 3579000;
11 
13  float reference_voltage = 0;
14  ESP_LOGCONFIG(TAG, "Setting up HLW8012...");
15  this->sel_pin_->setup();
16  this->sel_pin_->digital_write(this->current_mode_);
19 
20  // Initialize multipliers
22  reference_voltage = 1.218f;
23  this->power_multiplier_ =
24  reference_voltage * reference_voltage * this->voltage_divider_ / this->current_resistor_ / 1721506.0f;
25  this->current_multiplier_ = reference_voltage / this->current_resistor_ / 94638.0f;
26  this->voltage_multiplier_ = reference_voltage * this->voltage_divider_ / 15397.0f;
27  } else {
28  // HLW8012 and CSE7759 have same reference specs
29  reference_voltage = 2.43f;
30  this->power_multiplier_ = reference_voltage * reference_voltage * this->voltage_divider_ / this->current_resistor_ *
31  64.0f / 24.0f / HLW8012_CLOCK_FREQUENCY;
32  this->current_multiplier_ = reference_voltage / this->current_resistor_ * 512.0f / 24.0f / HLW8012_CLOCK_FREQUENCY;
33  this->voltage_multiplier_ = reference_voltage * this->voltage_divider_ * 256.0f / HLW8012_CLOCK_FREQUENCY;
34  }
35 }
37  ESP_LOGCONFIG(TAG, "HLW8012:");
38  LOG_PIN(" SEL Pin: ", this->sel_pin_)
39  LOG_PIN(" CF Pin: ", this->cf_pin_)
40  LOG_PIN(" CF1 Pin: ", this->cf1_pin_)
41  ESP_LOGCONFIG(TAG, " Change measurement mode every %" PRIu32, this->change_mode_every_);
42  ESP_LOGCONFIG(TAG, " Current resistor: %.1f mΩ", this->current_resistor_ * 1000.0f);
43  ESP_LOGCONFIG(TAG, " Voltage Divider: %.1f", this->voltage_divider_);
44  LOG_UPDATE_INTERVAL(this)
45  LOG_SENSOR(" ", "Voltage", this->voltage_sensor_)
46  LOG_SENSOR(" ", "Current", this->current_sensor_)
47  LOG_SENSOR(" ", "Power", this->power_sensor_)
48  LOG_SENSOR(" ", "Energy", this->energy_sensor_)
49 }
52  // HLW8012 has 50% duty cycle
55  float cf_hz = raw_cf / (this->get_update_interval() / 1000.0f);
56  if (raw_cf <= 1) {
57  // don't count single pulse as power
58  cf_hz = 0.0f;
59  }
60  float cf1_hz = raw_cf1 / (this->get_update_interval() / 1000.0f);
61  if (raw_cf1 <= 1) {
62  // don't count single pulse as anything
63  cf1_hz = 0.0f;
64  }
65 
66  if (this->nth_value_++ < 2) {
67  return;
68  }
69 
70  float power = cf_hz * this->power_multiplier_;
71 
72  if (this->change_mode_at_ != 0) {
73  // Only read cf1 after one cycle. Apparently it's quite unstable after being changed.
74  if (this->current_mode_) {
75  float current = cf1_hz * this->current_multiplier_;
76  ESP_LOGD(TAG, "Got power=%.1fW, current=%.1fA", power, current);
77  if (this->current_sensor_ != nullptr) {
78  this->current_sensor_->publish_state(current);
79  }
80  } else {
81  float voltage = cf1_hz * this->voltage_multiplier_;
82  ESP_LOGD(TAG, "Got power=%.1fW, voltage=%.1fV", power, voltage);
83  if (this->voltage_sensor_ != nullptr) {
84  this->voltage_sensor_->publish_state(voltage);
85  }
86  }
87  }
88 
89  if (this->power_sensor_ != nullptr) {
90  this->power_sensor_->publish_state(power);
91  }
92 
93  if (this->energy_sensor_ != nullptr) {
94  cf_total_pulses_ += raw_cf;
95  float energy = cf_total_pulses_ * this->power_multiplier_ / 3600;
96  this->energy_sensor_->publish_state(energy);
97  }
98 
99  if (this->change_mode_every_ != 0 && this->change_mode_at_++ == this->change_mode_every_) {
100  this->current_mode_ = !this->current_mode_;
101  ESP_LOGV(TAG, "Changing mode to %s mode", this->current_mode_ ? "CURRENT" : "VOLTAGE");
102  this->change_mode_at_ = 0;
103  this->sel_pin_->digital_write(this->current_mode_);
104  }
105 }
106 
107 } // namespace hlw8012
108 } // namespace esphome
virtual void digital_write(bool value)=0
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
virtual void setup()=0
sensor::Sensor * energy_sensor_
Definition: hlw8012.h:69
sensor::Sensor * power_sensor_
Definition: hlw8012.h:68
InternalGPIOPin * cf_pin_
Definition: hlw8012.h:62
virtual pulse_counter_t read_raw_value()=0
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
pulse_counter::PulseCounterStorageBase & cf_store_
Definition: hlw8012.h:63
virtual uint32_t get_update_interval() const
Get the update interval in ms of this sensor.
Definition: component.cpp:228
HLW8012SensorModels sensor_model_
Definition: hlw8012.h:59
sensor::Sensor * voltage_sensor_
Definition: hlw8012.h:66
float get_setup_priority() const override
Definition: hlw8012.cpp:50
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
sensor::Sensor * current_sensor_
Definition: hlw8012.h:67
pulse_counter::PulseCounterStorageBase & cf1_store_
Definition: hlw8012.h:65
InternalGPIOPin * cf1_pin_
Definition: hlw8012.h:64
virtual bool pulse_counter_setup(InternalGPIOPin *pin)=0