Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Modbus Controller] Added on_online and on_offline automation #7417

Merged
merged 10 commits into from
Nov 12, 2024
32 changes: 31 additions & 1 deletion esphome/components/modbus_controller/__init__.py
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@
CONF_MODBUS_CONTROLLER_ID,
CONF_OFFLINE_SKIP_UPDATES,
CONF_ON_COMMAND_SENT,
CONF_ON_ONLINE,
CONF_ON_OFFLINE,
CONF_REGISTER_COUNT,
CONF_REGISTER_TYPE,
CONF_RESPONSE_SIZE,
@@ -114,6 +116,14 @@
"ModbusCommandSentTrigger", automation.Trigger.template(cg.int_, cg.int_)
)

ModbusOnlineTrigger = modbus_controller_ns.class_(
"ModbusOnlineTrigger", automation.Trigger.template(cg.int_, cg.int_)
)

ModbusOfflineTrigger = modbus_controller_ns.class_(
"ModbusOfflineTrigger", automation.Trigger.template(cg.int_, cg.int_)
)

_LOGGER = logging.getLogger(__name__)

ModbusServerRegisterSchema = cv.Schema(
@@ -146,6 +156,16 @@
),
}
),
cv.Optional(CONF_ON_ONLINE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ModbusOnlineTrigger),
}
),
cv.Optional(CONF_ON_OFFLINE): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ModbusOnlineTrigger),
}
),
}
)
.extend(cv.polling_component_schema("60s"))
@@ -284,7 +304,17 @@ async def to_code(config):
for conf in config.get(CONF_ON_COMMAND_SENT, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(
trigger, [(int, "function_code"), (int, "address")], conf
trigger, [(cg.int_, "function_code"), (cg.int_, "address")], conf
)
for conf in config.get(CONF_ON_ONLINE, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(
trigger, [(cg.int_, "function_code"), (cg.int_, "address")], conf
)
for conf in config.get(CONF_ON_OFFLINE, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(
trigger, [(cg.int_, "function_code"), (cg.int_, "address")], conf
)


16 changes: 16 additions & 0 deletions esphome/components/modbus_controller/automation.h
Original file line number Diff line number Diff line change
@@ -15,5 +15,21 @@ class ModbusCommandSentTrigger : public Trigger<int, int> {
}
};

class ModbusOnlineTrigger : public Trigger<int, int> {
public:
ModbusOnlineTrigger(ModbusController *a_modbuscontroller) {
a_modbuscontroller->add_on_online_callback(
[this](int function_code, int address) { this->trigger(function_code, address); });
}
};

class ModbusOfflineTrigger : public Trigger<int, int> {
public:
ModbusOfflineTrigger(ModbusController *a_modbuscontroller) {
a_modbuscontroller->add_on_offline_callback(
[this](int function_code, int address) { this->trigger(function_code, address); });
}
};

} // namespace modbus_controller
} // namespace esphome
2 changes: 2 additions & 0 deletions esphome/components/modbus_controller/const.py
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@
CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id"
CONF_MODBUS_FUNCTIONCODE = "modbus_functioncode"
CONF_ON_COMMAND_SENT = "on_command_sent"
CONF_ON_ONLINE = "on_online"
CONF_ON_OFFLINE = "on_offline"
CONF_RAW_ENCODE = "raw_encode"
CONF_REGISTER_COUNT = "register_count"
CONF_REGISTER_TYPE = "register_type"
16 changes: 14 additions & 2 deletions esphome/components/modbus_controller/modbus_controller.cpp
Original file line number Diff line number Diff line change
@@ -32,8 +32,10 @@ bool ModbusController::send_next_command_() {
r.skip_updates_counter = this->offline_skip_updates_;
}
}

this->module_offline_ = true;
this->offline_callback_.call((int) command->function_code, command->register_address);
}
this->module_offline_ = true;
ESP_LOGD(TAG, "Modbus command to device=%d register=0x%02X no response received - removed from send queue",
this->address_, command->register_address);
this->command_queue_.pop_front();
@@ -68,8 +70,10 @@ void ModbusController::on_modbus_data(const std::vector<uint8_t> &data) {
r.skip_updates_counter = 0;
}
}
// Restore module online state
this->module_offline_ = false;
this->online_callback_.call((int) current_command->function_code, current_command->register_address);
}
this->module_offline_ = false;

// Move the commandItem to the response queue
current_command->payload = data;
@@ -670,5 +674,13 @@ void ModbusController::add_on_command_sent_callback(std::function<void(int, int)
this->command_sent_callback_.add(std::move(callback));
}

void ModbusController::add_on_online_callback(std::function<void(int, int)> &&callback) {
this->online_callback_.add(std::move(callback));
}

void ModbusController::add_on_offline_callback(std::function<void(int, int)> &&callback) {
this->offline_callback_.add(std::move(callback));
}

} // namespace modbus_controller
} // namespace esphome
9 changes: 9 additions & 0 deletions esphome/components/modbus_controller/modbus_controller.h
Original file line number Diff line number Diff line change
@@ -468,6 +468,10 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
bool get_module_offline() { return module_offline_; }
/// Set callback for commands
void add_on_command_sent_callback(std::function<void(int, int)> &&callback);
/// Set callback for online changes
void add_on_online_callback(std::function<void(int, int)> &&callback);
/// Set callback for offline changes
void add_on_offline_callback(std::function<void(int, int)> &&callback);
/// called by esphome generated code to set the max_cmd_retries.
void set_max_cmd_retries(uint8_t max_cmd_retries) { this->max_cmd_retries_ = max_cmd_retries; }
/// get how many times a command will be (re)sent if no response is received
@@ -508,7 +512,12 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
uint16_t offline_skip_updates_;
/// How many times we will retry a command if we get no response
uint8_t max_cmd_retries_{4};
/// Command sent callback
CallbackManager<void(int, int)> command_sent_callback_{};
/// Server online callback
CallbackManager<void(int, int)> online_callback_{};
/// Server offline callback
CallbackManager<void(int, int)> offline_callback_{};
};

/** Convert vector<uint8_t> response payload to float.
3 changes: 3 additions & 0 deletions tests/components/modbus_controller/test.esp32-ard.yaml
Original file line number Diff line number Diff line change
@@ -21,6 +21,9 @@ modbus_controller:
address: 0x2
modbus_id: mod_bus1
allow_duplicate_commands: false
on_online:
then:
logger.log: "Module Online"
- id: modbus_controller2
address: 0x2
modbus_id: mod_bus2
3 changes: 3 additions & 0 deletions tests/components/modbus_controller/test.esp32-idf.yaml
Original file line number Diff line number Diff line change
@@ -13,4 +13,7 @@ modbus_controller:
address: 0x2
modbus_id: mod_bus1
allow_duplicate_commands: true
on_offline:
then:
logger.log: "Module Offline"
max_cmd_retries: 10