mirror of
https://github.com/esphome/esphome.git
synced 2026-08-22 22:26:21 +00:00
[modbus] Update client components to use ModbusClientDevice (#11987)
This commit is contained in:
@@ -65,7 +65,7 @@ constexpr size_t RTU2_TODAY_PRODUCTION = 53; // length = 2
|
||||
constexpr size_t RTU2_TOTAL_ENERGY_PRODUCTION = 55; // length = 2
|
||||
constexpr size_t RTU2_INVERTER_MODULE_TEMP = 93; // length = 1
|
||||
|
||||
class GrowattSolar final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class GrowattSolar final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
void loop() override;
|
||||
void update() override;
|
||||
|
||||
@@ -25,6 +25,7 @@ from esphome.const import (
|
||||
UNIT_VOLT,
|
||||
UNIT_WATT,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CONF_ENERGY_PRODUCTION_DAY = "energy_production_day"
|
||||
CONF_TOTAL_ENERGY_PRODUCTION = "total_energy_production"
|
||||
@@ -47,7 +48,7 @@ CODEOWNERS = ["@leeuwte"]
|
||||
|
||||
growatt_solar_ns = cg.esphome_ns.namespace("growatt_solar")
|
||||
GrowattSolar = growatt_solar_ns.class_(
|
||||
"GrowattSolar", cg.PollingComponent, modbus.ModbusDevice
|
||||
"GrowattSolar", cg.PollingComponent, modbus.ModbusClientDevice
|
||||
)
|
||||
|
||||
PHASE_SENSORS = {
|
||||
@@ -162,10 +163,17 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("growatt_solar", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
cg.add(var.set_protocol_version(config[CONF_PROTOCOL_VERSION]))
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace esphome::havells_solar {
|
||||
|
||||
class HavellsSolar final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class HavellsSolar final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
void set_voltage_sensor(uint8_t phase, sensor::Sensor *voltage_sensor) {
|
||||
this->phases_[phase].setup = true;
|
||||
|
||||
@@ -28,6 +28,7 @@ from esphome.const import (
|
||||
UNIT_VOLT_AMPS_REACTIVE,
|
||||
UNIT_WATT,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CONF_ENERGY_PRODUCTION_DAY = "energy_production_day"
|
||||
CONF_TOTAL_ENERGY_PRODUCTION = "total_energy_production"
|
||||
@@ -58,7 +59,7 @@ CODEOWNERS = ["@sourabhjaiswal"]
|
||||
|
||||
havells_solar_ns = cg.esphome_ns.namespace("havells_solar")
|
||||
HavellsSolar = havells_solar_ns.class_(
|
||||
"HavellsSolar", cg.PollingComponent, modbus.ModbusDevice
|
||||
"HavellsSolar", cg.PollingComponent, modbus.ModbusClientDevice
|
||||
)
|
||||
|
||||
PHASE_SENSORS = {
|
||||
@@ -216,10 +217,17 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("havells_solar", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
if CONF_FREQUENCY in config:
|
||||
sens = await sensor.new_sensor(config[CONF_FREQUENCY])
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace esphome::kuntze {
|
||||
|
||||
class Kuntze final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class Kuntze final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
void set_ph_sensor(sensor::Sensor *ph_sensor) { ph_sensor_ = ph_sensor; }
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
|
||||
|
||||
@@ -15,13 +15,14 @@ from esphome.const import (
|
||||
UNIT_EMPTY,
|
||||
UNIT_PH,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CODEOWNERS = ["@ssieb"]
|
||||
|
||||
AUTO_LOAD = ["modbus"]
|
||||
|
||||
kuntze_ns = cg.esphome_ns.namespace("kuntze")
|
||||
Kuntze = kuntze_ns.class_("Kuntze", cg.PollingComponent, modbus.ModbusDevice)
|
||||
Kuntze = kuntze_ns.class_("Kuntze", cg.PollingComponent, modbus.ModbusClientDevice)
|
||||
|
||||
CONF_DIS1 = "dis1"
|
||||
CONF_DIS2 = "dis2"
|
||||
@@ -88,10 +89,17 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("kuntze", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
if CONF_PH in config:
|
||||
conf = config[CONF_PH]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Literal
|
||||
|
||||
from esphome import pins
|
||||
@@ -10,6 +11,8 @@ from esphome.const import CONF_ADDRESS, CONF_DISABLE_CRC, CONF_FLOW_CONTROL_PIN,
|
||||
from esphome.cpp_helpers import gpio_pin_expression
|
||||
import esphome.final_validate as fv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ["uart"]
|
||||
|
||||
modbus_ns = cg.esphome_ns.namespace("modbus")
|
||||
@@ -129,4 +132,9 @@ async def register_modbus_server_device(var, config):
|
||||
|
||||
|
||||
async def register_modbus_device(var, config):
|
||||
# Remove before 2026.12.0
|
||||
_LOGGER.warning(
|
||||
"'register_modbus_device' is deprecated, use 'register_modbus_client_device' "
|
||||
"instead. Will be removed in 2026.12.0"
|
||||
)
|
||||
return await register_modbus_client_device(var, config)
|
||||
|
||||
@@ -197,7 +197,9 @@ class ModbusClientDevice {
|
||||
};
|
||||
|
||||
// This is for compatibility with external components using the former class name
|
||||
using ModbusDevice = ModbusClientDevice;
|
||||
// Remove before 2026.12.0
|
||||
using ModbusDevice ESPDEPRECATED("Use ModbusClientDevice instead. Removed in 2026.12.0",
|
||||
"2026.6.0") = ModbusClientDevice;
|
||||
|
||||
// Result of a server register handler: std::nullopt means success, otherwise the Modbus exception code to return.
|
||||
using ServerResponseStatus = std::optional<ModbusExceptionCode>;
|
||||
|
||||
@@ -11,6 +11,7 @@ from esphome.components.modbus.helpers import (
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OFFSET
|
||||
from esphome.cpp_helpers import logging
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .const import (
|
||||
CONF_ALLOW_DUPLICATE_COMMANDS,
|
||||
@@ -42,7 +43,7 @@ MULTI_CONF = True
|
||||
|
||||
modbus_controller_ns = cg.esphome_ns.namespace("modbus_controller")
|
||||
ModbusController = modbus_controller_ns.class_(
|
||||
"ModbusController", cg.PollingComponent, modbus.ModbusDevice
|
||||
"ModbusController", cg.PollingComponent, modbus.ModbusClientDevice
|
||||
)
|
||||
|
||||
SensorItem = modbus_controller_ns.struct("SensorItem")
|
||||
@@ -117,7 +118,7 @@ def validate_modbus_register(config):
|
||||
return config
|
||||
|
||||
|
||||
def _final_validate(config):
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("modbus_controller", role="client")(
|
||||
config
|
||||
)
|
||||
@@ -211,7 +212,7 @@ async def to_code(config):
|
||||
async def register_modbus_device(var, config):
|
||||
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||
await cg.register_component(var, config)
|
||||
return await modbus.register_modbus_device(var, config)
|
||||
return await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
|
||||
def function_code_to_register(function_code):
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace esphome::pzemac {
|
||||
|
||||
template<typename... Ts> class ResetEnergyAction;
|
||||
|
||||
class PZEMAC final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class PZEMAC final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
||||
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
|
||||
|
||||
@@ -26,11 +26,12 @@ from esphome.const import (
|
||||
UNIT_WATT,
|
||||
UNIT_WATT_HOURS,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["modbus"]
|
||||
|
||||
pzemac_ns = cg.esphome_ns.namespace("pzemac")
|
||||
PZEMAC = pzemac_ns.class_("PZEMAC", cg.PollingComponent, modbus.ModbusDevice)
|
||||
PZEMAC = pzemac_ns.class_("PZEMAC", cg.PollingComponent, modbus.ModbusClientDevice)
|
||||
|
||||
# Actions
|
||||
ResetEnergyAction = pzemac_ns.class_("ResetEnergyAction", automation.Action)
|
||||
@@ -97,10 +98,17 @@ async def reset_energy_to_code(config, action_id, template_arg, args):
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("pzemac", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
if CONF_VOLTAGE in config:
|
||||
conf = config[CONF_VOLTAGE]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace esphome::pzemdc {
|
||||
|
||||
class PZEMDC final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class PZEMDC final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
||||
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
|
||||
|
||||
@@ -20,11 +20,12 @@ from esphome.const import (
|
||||
UNIT_VOLT,
|
||||
UNIT_WATT,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["modbus"]
|
||||
|
||||
pzemdc_ns = cg.esphome_ns.namespace("pzemdc")
|
||||
PZEMDC = pzemdc_ns.class_("PZEMDC", cg.PollingComponent, modbus.ModbusDevice)
|
||||
PZEMDC = pzemdc_ns.class_("PZEMDC", cg.PollingComponent, modbus.ModbusClientDevice)
|
||||
|
||||
# Actions
|
||||
ResetEnergyAction = pzemdc_ns.class_("ResetEnergyAction", automation.Action)
|
||||
@@ -79,10 +80,17 @@ async def reset_energy_to_code(config, action_id, template_arg, args):
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("pzemdc", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
if CONF_VOLTAGE in config:
|
||||
conf = config[CONF_VOLTAGE]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace esphome::sdm_meter {
|
||||
|
||||
class SDMMeter final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class SDMMeter final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
void set_voltage_sensor(uint8_t phase, sensor::Sensor *voltage_sensor) {
|
||||
this->phases_[phase].setup = true;
|
||||
|
||||
@@ -41,12 +41,15 @@ from esphome.const import (
|
||||
UNIT_VOLT_AMPS_REACTIVE,
|
||||
UNIT_WATT,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["modbus"]
|
||||
CODEOWNERS = ["@polyfaces", "@jesserockz"]
|
||||
|
||||
sdm_meter_ns = cg.esphome_ns.namespace("sdm_meter")
|
||||
SDMMeter = sdm_meter_ns.class_("SDMMeter", cg.PollingComponent, modbus.ModbusDevice)
|
||||
SDMMeter = sdm_meter_ns.class_(
|
||||
"SDMMeter", cg.PollingComponent, modbus.ModbusClientDevice
|
||||
)
|
||||
|
||||
PHASE_SENSORS = {
|
||||
CONF_VOLTAGE: sensor.sensor_schema(
|
||||
@@ -145,10 +148,17 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("sdm_meter", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
|
||||
if CONF_TOTAL_POWER in config:
|
||||
sens = await sensor.new_sensor(config[CONF_TOTAL_POWER])
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace esphome::selec_meter {
|
||||
public: \
|
||||
void set_##name##_sensor(sensor::Sensor *(name)) { this->name##_sensor_ = name; }
|
||||
|
||||
class SelecMeter final : public PollingComponent, public modbus::ModbusDevice {
|
||||
class SelecMeter final : public PollingComponent, public modbus::ModbusClientDevice {
|
||||
public:
|
||||
SELEC_METER_SENSOR(total_active_energy)
|
||||
SELEC_METER_SENSOR(import_active_energy)
|
||||
|
||||
@@ -32,6 +32,7 @@ from esphome.const import (
|
||||
UNIT_VOLT_AMPS_REACTIVE,
|
||||
UNIT_WATT,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["modbus"]
|
||||
CODEOWNERS = ["@sourabhjaiswal"]
|
||||
@@ -49,7 +50,7 @@ UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kVARh"
|
||||
|
||||
selec_meter_ns = cg.esphome_ns.namespace("selec_meter")
|
||||
SelecMeter = selec_meter_ns.class_(
|
||||
"SelecMeter", cg.PollingComponent, modbus.ModbusDevice
|
||||
"SelecMeter", cg.PollingComponent, modbus.ModbusClientDevice
|
||||
)
|
||||
|
||||
SENSORS = {
|
||||
@@ -163,10 +164,17 @@ CONFIG_SCHEMA = (
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config: ConfigType) -> ConfigType:
|
||||
return modbus.final_validate_modbus_device("selec_meter", role="client")(config)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await modbus.register_modbus_device(var, config)
|
||||
await modbus.register_modbus_client_device(var, config)
|
||||
for name in SENSORS:
|
||||
if name in config:
|
||||
sens = await sensor.new_sensor(config[name])
|
||||
|
||||
Reference in New Issue
Block a user