ESPHome 2026.8.2
Loading...
Searching...
No Matches
modbus_switch.cpp
Go to the documentation of this file.
1
2#include "modbus_switch.h"
4#include "esphome/core/log.h"
5
7
8static const char *const TAG = "modbus_controller.switch";
9
10// Maximum bytes to log in verbose hex output
11static constexpr size_t MODBUS_SWITCH_MAX_LOG_BYTES = 64;
12
14 optional<bool> initial_state = Switch::get_initial_state_with_restore_mode();
15 if (initial_state.has_value()) {
16 // if it has a value, restore_mode is not "DISABLED", therefore act on the switch:
17 if (initial_state.value()) {
18 this->turn_on();
19 } else {
20 this->turn_off();
21 }
22 }
23}
24void ModbusSwitch::dump_config() { LOG_SWITCH(TAG, "Modbus Controller Switch", this); }
25
27
29
30void ModbusSwitch::parse_and_publish(std::span<const uint8_t> data) {
31 bool value = false;
32 // For coils/discrete inputs this is the bit index; for registers it is the byte offset.
33 const size_t offset = this->offset;
34 switch (this->register_type) {
38 break;
39 default:
41 break;
42 }
43
44 // Is there a lambda registered
45 // call it with the pre converted value and the raw data array
46 if (this->publish_transform_func_) {
47 // the lambda can parse the response itself
48 auto val = (*this->publish_transform_func_)(this, value, data);
49 if (val.has_value()) {
50 ESP_LOGV(TAG, "Value overwritten by lambda");
51 value = val.value();
52 }
53 }
54
55 ESP_LOGV(TAG, "Publish '%s': new value = %s type = %d address = %X offset = %zx", this->get_name().c_str(),
56 ONOFF(value), (int) this->register_type, this->start_address, offset);
57 this->publish_state(value);
58}
59
61 // This will be called every time the user requests a state change.
62 optional<ModbusCommandItem> cmd;
63 std::vector<uint8_t> data;
64 // Is there are lambda configured?
65 if (this->write_transform_func_.has_value()) {
66 // data is passed by reference
67 // the lambda can fill the empty vector directly
68 // in that case the return value is ignored
69 auto val = (*this->write_transform_func_)(this, state, data);
70 if (val.has_value()) {
71 ESP_LOGV(TAG, "Value overwritten by lambda");
72 state = val.value();
73 } else {
74 ESP_LOGV(TAG, "Communication handled by lambda - exiting control");
75 return;
76 }
77 }
78 if (!data.empty()) {
79#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
80 char hex_buf[format_hex_pretty_size(MODBUS_SWITCH_MAX_LOG_BYTES)];
81#endif
82 ESP_LOGV(TAG, "Modbus Switch write raw: %s",
83 format_hex_pretty_to(hex_buf, sizeof(hex_buf), data.data(), data.size()));
85 this->parent_, data,
86 [this](modbus::EntityType register_type, uint16_t start_address, std::span<const uint8_t> data) {
87 this->parent_->on_write_register_response(register_type, this->start_address, data);
88 }));
89 } else {
90 ESP_LOGV(TAG, "write_state '%s': new value = %s type = %d address = %X offset = %x", this->get_name().c_str(),
91 ONOFF(state), (int) this->register_type, this->start_address, this->offset);
92 if (this->register_type == modbus::EntityType::COIL) {
93 // offset for coil and discrete inputs is the coil/register number not bytes
94 if (this->use_write_multiple_) {
95 std::vector<bool> states{state};
96 cmd.emplace(ModbusCommandItem::create_write_multiple_coils(this->parent_, this->write_address(), states));
97 } else {
98 cmd.emplace(ModbusCommandItem::create_write_single_coil(this->parent_, this->write_address(), state));
99 }
100 } else {
101 if (this->use_write_multiple_) {
102 std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
103 cmd.emplace(
105 } else {
107 state ? 0xFFFF & this->bitmask : 0u));
108 }
109 }
110 }
111 this->parent_->queue_command(std::move(*cmd));
112 this->publish_state(state);
113}
114// ModbusSwitch end
115} // namespace esphome::modbus_controller
const StringRef & get_name() const
Definition entity_base.h:71
static ModbusCommandItem create_write_multiple_coils(ModbusController *modbusdevice, uint16_t start_address, const std::vector< bool > &values)
Create modbus write multiple registers command Function 15 (0Fhex) Write Multiple Coils.
static ModbusCommandItem create_write_single_coil(ModbusController *modbusdevice, uint16_t address, bool value)
Create modbus write single registers command Function 05 (05hex) Write Single Coil.
static ModbusCommandItem create_write_single_command(ModbusController *modbusdevice, uint16_t start_address, uint16_t value)
Create modbus write multiple registers command Function 16 (10hex) Write Multiple Registers.
static ModbusCommandItem create_custom_command(ModbusController *modbusdevice, const std::vector< uint8_t > &values, std::function< void(EntityType register_type, uint16_t start_address, std::span< const uint8_t > data)> &&handler=nullptr)
Create custom modbus command.
static ModbusCommandItem create_write_multiple_command(ModbusController *modbusdevice, uint16_t start_address, uint16_t register_count, const std::vector< uint16_t > &values)
Create modbus read command Function code 02-04.
void queue_command(ModbusCommandItem command)
Queues a one-shot modbus command (writes, custom commands); taken by value, so std::move to avoid a c...
void on_write_register_response(EntityType register_type, uint16_t start_address, std::span< const uint8_t > data)
Handles a write command acknowledgement (used by write command on_data_func handlers).
void parse_and_publish(std::span< const uint8_t > data) override
optional< write_transform_func_t > write_transform_func_
void set_assumed_state(bool assumed_state)
optional< transform_func_t > publish_transform_func_
uint8_t offset
Position of this sensor's data within its range's response - a byte offset for registers,...
uint16_t write_address() const
Address a write entity (switch/number/select) targets, derived from its resolved position within the ...
void turn_on()
Turn this switch on.
Definition switch.cpp:20
void turn_off()
Turn this switch off.
Definition switch.cpp:24
bool state
The current reported state of the binary sensor.
Definition switch.h:55
void publish_state(bool state)
Publish a state to the front-end from the back-end.
Definition switch.cpp:56
bool state
Definition fan.h:2
mopeka_std_values val[3]
T get_data(const uint8_t *data, size_t buffer_offset)
Extract data from modbus response buffer.
bool bit_from_packed(int bit, std::span< const uint8_t > data)
Extract coil data from modbus response buffer Responses for coil are packed into bytes .
const std::vector< uint8_t > & data
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
Definition helpers.cpp:406
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Definition helpers.h:1426