ESPHome 2026.2.1
Loading...
Searching...
No Matches
modbus_output.cpp
Go to the documentation of this file.
1#include "modbus_output.h"
3#include "esphome/core/log.h"
4
5namespace esphome {
6namespace modbus_controller {
7
8static const char *const TAG = "modbus_controller.output";
9
10// Maximum bytes to log in verbose hex output
11static constexpr size_t MODBUS_OUTPUT_MAX_LOG_BYTES = 64;
12
17 std::vector<uint16_t> data;
18 auto original_value = value;
19 // Is there are lambda configured?
20 if (this->write_transform_func_.has_value()) {
21 // data is passed by reference
22 // the lambda can fill the empty vector directly
23 // in that case the return value is ignored
24 auto val = (*this->write_transform_func_)(this, value, data);
25 if (val.has_value()) {
26 ESP_LOGV(TAG, "Value overwritten by lambda");
27 value = val.value();
28 } else {
29 ESP_LOGV(TAG, "Communication handled by lambda - exiting control");
30 return;
31 }
32 } else {
33 value = this->multiply_by_ * value;
34 }
35 // lambda didn't set payload
36 if (data.empty()) {
37 data = float_to_payload(value, this->sensor_value_type);
38 }
39
40 ESP_LOGD(TAG, "Updating register: start address=0x%X register count=%d new value=%.02f (val=%.02f)",
41 this->start_address, this->register_count, value, original_value);
42
43 // Create and send the write command
44 ModbusCommandItem write_cmd;
45 if (this->register_count == 1 && !this->use_write_multiple_) {
46 write_cmd =
48 } else {
50 this->register_count, data);
51 }
52 this->parent_->queue_command(write_cmd);
53}
54
56 ESP_LOGCONFIG(TAG, "Modbus Float Output:");
57 LOG_FLOAT_OUTPUT(this);
58 ESP_LOGCONFIG(TAG,
59 " Device start address: 0x%X\n"
60 " Register count: %d\n"
61 " Value type: %d",
62 this->start_address, this->register_count, static_cast<int>(this->sensor_value_type));
63}
64
65// ModbusBinaryOutput
67 // This will be called every time the user requests a state change.
69 std::vector<uint8_t> data;
70
71 // Is there are lambda configured?
72 if (this->write_transform_func_.has_value()) {
73 // data is passed by reference
74 // the lambda can fill the empty vector directly
75 // in that case the return value is ignored
76 auto val = (*this->write_transform_func_)(this, state, data);
77 if (val.has_value()) {
78 ESP_LOGV(TAG, "Value overwritten by lambda");
79 state = val.value();
80 } else {
81 ESP_LOGV(TAG, "Communication handled by lambda - exiting control");
82 return;
83 }
84 }
85 if (!data.empty()) {
86#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
87 char hex_buf[format_hex_pretty_size(MODBUS_OUTPUT_MAX_LOG_BYTES)];
88#endif
89 ESP_LOGV(TAG, "Modbus binary output write raw: %s",
90 format_hex_pretty_to(hex_buf, sizeof(hex_buf), data.data(), data.size()));
92 this->parent_, data,
93 [this, cmd](ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data) {
94 this->parent_->on_write_register_response(cmd.register_type, this->start_address, data);
95 });
96 } else {
97 ESP_LOGV(TAG, "Write new state: value is %s, type is %d address = %X, offset = %x", ONOFF(state),
98 (int) this->register_type, this->start_address, this->offset);
99
100 // offset for coil and discrete inputs is the coil/register number not bytes
101 if (this->use_write_multiple_) {
102 std::vector<bool> states{state};
104 } else {
106 }
107 }
108 this->parent_->queue_command(cmd);
109}
110
112 ESP_LOGCONFIG(TAG, "Modbus Binary Output:");
113 LOG_BINARY_OUTPUT(this);
114 ESP_LOGCONFIG(TAG,
115 " Device start address: 0x%X\n"
116 " Register count: %d\n"
117 " Value type: %d",
118 this->start_address, this->register_count, static_cast<int>(this->sensor_value_type));
119}
120
121} // namespace modbus_controller
122} // namespace esphome
optional< write_transform_func_t > write_transform_func_
static ModbusCommandItem create_custom_command(ModbusController *modbusdevice, const std::vector< uint8_t > &values, std::function< void(ModbusRegisterType register_type, uint16_t start_address, const std::vector< uint8_t > &data)> &&handler=nullptr)
Create custom modbus command.
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_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 on_write_register_response(ModbusRegisterType register_type, uint16_t start_address, const std::vector< uint8_t > &data)
default delegate called by process_modbus_data when a response for a write response has retrieved fro...
void queue_command(const ModbusCommandItem &command)
queues a modbus command in the send queue
void write_state(float value) override
Write a value to the device.
optional< write_transform_func_t > write_transform_func_
bool has_value() const
Definition optional.h:92
bool state
Definition fan.h:2
mopeka_std_values val[4]
std::vector< uint16_t > float_to_payload(float value, SensorValueType value_type)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
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:353
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:978