14 namespace modbus_controller {
16 class ModbusController;
102 inline uint8_t
c_to_hex(
char c) {
return (c >=
'A') ? (c >=
'a') ? (c -
'a' + 10) : (c -
'A' + 10) : (c -
'0'); }
113 if (value.length() < pos * 2 + 1)
155 template<
typename T> T
get_data(
const std::vector<uint8_t> &data,
size_t buffer_offset) {
156 if (
sizeof(T) ==
sizeof(uint8_t)) {
157 return T(data[buffer_offset]);
159 if (
sizeof(T) ==
sizeof(uint16_t)) {
160 return T((uint16_t(data[buffer_offset + 0]) << 8) | (uint16_t(data[buffer_offset + 1]) << 0));
163 if (
sizeof(T) ==
sizeof(uint32_t)) {
164 return get_data<uint16_t>(data, buffer_offset) << 16 | get_data<uint16_t>(data, (buffer_offset + 2));
167 if (
sizeof(T) ==
sizeof(uint64_t)) {
168 return static_cast<uint64_t
>(get_data<uint32_t>(data, buffer_offset)) << 32 |
169 (
static_cast<uint64_t
>(get_data<uint32_t>(data, buffer_offset + 4)));
182 auto data_byte = coil / 8;
183 return (data[data_byte] & (1 << (coil % 8))) > 0;
197 auto result = (mask & data);
198 if (result == 0 || mask == 0xFFFFFFFF) {
201 for (
size_t pos = 0; pos <
sizeof(N) << 3; pos++) {
202 if ((mask & (1 << pos)) != 0)
203 return result >> pos;
230 virtual void parse_and_publish(
const std::vector<uint8_t> &data) = 0;
237 return response_bytes > 0 ? response_bytes : register_count * 2;
248 uint8_t response_bytes{0};
250 std::vector<uint8_t> custom_data{};
251 bool force_new_range{
false};
285 using SensorSet = std::set<SensorItem *, SensorItemsComparator>;
298 static const size_t MAX_PAYLOAD_BYTES = 240;
299 static const uint8_t MAX_SEND_REPEATS = 5;
305 std::function<void(ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data)>
307 std::vector<uint8_t> payload = {};
311 uint8_t send_countdown{MAX_SEND_REPEATS};
324 std::function<
void(
ModbusRegisterType register_type, uint16_t start_address,
const std::vector<uint8_t> &data)>
335 uint16_t start_address, uint16_t register_count);
346 uint16_t register_count,
const std::vector<uint16_t> &values);
374 const std::vector<bool> &values);
384 std::function<
void(
ModbusRegisterType register_type, uint16_t start_address,
const std::vector<uint8_t> &data)>
385 &&handler =
nullptr);
396 std::function<
void(
ModbusRegisterType register_type, uint16_t start_address,
const std::vector<uint8_t> &data)>
397 &&handler =
nullptr);
412 void dump_config()
override;
413 void loop()
override;
414 void setup()
override;
415 void update()
override;
422 void on_modbus_data(
const std::vector<uint8_t> &data)
override;
424 void on_modbus_error(uint8_t function_code, uint8_t exception_code)
override;
426 void on_register_data(
ModbusRegisterType register_type, uint16_t start_address,
const std::vector<uint8_t> &data);
429 void on_write_register_response(
ModbusRegisterType register_type, uint16_t start_address,
430 const std::vector<uint8_t> &data);
442 size_t create_register_ranges_();
450 bool send_next_command_();
452 void dump_sensors_();
481 float_value =
bit_cast<
float>(
static_cast<uint32_t
>(number));
483 float_value =
static_cast<float>(number);
495 val = llroundf(value);
498 std::vector<uint16_t> data;
SensorValueType sensor_value_type
bool operator()(const SensorItem *lhs, const SensorItem *rhs) const
uint16_t word_from_hex_str(const std::string &value, uint8_t pos)
Get a word from a hex string.
bool module_offline_
if module didn't respond the last command
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...
ModbusRegisterType register_type
std::vector< uint16_t > float_to_payload(float value, SensorValueType value_type)
virtual size_t get_register_size() const
uint16_t command_throttle_
min time in ms between sending modbus commands
This class simplifies creating components that periodically check a state.
T get_data(const std::vector< uint8_t > &data, size_t buffer_offset)
Extract data from modbus response buffer.
uint32_t last_command_timestamp_
when was the last send operation
ModbusRegisterType register_type
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 ...
void set_register_size(uint8_t register_size)
SensorSet sensorset_
Collection of all sensors for this component.
uint64_t qword_from_hex_str(const std::string &value, uint8_t pos)
Get a qword from a hex string.
void set_offline_skip_updates(uint16_t offline_skip_updates)
called by esphome generated code to set the offline_skip_updates
uint32_t dword_from_hex_str(const std::string &value, uint8_t pos)
Get a dword from a hex string.
float payload_to_float(const std::vector< uint8_t > &data, const SensorItem &item)
Convert vector<uint8_t> response payload to float.
size_t get_command_queue_length()
get the number of queued modbus commands (should be mostly empty)
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.
uint8_t byte_from_hex_str(const std::string &value, uint8_t pos)
Get a byte from a hex string hex_byte_from_str("1122",1) returns uint_8 value 0x22 == 34 hex_byte_fro...
void add_sensor_item(SensorItem *item)
Registers a sensor with the controller. Called by esphomes code generator.
uint16_t skip_updates_counter
void set_command_throttle(uint16_t command_throttle)
called by esphome generated code to set the command_throttle period
std::list< std::unique_ptr< ModbusCommandItem > > command_queue_
Hold the pending requests to be sent.
ModbusFunctionCode modbus_register_write_function(ModbusRegisterType reg_type)
ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type)
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.
std::vector< RegisterRange > register_ranges_
Continuous range of modbus registers.
bool get_module_offline()
get if the module is offline, didn't respond the last command
To bit_cast(const From &src)
Convert data between types, without aliasing issues or undefined behaviour.
void set_custom_data(const std::vector< uint8_t > &data)
Implementation of SPI Controller mode.
uint16_t offline_skip_updates_
how many updates to skip if module is offline
ModbusFunctionCode function_code
std::set< SensorItem *, SensorItemsComparator > SensorSet
std::queue< std::unique_ptr< ModbusCommandItem > > incoming_queue_
modbus response data waiting to get processed
ModbusRegisterType register_type
ModbusController * modbusdevice
uint16_t register_address