From e9073f7298f70cf85efb095a7898a4672511b3e0 Mon Sep 17 00:00:00 2001 From: Mat931 <49403702+Mat931@users.noreply.github.com> Date: Sun, 11 Oct 2026 17:38:37 +0000 Subject: [PATCH] [systa_bus] Add text_sensor (#20518) Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- esphome/components/systa_bus/__init__.py | 2 + .../components/systa_bus/sensor/__init__.py | 9 +++- esphome/components/systa_bus/systa_bus.h | 3 +- .../systa_bus/text_sensor/__init__.py | 45 +++++++++++++++++++ .../text_sensor/systa_bus_text_sensor.cpp | 27 +++++++++++ .../text_sensor/systa_bus_text_sensor.h | 20 +++++++++ esphome/core/defines.h | 2 +- tests/components/systa_bus/common.yaml | 6 +++ 8 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 esphome/components/systa_bus/text_sensor/__init__.py create mode 100644 esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.cpp create mode 100644 esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.h diff --git a/esphome/components/systa_bus/__init__.py b/esphome/components/systa_bus/__init__.py index 49ac214d400..ae44017112b 100644 --- a/esphome/components/systa_bus/__init__.py +++ b/esphome/components/systa_bus/__init__.py @@ -17,6 +17,8 @@ SystaBus = systa_bus_ns.class_("SystaBus", cg.Component, uart.UARTDevice) CONF_SYSTA_BUS_ID = "systa_bus_id" +CONF_SYSTASOLAR_AQUA = "systasolar_aqua" + CONFIG_SCHEMA = uart.UART_DEVICE_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(SystaBus), diff --git a/esphome/components/systa_bus/sensor/__init__.py b/esphome/components/systa_bus/sensor/__init__.py index 3def5fba12f..e4aa0684c78 100644 --- a/esphome/components/systa_bus/sensor/__init__.py +++ b/esphome/components/systa_bus/sensor/__init__.py @@ -13,11 +13,16 @@ from esphome.const import ( ) from esphome.types import ConfigType -from .. import CONF_SYSTA_BUS_ID, SystaBus, register_systa_bus_listener, systa_bus_ns +from .. import ( + CONF_SYSTA_BUS_ID, + CONF_SYSTASOLAR_AQUA, + SystaBus, + register_systa_bus_listener, + systa_bus_ns, +) SystaSolarAquaSensor = systa_bus_ns.class_("SystaSolarAquaSensor", cg.Component) -CONF_SYSTASOLAR_AQUA = "systasolar_aqua" CONF_TEMPERATURE_TSA = "temperature_tsa" CONF_TEMPERATURE_TSE = "temperature_tse" CONF_TEMPERATURE_TWU = "temperature_twu" diff --git a/esphome/components/systa_bus/systa_bus.h b/esphome/components/systa_bus/systa_bus.h index 99ca31590f5..b46f769db00 100644 --- a/esphome/components/systa_bus/systa_bus.h +++ b/esphome/components/systa_bus/systa_bus.h @@ -14,7 +14,8 @@ static constexpr uint8_t START_BYTE = 0xfc; static constexpr uint8_t FRAME_OVERHEAD = 3; // start byte, length, checksum // SystaSolar Aqua sensor data, 25 bytes: [0..1] type, [2..3] not decoded, big-endian int16 in 0.1 degrees at -// [4..5] TSA, [6..7] TSE, [8..9] TWU and [10..11] TW2, pump speed in percent at [12], [13..23] not decoded. +// [4..5] TSA, [6..7] TSE, [8..9] TWU and [10..11] TW2, pump speed in percent at [12], [13..14] not decoded, +// [15] error code (zero for no error), [16..23] not decoded. static constexpr uint16_t MESSAGE_TYPE_AQUA_SENSOR_DATA = 0xfc16; // The bus only buffers known message types, so the buffer is sized by the longest of them diff --git a/esphome/components/systa_bus/text_sensor/__init__.py b/esphome/components/systa_bus/text_sensor/__init__.py new file mode 100644 index 00000000000..4b5cb52b087 --- /dev/null +++ b/esphome/components/systa_bus/text_sensor/__init__.py @@ -0,0 +1,45 @@ +import esphome.codegen as cg +from esphome.components import text_sensor +import esphome.config_validation as cv +from esphome.const import CONF_ID, CONF_MODEL +from esphome.types import ConfigType + +from .. import ( + CONF_SYSTA_BUS_ID, + CONF_SYSTASOLAR_AQUA, + SystaBus, + register_systa_bus_listener, + systa_bus_ns, +) + +SystaSolarAquaTextSensor = systa_bus_ns.class_("SystaSolarAquaTextSensor", cg.Component) + +CONF_ERROR_CODE = "error_code" + + +CONFIG_SCHEMA = cv.typed_schema( + { + CONF_SYSTASOLAR_AQUA: cv.COMPONENT_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(SystaSolarAquaTextSensor), + cv.GenerateID(CONF_SYSTA_BUS_ID): cv.use_id(SystaBus), + cv.Optional(CONF_ERROR_CODE): text_sensor.text_sensor_schema(), + } + ), + }, + key=CONF_MODEL, + lower=True, + space="_", +) + + +async def to_code(config: ConfigType) -> None: + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + if config[CONF_MODEL] == CONF_SYSTASOLAR_AQUA and CONF_ERROR_CODE in config: + sens = await text_sensor.new_text_sensor(config[CONF_ERROR_CODE]) + cg.add(var.set_error_code_text_sensor(sens)) + + systa_bus = await cg.get_variable(config[CONF_SYSTA_BUS_ID]) + await register_systa_bus_listener(systa_bus, var) diff --git a/esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.cpp b/esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.cpp new file mode 100644 index 00000000000..cba3caa8a6d --- /dev/null +++ b/esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.cpp @@ -0,0 +1,27 @@ +#include "systa_bus_text_sensor.h" +#include "esphome/core/log.h" + +namespace esphome::systa_bus { + +ESPHOME_LOG_TAG(TAG, "systa_bus.text_sensor"); + +void SystaSolarAquaTextSensor::dump_config() { + ESP_LOGCONFIG(TAG, "SystaSolar Aqua:"); + LOG_TEXT_SENSOR(" ", "Error code", this->error_code_text_sensor_); +} + +void SystaSolarAquaTextSensor::handle_message(std::span message) { + if (get_message_type(message) == MESSAGE_TYPE_AQUA_SENSOR_DATA) { + if (this->error_code_text_sensor_ != nullptr) { + if (message[15] == 0) { + this->error_code_text_sensor_->publish_state("--"); + } else { + char buf[4]; + int len = snprintf(buf, sizeof(buf), "%02d", message[15]); + this->error_code_text_sensor_->publish_state(buf, static_cast(len)); + } + } + } +} + +} // namespace esphome::systa_bus diff --git a/esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.h b/esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.h new file mode 100644 index 00000000000..f0c12b5dce5 --- /dev/null +++ b/esphome/components/systa_bus/text_sensor/systa_bus_text_sensor.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../systa_bus.h" +#include "esphome/components/text_sensor/text_sensor.h" + +#include + +namespace esphome::systa_bus { + +class SystaSolarAquaTextSensor : public SystaBusListener, public Component { + public: + void dump_config() override; + void set_error_code_text_sensor(text_sensor::TextSensor *sensor) { this->error_code_text_sensor_ = sensor; } + void handle_message(std::span message) override; + + protected: + text_sensor::TextSensor *error_code_text_sensor_{nullptr}; +}; + +} // namespace esphome::systa_bus diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 0e5e2f4f292..de621f891a1 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -188,7 +188,7 @@ #define USE_REMOTE_PROTOCOL_SYMPHONY #define USE_REMOTE_PROTOCOL_TOSHIBA_AC #define USE_REMOTE_PROTOCOL_TOTO -#define SYSTA_BUS_LISTENER_COUNT 1 +#define SYSTA_BUS_LISTENER_COUNT 2 #define SERIAL_PROXY_COUNT 2 #define SNTP_SERVER_COUNT 3 #define USE_MEDIA_PLAYER diff --git a/tests/components/systa_bus/common.yaml b/tests/components/systa_bus/common.yaml index ea97e2d840b..b4ae2410fde 100644 --- a/tests/components/systa_bus/common.yaml +++ b/tests/components/systa_bus/common.yaml @@ -13,3 +13,9 @@ sensor: name: TW2 pump_speed: name: Pump Speed + +text_sensor: + - platform: systa_bus + model: systasolar_aqua + error_code: + name: Error Code