ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
selec_meter.h
Go to the documentation of this file.
1#pragma once
2
4#include "esphome/core/log.h"
7#ifdef USE_BINARY_SENSOR
9#endif
10#ifdef USE_TEXT_SENSOR
12#endif
13
14#include <span>
15
16namespace esphome::selec_meter {
17
18#define SELEC_METER_SENSOR(name) \
19 protected: \
20 sensor::Sensor *name##_sensor_{nullptr}; \
21\
22 public: \
23 void set_##name##_sensor(sensor::Sensor *(name)) { this->name##_sensor_ = name; }
24
25// Per-phase sensor in the Phase struct, setter indexed by phase (0 = L1/A, 1 = L2/B, 2 = L3/C)
26#define SELEC_METER_PHASE_SENSOR(name) \
27 void set_##name##_sensor(uint8_t phase, sensor::Sensor *(name)) { this->phases_[phase].name##_sensor_ = name; }
28
29enum class Model : uint8_t {
32};
33
34// Read cycle steps in the order they run. The extra reads (serial number, DG sensing) sit far outside
35// the main block and get their own transaction.
42
44 public:
45 SELEC_METER_SENSOR(total_active_energy)
46 SELEC_METER_SENSOR(import_active_energy)
47 SELEC_METER_SENSOR(export_active_energy)
48 SELEC_METER_SENSOR(total_reactive_energy)
49 SELEC_METER_SENSOR(import_reactive_energy)
50 SELEC_METER_SENSOR(export_reactive_energy)
51 SELEC_METER_SENSOR(apparent_energy)
52 SELEC_METER_SENSOR(active_power)
53 SELEC_METER_SENSOR(reactive_power)
54 SELEC_METER_SENSOR(apparent_power)
55 SELEC_METER_SENSOR(voltage)
56 SELEC_METER_SENSOR(current)
57 SELEC_METER_SENSOR(power_factor)
59 SELEC_METER_SENSOR(maximum_demand_active_power)
60 SELEC_METER_SENSOR(maximum_demand_reactive_power)
61 SELEC_METER_SENSOR(maximum_demand_apparent_power)
62
63#ifdef USE_SELEC_METER_EM4M
64 // EM4M per-phase sensors, indexed by phase (see Phase below)
65 SELEC_METER_PHASE_SENSOR(voltage)
66 SELEC_METER_PHASE_SENSOR(current)
67 SELEC_METER_PHASE_SENSOR(active_power)
68 SELEC_METER_PHASE_SENSOR(reactive_power)
69 SELEC_METER_PHASE_SENSOR(apparent_power)
70 SELEC_METER_PHASE_SENSOR(power_factor)
71 SELEC_METER_PHASE_SENSOR(import_active_energy)
72 SELEC_METER_PHASE_SENSOR(export_active_energy)
73 SELEC_METER_PHASE_SENSOR(import_reactive_energy)
74 SELEC_METER_PHASE_SENSOR(export_reactive_energy)
75 SELEC_METER_PHASE_SENSOR(apparent_energy)
76
77 // Line-to-line and aggregate sensors, not tied to one phase
78 SELEC_METER_SENSOR(voltage_l12)
79 SELEC_METER_SENSOR(voltage_l23)
80 SELEC_METER_SENSOR(voltage_l31)
81 SELEC_METER_SENSOR(average_voltage_ll)
82 SELEC_METER_SENSOR(net_active_energy_mains)
83 SELEC_METER_SENSOR(net_reactive_energy_mains)
84 SELEC_METER_SENSOR(net_apparent_energy_mains)
85 SELEC_METER_SENSOR(net_active_energy_dg)
86 SELEC_METER_SENSOR(net_reactive_energy_dg)
87 SELEC_METER_SENSOR(net_apparent_energy_dg)
88#endif
89
90 void set_model(Model model) { this->model_ = model; }
91 // true: registers are word-swapped (LSRF / Mid Little Endian, CDAB byte order)
92 // false: registers are in the meter's straightforward order (MSRF / Big Endian, ABCD byte order)
93 void set_word_swap(bool word_swap) { this->word_swap_ = word_swap; }
94#if defined(USE_SELEC_METER_EM4M) && defined(USE_TEXT_SENSOR)
96#endif
97#if defined(USE_SELEC_METER_EM4M) && defined(USE_BINARY_SENSOR)
99#endif
100
101 void update() override;
102
103 void on_read_input_registers(uint16_t start_address, std::span<const uint16_t> registers,
104 modbus::ResponseStatus status) override;
105 bool on_no_response(std::span<const uint8_t> request_pdu) override;
106 void on_not_sent(std::span<const uint8_t> request_pdu) override;
107
108 void dump_config() override;
109
110 protected:
111 // One float field of the main block: target sensor, register and whether it is published x1000
112 struct FloatField {
114 uint16_t reg;
115 bool kilo;
116 };
117
118 // Publishes each configured field in `fields` (a PROGMEM table); false on a payload shorter than
119 // `min_count`, and the caller sets or clears the warning from the result
120 bool publish_fields_(std::span<const uint16_t> registers, std::span<const FloatField> fields, uint8_t min_count);
121 bool decode_em2m_(std::span<const uint16_t> registers);
122#ifdef USE_SELEC_METER_EM4M
123 bool decode_em4m_(std::span<const uint16_t> registers);
124#ifdef USE_TEXT_SENSOR
125 void decode_serial_number_(std::span<const uint16_t> registers);
126#endif
127#ifdef USE_BINARY_SENSOR
128 void decode_dg_sensing_(std::span<const uint16_t> registers);
129#endif
130#endif
131 // First register and register count of the read for `state`
132 struct ReadRange {
133 uint16_t start;
134 uint8_t count;
135 };
137 // Whether the read cycle should run `state` on this pass
138 bool wanted_(ReadState state) const;
139 // Next wanted step after `current`, so one failed range does not cancel the other reads
141 // Sends the read for `state`; safe from a callback per the modbus callback contract
143 // Clears the pending read and advances the chain. Only a MAIN_BLOCK failure sets the warning and
144 // only a `durable` refusal counts toward MAX_OPTIONAL_READ_FAILURES; `reason` nullptr means already logged
145 void fail_current_read_(const LogString *reason, bool durable = false);
146
147#ifdef USE_SELEC_METER_EM4M
148 // phases_[0..2] are L1/L2/L3 (A/B/C), EM4M_PHASE_STRIDE registers apart
163#endif
164
166 bool word_swap_{false};
168
169 // An optional read stops once its counter reaches MAX_OPTIONAL_READ_FAILURES
170#if defined(USE_SELEC_METER_EM4M) && defined(USE_TEXT_SENSOR)
172 // Also set to the limit once the serial number is published, since it never changes
174#endif
175#if defined(USE_SELEC_METER_EM4M) && defined(USE_BINARY_SENSOR)
178#endif
179};
180
181} // namespace esphome::selec_meter
uint16_le_t frequency
Definition bl0942.h:6
This class simplifies creating components that periodically check a state.
Definition component.h:519
Base class for all binary_sensor-type classes.
binary_sensor::BinarySensor * dg_sensing_sensor_
ReadState next_read_state_after_(ReadState current) const
SELEC_METER_SENSOR(total_active_energy) SELEC_METER_SENSOR(import_active_energy) SELEC_METER_SENSOR(export_active_energy) SELEC_METER_SENSOR(total_reactive_energy) SELEC_METER_SENSOR(import_reactive_energy) SELEC_METER_SENSOR(export_reactive_energy) SELEC_METER_SENSOR(apparent_energy) SELEC_METER_SENSOR(active_power) SELEC_METER_SENSOR(reactive_power) SELEC_METER_SENSOR(apparent_power) SELEC_METER_SENSOR(voltage) SELEC_METER_SENSOR(current) SELEC_METER_SENSOR(power_factor) SELEC_METER_SENSOR(frequency) SELEC_METER_SENSOR(maximum_demand_active_power) SELEC_METER_SENSOR(maximum_demand_reactive_power) SELEC_METER_SENSOR(maximum_demand_apparent_power) SELEC_METER_PHASE_SENSOR(voltage) SELEC_METER_PHASE_SENSOR(current) SELEC_METER_PHASE_SENSOR(active_power) SELEC_METER_PHASE_SENSOR(reactive_power) SELEC_METER_PHASE_SENSOR(apparent_power) SELEC_METER_PHASE_SENSOR(power_factor) SELEC_METER_PHASE_SENSOR(import_active_energy) SELEC_METER_PHASE_SENSOR(export_active_energy) SELEC_METER_PHASE_SENSOR(import_reactive_energy) SELEC_METER_PHASE_SENSOR(export_reactive_energy) SELEC_METER_PHASE_SENSOR(apparent_energy) SELEC_METER_SENSOR(voltage_l12) SELEC_METER_SENSOR(voltage_l23) SELEC_METER_SENSOR(voltage_l31) SELEC_METER_SENSOR(average_voltage_ll) SELEC_METER_SENSOR(net_active_energy_mains) SELEC_METER_SENSOR(net_reactive_energy_mains) SELEC_METER_SENSOR(net_apparent_energy_mains) SELEC_METER_SENSOR(net_active_energy_dg) SELEC_METER_SENSOR(net_reactive_energy_dg) SELEC_METER_SENSOR(net_apparent_energy_dg) void set_model(Model model)
Definition selec_meter.h:45
void set_serial_number_sensor(text_sensor::TextSensor *serial_number)
Definition selec_meter.h:95
void start_read_(ReadState state)
void set_word_swap(bool word_swap)
Definition selec_meter.h:93
void on_not_sent(std::span< const uint8_t > request_pdu) override
bool publish_fields_(std::span< const uint16_t > registers, std::span< const FloatField > fields, uint8_t min_count)
void on_read_input_registers(uint16_t start_address, std::span< const uint16_t > registers, modbus::ResponseStatus status) override
ReadRange read_range_(ReadState state) const
bool decode_em4m_(std::span< const uint16_t > registers)
void decode_serial_number_(std::span< const uint16_t > registers)
void fail_current_read_(const LogString *reason, bool durable=false)
text_sensor::TextSensor * serial_number_sensor_
bool wanted_(ReadState state) const
bool decode_em2m_(std::span< const uint16_t > registers)
void set_dg_sensing_sensor(binary_sensor::BinarySensor *dg_sensing)
Definition selec_meter.h:98
void decode_dg_sensing_(std::span< const uint16_t > registers)
bool on_no_response(std::span< const uint8_t > request_pdu) override
Base-class for all sensors.
Definition sensor.h:47
bool state
Definition fan.h:2
std::optional< ExceptionCode > ResponseStatus
Definition modbus.h:307
sensor::Sensor *SelecMeter::* sensor
char serial_number[10]
Definition sun_gtil2.cpp:15