ESPHome  2024.2.2
sdm_meter.cpp
Go to the documentation of this file.
1 #include "sdm_meter.h"
2 #include "sdm_meter_registers.h"
3 #include "esphome/core/log.h"
4 
5 namespace esphome {
6 namespace sdm_meter {
7 
8 static const char *const TAG = "sdm_meter";
9 
10 static const uint8_t MODBUS_CMD_READ_IN_REGISTERS = 0x04;
11 static const uint8_t MODBUS_REGISTER_COUNT = 80; // 74 x 16-bit registers
12 
13 void SDMMeter::on_modbus_data(const std::vector<uint8_t> &data) {
14  if (data.size() < MODBUS_REGISTER_COUNT * 2) {
15  ESP_LOGW(TAG, "Invalid size for SDMMeter!");
16  return;
17  }
18 
19  auto sdm_meter_get_float = [&](size_t i) -> float {
20  uint32_t temp = encode_uint32(data[i], data[i + 1], data[i + 2], data[i + 3]);
21  float f;
22  memcpy(&f, &temp, sizeof(f));
23  return f;
24  };
25 
26  for (uint8_t i = 0; i < 3; i++) {
27  auto phase = this->phases_[i];
28  if (!phase.setup)
29  continue;
30 
31  float voltage = sdm_meter_get_float(SDM_PHASE_1_VOLTAGE * 2 + (i * 4));
32  float current = sdm_meter_get_float(SDM_PHASE_1_CURRENT * 2 + (i * 4));
33  float active_power = sdm_meter_get_float(SDM_PHASE_1_ACTIVE_POWER * 2 + (i * 4));
34  float apparent_power = sdm_meter_get_float(SDM_PHASE_1_APPARENT_POWER * 2 + (i * 4));
35  float reactive_power = sdm_meter_get_float(SDM_PHASE_1_REACTIVE_POWER * 2 + (i * 4));
36  float power_factor = sdm_meter_get_float(SDM_PHASE_1_POWER_FACTOR * 2 + (i * 4));
37  float phase_angle = sdm_meter_get_float(SDM_PHASE_1_ANGLE * 2 + (i * 4));
38 
39  ESP_LOGD(
40  TAG,
41  "SDMMeter Phase %c: V=%.3f V, I=%.3f A, Active P=%.3f W, Apparent P=%.3f VA, Reactive P=%.3f VAR, PF=%.3f, "
42  "PA=%.3f °",
43  i + 'A', voltage, current, active_power, apparent_power, reactive_power, power_factor, phase_angle);
44  if (phase.voltage_sensor_ != nullptr)
45  phase.voltage_sensor_->publish_state(voltage);
46  if (phase.current_sensor_ != nullptr)
47  phase.current_sensor_->publish_state(current);
48  if (phase.active_power_sensor_ != nullptr)
49  phase.active_power_sensor_->publish_state(active_power);
50  if (phase.apparent_power_sensor_ != nullptr)
51  phase.apparent_power_sensor_->publish_state(apparent_power);
52  if (phase.reactive_power_sensor_ != nullptr)
53  phase.reactive_power_sensor_->publish_state(reactive_power);
54  if (phase.power_factor_sensor_ != nullptr)
55  phase.power_factor_sensor_->publish_state(power_factor);
56  if (phase.phase_angle_sensor_ != nullptr)
57  phase.phase_angle_sensor_->publish_state(phase_angle);
58  }
59 
60  float total_power = sdm_meter_get_float(SDM_TOTAL_SYSTEM_POWER * 2);
61  float frequency = sdm_meter_get_float(SDM_FREQUENCY * 2);
62  float import_active_energy = sdm_meter_get_float(SDM_IMPORT_ACTIVE_ENERGY * 2);
63  float export_active_energy = sdm_meter_get_float(SDM_EXPORT_ACTIVE_ENERGY * 2);
64  float import_reactive_energy = sdm_meter_get_float(SDM_IMPORT_REACTIVE_ENERGY * 2);
65  float export_reactive_energy = sdm_meter_get_float(SDM_EXPORT_REACTIVE_ENERGY * 2);
66 
67  ESP_LOGD(TAG, "SDMMeter: F=%.3f Hz, Im.A.E=%.3f Wh, Ex.A.E=%.3f Wh, Im.R.E=%.3f VARh, Ex.R.E=%.3f VARh, T.P=%.3f W",
68  frequency, import_active_energy, export_active_energy, import_reactive_energy, export_reactive_energy,
69  total_power);
70 
71  if (this->total_power_sensor_ != nullptr)
72  this->total_power_sensor_->publish_state(total_power);
73  if (this->frequency_sensor_ != nullptr)
74  this->frequency_sensor_->publish_state(frequency);
75  if (this->import_active_energy_sensor_ != nullptr)
76  this->import_active_energy_sensor_->publish_state(import_active_energy);
77  if (this->export_active_energy_sensor_ != nullptr)
78  this->export_active_energy_sensor_->publish_state(export_active_energy);
79  if (this->import_reactive_energy_sensor_ != nullptr)
80  this->import_reactive_energy_sensor_->publish_state(import_reactive_energy);
81  if (this->export_reactive_energy_sensor_ != nullptr)
82  this->export_reactive_energy_sensor_->publish_state(export_reactive_energy);
83 }
84 
85 void SDMMeter::update() { this->send(MODBUS_CMD_READ_IN_REGISTERS, 0, MODBUS_REGISTER_COUNT); }
87  ESP_LOGCONFIG(TAG, "SDM Meter:");
88  ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_);
89  for (uint8_t i = 0; i < 3; i++) {
90  auto phase = this->phases_[i];
91  if (!phase.setup)
92  continue;
93  ESP_LOGCONFIG(TAG, " Phase %c", i + 'A');
94  LOG_SENSOR(" ", "Voltage", phase.voltage_sensor_);
95  LOG_SENSOR(" ", "Current", phase.current_sensor_);
96  LOG_SENSOR(" ", "Active Power", phase.active_power_sensor_);
97  LOG_SENSOR(" ", "Apparent Power", phase.apparent_power_sensor_);
98  LOG_SENSOR(" ", "Reactive Power", phase.reactive_power_sensor_);
99  LOG_SENSOR(" ", "Power Factor", phase.power_factor_sensor_);
100  LOG_SENSOR(" ", "Phase Angle", phase.phase_angle_sensor_);
101  }
102  LOG_SENSOR(" ", "Total Power", this->total_power_sensor_);
103  LOG_SENSOR(" ", "Frequency", this->frequency_sensor_);
104  LOG_SENSOR(" ", "Import Active Energy", this->import_active_energy_sensor_);
105  LOG_SENSOR(" ", "Export Active Energy", this->export_active_energy_sensor_);
106  LOG_SENSOR(" ", "Import Reactive Energy", this->import_reactive_energy_sensor_);
107  LOG_SENSOR(" ", "Export Reactive Energy", this->export_reactive_energy_sensor_);
108 }
109 
110 } // namespace sdm_meter
111 } // namespace esphome
sensor::Sensor * import_active_energy_sensor_
Definition: sdm_meter.h:76
void dump_config() override
Definition: sdm_meter.cpp:86
struct esphome::sdm_meter::SDMMeter::SDMPhase phases_[3]
sensor::Sensor * frequency_sensor_
Definition: sdm_meter.h:74
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition: helpers.h:186
sensor::Sensor * export_active_energy_sensor_
Definition: sdm_meter.h:77
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
uint16_le_t frequency
Definition: bl0942.h:21
sensor::Sensor * export_reactive_energy_sensor_
Definition: sdm_meter.h:79
sensor::Sensor * import_reactive_energy_sensor_
Definition: sdm_meter.h:78
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void on_modbus_data(const std::vector< uint8_t > &data) override
Definition: sdm_meter.cpp:13
void send(uint8_t function, uint16_t start_address, uint16_t number_of_entities, uint8_t payload_len=0, const uint8_t *payload=nullptr)
Definition: modbus.h:53
sensor::Sensor * total_power_sensor_
Definition: sdm_meter.h:75