mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 00:48:19 +01:00
Modbus_controller: Add custom command. (#2680)
This commit is contained in:
parent
e7827a6997
commit
17a37b1de9
13 changed files with 315 additions and 261 deletions
|
@ -1,10 +1,20 @@
|
|||
import binascii
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import modbus
|
||||
from esphome.const import CONF_ID, CONF_ADDRESS
|
||||
from esphome.const import CONF_ADDRESS, CONF_ID, CONF_NAME, CONF_LAMBDA, CONF_OFFSET
|
||||
from esphome.cpp_helpers import logging
|
||||
from .const import (
|
||||
CONF_BITMASK,
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_COMMAND_THROTTLE,
|
||||
CONF_CUSTOM_COMMAND,
|
||||
CONF_FORCE_NEW_RANGE,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_COUNT,
|
||||
CONF_REGISTER_TYPE,
|
||||
CONF_SKIP_UPDATES,
|
||||
CONF_VALUE_TYPE,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@martgras"]
|
||||
|
@ -37,6 +47,7 @@ MODBUS_FUNCTION_CODE = {
|
|||
ModbusRegisterType_ns = modbus_controller_ns.namespace("ModbusRegisterType")
|
||||
ModbusRegisterType = ModbusRegisterType_ns.enum("ModbusRegisterType")
|
||||
MODBUS_REGISTER_TYPE = {
|
||||
"custom": ModbusRegisterType.CUSTOM,
|
||||
"coil": ModbusRegisterType.COIL,
|
||||
"discrete_input": ModbusRegisterType.DISCRETE_INPUT,
|
||||
"holding": ModbusRegisterType.HOLDING,
|
||||
|
@ -95,6 +106,96 @@ CONFIG_SCHEMA = cv.All(
|
|||
)
|
||||
|
||||
|
||||
ModbusItemBaseSchema = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.Optional(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Optional(CONF_CUSTOM_COMMAND): cv.ensure_list(cv.hex_uint8_t),
|
||||
cv.Exclusive(
|
||||
CONF_OFFSET,
|
||||
"offset",
|
||||
f"{CONF_OFFSET} and {CONF_BYTE_OFFSET} can't be used together",
|
||||
): cv.positive_int,
|
||||
cv.Exclusive(
|
||||
CONF_BYTE_OFFSET,
|
||||
"offset",
|
||||
f"{CONF_OFFSET} and {CONF_BYTE_OFFSET} can't be used together",
|
||||
): cv.positive_int,
|
||||
cv.Optional(CONF_BITMASK, default=0xFFFFFFFF): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def validate_modbus_register(config):
|
||||
if CONF_CUSTOM_COMMAND not in config and CONF_ADDRESS not in config:
|
||||
raise cv.Invalid(
|
||||
f" {CONF_ADDRESS} is a required property if '{CONF_CUSTOM_COMMAND}:' isn't used"
|
||||
)
|
||||
if CONF_CUSTOM_COMMAND in config and CONF_REGISTER_TYPE in config:
|
||||
raise cv.Invalid(
|
||||
f"can't use '{CONF_REGISTER_TYPE}:' together with '{CONF_CUSTOM_COMMAND}:'",
|
||||
)
|
||||
|
||||
if CONF_CUSTOM_COMMAND not in config and CONF_REGISTER_TYPE not in config:
|
||||
raise cv.Invalid(
|
||||
f" {CONF_REGISTER_TYPE} is a required property if '{CONF_CUSTOM_COMMAND}:' isn't used"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def modbus_calc_properties(config):
|
||||
byte_offset = 0
|
||||
reg_count = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
if CONF_REGISTER_COUNT in config:
|
||||
reg_count = config[CONF_REGISTER_COUNT]
|
||||
if CONF_VALUE_TYPE in config:
|
||||
value_type = config[CONF_VALUE_TYPE]
|
||||
if reg_count == 0:
|
||||
reg_count = TYPE_REGISTER_MAP[value_type]
|
||||
if CONF_CUSTOM_COMMAND in config:
|
||||
if CONF_ADDRESS not in config:
|
||||
# generate a unique modbus address using the hash of the name
|
||||
# CONF_NAME set even if only CONF_ID is used.
|
||||
# a modbus register address is required to add the item to sensormap
|
||||
value = config[CONF_NAME]
|
||||
if isinstance(value, str):
|
||||
value = value.encode()
|
||||
config[CONF_ADDRESS] = binascii.crc_hqx(value, 0)
|
||||
config[CONF_REGISTER_TYPE] = ModbusRegisterType.CUSTOM
|
||||
config[CONF_FORCE_NEW_RANGE] = True
|
||||
return byte_offset, reg_count
|
||||
|
||||
|
||||
async def add_modbus_base_properties(
|
||||
var, config, sensor_type, lamdba_param_type=cg.float_, lamdba_return_type=float
|
||||
):
|
||||
if CONF_CUSTOM_COMMAND in config:
|
||||
cg.add(var.set_custom_data(config[CONF_CUSTOM_COMMAND]))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA],
|
||||
[
|
||||
(sensor_type.operator("ptr"), "item"),
|
||||
(lamdba_param_type, "x"),
|
||||
(
|
||||
cg.std_vector.template(cg.uint8).operator("const").operator("ref"),
|
||||
"data",
|
||||
),
|
||||
],
|
||||
return_type=cg.optional.template(lamdba_return_type),
|
||||
)
|
||||
cg.add(var.set_template(template_))
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_COMMAND_THROTTLE])
|
||||
cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE]))
|
||||
|
@ -119,11 +220,3 @@ def function_code_to_register(function_code):
|
|||
"write_multiple_registers": ModbusRegisterType.HOLDING,
|
||||
}
|
||||
return FUNCTION_CODE_TYPE_MAP[function_code]
|
||||
|
||||
|
||||
def find_by_value(dict, find_value):
|
||||
for (key, value) in MODBUS_REGISTER_TYPE.items():
|
||||
print(find_value, value)
|
||||
if find_value == value:
|
||||
return key
|
||||
return "not found"
|
||||
|
|
|
@ -2,16 +2,18 @@ from esphome.components import binary_sensor
|
|||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
|
||||
from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_OFFSET
|
||||
from esphome.const import CONF_ADDRESS, CONF_ID
|
||||
from .. import (
|
||||
SensorItem,
|
||||
add_modbus_base_properties,
|
||||
modbus_controller_ns,
|
||||
ModbusController,
|
||||
modbus_calc_properties,
|
||||
validate_modbus_register,
|
||||
ModbusItemBaseSchema,
|
||||
SensorItem,
|
||||
MODBUS_REGISTER_TYPE,
|
||||
)
|
||||
from ..const import (
|
||||
CONF_BITMASK,
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_FORCE_NEW_RANGE,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_TYPE,
|
||||
|
@ -27,30 +29,20 @@ ModbusBinarySensor = modbus_controller_ns.class_(
|
|||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||
binary_sensor.BINARY_SENSOR_SCHEMA.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(ModbusItemBaseSchema)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ModbusBinarySensor),
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.Required(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Required(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Optional(CONF_OFFSET, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_BYTE_OFFSET): cv.positive_int,
|
||||
cv.Optional(CONF_BITMASK, default=0x1): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
),
|
||||
validate_modbus_register,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
byte_offset = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
byte_offset, _ = modbus_calc_properties(config)
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
config[CONF_REGISTER_TYPE],
|
||||
|
@ -65,17 +57,4 @@ async def to_code(config):
|
|||
|
||||
paren = await cg.get_variable(config[CONF_MODBUS_CONTROLLER_ID])
|
||||
cg.add(paren.add_sensor_item(var))
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA],
|
||||
[
|
||||
(ModbusBinarySensor.operator("ptr"), "item"),
|
||||
(cg.float_, "x"),
|
||||
(
|
||||
cg.std_vector.template(cg.uint8).operator("const").operator("ref"),
|
||||
"data",
|
||||
),
|
||||
],
|
||||
return_type=cg.optional.template(bool),
|
||||
)
|
||||
cg.add(var.set_template(template_))
|
||||
await add_modbus_base_properties(var, config, ModbusBinarySensor, cg.float_, bool)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONF_BITMASK = "bitmask"
|
||||
CONF_BYTE_OFFSET = "byte_offset"
|
||||
CONF_COMMAND_THROTTLE = "command_throttle"
|
||||
CONF_CUSTOM_COMMAND = "custom_command"
|
||||
CONF_FORCE_NEW_RANGE = "force_new_range"
|
||||
CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id"
|
||||
CONF_MODBUS_FUNCTIONCODE = "modbus_functioncode"
|
||||
|
|
|
@ -28,7 +28,10 @@ bool ModbusController::send_next_command_() {
|
|||
command->register_address, command->register_count);
|
||||
command->send();
|
||||
this->last_command_timestamp_ = millis();
|
||||
if (!command->on_data_func) { // No handler remove from queue directly after sending
|
||||
// remove from queue if no handler is defined or command was sent too often
|
||||
if (!command->on_data_func || command->send_countdown < 1) {
|
||||
ESP_LOGD(TAG, "Modbus command to device=%d register=0x%02X countdown=%d removed from queue after send",
|
||||
this->address_, command->register_address, command->send_countdown);
|
||||
command_queue_.pop_front();
|
||||
}
|
||||
}
|
||||
|
@ -69,24 +72,30 @@ void ModbusController::on_modbus_error(uint8_t function_code, uint8_t exception_
|
|||
}
|
||||
}
|
||||
|
||||
void ModbusController::on_register_data(ModbusRegisterType register_type, uint16_t start_address,
|
||||
const std::vector<uint8_t> &data) {
|
||||
ESP_LOGV(TAG, "data for register address : 0x%X : ", start_address);
|
||||
|
||||
std::map<uint64_t, SensorItem *>::iterator ModbusController::find_register_(ModbusRegisterType register_type,
|
||||
uint16_t start_address) {
|
||||
auto vec_it = find_if(begin(register_ranges_), end(register_ranges_), [=](RegisterRange const &r) {
|
||||
return (r.start_address == start_address && r.register_type == register_type);
|
||||
});
|
||||
|
||||
if (vec_it == register_ranges_.end()) {
|
||||
ESP_LOGE(TAG, "Handle incoming data : No matching range for sensor found - start_address : 0x%X", start_address);
|
||||
return;
|
||||
}
|
||||
auto map_it = sensormap_.find(vec_it->first_sensorkey);
|
||||
if (map_it == sensormap_.end()) {
|
||||
ESP_LOGE(TAG, "Handle incoming data : No sensor found in at start_address : 0x%X (0x%llX)", start_address,
|
||||
vec_it->first_sensorkey);
|
||||
return;
|
||||
ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address);
|
||||
} else {
|
||||
auto map_it = sensormap_.find(vec_it->first_sensorkey);
|
||||
if (map_it == sensormap_.end()) {
|
||||
ESP_LOGE(TAG, "No sensor found in at start_address : 0x%X (0x%llX)", start_address, vec_it->first_sensorkey);
|
||||
} else {
|
||||
return sensormap_.find(vec_it->first_sensorkey);
|
||||
}
|
||||
}
|
||||
// not found
|
||||
return std::end(sensormap_);
|
||||
}
|
||||
void ModbusController::on_register_data(ModbusRegisterType register_type, uint16_t start_address,
|
||||
const std::vector<uint8_t> &data) {
|
||||
ESP_LOGV(TAG, "data for register address : 0x%X : ", start_address);
|
||||
|
||||
auto map_it = find_register_(register_type, start_address);
|
||||
// loop through all sensors with the same start address
|
||||
while (map_it != sensormap_.end() && map_it->second->start_address == start_address) {
|
||||
if (map_it->second->register_type == register_type) {
|
||||
|
@ -116,9 +125,23 @@ void ModbusController::update_range_(RegisterRange &r) {
|
|||
ESP_LOGV(TAG, "Range : %X Size: %x (%d) skip: %d", r.start_address, r.register_count, (int) r.register_type,
|
||||
r.skip_updates_counter);
|
||||
if (r.skip_updates_counter == 0) {
|
||||
ModbusCommandItem command_item =
|
||||
ModbusCommandItem::create_read_command(this, r.register_type, r.start_address, r.register_count);
|
||||
queue_command(command_item);
|
||||
// if a custom command is used the user supplied custom_data is only available in the SensorItem.
|
||||
if (r.register_type == ModbusRegisterType::CUSTOM) {
|
||||
auto it = this->find_register_(r.register_type, r.start_address);
|
||||
if (it != sensormap_.end()) {
|
||||
auto command_item = ModbusCommandItem::create_custom_command(
|
||||
this, it->second->custom_data,
|
||||
[this](ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data) {
|
||||
this->on_register_data(ModbusRegisterType::CUSTOM, start_address, data);
|
||||
});
|
||||
command_item.register_address = it->second->start_address;
|
||||
command_item.register_count = it->second->register_count;
|
||||
command_item.function_code = ModbusFunctionCode::CUSTOM;
|
||||
queue_command(command_item);
|
||||
}
|
||||
} else {
|
||||
queue_command(ModbusCommandItem::create_read_command(this, r.register_type, r.start_address, r.register_count));
|
||||
}
|
||||
r.skip_updates_counter = r.skip_updates; // reset counter to config value
|
||||
} else {
|
||||
r.skip_updates_counter--;
|
||||
|
@ -422,6 +445,7 @@ bool ModbusCommandItem::send() {
|
|||
modbusdevice->send_raw(this->payload);
|
||||
}
|
||||
ESP_LOGV(TAG, "Command sent %d 0x%X %d", uint8_t(this->function_code), this->register_address, this->register_count);
|
||||
send_countdown--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -549,6 +573,9 @@ float payload_to_float(const std::vector<uint8_t> &data, SensorValueType sensor_
|
|||
ESP_LOGD(TAG, "FP32_R = 0x%08X => %f", raw_to_float.raw, raw_to_float.float_value);
|
||||
result = raw_to_float.float_value;
|
||||
} break;
|
||||
case SensorValueType::RAW:
|
||||
result = NAN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -247,18 +247,11 @@ float payload_to_float(const std::vector<uint8_t> &data, SensorValueType sensor_
|
|||
|
||||
class ModbusController;
|
||||
|
||||
struct SensorItem {
|
||||
ModbusRegisterType register_type;
|
||||
SensorValueType sensor_value_type;
|
||||
uint16_t start_address;
|
||||
uint32_t bitmask;
|
||||
uint8_t offset;
|
||||
uint8_t register_count;
|
||||
uint8_t skip_updates;
|
||||
bool force_new_range{false};
|
||||
|
||||
class SensorItem {
|
||||
public:
|
||||
virtual void parse_and_publish(const std::vector<uint8_t> &data) = 0;
|
||||
|
||||
void set_custom_data(const std::vector<uint8_t> &data) { custom_data = data; }
|
||||
uint64_t getkey() const { return calc_key(register_type, start_address, offset, bitmask); }
|
||||
size_t virtual get_register_size() const {
|
||||
if (register_type == ModbusRegisterType::COIL || register_type == ModbusRegisterType::DISCRETE_INPUT)
|
||||
|
@ -266,10 +259,22 @@ struct SensorItem {
|
|||
else
|
||||
return register_count * 2;
|
||||
}
|
||||
|
||||
ModbusRegisterType register_type;
|
||||
SensorValueType sensor_value_type;
|
||||
uint16_t start_address;
|
||||
uint32_t bitmask;
|
||||
uint8_t offset;
|
||||
uint8_t register_count;
|
||||
uint8_t skip_updates;
|
||||
std::vector<uint8_t> custom_data{};
|
||||
bool force_new_range{false};
|
||||
};
|
||||
|
||||
struct ModbusCommandItem {
|
||||
class ModbusCommandItem {
|
||||
public:
|
||||
static const size_t MAX_PAYLOAD_BYTES = 240;
|
||||
static const uint8_t MAX_SEND_REPEATS = 5;
|
||||
ModbusController *modbusdevice;
|
||||
uint16_t register_address;
|
||||
uint16_t register_count;
|
||||
|
@ -279,7 +284,9 @@ struct ModbusCommandItem {
|
|||
on_data_func;
|
||||
std::vector<uint8_t> payload = {};
|
||||
bool send();
|
||||
|
||||
// wrong commands (esp. custom commands) can block the send queue
|
||||
// limit the number of repeats
|
||||
uint8_t send_countdown{MAX_SEND_REPEATS};
|
||||
/// factory methods
|
||||
/** Create modbus read command
|
||||
* Function code 02-04
|
||||
|
@ -392,6 +399,8 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
|||
protected:
|
||||
/// parse sensormap_ and create range of sequential addresses
|
||||
size_t create_register_ranges_();
|
||||
// find register in sensormap. Returns iterator with all registers having the same start address
|
||||
std::map<uint64_t, SensorItem *>::iterator find_register_(ModbusRegisterType register_type, uint16_t start_address);
|
||||
/// submit the read command for the address range to the send queue
|
||||
void update_range_(RegisterRange &r);
|
||||
/// parse incoming modbus data
|
||||
|
|
|
@ -4,29 +4,26 @@ from esphome.components import number
|
|||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
CONF_MAX_VALUE,
|
||||
CONF_MIN_VALUE,
|
||||
CONF_MULTIPLY,
|
||||
CONF_OFFSET,
|
||||
CONF_STEP,
|
||||
)
|
||||
|
||||
from .. import (
|
||||
add_modbus_base_properties,
|
||||
modbus_controller_ns,
|
||||
ModbusController,
|
||||
SENSOR_VALUE_TYPE,
|
||||
modbus_calc_properties,
|
||||
ModbusItemBaseSchema,
|
||||
SensorItem,
|
||||
TYPE_REGISTER_MAP,
|
||||
SENSOR_VALUE_TYPE,
|
||||
)
|
||||
|
||||
|
||||
from ..const import (
|
||||
CONF_BITMASK,
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_CUSTOM_COMMAND,
|
||||
CONF_FORCE_NEW_RANGE,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_COUNT,
|
||||
CONF_SKIP_UPDATES,
|
||||
CONF_VALUE_TYPE,
|
||||
CONF_WRITE_LAMBDA,
|
||||
|
@ -51,22 +48,21 @@ def validate_min_max(config):
|
|||
return config
|
||||
|
||||
|
||||
def validate_modbus_number(config):
|
||||
if CONF_CUSTOM_COMMAND not in config and CONF_ADDRESS not in config:
|
||||
raise cv.Invalid(
|
||||
f" {CONF_ADDRESS} is a required property if '{CONF_CUSTOM_COMMAND}:' isn't used"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
number.NUMBER_SCHEMA.extend(
|
||||
number.NUMBER_SCHEMA.extend(ModbusItemBaseSchema)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ModbusNumber),
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.Required(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Optional(CONF_OFFSET, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_BYTE_OFFSET): cv.positive_int,
|
||||
cv.Optional(CONF_BITMASK, default=0xFFFFFFFF): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE),
|
||||
cv.Optional(CONF_REGISTER_COUNT, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda,
|
||||
cv.GenerateID(): cv.declare_id(ModbusNumber),
|
||||
# 24 bits are the maximum value for fp32 before precison is lost
|
||||
# 0x00FFFFFF = 16777215
|
||||
cv.Optional(CONF_MAX_VALUE, default=16777215.0): cv.float_,
|
||||
|
@ -74,22 +70,15 @@ CONFIG_SCHEMA = cv.All(
|
|||
cv.Optional(CONF_STEP, default=1): cv.positive_float,
|
||||
cv.Optional(CONF_MULTIPLY, default=1.0): cv.float_,
|
||||
}
|
||||
).extend(cv.polling_component_schema("60s")),
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s")),
|
||||
validate_min_max,
|
||||
validate_modbus_number,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
byte_offset = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
value_type = config[CONF_VALUE_TYPE]
|
||||
reg_count = config[CONF_REGISTER_COUNT]
|
||||
if reg_count == 0:
|
||||
reg_count = TYPE_REGISTER_MAP[value_type]
|
||||
byte_offset, reg_count = modbus_calc_properties(config)
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
config[CONF_ADDRESS],
|
||||
|
@ -115,20 +104,7 @@ async def to_code(config):
|
|||
|
||||
cg.add(var.set_parent(parent))
|
||||
cg.add(parent.add_sensor_item(var))
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA],
|
||||
[
|
||||
(ModbusNumber.operator("ptr"), "item"),
|
||||
(cg.float_, "x"),
|
||||
(
|
||||
cg.std_vector.template(cg.uint8).operator("const").operator("ref"),
|
||||
"data",
|
||||
),
|
||||
],
|
||||
return_type=cg.optional.template(float),
|
||||
)
|
||||
cg.add(var.set_template(template_))
|
||||
await add_modbus_base_properties(var, config, ModbusNumber)
|
||||
if CONF_WRITE_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_WRITE_LAMBDA],
|
||||
|
|
|
@ -6,24 +6,21 @@ from esphome.const import (
|
|||
CONF_ADDRESS,
|
||||
CONF_ID,
|
||||
CONF_MULTIPLY,
|
||||
CONF_OFFSET,
|
||||
)
|
||||
|
||||
from .. import (
|
||||
SensorItem,
|
||||
modbus_controller_ns,
|
||||
ModbusController,
|
||||
TYPE_REGISTER_MAP,
|
||||
modbus_calc_properties,
|
||||
validate_modbus_register,
|
||||
ModbusItemBaseSchema,
|
||||
SensorItem,
|
||||
)
|
||||
|
||||
from ..const import (
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_COUNT,
|
||||
CONF_VALUE_TYPE,
|
||||
CONF_WRITE_LAMBDA,
|
||||
)
|
||||
from ..sensor import SENSOR_VALUE_TYPE
|
||||
|
||||
DEPENDENCIES = ["modbus_controller"]
|
||||
CODEOWNERS = ["@martgras"]
|
||||
|
@ -34,38 +31,24 @@ ModbusOutput = modbus_controller_ns.class_(
|
|||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
output.FLOAT_OUTPUT_SCHEMA.extend(
|
||||
output.FLOAT_OUTPUT_SCHEMA.extend(ModbusItemBaseSchema).extend(
|
||||
{
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.GenerateID(): cv.declare_id(ModbusOutput),
|
||||
cv.Required(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Optional(CONF_OFFSET, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_BYTE_OFFSET): cv.positive_int,
|
||||
cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE),
|
||||
cv.Optional(CONF_REGISTER_COUNT, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_MULTIPLY, default=1.0): cv.float_,
|
||||
}
|
||||
),
|
||||
validate_modbus_register,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
byte_offset = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
value_type = config[CONF_VALUE_TYPE]
|
||||
reg_count = config[CONF_REGISTER_COUNT]
|
||||
if reg_count == 0:
|
||||
reg_count = TYPE_REGISTER_MAP[value_type]
|
||||
byte_offset, reg_count = modbus_calc_properties(config)
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
config[CONF_ADDRESS],
|
||||
byte_offset,
|
||||
value_type,
|
||||
config[CONF_VALUE_TYPE],
|
||||
reg_count,
|
||||
)
|
||||
await output.register_output(var, config)
|
||||
|
|
|
@ -2,18 +2,19 @@ from esphome.components import sensor
|
|||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
|
||||
from esphome.const import CONF_ID, CONF_ADDRESS, CONF_LAMBDA, CONF_OFFSET
|
||||
from esphome.const import CONF_ID, CONF_ADDRESS
|
||||
from .. import (
|
||||
SensorItem,
|
||||
add_modbus_base_properties,
|
||||
modbus_controller_ns,
|
||||
ModbusController,
|
||||
modbus_calc_properties,
|
||||
validate_modbus_register,
|
||||
ModbusItemBaseSchema,
|
||||
SensorItem,
|
||||
MODBUS_REGISTER_TYPE,
|
||||
SENSOR_VALUE_TYPE,
|
||||
TYPE_REGISTER_MAP,
|
||||
)
|
||||
from ..const import (
|
||||
CONF_BITMASK,
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_FORCE_NEW_RANGE,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_COUNT,
|
||||
|
@ -31,43 +32,30 @@ ModbusSensor = modbus_controller_ns.class_(
|
|||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
sensor.SENSOR_SCHEMA.extend(
|
||||
sensor.SENSOR_SCHEMA.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(ModbusItemBaseSchema)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ModbusSensor),
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.Required(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Required(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Optional(CONF_OFFSET, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_BYTE_OFFSET): cv.positive_int,
|
||||
cv.Optional(CONF_BITMASK, default=0xFFFFFFFF): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE),
|
||||
cv.Optional(CONF_REGISTER_COUNT, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
),
|
||||
validate_modbus_register,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
byte_offset = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
byte_offset, reg_count = modbus_calc_properties(config)
|
||||
value_type = config[CONF_VALUE_TYPE]
|
||||
reg_count = config[CONF_REGISTER_COUNT]
|
||||
if reg_count == 0:
|
||||
reg_count = TYPE_REGISTER_MAP[value_type]
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
config[CONF_REGISTER_TYPE],
|
||||
config[CONF_ADDRESS],
|
||||
byte_offset,
|
||||
config[CONF_BITMASK],
|
||||
config[CONF_VALUE_TYPE],
|
||||
value_type,
|
||||
reg_count,
|
||||
config[CONF_SKIP_UPDATES],
|
||||
config[CONF_FORCE_NEW_RANGE],
|
||||
|
@ -77,17 +65,4 @@ async def to_code(config):
|
|||
|
||||
paren = await cg.get_variable(config[CONF_MODBUS_CONTROLLER_ID])
|
||||
cg.add(paren.add_sensor_item(var))
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA],
|
||||
[
|
||||
(ModbusSensor.operator("ptr"), "item"),
|
||||
(cg.float_, "x"),
|
||||
(
|
||||
cg.std_vector.template(cg.uint8).operator("const").operator("ref"),
|
||||
"data",
|
||||
),
|
||||
],
|
||||
return_type=cg.optional.template(float),
|
||||
)
|
||||
cg.add(var.set_template(template_))
|
||||
await add_modbus_base_properties(var, config, ModbusSensor)
|
||||
|
|
|
@ -25,6 +25,7 @@ class ModbusSensor : public Component, public sensor::Sensor, public SensorItem
|
|||
void parse_and_publish(const std::vector<uint8_t> &data) override;
|
||||
void dump_config() override;
|
||||
using transform_func_t = std::function<optional<float>(ModbusSensor *, float, const std::vector<uint8_t> &)>;
|
||||
|
||||
void set_template(transform_func_t &&f) { this->transform_func_ = f; }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -3,21 +3,25 @@ import esphome.config_validation as cv
|
|||
import esphome.codegen as cg
|
||||
|
||||
|
||||
from esphome.const import CONF_ID, CONF_ADDRESS, CONF_LAMBDA, CONF_OFFSET
|
||||
from esphome.const import CONF_ID, CONF_ADDRESS
|
||||
from .. import (
|
||||
MODBUS_REGISTER_TYPE,
|
||||
SensorItem,
|
||||
add_modbus_base_properties,
|
||||
modbus_controller_ns,
|
||||
ModbusController,
|
||||
modbus_calc_properties,
|
||||
validate_modbus_register,
|
||||
ModbusItemBaseSchema,
|
||||
SensorItem,
|
||||
MODBUS_REGISTER_TYPE,
|
||||
)
|
||||
from ..const import (
|
||||
CONF_BITMASK,
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_FORCE_NEW_RANGE,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_TYPE,
|
||||
CONF_WRITE_LAMBDA,
|
||||
)
|
||||
|
||||
CONF_USE_WRITE_MULTIPLE = "use_write_multiple"
|
||||
DEPENDENCIES = ["modbus_controller"]
|
||||
CODEOWNERS = ["@martgras"]
|
||||
|
||||
|
@ -26,31 +30,23 @@ ModbusSwitch = modbus_controller_ns.class_(
|
|||
"ModbusSwitch", cg.Component, switch.Switch, SensorItem
|
||||
)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
switch.SWITCH_SCHEMA.extend(
|
||||
switch.SWITCH_SCHEMA.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(ModbusItemBaseSchema)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ModbusSwitch),
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.Required(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Required(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Optional(CONF_OFFSET, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_BYTE_OFFSET): cv.positive_int,
|
||||
cv.Optional(CONF_BITMASK, default=0x1): cv.hex_uint32_t,
|
||||
cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
cv.Optional(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Optional(CONF_USE_WRITE_MULTIPLE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
),
|
||||
validate_modbus_register,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
byte_offset = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
byte_offset, _ = modbus_calc_properties(config)
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
config[CONF_REGISTER_TYPE],
|
||||
|
@ -63,19 +59,18 @@ async def to_code(config):
|
|||
await switch.register_switch(var, config)
|
||||
|
||||
paren = await cg.get_variable(config[CONF_MODBUS_CONTROLLER_ID])
|
||||
cg.add(paren.add_sensor_item(var))
|
||||
cg.add(var.set_parent(paren))
|
||||
if CONF_LAMBDA in config:
|
||||
publish_template_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA],
|
||||
cg.add(var.set_use_write_mutiple(config[CONF_USE_WRITE_MULTIPLE]))
|
||||
cg.add(paren.add_sensor_item(var))
|
||||
if CONF_WRITE_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_WRITE_LAMBDA],
|
||||
[
|
||||
(ModbusSwitch.operator("ptr"), "item"),
|
||||
(bool, "x"),
|
||||
(
|
||||
cg.std_vector.template(cg.uint8).operator("const").operator("ref"),
|
||||
"data",
|
||||
),
|
||||
(cg.bool_, "x"),
|
||||
(cg.std_vector.template(cg.uint8).operator("ref"), "payload"),
|
||||
],
|
||||
return_type=cg.optional.template(bool),
|
||||
)
|
||||
cg.add(var.set_template(publish_template_))
|
||||
cg.add(var.set_write_template(template_))
|
||||
await add_modbus_base_properties(var, config, ModbusSwitch, bool, bool)
|
||||
|
|
|
@ -45,22 +45,50 @@ void ModbusSwitch::parse_and_publish(const std::vector<uint8_t> &data) {
|
|||
void ModbusSwitch::write_state(bool state) {
|
||||
// This will be called every time the user requests a state change.
|
||||
ModbusCommandItem cmd;
|
||||
ESP_LOGV(TAG, "write_state '%s': new value = %s type = %d address = %X offset = %x", this->get_name().c_str(),
|
||||
ONOFF(state), (int) this->register_type, this->start_address, this->offset);
|
||||
switch (this->register_type) {
|
||||
case ModbusRegisterType::COIL:
|
||||
std::vector<uint8_t> data;
|
||||
// Is there are lambda configured?
|
||||
if (this->write_transform_func_.has_value()) {
|
||||
// data is passed by reference
|
||||
// the lambda can fill the empty vector directly
|
||||
// in that case the return value is ignored
|
||||
auto val = (*this->write_transform_func_)(this, state, data);
|
||||
if (val.has_value()) {
|
||||
ESP_LOGV(TAG, "Value overwritten by lambda");
|
||||
state = val.value();
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Communication handled by lambda - exiting control");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!data.empty()) {
|
||||
ESP_LOGV(TAG, "Modbus Switch write raw: %s", hexencode(data).c_str());
|
||||
cmd = ModbusCommandItem::create_custom_command(
|
||||
this->parent_, data,
|
||||
[this, cmd](ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data) {
|
||||
this->parent_->on_write_register_response(cmd.register_type, this->start_address, data);
|
||||
});
|
||||
} else {
|
||||
ESP_LOGV(TAG, "write_state '%s': new value = %s type = %d address = %X offset = %x", this->get_name().c_str(),
|
||||
ONOFF(state), (int) this->register_type, this->start_address, this->offset);
|
||||
if (this->register_type == ModbusRegisterType::COIL) {
|
||||
// offset for coil and discrete inputs is the coil/register number not bytes
|
||||
cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
|
||||
break;
|
||||
case ModbusRegisterType::DISCRETE_INPUT:
|
||||
cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset, state);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (this->use_write_multiple_) {
|
||||
std::vector<bool> states{state};
|
||||
cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states);
|
||||
} else {
|
||||
cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
|
||||
}
|
||||
} else {
|
||||
// since offset is in bytes and a register is 16 bits we get the start by adding offset/2
|
||||
cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2,
|
||||
state ? 0xFFFF & this->bitmask : 0);
|
||||
break;
|
||||
if (this->use_write_multiple_) {
|
||||
std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
|
||||
cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2, 1,
|
||||
bool_states);
|
||||
} else {
|
||||
cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2,
|
||||
state ? 0xFFFF & this->bitmask : 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->parent_->queue_command(cmd);
|
||||
publish_state(state);
|
||||
|
|
|
@ -33,11 +33,16 @@ class ModbusSwitch : public Component, public switch_::Switch, public SensorItem
|
|||
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
||||
|
||||
using transform_func_t = std::function<optional<bool>(ModbusSwitch *, bool, const std::vector<uint8_t> &)>;
|
||||
using write_transform_func_t = std::function<optional<bool>(ModbusSwitch *, bool, std::vector<uint8_t> &)>;
|
||||
void set_template(transform_func_t &&f) { this->publish_transform_func_ = f; }
|
||||
void set_write_template(write_transform_func_t &&f) { this->write_transform_func_ = f; }
|
||||
void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; }
|
||||
|
||||
protected:
|
||||
ModbusController *parent_;
|
||||
bool use_write_multiple_;
|
||||
optional<transform_func_t> publish_transform_func_{nullopt};
|
||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||
};
|
||||
|
||||
} // namespace modbus_controller
|
||||
|
|
|
@ -3,15 +3,17 @@ import esphome.config_validation as cv
|
|||
import esphome.codegen as cg
|
||||
|
||||
|
||||
from esphome.const import CONF_ID, CONF_ADDRESS, CONF_LAMBDA, CONF_OFFSET
|
||||
from esphome.const import CONF_ADDRESS, CONF_ID
|
||||
from .. import (
|
||||
SensorItem,
|
||||
add_modbus_base_properties,
|
||||
modbus_controller_ns,
|
||||
ModbusController,
|
||||
modbus_calc_properties,
|
||||
validate_modbus_register,
|
||||
ModbusItemBaseSchema,
|
||||
SensorItem,
|
||||
MODBUS_REGISTER_TYPE,
|
||||
)
|
||||
from ..const import (
|
||||
CONF_BYTE_OFFSET,
|
||||
CONF_FORCE_NEW_RANGE,
|
||||
CONF_MODBUS_CONTROLLER_ID,
|
||||
CONF_REGISTER_COUNT,
|
||||
|
@ -38,32 +40,23 @@ RAW_ENCODING = {
|
|||
}
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
text_sensor.TEXT_SENSOR_SCHEMA.extend(
|
||||
text_sensor.TEXT_SENSOR_SCHEMA.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(ModbusItemBaseSchema)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ModbusTextSensor),
|
||||
cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController),
|
||||
cv.Required(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Required(CONF_ADDRESS): cv.positive_int,
|
||||
cv.Optional(CONF_OFFSET, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_BYTE_OFFSET): cv.positive_int,
|
||||
cv.Optional(CONF_REGISTER_TYPE): cv.enum(MODBUS_REGISTER_TYPE),
|
||||
cv.Optional(CONF_REGISTER_COUNT, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_RESPONSE_SIZE, default=2): cv.positive_int,
|
||||
cv.Optional(CONF_RAW_ENCODE, default="NONE"): cv.enum(RAW_ENCODING),
|
||||
cv.Optional(CONF_SKIP_UPDATES, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean,
|
||||
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
),
|
||||
validate_modbus_register,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
byte_offset = 0
|
||||
if CONF_OFFSET in config:
|
||||
byte_offset = config[CONF_OFFSET]
|
||||
# A CONF_BYTE_OFFSET setting overrides CONF_OFFSET
|
||||
if CONF_BYTE_OFFSET in config:
|
||||
byte_offset = config[CONF_BYTE_OFFSET]
|
||||
byte_offset, reg_count = modbus_calc_properties(config)
|
||||
response_size = config[CONF_RESPONSE_SIZE]
|
||||
reg_count = config[CONF_REGISTER_COUNT]
|
||||
if reg_count == 0:
|
||||
|
@ -85,17 +78,6 @@ async def to_code(config):
|
|||
|
||||
paren = await cg.get_variable(config[CONF_MODBUS_CONTROLLER_ID])
|
||||
cg.add(paren.add_sensor_item(var))
|
||||
if CONF_LAMBDA in config:
|
||||
template_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA],
|
||||
[
|
||||
(ModbusTextSensor.operator("ptr"), "item"),
|
||||
(cg.std_string.operator("const").operator("ref"), "x"),
|
||||
(
|
||||
cg.std_vector.template(cg.uint8).operator("const").operator("ref"),
|
||||
"data",
|
||||
),
|
||||
],
|
||||
return_type=cg.optional.template(cg.std_string),
|
||||
)
|
||||
cg.add(var.set_template(template_))
|
||||
await add_modbus_base_properties(
|
||||
var, config, ModbusTextSensor, cg.std_string, cg.std_string
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue