From f1df1966872b183cc32d92adabe21b1163ab2793 Mon Sep 17 00:00:00 2001 From: j0ta29 Date: Sat, 26 Aug 2023 18:48:36 +0000 Subject: [PATCH 01/20] added textsensor mode --- esphome/components/optolink/__init__.py | 18 +++++ esphome/components/optolink/binary_sensor.py | 15 +--- esphome/components/optolink/number.py | 12 +-- .../optolink/optolink_text_sensor.cpp | 27 ++++++- .../optolink/optolink_text_sensor.h | 10 ++- esphome/components/optolink/select.py | 12 +-- esphome/components/optolink/sensor.py | 22 +----- esphome/components/optolink/text_sensor.py | 73 +++++++++++++++---- 8 files changed, 115 insertions(+), 74 deletions(-) diff --git a/esphome/components/optolink/__init__.py b/esphome/components/optolink/__init__.py index 49630e804b..d3e879868e 100644 --- a/esphome/components/optolink/__init__.py +++ b/esphome/components/optolink/__init__.py @@ -1,14 +1,18 @@ +from esphome import core from esphome import pins import esphome.codegen as cg from esphome.components import text_sensor as ts import esphome.config_validation as cv from esphome.const import ( + CONF_ADDRESS, + CONF_DIV_RATIO, CONF_ID, CONF_LOGGER, CONF_PROTOCOL, CONF_RX_PIN, CONF_STATE, CONF_TX_PIN, + CONF_UPDATE_INTERVAL, ) from esphome.core import CORE @@ -31,6 +35,20 @@ DeviceInfoSensor = optolink_ns.class_( ) DEVICE_INFO_SENSOR_ID = "device_info_sensor_id" +CONF_OPTOLINK_ID = "optolink_id" +SENSOR_BASE_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_OPTOLINK_ID): cv.use_id(OptolinkComponent), + cv.Optional(CONF_UPDATE_INTERVAL, default="10s"): cv.All( + cv.positive_time_period_milliseconds, + cv.Range(min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800)), + ), + cv.Required(CONF_ADDRESS): cv.hex_uint32_t, + # cv.Required(CONF_BYTES): cv.one_of(1, 2, 4, int=True), + cv.Optional(CONF_DIV_RATIO, default=1): cv.one_of(1, 10, 100, 3600, int=True), + } +) + def required_on_esp32(attribute): """Validate that this option can only be specified on the given target platforms.""" diff --git a/esphome/components/optolink/binary_sensor.py b/esphome/components/optolink/binary_sensor.py index f55b9c6d16..9d1495437e 100644 --- a/esphome/components/optolink/binary_sensor.py +++ b/esphome/components/optolink/binary_sensor.py @@ -1,22 +1,13 @@ -from esphome import core import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import binary_sensor -from esphome.const import CONF_ID, CONF_ADDRESS, CONF_UPDATE_INTERVAL -from . import OptolinkComponent, optolink_ns, CONF_OPTOLINK_ID +from esphome.const import CONF_ADDRESS, CONF_ID +from . import SENSOR_BASE_SCHEMA, optolink_ns, CONF_OPTOLINK_ID OptolinkBinarySensor = optolink_ns.class_( "OptolinkBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent ) CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(OptolinkBinarySensor).extend( - { - cv.GenerateID(CONF_OPTOLINK_ID): cv.use_id(OptolinkComponent), - cv.Required(CONF_ADDRESS): cv.hex_uint32_t, - cv.Optional(CONF_UPDATE_INTERVAL, default="10s"): cv.All( - cv.positive_time_period_milliseconds, - cv.Range(min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800)), - ), - } + SENSOR_BASE_SCHEMA ) diff --git a/esphome/components/optolink/number.py b/esphome/components/optolink/number.py index 2f4802cd9b..ab9a4e8c09 100644 --- a/esphome/components/optolink/number.py +++ b/esphome/components/optolink/number.py @@ -1,4 +1,3 @@ -from esphome import core import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import number @@ -10,10 +9,9 @@ from esphome.const import ( CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_STEP, - CONF_UPDATE_INTERVAL, ) from .sensor import SENSOR_BASE_SCHEMA -from . import OptolinkComponent, optolink_ns, CONF_OPTOLINK_ID +from . import optolink_ns, CONF_OPTOLINK_ID OptolinkNumber = optolink_ns.class_( "OptolinkNumber", number.Number, cg.PollingComponent @@ -22,17 +20,11 @@ OptolinkNumber = optolink_ns.class_( CONFIG_SCHEMA = ( number.NUMBER_SCHEMA.extend( { - cv.GenerateID(CONF_OPTOLINK_ID): cv.use_id(OptolinkComponent), cv.GenerateID(): cv.declare_id(OptolinkNumber), cv.Required(CONF_MAX_VALUE): cv.float_, cv.Required(CONF_MIN_VALUE): cv.float_range(min=0.0), cv.Required(CONF_STEP): cv.float_, - cv.Optional(CONF_UPDATE_INTERVAL, default="10s"): cv.All( - cv.positive_time_period_milliseconds, - cv.Range( - min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800) - ), - ), + cv.Required(CONF_BYTES): cv.one_of(1, 2, 4, int=True), } ) .extend(cv.COMPONENT_SCHEMA) diff --git a/esphome/components/optolink/optolink_text_sensor.cpp b/esphome/components/optolink/optolink_text_sensor.cpp index 700e9578f7..f3e096684f 100644 --- a/esphome/components/optolink/optolink_text_sensor.cpp +++ b/esphome/components/optolink/optolink_text_sensor.cpp @@ -8,18 +8,37 @@ namespace esphome { namespace optolink { void OptolinkTextSensor::setup() { - if (!raw_) { - setup_datapoint_(); - } else { + if (mode_ == RAW) { datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); datapoint_->setLength(bytes_); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: ", dp.getGroup(), dp.getName()); uint8_t buffer[bytes_ + 1]; dp_value.getRaw(buffer); buffer[bytes_] = 0x0; + ESP_LOGD("OptolinkTextSensor", "Datapoint %s - %s: %s", dp.getGroup(), dp.getName(), buffer); publish_state((char *) buffer); }); + } else if (mode_ == DAY_SCHEDULE) { + datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_ + 8 * dow_, writeable_); + datapoint_->setLength(8); + datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { + uint8_t data[8]; + dp_value.getRaw(data); + ESP_LOGD("OptolinkTextSensor", "Datapoint %s - %s", dp.getGroup(), dp.getName()); + char buffer[100]; + for (int i = 0; i < 8; i++) { + if (data[i] != 0xFF) { + int hour = data[i] >> 3; + int minute = (data[i] & 0b111) * 10; + sprintf(buffer + i * 6, "%02d:%02d ", hour, minute); + } else { + sprintf(buffer + i * 6, " "); + } + } + publish_state(buffer); + }); + } else { + setup_datapoint_(); } }; diff --git a/esphome/components/optolink/optolink_text_sensor.h b/esphome/components/optolink/optolink_text_sensor.h index 950b68f1cb..fd6a64a60e 100644 --- a/esphome/components/optolink/optolink_text_sensor.h +++ b/esphome/components/optolink/optolink_text_sensor.h @@ -10,23 +10,27 @@ namespace esphome { namespace optolink { +enum TextSensorMode { MAP, RAW, DAY_SCHEDULE }; + class OptolinkTextSensor : public OptolinkSensorBase, public esphome::text_sensor::TextSensor, public esphome::PollingComponent { public: OptolinkTextSensor(Optolink *optolink) : OptolinkSensorBase(optolink) {} - void set_raw(bool raw) { raw_ = raw; } + void set_mode(TextSensorMode mode) { mode_ = mode; } + void set_day_of_week(int dow) { dow_ = dow; } protected: void setup() override; void update() override { optolink_->read_value(datapoint_); } const StringRef &get_sensor_name() override { return get_name(); } - void value_changed(float state) override { publish_state(std::to_string(state)); }; + void value_changed(float state) override { publish_state(std::to_string((uint32_t) state)); }; private: - bool raw_ = false; + TextSensorMode mode_ = MAP; + int dow_ = 0; }; } // namespace optolink diff --git a/esphome/components/optolink/select.py b/esphome/components/optolink/select.py index 5d6aa2ff85..779800efef 100644 --- a/esphome/components/optolink/select.py +++ b/esphome/components/optolink/select.py @@ -1,4 +1,3 @@ -from esphome import core import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import select @@ -9,9 +8,8 @@ from esphome.const import ( CONF_FROM, CONF_ID, CONF_TO, - CONF_UPDATE_INTERVAL, ) -from . import OptolinkComponent, optolink_ns, CONF_OPTOLINK_ID +from . import optolink_ns, CONF_OPTOLINK_ID from .sensor import SENSOR_BASE_SCHEMA OptolinkSelect = optolink_ns.class_( @@ -37,18 +35,12 @@ MAP_ID = "mappings" CONFIG_SCHEMA = ( select.SELECT_SCHEMA.extend( { - cv.GenerateID(CONF_OPTOLINK_ID): cv.use_id(OptolinkComponent), cv.GenerateID(): cv.declare_id(OptolinkSelect), cv.GenerateID(MAP_ID): cv.declare_id( cg.std_ns.class_("map").template(cg.std_string, cg.std_string) ), cv.Required(CONF_MAP): cv.ensure_list(validate_mapping), - cv.Optional(CONF_UPDATE_INTERVAL, default="10s"): cv.All( - cv.positive_time_period_milliseconds, - cv.Range( - min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800) - ), - ), + cv.Required(CONF_BYTES): cv.one_of(1, 2, 4, int=True), } ) .extend(cv.COMPONENT_SCHEMA) diff --git a/esphome/components/optolink/sensor.py b/esphome/components/optolink/sensor.py index 4991ac110d..a403f302a8 100644 --- a/esphome/components/optolink/sensor.py +++ b/esphome/components/optolink/sensor.py @@ -1,38 +1,22 @@ -from esphome import core import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import sensor from esphome.const import ( - CONF_ID, CONF_ADDRESS, CONF_BYTES, CONF_DIV_RATIO, - CONF_UPDATE_INTERVAL, + CONF_ID, ) -from . import optolink_ns, OptolinkComponent +from . import CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA, optolink_ns OptolinkSensor = optolink_ns.class_( "OptolinkSensor", sensor.Sensor, cg.PollingComponent ) -CONF_OPTOLINK_ID = "optolink_id" -SENSOR_BASE_SCHEMA = cv.Schema( - { - cv.Required(CONF_ADDRESS): cv.hex_uint32_t, - cv.Required(CONF_BYTES): cv.one_of(1, 2, 4, int=True), - cv.Optional(CONF_DIV_RATIO, default=1): cv.one_of(1, 10, 100, 3600, int=True), - } -) CONFIG_SCHEMA = ( sensor.sensor_schema(OptolinkSensor) .extend( { - cv.GenerateID(CONF_OPTOLINK_ID): cv.use_id(OptolinkComponent), - cv.Optional(CONF_UPDATE_INTERVAL, default="10s"): cv.All( - cv.positive_time_period_milliseconds, - cv.Range( - min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800) - ), - ), + cv.Required(CONF_BYTES): cv.one_of(1, 2, 4, int=True), } ) .extend(SENSOR_BASE_SCHEMA) diff --git a/esphome/components/optolink/text_sensor.py b/esphome/components/optolink/text_sensor.py index 09280c91aa..ea6fb4c0bf 100644 --- a/esphome/components/optolink/text_sensor.py +++ b/esphome/components/optolink/text_sensor.py @@ -1,4 +1,3 @@ -from esphome import core import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import text_sensor @@ -7,32 +6,71 @@ from esphome.const import ( CONF_BYTES, CONF_DIV_RATIO, CONF_ID, - CONF_RAW, - CONF_UPDATE_INTERVAL, + CONF_MODE, ) -from . import optolink_ns, OptolinkComponent, CONF_OPTOLINK_ID +from . import optolink_ns, CONF_OPTOLINK_ID from .sensor import SENSOR_BASE_SCHEMA OptolinkTextSensor = optolink_ns.class_( "OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent ) +TextSensorMode = optolink_ns.enum("TextSensorMode") +MODE = { + "MAP": TextSensorMode.MAP, + "RAW": TextSensorMode.RAW, + "DAY_SCHEDULE": TextSensorMode.DAY_SCHEDULE, +} + +DAY_OF_WEEK = { + "MONDAY": 0, + "TUESDAY": 1, + "WEDNESDAY": 2, + "THURSDAY": 3, + "FRIDAY": 4, + "SATURDAY": 5, + "SUNDAY": 6, +} + +CONF_DOW = "day_of_week" + + +def check_bytes(): + def validator_(config): + bytes_needed = config[CONF_MODE] in ["MAP", "RAW"] + bytes_defined = CONF_BYTES in config + if bytes_needed and not bytes_defined: + raise cv.Invalid(f"{CONF_BYTES} is required in mode MAP or RAW") + if not bytes_needed and bytes_defined: + raise cv.Invalid(f"{CONF_BYTES} is not allowed in mode DAY_SCHEDULE") + return config + + return validator_ + + +def check_dow(): + def validator_(config): + if config[CONF_MODE] == "DAY_SCHEDULE" and CONF_DOW not in config: + raise cv.Invalid(f"{CONF_DOW} is required in mode DAY_SCHEDULE") + if config[CONF_MODE] != "DAY_SCHEDULE" and CONF_DOW in config: + raise cv.Invalid(f"{CONF_DOW} is only allowed in mode DAY_SCHEDULE") + return config + + return validator_ + + CONFIG_SCHEMA = cv.All( text_sensor.text_sensor_schema(OptolinkTextSensor) .extend( { - cv.GenerateID(CONF_OPTOLINK_ID): cv.use_id(OptolinkComponent), - cv.Optional(CONF_UPDATE_INTERVAL, default="10s"): cv.All( - cv.positive_time_period_milliseconds, - cv.Range( - min=core.TimePeriod(seconds=1), max=core.TimePeriod(seconds=1800) - ), - ), - cv.Optional(CONF_RAW, default=False): cv.boolean, + cv.Optional(CONF_MODE, default="MAP"): cv.enum(MODE, upper=True), + cv.Optional(CONF_BYTES): cv.int_range(min=1, max=9), + cv.Optional(CONF_DOW): cv.enum(DAY_OF_WEEK, upper=True), } ) - .extend(SENSOR_BASE_SCHEMA) - .extend({cv.Required(CONF_BYTES): cv.int_}), + .extend(SENSOR_BASE_SCHEMA), + check_bytes(), + check_dow(), ) @@ -43,7 +81,10 @@ async def to_code(config): await cg.register_component(var, config) await text_sensor.register_text_sensor(var, config) - cg.add(var.set_raw(config[CONF_RAW])) + cg.add(var.set_mode(config[CONF_MODE])) cg.add(var.set_address(config[CONF_ADDRESS])) - cg.add(var.set_bytes(config[CONF_BYTES])) cg.add(var.set_div_ratio(config[CONF_DIV_RATIO])) + if CONF_BYTES in config: + cg.add(var.set_bytes(config[CONF_BYTES])) + if CONF_DOW in config: + cg.add(var.set_day_of_week(config[CONF_DOW])) From 878e7c93a35e297fb1e55f6ccca062b811d3071a Mon Sep 17 00:00:00 2001 From: j0ta29 Date: Sat, 26 Aug 2023 18:48:36 +0000 Subject: [PATCH 02/20] component source directory structure refactored --- .../optolink/{binary_sensor.py => binary_sensor/__init__.py} | 2 +- .../optolink/{ => binary_sensor}/optolink_binary_sensor.h | 4 ++-- esphome/components/optolink/{number.py => number/__init__.py} | 3 +-- esphome/components/optolink/{ => number}/optolink_number.cpp | 2 +- esphome/components/optolink/{ => number}/optolink_number.h | 4 ++-- esphome/components/optolink/{select.py => select/__init__.py} | 3 +-- esphome/components/optolink/{ => select}/optolink_select.cpp | 2 +- esphome/components/optolink/{ => select}/optolink_select.h | 4 ++-- esphome/components/optolink/{sensor.py => sensor/__init__.py} | 2 +- esphome/components/optolink/{ => sensor}/optolink_sensor.h | 4 ++-- esphome/components/optolink/{switch.py => switch/__init__.py} | 2 +- esphome/components/optolink/{ => switch}/optolink_switch.cpp | 2 +- esphome/components/optolink/{ => switch}/optolink_switch.h | 4 ++-- .../optolink/{text_sensor.py => text_sensor/__init__.py} | 3 +-- .../{ => text_sensor}/optolink_device_info_sensor.cpp | 0 .../optolink/{ => text_sensor}/optolink_device_info_sensor.h | 4 ++-- .../optolink/{ => text_sensor}/optolink_state_sensor.h | 4 ++-- .../optolink/{ => text_sensor}/optolink_text_sensor.cpp | 2 +- .../optolink/{ => text_sensor}/optolink_text_sensor.h | 4 ++-- 19 files changed, 26 insertions(+), 29 deletions(-) rename esphome/components/optolink/{binary_sensor.py => binary_sensor/__init__.py} (90%) rename esphome/components/optolink/{ => binary_sensor}/optolink_binary_sensor.h (92%) rename esphome/components/optolink/{number.py => number/__init__.py} (94%) rename esphome/components/optolink/{ => number}/optolink_number.cpp (96%) rename esphome/components/optolink/{ => number}/optolink_number.h (92%) rename esphome/components/optolink/{select.py => select/__init__.py} (95%) rename esphome/components/optolink/{ => select}/optolink_select.cpp (98%) rename esphome/components/optolink/{ => select}/optolink_select.h (94%) rename esphome/components/optolink/{sensor.py => sensor/__init__.py} (93%) rename esphome/components/optolink/{ => sensor}/optolink_sensor.h (92%) rename esphome/components/optolink/{switch.py => switch/__init__.py} (96%) rename esphome/components/optolink/{ => switch}/optolink_switch.cpp (96%) rename esphome/components/optolink/{ => switch}/optolink_switch.h (92%) rename esphome/components/optolink/{text_sensor.py => text_sensor/__init__.py} (96%) rename esphome/components/optolink/{ => text_sensor}/optolink_device_info_sensor.cpp (100%) rename esphome/components/optolink/{ => text_sensor}/optolink_device_info_sensor.h (92%) rename esphome/components/optolink/{ => text_sensor}/optolink_state_sensor.h (91%) rename esphome/components/optolink/{ => text_sensor}/optolink_text_sensor.cpp (98%) rename esphome/components/optolink/{ => text_sensor}/optolink_text_sensor.h (93%) diff --git a/esphome/components/optolink/binary_sensor.py b/esphome/components/optolink/binary_sensor/__init__.py similarity index 90% rename from esphome/components/optolink/binary_sensor.py rename to esphome/components/optolink/binary_sensor/__init__.py index 9d1495437e..4f20fca563 100644 --- a/esphome/components/optolink/binary_sensor.py +++ b/esphome/components/optolink/binary_sensor/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg from esphome.components import binary_sensor from esphome.const import CONF_ADDRESS, CONF_ID -from . import SENSOR_BASE_SCHEMA, optolink_ns, CONF_OPTOLINK_ID +from .. import SENSOR_BASE_SCHEMA, optolink_ns, CONF_OPTOLINK_ID OptolinkBinarySensor = optolink_ns.class_( "OptolinkBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent diff --git a/esphome/components/optolink/optolink_binary_sensor.h b/esphome/components/optolink/binary_sensor/optolink_binary_sensor.h similarity index 92% rename from esphome/components/optolink/optolink_binary_sensor.h rename to esphome/components/optolink/binary_sensor/optolink_binary_sensor.h index 6ec63cc855..b3565030f2 100644 --- a/esphome/components/optolink/optolink_binary_sensor.h +++ b/esphome/components/optolink/binary_sensor/optolink_binary_sensor.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/binary_sensor/binary_sensor.h" -#include "optolink.h" -#include "optolink_sensor_base.h" +#include "../optolink.h" +#include "../optolink_sensor_base.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/number.py b/esphome/components/optolink/number/__init__.py similarity index 94% rename from esphome/components/optolink/number.py rename to esphome/components/optolink/number/__init__.py index ab9a4e8c09..5e81852e33 100644 --- a/esphome/components/optolink/number.py +++ b/esphome/components/optolink/number/__init__.py @@ -10,8 +10,7 @@ from esphome.const import ( CONF_MIN_VALUE, CONF_STEP, ) -from .sensor import SENSOR_BASE_SCHEMA -from . import optolink_ns, CONF_OPTOLINK_ID +from .. import optolink_ns, CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA OptolinkNumber = optolink_ns.class_( "OptolinkNumber", number.Number, cg.PollingComponent diff --git a/esphome/components/optolink/optolink_number.cpp b/esphome/components/optolink/number/optolink_number.cpp similarity index 96% rename from esphome/components/optolink/optolink_number.cpp rename to esphome/components/optolink/number/optolink_number.cpp index 3039d219fb..97877a573a 100644 --- a/esphome/components/optolink/optolink_number.cpp +++ b/esphome/components/optolink/number/optolink_number.cpp @@ -1,7 +1,7 @@ #ifdef USE_ARDUINO #include "optolink_number.h" -#include "optolink.h" +#include "../optolink.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/optolink_number.h b/esphome/components/optolink/number/optolink_number.h similarity index 92% rename from esphome/components/optolink/optolink_number.h rename to esphome/components/optolink/number/optolink_number.h index 6b8409d539..d12db821d3 100644 --- a/esphome/components/optolink/optolink_number.h +++ b/esphome/components/optolink/number/optolink_number.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/number/number.h" -#include "optolink_sensor_base.h" -#include "optolink.h" +#include "../optolink_sensor_base.h" +#include "../optolink.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/select.py b/esphome/components/optolink/select/__init__.py similarity index 95% rename from esphome/components/optolink/select.py rename to esphome/components/optolink/select/__init__.py index 779800efef..c959b4e5bd 100644 --- a/esphome/components/optolink/select.py +++ b/esphome/components/optolink/select/__init__.py @@ -9,8 +9,7 @@ from esphome.const import ( CONF_ID, CONF_TO, ) -from . import optolink_ns, CONF_OPTOLINK_ID -from .sensor import SENSOR_BASE_SCHEMA +from .. import optolink_ns, CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA OptolinkSelect = optolink_ns.class_( "OptolinkSelect", select.Select, cg.PollingComponent diff --git a/esphome/components/optolink/optolink_select.cpp b/esphome/components/optolink/select/optolink_select.cpp similarity index 98% rename from esphome/components/optolink/optolink_select.cpp rename to esphome/components/optolink/select/optolink_select.cpp index 783c614bce..4bdf6201f1 100644 --- a/esphome/components/optolink/optolink_select.cpp +++ b/esphome/components/optolink/select/optolink_select.cpp @@ -1,7 +1,7 @@ #ifdef USE_ARDUINO #include "optolink_select.h" -#include "optolink.h" +#include "../optolink.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/optolink_select.h b/esphome/components/optolink/select/optolink_select.h similarity index 94% rename from esphome/components/optolink/optolink_select.h rename to esphome/components/optolink/select/optolink_select.h index 995c9923f3..b7a5eab47e 100644 --- a/esphome/components/optolink/optolink_select.h +++ b/esphome/components/optolink/select/optolink_select.h @@ -4,8 +4,8 @@ #include #include "esphome/components/select/select.h" -#include "optolink.h" -#include "optolink_sensor_base.h" +#include "../optolink.h" +#include "../optolink_sensor_base.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/sensor.py b/esphome/components/optolink/sensor/__init__.py similarity index 93% rename from esphome/components/optolink/sensor.py rename to esphome/components/optolink/sensor/__init__.py index a403f302a8..360ecaf385 100644 --- a/esphome/components/optolink/sensor.py +++ b/esphome/components/optolink/sensor/__init__.py @@ -7,7 +7,7 @@ from esphome.const import ( CONF_DIV_RATIO, CONF_ID, ) -from . import CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA, optolink_ns +from .. import CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA, optolink_ns OptolinkSensor = optolink_ns.class_( "OptolinkSensor", sensor.Sensor, cg.PollingComponent diff --git a/esphome/components/optolink/optolink_sensor.h b/esphome/components/optolink/sensor/optolink_sensor.h similarity index 92% rename from esphome/components/optolink/optolink_sensor.h rename to esphome/components/optolink/sensor/optolink_sensor.h index 032af7a03e..f0a7da49ac 100644 --- a/esphome/components/optolink/optolink_sensor.h +++ b/esphome/components/optolink/sensor/optolink_sensor.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/sensor/sensor.h" -#include "optolink.h" -#include "optolink_sensor_base.h" +#include "../optolink.h" +#include "../optolink_sensor_base.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/switch.py b/esphome/components/optolink/switch/__init__.py similarity index 96% rename from esphome/components/optolink/switch.py rename to esphome/components/optolink/switch/__init__.py index 32540cdf0f..464e9feea3 100644 --- a/esphome/components/optolink/switch.py +++ b/esphome/components/optolink/switch/__init__.py @@ -3,7 +3,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import switch from esphome.const import CONF_ADDRESS, CONF_ID, CONF_UPDATE_INTERVAL -from . import OptolinkComponent, optolink_ns +from .. import OptolinkComponent, optolink_ns OptolinkSwitch = optolink_ns.class_( "OptolinkSwitch", switch.Switch, cg.PollingComponent diff --git a/esphome/components/optolink/optolink_switch.cpp b/esphome/components/optolink/switch/optolink_switch.cpp similarity index 96% rename from esphome/components/optolink/optolink_switch.cpp rename to esphome/components/optolink/switch/optolink_switch.cpp index 066f11a1a4..4b08e9bda0 100644 --- a/esphome/components/optolink/optolink_switch.cpp +++ b/esphome/components/optolink/switch/optolink_switch.cpp @@ -1,7 +1,7 @@ #ifdef USE_ARDUINO #include "optolink_switch.h" -#include "optolink.h" +#include "../optolink.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/optolink_switch.h b/esphome/components/optolink/switch/optolink_switch.h similarity index 92% rename from esphome/components/optolink/optolink_switch.h rename to esphome/components/optolink/switch/optolink_switch.h index 970e7a1a67..e1a4ebfb80 100644 --- a/esphome/components/optolink/optolink_switch.h +++ b/esphome/components/optolink/switch/optolink_switch.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/switch/switch.h" -#include "optolink_sensor_base.h" -#include "optolink.h" +#include "../optolink_sensor_base.h" +#include "../optolink.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/text_sensor.py b/esphome/components/optolink/text_sensor/__init__.py similarity index 96% rename from esphome/components/optolink/text_sensor.py rename to esphome/components/optolink/text_sensor/__init__.py index ea6fb4c0bf..aaad5837e4 100644 --- a/esphome/components/optolink/text_sensor.py +++ b/esphome/components/optolink/text_sensor/__init__.py @@ -8,8 +8,7 @@ from esphome.const import ( CONF_ID, CONF_MODE, ) -from . import optolink_ns, CONF_OPTOLINK_ID -from .sensor import SENSOR_BASE_SCHEMA +from .. import optolink_ns, CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA OptolinkTextSensor = optolink_ns.class_( "OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent diff --git a/esphome/components/optolink/optolink_device_info_sensor.cpp b/esphome/components/optolink/text_sensor/optolink_device_info_sensor.cpp similarity index 100% rename from esphome/components/optolink/optolink_device_info_sensor.cpp rename to esphome/components/optolink/text_sensor/optolink_device_info_sensor.cpp diff --git a/esphome/components/optolink/optolink_device_info_sensor.h b/esphome/components/optolink/text_sensor/optolink_device_info_sensor.h similarity index 92% rename from esphome/components/optolink/optolink_device_info_sensor.h rename to esphome/components/optolink/text_sensor/optolink_device_info_sensor.h index 94ace35a25..73ce0cc326 100644 --- a/esphome/components/optolink/optolink_device_info_sensor.h +++ b/esphome/components/optolink/text_sensor/optolink_device_info_sensor.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/text_sensor/text_sensor.h" -#include "optolink.h" -#include "optolink_sensor_base.h" +#include "../optolink.h" +#include "../optolink_sensor_base.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/optolink_state_sensor.h b/esphome/components/optolink/text_sensor/optolink_state_sensor.h similarity index 91% rename from esphome/components/optolink/optolink_state_sensor.h rename to esphome/components/optolink/text_sensor/optolink_state_sensor.h index 9652bf2c61..0d67602b68 100644 --- a/esphome/components/optolink/optolink_state_sensor.h +++ b/esphome/components/optolink/text_sensor/optolink_state_sensor.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/text_sensor/text_sensor.h" -#include "optolink.h" -#include "optolink_sensor_base.h" +#include "../optolink.h" +#include "../optolink_sensor_base.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/optolink_text_sensor.cpp b/esphome/components/optolink/text_sensor/optolink_text_sensor.cpp similarity index 98% rename from esphome/components/optolink/optolink_text_sensor.cpp rename to esphome/components/optolink/text_sensor/optolink_text_sensor.cpp index f3e096684f..bbc18973cb 100644 --- a/esphome/components/optolink/optolink_text_sensor.cpp +++ b/esphome/components/optolink/text_sensor/optolink_text_sensor.cpp @@ -1,7 +1,7 @@ #ifdef USE_ARDUINO #include "optolink_text_sensor.h" -#include "optolink.h" +#include "../optolink.h" #include "VitoWiFi.h" namespace esphome { diff --git a/esphome/components/optolink/optolink_text_sensor.h b/esphome/components/optolink/text_sensor/optolink_text_sensor.h similarity index 93% rename from esphome/components/optolink/optolink_text_sensor.h rename to esphome/components/optolink/text_sensor/optolink_text_sensor.h index fd6a64a60e..21a0f3ea10 100644 --- a/esphome/components/optolink/optolink_text_sensor.h +++ b/esphome/components/optolink/text_sensor/optolink_text_sensor.h @@ -3,8 +3,8 @@ #ifdef USE_ARDUINO #include "esphome/components/text_sensor/text_sensor.h" -#include "optolink.h" -#include "optolink_sensor_base.h" +#include "../optolink.h" +#include "../optolink_sensor_base.h" #include "VitoWiFi.h" namespace esphome { From f0ba8873caff4f00af8a8f79dc3d8e9d1d811afb Mon Sep 17 00:00:00 2001 From: j0ta29 Date: Sat, 26 Aug 2023 18:48:37 +0000 Subject: [PATCH 03/20] first working rework for text_sendor mode DAY_SCHEDULE_SYNCHRONIZED --- esphome/components/optolink/__init__.py | 1 - .../binary_sensor/optolink_binary_sensor.h | 6 +- .../optolink/number/optolink_number.cpp | 8 +- .../optolink/number/optolink_number.h | 7 +- esphome/components/optolink/optolink.cpp | 10 +- .../optolink/optolink_sensor_base.cpp | 269 +++++++++++------- .../optolink/optolink_sensor_base.h | 38 ++- .../optolink/select/optolink_select.cpp | 43 ++- .../optolink/select/optolink_select.h | 8 +- .../optolink/sensor/optolink_sensor.h | 7 +- .../optolink/switch/optolink_switch.cpp | 8 +- .../optolink/switch/optolink_switch.h | 6 +- .../optolink/text_sensor/__init__.py | 55 +++- .../optolink_device_info_sensor.cpp | 4 +- .../text_sensor/optolink_text_sensor.cpp | 150 ++++++++-- .../text_sensor/optolink_text_sensor.h | 12 +- 16 files changed, 429 insertions(+), 203 deletions(-) diff --git a/esphome/components/optolink/__init__.py b/esphome/components/optolink/__init__.py index d3e879868e..2b086db404 100644 --- a/esphome/components/optolink/__init__.py +++ b/esphome/components/optolink/__init__.py @@ -34,7 +34,6 @@ DeviceInfoSensor = optolink_ns.class_( "OptolinkDeviceInfoSensor", ts.TextSensor, cg.PollingComponent ) DEVICE_INFO_SENSOR_ID = "device_info_sensor_id" - CONF_OPTOLINK_ID = "optolink_id" SENSOR_BASE_SCHEMA = cv.Schema( { diff --git a/esphome/components/optolink/binary_sensor/optolink_binary_sensor.h b/esphome/components/optolink/binary_sensor/optolink_binary_sensor.h index b3565030f2..5284c37b6c 100644 --- a/esphome/components/optolink/binary_sensor/optolink_binary_sensor.h +++ b/esphome/components/optolink/binary_sensor/optolink_binary_sensor.h @@ -20,11 +20,11 @@ class OptolinkBinarySensor : public OptolinkSensorBase, } protected: - void setup() override { setup_datapoint_(); } + void setup() override { setup_datapoint(); } void update() override { optolink_->read_value(datapoint_); } - const StringRef &get_sensor_name() override { return get_name(); } - void value_changed(float state) override { publish_state(state); }; + const StringRef &get_component_name() override { return get_name(); } + void value_changed(uint8_t state) override { publish_state(state); }; }; } // namespace optolink } // namespace esphome diff --git a/esphome/components/optolink/number/optolink_number.cpp b/esphome/components/optolink/number/optolink_number.cpp index 97877a573a..676ca32b7c 100644 --- a/esphome/components/optolink/number/optolink_number.cpp +++ b/esphome/components/optolink/number/optolink_number.cpp @@ -9,11 +9,11 @@ namespace optolink { void OptolinkNumber::control(float value) { if (value > traits.get_max_value() || value < traits.get_min_value()) { - optolink_->set_error("datapoint value of number %s not in allowed range", get_sensor_name().c_str()); - ESP_LOGE("OptolinkNumber", "datapoint value of number %s not in allowed range", get_sensor_name().c_str()); + optolink_->set_error("datapoint value of number %s not in allowed range", get_component_name().c_str()); + ESP_LOGE("OptolinkNumber", "datapoint value of number %s not in allowed range", get_component_name().c_str()); } else { - ESP_LOGI("OptolinkNumber", "control of number %s to value %f", get_sensor_name().c_str(), value); - update_datapoint_(value); + ESP_LOGI("OptolinkNumber", "control of number %s to value %f", get_component_name().c_str(), value); + update_datapoint(value); publish_state(value); } }; diff --git a/esphome/components/optolink/number/optolink_number.h b/esphome/components/optolink/number/optolink_number.h index d12db821d3..097039878b 100644 --- a/esphome/components/optolink/number/optolink_number.h +++ b/esphome/components/optolink/number/optolink_number.h @@ -15,11 +15,14 @@ class OptolinkNumber : public OptolinkSensorBase, public esphome::number::Number OptolinkNumber(Optolink *optolink) : OptolinkSensorBase(optolink, true) {} protected: - void setup() override { setup_datapoint_(); } + void setup() override { setup_datapoint(); } void update() override { optolink_->read_value(datapoint_); } - const StringRef &get_sensor_name() override { return get_name(); } + const StringRef &get_component_name() override { return get_name(); } void value_changed(float state) override { publish_state(state); }; + void value_changed(uint8_t state) override { publish_state(state); }; + void value_changed(uint16_t state) override { publish_state(state); }; + void value_changed(uint32_t state) override { publish_state(state); }; void control(float value) override; }; diff --git a/esphome/components/optolink/optolink.cpp b/esphome/components/optolink/optolink.cpp index e5fe87d5d2..efe2c90b1f 100644 --- a/esphome/components/optolink/optolink.cpp +++ b/esphome/components/optolink/optolink.cpp @@ -15,10 +15,12 @@ VitoWiFiClass VitoWiFi; // this is not really a fallback but dedicated to namespace esphome { namespace optolink { +static const char *const TAG = "optolink"; + void Optolink::comm_() { - ESP_LOGD("Optolink", "enter _comm"); + ESP_LOGD(TAG, "enter _comm"); VitoWiFi.readAll(); - ESP_LOGD("Optolink", "exit _comm"); + ESP_LOGD(TAG, "exit _comm"); } void Optolink::setup() { @@ -52,7 +54,7 @@ void Optolink::set_error(const char *format, ...) { void Optolink::read_value(IDatapoint *datapoint) { if (datapoint != nullptr) { - ESP_LOGI("Optolink", " read value of datapoint %s", datapoint->getName()); + ESP_LOGI("Optolink", "requesting value of datapoint %s", datapoint->getName()); VitoWiFi.readDatapoint(*datapoint); } } @@ -61,7 +63,7 @@ void Optolink::write_value(IDatapoint *datapoint, DPValue dp_value) { if (datapoint != nullptr) { char buffer[64]; dp_value.getString(buffer, sizeof(buffer)); - ESP_LOGI("Optolink", " write value %s of datapoint %s", buffer, datapoint->getName()); + ESP_LOGI("Optolink", "sending value %s to datapoint %s", buffer, datapoint->getName()); VitoWiFi.writeDatapoint(*datapoint, dp_value); } } diff --git a/esphome/components/optolink/optolink_sensor_base.cpp b/esphome/components/optolink/optolink_sensor_base.cpp index abe2b48c4e..856a59d56e 100644 --- a/esphome/components/optolink/optolink_sensor_base.cpp +++ b/esphome/components/optolink/optolink_sensor_base.cpp @@ -6,148 +6,197 @@ namespace esphome { namespace optolink { -void OptolinkSensorBase::update_datapoint_(float value) { - if (!writeable_) { - optolink_->set_error("try to control not writable number %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "try to control not writable number %s", get_sensor_name().c_str()); - } else if (datapoint_ != nullptr) { - switch (bytes_) { - case 1: - switch (div_ratio_) { - case 1: - optolink_->write_value(datapoint_, DPValue((uint8_t) value)); - break; - case 10: - optolink_->write_value(datapoint_, DPValue((float) value)); - break; - default: - optolink_->set_error("Unknown byte/div_ratio combination for number %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for number %s", - get_sensor_name().c_str()); - break; - } - break; - case 2: - switch (div_ratio_) { - case 1: - optolink_->write_value(datapoint_, DPValue((uint16_t) value)); - break; - case 10: - case 100: - optolink_->write_value(datapoint_, DPValue((float) value)); - break; - default: - optolink_->set_error("Unknown byte/div_ratio combination for number %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for number %s", - get_sensor_name().c_str()); - break; - } - break; - case 4: - switch (div_ratio_) { - case 1: - optolink_->write_value(datapoint_, DPValue((uint32_t) value)); - break; - case 3600: - optolink_->write_value(datapoint_, DPValue((float) value)); - break; - default: - optolink_->set_error("Unknown byte/div_ratio combination for number %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for number %s", - get_sensor_name().c_str()); - break; - } - break; - default: - optolink_->set_error("Unknown byte value for number %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte value for number %s", get_sensor_name().c_str()); - break; - } - } -} +static const char *const TAG = "optolink.sensor_base"; -void OptolinkSensorBase::setup_datapoint_() { - switch (bytes_) { +void OptolinkSensorBase::setup_datapoint() { + switch (div_ratio_) { + case 0: + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); + datapoint_->setLength(bytes_); + datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { + uint8_t buffer[bytes_]; + dp_value.getRaw(buffer); +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_INFO + char print_buffer[bytes_ * 2 + 1]; + dp_value.getString(print_buffer, sizeof(print_buffer)); + ESP_LOGI(TAG, "recieved data for datapoint %s: %s", dp.getName(), print_buffer); +#endif + value_changed((uint8_t *) buffer, bytes_); + }); + break; case 1: - switch (div_ratio_) { + switch (bytes_) { case 1: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), dp_value.getU8()); + ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), dp_value.getU8()); value_changed(dp_value.getU8()); }); break; - case 10: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); + case 2: + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat()); - value_changed(dp_value.getFloat()); - }); - break; - default: - optolink_->set_error("Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str()); - break; - } - break; - case 2: - switch (div_ratio_) { - case 1: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); - datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), dp_value.getU16()); + ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), dp_value.getU16()); value_changed(dp_value.getU16()); }); break; - case 10: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); + case 4: + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat()); - value_changed(dp_value.getFloat()); - }); - break; - case 100: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); - datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat()); - value_changed(dp_value.getFloat()); + ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), dp_value.getU32()); + value_changed((uint32_t) dp_value.getU32()); }); break; default: - optolink_->set_error("Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str()); - break; + unfitting_value_type(); } break; - case 4: - switch (div_ratio_) { + case 10: + switch (bytes_) { case 1: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), dp_value.getU32()); - value_changed(dp_value.getU32()); + ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat()); + value_changed(dp_value.getFloat()); }); break; - case 3600: - datapoint_ = new Datapoint(get_sensor_name().c_str(), "optolink", address_, writeable_); + case 2: + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { - ESP_LOGD("OptolinkSensorBase", "Datapoint %s - %s: %f", dp.getGroup(), dp.getName(), dp_value.getFloat()); + ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat()); value_changed(dp_value.getFloat()); }); break; default: - optolink_->set_error("Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte/div_ratio combination for sensor %s", get_sensor_name().c_str()); - break; + unfitting_value_type(); } break; - default: - optolink_->set_error("Unknown byte value for sensor %s", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSensorBase", "Unknown byte value for sensor %s", get_sensor_name().c_str()); + case 100: + switch (bytes_) { + case 2: + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); + datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { + ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat()); + value_changed(dp_value.getFloat()); + }); + break; + default: + unfitting_value_type(); + } break; + case 3600: + switch (bytes_) { + case 4: + datapoint_ = new Datapoint(get_component_name().c_str(), "optolink", address_, writeable_); + datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { + ESP_LOGI(TAG, "recieved data for datapoint %s: %f", dp.getName(), dp_value.getFloat()); + value_changed(dp_value.getFloat()); + }); + break; + } + default: + unfitting_value_type(); } } +void OptolinkSensorBase::value_changed(float value) { + ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str()); +} + +void OptolinkSensorBase::value_changed(uint8_t value) { + ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str()); +} + +void OptolinkSensorBase::value_changed(uint16_t value) { + ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str()); +} + +void OptolinkSensorBase::value_changed(uint32_t value) { + ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str()); +} + +void OptolinkSensorBase::value_changed(std::string value) { + ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str()); +} + +void OptolinkSensorBase::value_changed(uint8_t *value, size_t length) { + ESP_LOGW(TAG, "unused value update by sensor %s", get_component_name().c_str()); +} + +void OptolinkSensorBase::update_datapoint(DPValue dp_value) { + if (!writeable_) { + optolink_->set_error("trying to control not writable datapoint %s", get_component_name().c_str()); + ESP_LOGE(TAG, "trying to control not writable datapoint %s", get_component_name().c_str()); + } else if (datapoint_ != nullptr) { +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_INFO + char buffer[100]; + dp_value.getString(buffer, sizeof(buffer)); + ESP_LOGI(TAG, "updating datapoint %s value: %s", datapoint_->getName(), buffer); +#endif + optolink_->write_value(datapoint_, dp_value); + } +} + +void OptolinkSensorBase::update_datapoint(float value) { + if (div_ratio_ > 1) { + update_datapoint(DPValue(value)); + } else if (div_ratio_ == 1) { + switch (bytes_) { + case 1: + update_datapoint(DPValue((uint8_t) value)); + break; + case 2: + update_datapoint(DPValue((uint16_t) value)); + break; + case 4: + update_datapoint(DPValue((uint32_t) value)); + break; + default: + unfitting_value_type(); + break; + } + } else { + unfitting_value_type(); + } +} + +void OptolinkSensorBase::update_datapoint(uint8_t value) { + if (bytes_ == 1 && div_ratio_ == 1) { + update_datapoint(DPValue(value)); + } else { + unfitting_value_type(); + } +} + +void OptolinkSensorBase::update_datapoint(uint16_t value) { + if (bytes_ == 2 && div_ratio_ == 1) { + update_datapoint(DPValue(value)); + } else { + unfitting_value_type(); + } +} + +void OptolinkSensorBase::update_datapoint(uint32_t value) { + if (bytes_ == 4 && div_ratio_ == 1) { + update_datapoint(DPValue(value)); + } else { + unfitting_value_type(); + } +} + +void OptolinkSensorBase::update_datapoint(uint8_t *value, size_t length) { + if (bytes_ == length && div_ratio_ == 0) { + update_datapoint(DPValue(value, length)); + } else { + unfitting_value_type(); + } +} + +void OptolinkSensorBase::unfitting_value_type() { + optolink_->set_error("Unfitting byte/div_ratio combination for sensor/component %s", get_component_name().c_str()); + ESP_LOGE(TAG, "Unfitting byte/div_ratio combination for sensor/component %s", get_component_name().c_str()); +} + void conv2_100_F::encode(uint8_t *out, DPValue in) { int16_t tmp = floor((in.getFloat() * 100) + 0.5); out[1] = tmp >> 8; diff --git a/esphome/components/optolink/optolink_sensor_base.h b/esphome/components/optolink/optolink_sensor_base.h index 3c84de4d85..abb6b56967 100644 --- a/esphome/components/optolink/optolink_sensor_base.h +++ b/esphome/components/optolink/optolink_sensor_base.h @@ -12,17 +12,6 @@ namespace optolink { class Optolink; class OptolinkSensorBase { - protected: - Optolink *optolink_; - bool writeable_; - IDatapoint *datapoint_ = nullptr; - uint32_t address_; - int bytes_; - int div_ratio_ = 1; - - void setup_datapoint_(); - void update_datapoint_(float value); - public: OptolinkSensorBase(Optolink *optolink, bool writeable = false) { optolink_ = optolink; @@ -34,8 +23,31 @@ class OptolinkSensorBase { void set_div_ratio(int div_ratio) { div_ratio_ = div_ratio; } protected: - virtual const StringRef &get_sensor_name() = 0; - virtual void value_changed(float state) = 0; + Optolink *optolink_; + bool writeable_; + IDatapoint *datapoint_ = nullptr; + uint32_t address_; + size_t bytes_; + size_t div_ratio_ = 0; + + virtual const StringRef &get_component_name() = 0; + void setup_datapoint(); + virtual void value_changed(float value); + virtual void value_changed(uint8_t value); + virtual void value_changed(uint16_t value); + virtual void value_changed(uint32_t value); + virtual void value_changed(std::string value); + virtual void value_changed(uint8_t *value, size_t length); + void update_datapoint(float value); + void update_datapoint(uint8_t value); + void update_datapoint(uint16_t value); + void update_datapoint(uint32_t value); + void update_datapoint(uint8_t *value, size_t length); + + void unfitting_value_type(); + + private: + void update_datapoint(DPValue dp_value); }; // NOLINTNEXTLINE diff --git a/esphome/components/optolink/select/optolink_select.cpp b/esphome/components/optolink/select/optolink_select.cpp index 4bdf6201f1..68fb6140bd 100644 --- a/esphome/components/optolink/select/optolink_select.cpp +++ b/esphome/components/optolink/select/optolink_select.cpp @@ -10,34 +10,47 @@ namespace optolink { void OptolinkSelect::control(const std::string &value) { for (auto it = mapping_->begin(); it != mapping_->end(); ++it) { if (it->second == value) { - ESP_LOGI("OptolinkSelect", "control of select %s to value %s", get_sensor_name().c_str(), it->first.c_str()); - update_datapoint_(std::stof(it->first)); + ESP_LOGI("OptolinkSelect", "control of select %s to value %s", get_component_name().c_str(), it->first.c_str()); + update_datapoint(std::stof(it->first)); publish_state(it->second); break; } if (it == mapping_->end()) { - optolink_->set_error("unknown value %s of select %s", value.c_str(), get_sensor_name().c_str()); - ESP_LOGE("OptolinkSelect", "unknown value %s of select %s", value.c_str(), get_sensor_name().c_str()); + optolink_->set_error("unknown value %s of select %s", value.c_str(), get_component_name().c_str()); + ESP_LOGE("OptolinkSelect", "unknown value %s of select %s", value.c_str(), get_component_name().c_str()); } } }; -void OptolinkSelect::value_changed(float state) { - std::string key; - if (div_ratio_ == 1) { - key = std::to_string((int) state); - } else { - key = std::to_string(state); - } +void OptolinkSelect::value_changed(std::string key) { auto pos = mapping_->find(key); if (pos == mapping_->end()) { - optolink_->set_error("value %s not found in select %s", key.c_str(), get_sensor_name().c_str()); - ESP_LOGE("OptolinkSelect", "value %s not found in select %s", key.c_str(), get_sensor_name().c_str()); + optolink_->set_error("value %s not found in select %s", key.c_str(), get_component_name().c_str()); + ESP_LOGE("OptolinkSelect", "value %s not found in select %s", key.c_str(), get_component_name().c_str()); } else { publish_state(pos->second); } - //-----------------------------------------------publish_state(state); -}; +} + +void OptolinkSelect::value_changed(uint8_t state) { + std::string key = std::to_string(state); + value_changed(key); +} + +void OptolinkSelect::value_changed(uint16_t state) { + std::string key = std::to_string(state); + value_changed(key); +} + +void OptolinkSelect::value_changed(uint32_t state) { + std::string key = std::to_string(state); + value_changed(key); +} + +void OptolinkSelect::value_changed(float state) { + std::string key = std::to_string(state); + value_changed(key); +} } // namespace optolink } // namespace esphome diff --git a/esphome/components/optolink/select/optolink_select.h b/esphome/components/optolink/select/optolink_select.h index b7a5eab47e..20137b0d1d 100644 --- a/esphome/components/optolink/select/optolink_select.h +++ b/esphome/components/optolink/select/optolink_select.h @@ -25,10 +25,14 @@ class OptolinkSelect : public OptolinkSensorBase, public esphome::select::Select }; protected: - void setup() override { setup_datapoint_(); } + void setup() override { setup_datapoint(); } void update() override { optolink_->read_value(datapoint_); } - const StringRef &get_sensor_name() override { return get_name(); } + const StringRef &get_component_name() override { return get_name(); } + void value_changed(std::string state) override; + void value_changed(uint8_t state) override; + void value_changed(uint16_t state) override; + void value_changed(uint32_t state) override; void value_changed(float state) override; void control(const std::string &value) override; diff --git a/esphome/components/optolink/sensor/optolink_sensor.h b/esphome/components/optolink/sensor/optolink_sensor.h index f0a7da49ac..89474abcda 100644 --- a/esphome/components/optolink/sensor/optolink_sensor.h +++ b/esphome/components/optolink/sensor/optolink_sensor.h @@ -17,11 +17,14 @@ class OptolinkSensor : public OptolinkSensorBase, public esphome::sensor::Sensor } protected: - void setup() { setup_datapoint_(); } + void setup() { setup_datapoint(); } void update() override { optolink_->read_value(datapoint_); } - const StringRef &get_sensor_name() override { return get_name(); } + const StringRef &get_component_name() override { return get_name(); } void value_changed(float state) override { publish_state(state); }; + void value_changed(uint8_t state) override { publish_state(state); }; + void value_changed(uint16_t state) override { publish_state(state); }; + void value_changed(uint32_t state) override { publish_state(state); }; }; } // namespace optolink } // namespace esphome diff --git a/esphome/components/optolink/switch/optolink_switch.cpp b/esphome/components/optolink/switch/optolink_switch.cpp index 4b08e9bda0..b334398f53 100644 --- a/esphome/components/optolink/switch/optolink_switch.cpp +++ b/esphome/components/optolink/switch/optolink_switch.cpp @@ -9,11 +9,11 @@ namespace optolink { void OptolinkSwitch::write_state(bool value) { if (value != 0 && value != 1) { - optolink_->set_error("datapoint value of switch %s not 0 or 1", get_sensor_name().c_str()); - ESP_LOGE("OptolinkSwitch", "datapoint value of switch %s not 0 or 1", get_sensor_name().c_str()); + optolink_->set_error("datapoint value of switch %s not 0 or 1", get_component_name().c_str()); + ESP_LOGE("OptolinkSwitch", "datapoint value of switch %s not 0 or 1", get_component_name().c_str()); } else { - ESP_LOGI("OptolinkSwitch", "control of switch %s to value %d", get_sensor_name().c_str(), value); - update_datapoint_(value); + ESP_LOGI("OptolinkSwitch", "control of switch %s to value %d", get_component_name().c_str(), value); + update_datapoint((uint8_t) value); publish_state(value); } }; diff --git a/esphome/components/optolink/switch/optolink_switch.h b/esphome/components/optolink/switch/optolink_switch.h index e1a4ebfb80..6b5cffdf28 100644 --- a/esphome/components/optolink/switch/optolink_switch.h +++ b/esphome/components/optolink/switch/optolink_switch.h @@ -18,11 +18,11 @@ class OptolinkSwitch : public OptolinkSensorBase, public esphome::switch_::Switc } protected: - void setup() override { setup_datapoint_(); } + void setup() override { setup_datapoint(); } void update() override { optolink_->read_value(datapoint_); } - const StringRef &get_sensor_name() override { return get_name(); } - void value_changed(float state) override { publish_state(state); }; + const StringRef &get_component_name() override { return get_name(); } + void value_changed(uint8_t state) override { publish_state(state); }; void write_state(bool value) override; }; diff --git a/esphome/components/optolink/text_sensor/__init__.py b/esphome/components/optolink/text_sensor/__init__.py index aaad5837e4..56110527a6 100644 --- a/esphome/components/optolink/text_sensor/__init__.py +++ b/esphome/components/optolink/text_sensor/__init__.py @@ -5,22 +5,21 @@ from esphome.const import ( CONF_ADDRESS, CONF_BYTES, CONF_DIV_RATIO, + CONF_ENTITY_ID, CONF_ID, CONF_MODE, ) from .. import optolink_ns, CONF_OPTOLINK_ID, SENSOR_BASE_SCHEMA -OptolinkTextSensor = optolink_ns.class_( - "OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent -) +DEPENDENCIES = ["api"] TextSensorMode = optolink_ns.enum("TextSensorMode") MODE = { "MAP": TextSensorMode.MAP, "RAW": TextSensorMode.RAW, "DAY_SCHEDULE": TextSensorMode.DAY_SCHEDULE, + "DAY_SCHEDULE_SYNCHRONIZED": TextSensorMode.DAY_SCHEDULE_SYNCHRONIZED, } - DAY_OF_WEEK = { "MONDAY": 0, "TUESDAY": 1, @@ -30,9 +29,12 @@ DAY_OF_WEEK = { "SATURDAY": 5, "SUNDAY": 6, } - CONF_DOW = "day_of_week" +OptolinkTextSensor = optolink_ns.class_( + "OptolinkTextSensor", text_sensor.TextSensor, cg.PollingComponent +) + def check_bytes(): def validator_(config): @@ -41,7 +43,9 @@ def check_bytes(): if bytes_needed and not bytes_defined: raise cv.Invalid(f"{CONF_BYTES} is required in mode MAP or RAW") if not bytes_needed and bytes_defined: - raise cv.Invalid(f"{CONF_BYTES} is not allowed in mode DAY_SCHEDULE") + raise cv.Invalid( + f"{CONF_BYTES} is not allowed in mode DAY_SCHEDULE and DAY_SCHEDULE_SYNCHRONIZED" + ) return config return validator_ @@ -49,10 +53,39 @@ def check_bytes(): def check_dow(): def validator_(config): - if config[CONF_MODE] == "DAY_SCHEDULE" and CONF_DOW not in config: + if ( + config[CONF_MODE] in ["DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"] + and CONF_DOW not in config + ): raise cv.Invalid(f"{CONF_DOW} is required in mode DAY_SCHEDULE") - if config[CONF_MODE] != "DAY_SCHEDULE" and CONF_DOW in config: - raise cv.Invalid(f"{CONF_DOW} is only allowed in mode DAY_SCHEDULE") + if ( + config[CONF_MODE] not in ["DAY_SCHEDULE", "DAY_SCHEDULE_SYNCHRONIZED"] + and CONF_DOW in config + ): + raise cv.Invalid( + f"{CONF_DOW} is only allowed in mode DAY_SCHEDULE or DAY_SCHEDULE_SYNCHRONIZED" + ) + return config + + return validator_ + + +def check_entity_id(): + def validator_(config): + if ( + config[CONF_MODE] in ["DAY_SCHEDULE_SYNCHRONIZED"] + and CONF_ENTITY_ID not in config + ): + raise cv.Invalid( + f"{CONF_ENTITY_ID} is required in mode DAY_SCHEDULE_SYNCHRONIZED" + ) + if ( + config[CONF_MODE] not in ["DAY_SCHEDULE_SYNCHRONIZED"] + and CONF_ENTITY_ID in config + ): + raise cv.Invalid( + f"{CONF_ENTITY_ID} is only allowed in mode DAY_SCHEDULE_SYNCHRONIZED" + ) return config return validator_ @@ -65,11 +98,13 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_MODE, default="MAP"): cv.enum(MODE, upper=True), cv.Optional(CONF_BYTES): cv.int_range(min=1, max=9), cv.Optional(CONF_DOW): cv.enum(DAY_OF_WEEK, upper=True), + cv.Optional(CONF_ENTITY_ID): cv.entity_id, } ) .extend(SENSOR_BASE_SCHEMA), check_bytes(), check_dow(), + check_entity_id(), ) @@ -87,3 +122,5 @@ async def to_code(config): cg.add(var.set_bytes(config[CONF_BYTES])) if CONF_DOW in config: cg.add(var.set_day_of_week(config[CONF_DOW])) + if CONF_ENTITY_ID in config: + cg.add(var.set_entity_id(config[CONF_ENTITY_ID])) diff --git a/esphome/components/optolink/text_sensor/optolink_device_info_sensor.cpp b/esphome/components/optolink/text_sensor/optolink_device_info_sensor.cpp index 4ce4e19974..9de361841f 100644 --- a/esphome/components/optolink/text_sensor/optolink_device_info_sensor.cpp +++ b/esphome/components/optolink/text_sensor/optolink_device_info_sensor.cpp @@ -6,11 +6,13 @@ namespace esphome { namespace optolink { +static const char *const TAG = "optolink.text_sensor"; + void OptolinkDeviceInfoSensor::setup() { datapoint_ = new Datapoint(get_name().c_str(), "optolink", 0x00f8, false); datapoint_->setCallback([this](const IDatapoint &dp, DPValue dp_value) { uint32_t value = dp_value.getU32(); - ESP_LOGD("OptolinkTextSensor", "Datapoint %s - %s: %d", dp.getGroup(), dp.getName(), value); + ESP_LOGI(TAG, "recieved data for datapoint %s: %d", dp.getName(), value); uint8_t *bytes = (uint8_t *) &value; uint16_t tmp = esphome::byteswap(*((uint16_t *) bytes)); std::string geraetekennung = esphome::format_hex_pretty(&tmp, 1); diff --git a/esphome/components/optolink/text_sensor/optolink_text_sensor.cpp b/esphome/components/optolink/text_sensor/optolink_text_sensor.cpp index bbc18973cb..c65c2459d3 100644 --- a/esphome/components/optolink/text_sensor/optolink_text_sensor.cpp +++ b/esphome/components/optolink/text_sensor/optolink_text_sensor.cpp @@ -2,43 +2,139 @@ #include "optolink_text_sensor.h" #include "../optolink.h" +#include "esphome/components/api/api_server.h" #include "VitoWiFi.h" +#include +#include +#include namespace esphome { namespace optolink { +static const char *const TAG = "optolink.text_sensor"; + +struct Time { + int hours; + int minutes; +}; + +bool check_time_sequence(const Time &t1, const Time &t2) { + if (t2.hours > t1.hours || (t2.hours == t1.hours && t2.minutes >= t1.minutes)) { + return true; + } + return false; +} + +bool check_time_values(const Time &time) { + return (time.hours >= 0 && time.hours <= 23) && (time.minutes >= 0 && time.minutes <= 59); +} + +uint8_t *encode_time_string(std::string input) { + std::istringstream iss(input); + std::vector