16namespace modbus_controller {
18class ModbusController;
26ESPDEPRECATED(
"Use modbus::helpers::value_type_is_float() instead. Removed in 2026.10.0",
"2026.4.0")
29ESPDEPRECATED(
"Use modbus::helpers::modbus_register_read_function() instead. Removed in 2026.10.0",
"2026.4.0")
34ESPDEPRECATED(
"Use modbus::helpers::modbus_register_write_function() instead. Removed in 2026.10.0",
"2026.4.0")
39ESPDEPRECATED(
"Use modbus::helpers::c_to_hex() instead. Removed in 2026.10.0",
"2026.4.0")
42ESPDEPRECATED(
"Use modbus::helpers::byte_from_hex_str() instead. Removed in 2026.10.0",
"2026.4.0")
43inline uint8_t byte_from_hex_str(const std::
string &value, uint8_t
pos) {
47ESPDEPRECATED(
"Use modbus::helpers::word_from_hex_str() instead. Removed in 2026.10.0",
"2026.4.0")
48inline uint16_t word_from_hex_str(const std::
string &value, uint8_t
pos) {
52ESPDEPRECATED(
"Use modbus::helpers::dword_from_hex_str() instead. Removed in 2026.10.0",
"2026.4.0")
53inline
uint32_t dword_from_hex_str(const std::
string &value, uint8_t
pos) {
57ESPDEPRECATED(
"Use modbus::helpers::qword_from_hex_str() instead. Removed in 2026.10.0",
"2026.4.0")
58inline uint64_t qword_from_hex_str(const std::
string &value, uint8_t
pos) {
63ESPDEPRECATED(
"Use modbus::helpers::get_data() instead. Removed in 2026.10.0",
"2026.4.0")
64T get_data(const std::vector<uint8_t> &
data,
size_t buffer_offset) {
68ESPDEPRECATED(
"Use modbus::helpers::coil_from_vector() instead. Removed in 2026.10.0",
"2026.4.0")
69inline
bool coil_from_vector(
int coil, const std::vector<uint8_t> &
data) {
74ESPDEPRECATED(
"Use modbus::helpers::mask_and_shift_by_rightbit() instead. Removed in 2026.10.0",
"2026.4.0")
79ESPDEPRECATED(
"Use modbus::helpers::number_to_payload() instead. Removed in 2026.10.0",
"2026.4.0")
80inline
void number_to_payload(std::vector<uint16_t> &
data, int64_t value,
SensorValueType value_type) {
84ESPDEPRECATED(
"Use modbus::helpers::payload_to_number() instead. Removed in 2026.10.0",
"2026.4.0")
85inline int64_t payload_to_number(const std::vector<uint8_t> &
data,
SensorValueType sensor_value_type, uint8_t offset,
90ESPDEPRECATED(
"Use modbus::helpers::float_to_payload() instead. Removed in 2026.10.0",
"2026.4.0")
91inline std::vector<uint16_t> float_to_payload(
float value,
SensorValueType value_type) {
95class ModbusController;
130 using ReadLambda = std::function<int64_t()>;
131 using WriteLambda = std::function<bool(int64_t value)>;
141 this->
read_lambda = [
this, user_read_lambda]() -> int64_t {
142 T user_value = user_read_lambda(this->address);
143 if constexpr (std::is_same_v<T, float>) {
146 return static_cast<int64_t
>(user_value);
153 this->
write_lambda = [
this, user_write_lambda](int64_t number) {
154 if constexpr (std::is_same_v<T, float>) {
156 return user_write_lambda(this->address, float_value);
158 return user_write_lambda(this->address,
static_cast<T
>(number));
173 buf_append_printf(buf,
sizeof(buf), 0,
"%" PRIu64,
static_cast<uint64_t
>(value));
180 buf_append_printf(buf,
sizeof(buf), 0,
"%" PRId64, value);
184 buf_append_printf(buf,
sizeof(buf), 0,
"%.1f", bit_cast<float>(
static_cast<uint32_t>(value)));
187 buf_append_printf(buf,
sizeof(buf), 0,
"%" PRId64, value);
230using SensorSet = std::set<SensorItem *, SensorItemsComparator>;
318 const std::vector<bool> &values);
329 &&handler =
nullptr);
341 &&handler =
nullptr);
362 void loop()
override;
363 void setup()
override;
375 void on_modbus_error(uint8_t function_code, uint8_t exception_code)
override;
385 const std::vector<uint8_t> &
data);
466 .enabled =
false, .register_last_address = 0xFFFF, .register_value = 0};
481 float_value =
static_cast<float>(number);
This class simplifies creating components that periodically check a state.
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.
bool should_retry(uint8_t max_retries)
Check if the command should be retried based on the max_retries parameter.
bool is_equal(const ModbusCommandItem &other)
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.
uint8_t send_count_
How many times this command has been sent.
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_read_command(ModbusController *modbusdevice, ModbusRegisterType register_type, uint16_t start_address, uint16_t register_count, std::function< void(ModbusRegisterType register_type, uint16_t start_address, const std::vector< uint8_t > &data)> &&handler)
factory methods
ModbusRegisterType register_type
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.
uint16_t register_address
static const size_t MAX_PAYLOAD_BYTES
ModbusController * modbusdevice
ModbusFunctionCode function_code
std::function< void(ModbusRegisterType register_type, uint16_t start_address, const std::vector< uint8_t > &data)> on_data_func
std::vector< uint8_t > payload
void add_sensor_item(SensorItem *item)
Registers a sensor with the controller. Called by esphomes code generator.
void on_register_data(ModbusRegisterType register_type, uint16_t start_address, const std::vector< uint8_t > &data)
default delegate called by process_modbus_data when a response has retrieved from the incoming queue
void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers) final
called when a modbus request (function code 0x03 or 0x04) was parsed without errors
std::queue< std::unique_ptr< ModbusCommandItem > > incoming_queue_
modbus response data waiting to get processed
void set_command_throttle(uint16_t command_throttle)
called by esphome generated code to set the command_throttle period
void set_offline_skip_updates(uint16_t offline_skip_updates)
called by esphome generated code to set the offline_skip_updates
uint16_t command_throttle_
min time in ms between sending modbus commands
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...
bool allow_duplicate_commands_
if duplicate commands can be sent
bool get_allow_duplicate_commands()
get if a duplicate command can be sent
CallbackManager< void(int, int)> command_sent_callback_
Command sent callback.
void add_server_register(ServerRegister *server_register)
Registers a server register with the controller. Called by esphomes code generator.
std::vector< RegisterRange > register_ranges_
Continuous range of modbus registers.
uint32_t last_command_timestamp_
when was the last send operation
CallbackManager< void(int, int)> offline_callback_
Server offline callback.
void add_on_command_sent_callback(F &&callback)
Set callback for commands.
void dump_sensors_()
dump the parsed sensormap for diagnostics
std::vector< ServerRegister * > server_registers_
Collection of all server registers for this component.
SensorSet sensorset_
Collection of all sensors for this component.
uint8_t max_cmd_retries_
How many times we will retry a command if we get no response.
bool send_next_command_()
send the next modbus command from the send queue
ServerCourtesyResponse get_server_courtesy_response() const
Get the server courtesy response object.
std::list< std::unique_ptr< ModbusCommandItem > > command_queue_
Hold the pending requests to be sent.
size_t get_command_queue_length()
get the number of queued modbus commands (should be mostly empty)
void on_modbus_error(uint8_t function_code, uint8_t exception_code) override
called when a modbus error response was received
void process_modbus_data_(const ModbusCommandItem *response)
parse incoming modbus data
void set_allow_duplicate_commands(bool allow_duplicate_commands)
Allow a duplicate command to be sent.
void update_range_(RegisterRange &r)
submit the read command for the address range to the send queue
uint8_t get_max_cmd_retries()
get how many times a command will be (re)sent if no response is received
ServerCourtesyResponse server_courtesy_response_
Server courtesy response.
void set_max_cmd_retries(uint8_t max_cmd_retries)
called by esphome generated code to set the max_cmd_retries.
bool module_offline_
if module didn't respond the last command
size_t create_register_ranges_()
parse sensormap_ and create range of sequential addresses
void set_server_courtesy_response(const ServerCourtesyResponse &server_courtesy_response)
Called by esphome generated code to set the server courtesy response object.
uint16_t offline_skip_updates_
how many updates to skip if module is offline
bool get_module_offline()
get if the module is offline, didn't respond the last command
void on_modbus_write_registers(uint8_t function_code, const std::vector< uint8_t > &data) final
called when a modbus request (function code 0x06 or 0x10) was parsed without errors
void add_on_online_callback(F &&callback)
Set callback for online changes.
void add_on_offline_callback(F &&callback)
Set callback for offline changes.
void dump_config() override
void on_modbus_data(const std::vector< uint8_t > &data) override
called when a modbus response was parsed without errors
void queue_command(const ModbusCommandItem &command)
queues a modbus command in the send queue
SensorSet find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const
CallbackManager< void(int, int)> online_callback_
Server online callback.
void set_custom_data(const std::vector< uint8_t > &data)
virtual void parse_and_publish(const std::vector< uint8_t > &data)=0
ModbusRegisterType register_type
SensorValueType sensor_value_type
void set_register_size(uint8_t register_size)
std::vector< uint8_t > custom_data
virtual size_t get_register_size() const
bool operator()(const SensorItem *lhs, const SensorItem *rhs) const
void set_write_lambda(const std::function< bool(uint16_t address, const T v)> &&user_write_lambda)
std::string format_value(int64_t value) const
void set_read_lambda(const std::function< T(uint16_t address)> &&user_read_lambda)
SensorValueType value_type
ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count)
ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type)
ModbusFunctionCode modbus_register_write_function(ModbusRegisterType reg_type)
bool value_type_is_float(SensorValueType v)
bool coil_from_vector(int coil, const std::vector< uint8_t > &data)
Extract coil data from modbus response buffer Responses for coil are packed into bytes .
std::vector< uint16_t > float_to_payload(float value, SensorValueType value_type)
T get_data(const std::vector< uint8_t > &data, size_t buffer_offset)
Extract data from modbus response buffer.
uint64_t qword_from_hex_str(const std::string &value, uint8_t pos)
Get a qword from a hex string.
N mask_and_shift_by_rightbit(N data, uint32_t mask)
Extract bits from value and shift right according to the bitmask if the bitmask is 0x00F0 we want the...
uint32_t dword_from_hex_str(const std::string &value, uint8_t pos)
Get a dword from a hex string.
uint8_t byte_from_hex_str(const std::string &value, uint8_t pos)
Get a byte from a hex string byte_from_hex_str("1122", 1) returns uint_8 value 0x22 == 34 byte_from_h...
uint16_t word_from_hex_str(const std::string &value, uint8_t pos)
Get a word from a hex string.
int64_t payload_to_number(const std::vector< uint8_t > &data, SensorValueType sensor_value_type, uint8_t offset, uint32_t bitmask)
Convert vector<uint8_t> response payload to number.
void number_to_payload(std::vector< uint16_t > &data, int64_t value, SensorValueType value_type)
Convert float value to vector<uint16_t> suitable for sending.
ESPDEPRECATED("Use modbus::helpers::value_type_is_float() instead. Removed in 2026.10.0", "2026.4.0") inline bool value_type_is_float(SensorValueType v)
std::set< SensorItem *, SensorItemsComparator > SensorSet
float payload_to_float(const std::vector< uint8_t > &data, const SensorItem &item)
Convert vector<uint8_t> response payload to float.
const std::vector< uint8_t > & data
Providing packet encoding functions for exchanging data with a remote host.
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.
ModbusRegisterType register_type
uint16_t skip_updates_counter
uint16_t register_last_address