diff --git a/esphome/components/modbus_controller/number/__init__.py b/esphome/components/modbus_controller/number/__init__.py index 56ec734315..37a39ff334 100644 --- a/esphome/components/modbus_controller/number/__init__.py +++ b/esphome/components/modbus_controller/number/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( ) from .. import ( + MODBUS_WRITE_REGISTER_TYPE, add_modbus_base_properties, modbus_controller_ns, modbus_calc_properties, @@ -24,6 +25,7 @@ from ..const import ( CONF_CUSTOM_COMMAND, CONF_FORCE_NEW_RANGE, CONF_MODBUS_CONTROLLER_ID, + CONF_REGISTER_TYPE, CONF_SKIP_UPDATES, CONF_USE_WRITE_MULTIPLE, CONF_VALUE_TYPE, @@ -61,6 +63,9 @@ CONFIG_SCHEMA = cv.All( number.NUMBER_SCHEMA.extend(ModbusItemBaseSchema).extend( { cv.GenerateID(): cv.declare_id(ModbusNumber), + cv.Optional(CONF_REGISTER_TYPE, default="holding"): cv.enum( + MODBUS_WRITE_REGISTER_TYPE + ), cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE), cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda, # 24 bits are the maximum value for fp32 before precison is lost @@ -81,6 +86,7 @@ async def to_code(config): byte_offset, reg_count = modbus_calc_properties(config) var = cg.new_Pvariable( config[CONF_ID], + config[CONF_REGISTER_TYPE], config[CONF_ADDRESS], byte_offset, config[CONF_BITMASK], diff --git a/esphome/components/modbus_controller/number/modbus_number.h b/esphome/components/modbus_controller/number/modbus_number.h index 0c525d9c89..aa5c8d1500 100644 --- a/esphome/components/modbus_controller/number/modbus_number.h +++ b/esphome/components/modbus_controller/number/modbus_number.h @@ -11,9 +11,9 @@ using value_to_data_t = std::function(float); class ModbusNumber : public number::Number, public Component, public SensorItem { public: - ModbusNumber(uint16_t start_address, uint8_t offset, uint32_t bitmask, SensorValueType value_type, int register_count, - uint8_t skip_updates, bool force_new_range) { - this->register_type = ModbusRegisterType::HOLDING; + ModbusNumber(ModbusRegisterType register_type, uint16_t start_address, uint8_t offset, uint32_t bitmask, + SensorValueType value_type, int register_count, uint8_t skip_updates, bool force_new_range) { + this->register_type = register_type; this->start_address = start_address; this->offset = offset; this->bitmask = bitmask; diff --git a/esphome/components/modbus_controller/select/__init__.py b/esphome/components/modbus_controller/select/__init__.py index 7d03064fa5..6f194ef2a3 100644 --- a/esphome/components/modbus_controller/select/__init__.py +++ b/esphome/components/modbus_controller/select/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import select -from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA +from esphome.const import CONF_ADDRESS, CONF_ID, CONF_LAMBDA, CONF_OPTIMISTIC from esphome.jsonschema import jschema_composite from .. import ( @@ -79,6 +79,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_FORCE_NEW_RANGE, default=False): cv.boolean, cv.Required(CONF_OPTIONSMAP): ensure_option_map(), cv.Optional(CONF_USE_WRITE_MULTIPLE, default=False): cv.boolean, + cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean, cv.Optional(CONF_LAMBDA): cv.returning_lambda, cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda, }, @@ -112,6 +113,7 @@ async def to_code(config): cg.add(parent.add_sensor_item(var)) cg.add(var.set_parent(parent)) cg.add(var.set_use_write_mutiple(config[CONF_USE_WRITE_MULTIPLE])) + cg.add(var.set_optimistic(config[CONF_OPTIMISTIC])) if CONF_LAMBDA in config: template_ = await cg.process_lambda( diff --git a/esphome/components/modbus_controller/select/modbus_select.cpp b/esphome/components/modbus_controller/select/modbus_select.cpp index 2c6b32f545..33cef39a18 100644 --- a/esphome/components/modbus_controller/select/modbus_select.cpp +++ b/esphome/components/modbus_controller/select/modbus_select.cpp @@ -80,6 +80,9 @@ void ModbusSelect::control(const std::string &value) { } parent_->queue_command(write_cmd); + + if (this->optimistic_) + this->publish_state(value); } } // namespace modbus_controller diff --git a/esphome/components/modbus_controller/select/modbus_select.h b/esphome/components/modbus_controller/select/modbus_select.h index 0875194768..2a31dfd7cc 100644 --- a/esphome/components/modbus_controller/select/modbus_select.h +++ b/esphome/components/modbus_controller/select/modbus_select.h @@ -32,6 +32,7 @@ class ModbusSelect : public Component, public select::Select, public SensorItem void set_parent(ModbusController *const parent) { this->parent_ = parent; } void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; } + void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; } void set_template(transform_func_t &&f) { this->transform_func_ = f; } void set_write_template(write_transform_func_t &&f) { this->write_transform_func_ = f; } @@ -43,6 +44,7 @@ class ModbusSelect : public Component, public select::Select, public SensorItem std::vector mapping_; ModbusController *parent_; bool use_write_multiple_{false}; + bool optimistic_{false}; optional transform_func_; optional write_transform_func_; }; diff --git a/esphome/const.py b/esphome/const.py index 26444baffd..579cefd507 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2022.3.0b1" +__version__ = "2022.3.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index a346cd7e0b..b03d890ad8 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -213,6 +213,25 @@ std::string format_hex_pretty(const uint8_t *data, size_t length) { } std::string format_hex_pretty(const std::vector &data) { return format_hex_pretty(data.data(), data.size()); } +std::string format_hex_pretty(const uint16_t *data, size_t length) { + if (length == 0) + return ""; + std::string ret; + ret.resize(5 * length - 1); + for (size_t i = 0; i < length; i++) { + ret[5 * i] = format_hex_pretty_char((data[i] & 0xF000) >> 12); + ret[5 * i + 1] = format_hex_pretty_char((data[i] & 0x0F00) >> 8); + ret[5 * i + 2] = format_hex_pretty_char((data[i] & 0x00F0) >> 4); + ret[5 * i + 3] = format_hex_pretty_char(data[i] & 0x000F); + if (i != length - 1) + ret[5 * i + 2] = '.'; + } + if (length > 4) + return ret + " (" + to_string(length) + ")"; + return ret; +} +std::string format_hex_pretty(const std::vector &data) { return format_hex_pretty(data.data(), data.size()); } + ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) { if (on == nullptr && strcasecmp(str, "on") == 0) return PARSE_ON; diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index e0763d2c71..074bea6fd1 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -386,8 +386,12 @@ template::value, int> = 0> std::stri /// Format the byte array \p data of length \p len in pretty-printed, human-readable hex. std::string format_hex_pretty(const uint8_t *data, size_t length); +/// Format the word array \p data of length \p len in pretty-printed, human-readable hex. +std::string format_hex_pretty(const uint16_t *data, size_t length); /// Format the vector \p data in pretty-printed, human-readable hex. std::string format_hex_pretty(const std::vector &data); +/// Format the vector \p data in pretty-printed, human-readable hex. +std::string format_hex_pretty(const std::vector &data); /// Format an unsigned integer in pretty-printed, human-readable hex, starting with the most significant byte. template::value, int> = 0> std::string format_hex_pretty(T val) { val = convert_big_endian(val);