ESPHome  2022.11.4
modbus_switch.cpp
Go to the documentation of this file.
1 
2 #include "modbus_switch.h"
3 #include "esphome/core/log.h"
4 namespace esphome {
5 namespace modbus_controller {
6 
7 static const char *const TAG = "modbus_controller.switch";
8 
10  // value isn't required
11  // without it we crash on save
12  this->get_initial_state();
13 }
14 void ModbusSwitch::dump_config() { LOG_SWITCH(TAG, "Modbus Controller Switch", this); }
15 
16 void ModbusSwitch::parse_and_publish(const std::vector<uint8_t> &data) {
17  bool value = false;
18  switch (this->register_type) {
21  // offset for coil is the actual number of the coil not the byte offset
22  value = coil_from_vector(this->offset, data);
23  break;
24  default:
25  value = get_data<uint16_t>(data, this->offset) & this->bitmask;
26  break;
27  }
28 
29  // Is there a lambda registered
30  // call it with the pre converted value and the raw data array
31  if (this->publish_transform_func_) {
32  // the lambda can parse the response itself
33  auto val = (*this->publish_transform_func_)(this, value, data);
34  if (val.has_value()) {
35  ESP_LOGV(TAG, "Value overwritten by lambda");
36  value = val.value();
37  }
38  }
39 
40  ESP_LOGV(TAG, "Publish '%s': new value = %s type = %d address = %X offset = %x", this->get_name().c_str(),
41  ONOFF(value), (int) this->register_type, this->start_address, this->offset);
42  this->publish_state(value);
43 }
44 
46  // This will be called every time the user requests a state change.
48  std::vector<uint8_t> data;
49  // Is there are lambda configured?
50  if (this->write_transform_func_.has_value()) {
51  // data is passed by reference
52  // the lambda can fill the empty vector directly
53  // in that case the return value is ignored
54  auto val = (*this->write_transform_func_)(this, state, data);
55  if (val.has_value()) {
56  ESP_LOGV(TAG, "Value overwritten by lambda");
57  state = val.value();
58  } else {
59  ESP_LOGV(TAG, "Communication handled by lambda - exiting control");
60  return;
61  }
62  }
63  if (!data.empty()) {
64  ESP_LOGV(TAG, "Modbus Switch write raw: %s", format_hex_pretty(data).c_str());
66  this->parent_, data,
67  [this, cmd](ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data) {
68  this->parent_->on_write_register_response(cmd.register_type, this->start_address, data);
69  });
70  } else {
71  ESP_LOGV(TAG, "write_state '%s': new value = %s type = %d address = %X offset = %x", this->get_name().c_str(),
72  ONOFF(state), (int) this->register_type, this->start_address, this->offset);
73  if (this->register_type == ModbusRegisterType::COIL) {
74  // offset for coil and discrete inputs is the coil/register number not bytes
75  if (this->use_write_multiple_) {
76  std::vector<bool> states{state};
78  } else {
80  }
81  } else {
82  // since offset is in bytes and a register is 16 bits we get the start by adding offset/2
83  if (this->use_write_multiple_) {
84  std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
86  bool_states);
87  } else {
89  state ? 0xFFFF & this->bitmask : 0u);
90  }
91  }
92  }
93  this->parent_->queue_command(cmd);
94  publish_state(state);
95 }
96 // ModbusSwitch end
97 } // namespace modbus_controller
98 } // namespace esphome
void queue_command(const ModbusCommandItem &command)
queues a modbus command in the send queue
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
Definition: helpers.cpp:237
optional< write_transform_func_t > write_transform_func_
Definition: modbus_switch.h:44
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...
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...
const std::string & get_name() const
Definition: entity_base.cpp:11
optional< transform_func_t > publish_transform_func_
Definition: modbus_switch.h:43
bool has_value() const
Definition: optional.h:87
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 ...
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.
optional< bool > get_initial_state()
Definition: switch.cpp:24
void parse_and_publish(const std::vector< uint8_t > &data) override
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_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.
Definition: a4988.cpp:4
uint32_t val
Definition: datatypes.h:85
void publish_state(bool state)
Publish a state to the front-end from the back-end.
Definition: switch.cpp:31
bool state
The current reported state of the binary sensor.
Definition: switch.h:48
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.
stm32_cmd_t * cmd
Definition: stm32flash.h:96
void write_state(bool state) override