From 6f0184832c607a056a87980a3e30f731f4838edd Mon Sep 17 00:00:00 2001 From: Guido Schreuder Date: Wed, 21 Feb 2024 08:25:23 +0100 Subject: [PATCH] Add boolean sensor --- .../components/ebus/binary_sensor/__init__.py | 39 ++++++++++++ .../ebus/binary_sensor/ebus_binary_sensor.cpp | 16 +++++ .../ebus/binary_sensor/ebus_binary_sensor.h | 22 +++++++ esphome/components/ebus/ebus_sensor_base.cpp | 59 +++++++++++++++++++ esphome/components/ebus/ebus_sensor_base.h | 33 +++++++++++ 5 files changed, 169 insertions(+) create mode 100644 esphome/components/ebus/binary_sensor/__init__.py create mode 100644 esphome/components/ebus/binary_sensor/ebus_binary_sensor.cpp create mode 100644 esphome/components/ebus/binary_sensor/ebus_binary_sensor.h create mode 100644 esphome/components/ebus/ebus_sensor_base.cpp create mode 100644 esphome/components/ebus/ebus_sensor_base.h diff --git a/esphome/components/ebus/binary_sensor/__init__.py b/esphome/components/ebus/binary_sensor/__init__.py new file mode 100644 index 0000000000..2beac87439 --- /dev/null +++ b/esphome/components/ebus/binary_sensor/__init__.py @@ -0,0 +1,39 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor + +from .. import ( + CONF_EBUS_ID, + CONF_TELEGRAM, + CONF_DECODE, + ebus_ns, + create_telegram_schema, + sensor_base_config, +) + +AUTO_LOAD = ["ebus"] + +EbusBinarySensor = ebus_ns.class_( + "EbusBinarySensor", binary_sensor.BinarySensor, cg.Component +) + +CONF_MASK = "mask" + +CONFIG_SCHEMA = ( + binary_sensor.binary_sensor_schema(EbusBinarySensor).extend( + create_telegram_schema( + {cv.Optional(CONF_MASK, default=0xFF): cv.int_range(1, 255)} + ) + ) +).extend(cv.COMPONENT_SCHEMA) + + +async def to_code(config): + ebus = await cg.get_variable(config[CONF_EBUS_ID]) + sens = await binary_sensor.new_binary_sensor(config) + + sensor_base_config(sens, config) + cg.add(sens.set_response_read_mask(config[CONF_TELEGRAM][CONF_DECODE][CONF_MASK])) + + cg.add(ebus.add_receiver(sens)) + cg.add(ebus.add_sender(sens)) diff --git a/esphome/components/ebus/binary_sensor/ebus_binary_sensor.cpp b/esphome/components/ebus/binary_sensor/ebus_binary_sensor.cpp new file mode 100644 index 0000000000..e8502c6061 --- /dev/null +++ b/esphome/components/ebus/binary_sensor/ebus_binary_sensor.cpp @@ -0,0 +1,16 @@ + +#include "ebus_binary_sensor.h" + +namespace esphome { +namespace ebus { + +void EbusBinarySensor::process_received(Telegram telegram) { + if (!is_mine(telegram)) { + return; + } + uint8_t result = (uint8_t) this->get_response_bytes(telegram, this->response_position_, 1); + this->publish_state(result & this->mask_); +} + +} // namespace ebus +} // namespace esphome diff --git a/esphome/components/ebus/binary_sensor/ebus_binary_sensor.h b/esphome/components/ebus/binary_sensor/ebus_binary_sensor.h new file mode 100644 index 0000000000..a1bef3f8ae --- /dev/null +++ b/esphome/components/ebus/binary_sensor/ebus_binary_sensor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../ebus_sensor_base.h" +#include "esphome/components/binary_sensor/binary_sensor.h" + +namespace esphome { +namespace ebus { + +class EbusBinarySensor : public EbusSensorBase, public binary_sensor::BinarySensor { + public: + EbusBinarySensor() {} + + void set_response_read_mask(uint8_t mask) { this->mask_ = mask; }; + + void process_received(Telegram /*telegram*/) override; + + protected: + int8_t mask_; +}; + +} // namespace ebus +} // namespace esphome diff --git a/esphome/components/ebus/ebus_sensor_base.cpp b/esphome/components/ebus/ebus_sensor_base.cpp new file mode 100644 index 0000000000..ff5bf3234d --- /dev/null +++ b/esphome/components/ebus/ebus_sensor_base.cpp @@ -0,0 +1,59 @@ + +#include "ebus_sensor_base.h" + +namespace esphome { +namespace ebus { + +void EbusSensorBase::dump_config() { + ESP_LOGCONFIG(TAG, "EbusSensor"); + ESP_LOGCONFIG(TAG, " message:"); + ESP_LOGCONFIG(TAG, " send_poll: %s", this->send_poll_ ? "true" : "false"); + if (this->address_ == SYN) { + ESP_LOGCONFIG(TAG, " address: N/A"); + } else { + ESP_LOGCONFIG(TAG, " address: 0x%02x", this->address_); + } + ESP_LOGCONFIG(TAG, " command: 0x%04x", this->command_); +}; + +void EbusSensorBase::set_send_poll(bool send_poll) { this->send_poll_ = send_poll; } +void EbusSensorBase::set_command(uint16_t command) { this->command_ = command; } +void EbusSensorBase::set_payload(const std::vector &payload) { this->payload_ = payload; } +void EbusSensorBase::set_response_read_position(uint8_t response_position) { this->response_position_ = response_position; } + +optional EbusSensorBase::prepare_command() { + optional command; + + if (this->send_poll_) { + command = SendCommand( // + this->primary_address_, this->address_, this->command_, + this->payload_.size(), &this->payload_[0]); + } + return command; +} + +uint32_t EbusSensorBase::get_response_bytes(Telegram &telegram, uint8_t start, uint8_t length) { + uint32_t result = 0; + for (uint8_t i = 0; i < 4 && i < length; i++) { + result = result | (telegram.get_response_byte(start + i) << (i * 8)); + } + return result; +} + +bool EbusSensorBase::is_mine(Telegram &telegram) { + if (this->address_ != SYN && this->address_ != telegram.get_zz()) { + return false; + } + if (telegram.get_command() != this->command_) { + return false; + } + for (int i = 0; i < this->payload_.size(); i++) { + if (this->payload_[i] != telegram.get_request_byte(i)) { + return false; + } + } + return true; +} + +} // namespace ebus +} // namespace esphome diff --git a/esphome/components/ebus/ebus_sensor_base.h b/esphome/components/ebus/ebus_sensor_base.h new file mode 100644 index 0000000000..1f55220986 --- /dev/null +++ b/esphome/components/ebus/ebus_sensor_base.h @@ -0,0 +1,33 @@ +#pragma once + +#include "ebus_component.h" +#include + +namespace esphome { +namespace ebus { + +class EbusSensorBase : public EbusReceiver, public EbusSender, public Component { + public: + void dump_config() override; + + void set_send_poll(bool /*send_poll*/); + void set_command(uint16_t /*command*/); + void set_payload(const std::vector & /*payload*/); + + void set_response_read_position(uint8_t /*response_position*/); + + optional prepare_command() override; + + // TODO: refactor these + uint32_t get_response_bytes(Telegram &telegram, uint8_t start, uint8_t length); + bool is_mine(Telegram &telegram); + + protected: + bool send_poll_; + uint16_t command_; + std::vector payload_{}; + uint8_t response_position_; +}; + +} // namespace ebus +} // namespace esphome