esphome 2024.10.3__py3-none-any.whl → 2024.11.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +22 -4
- esphome/automation.py +29 -2
- esphome/components/animation/__init__.py +5 -8
- esphome/components/animation/animation.cpp +1 -1
- esphome/components/audio/__init__.py +9 -0
- esphome/components/audio/audio.h +21 -0
- esphome/components/axs15231/__init__.py +6 -0
- esphome/components/axs15231/touchscreen/__init__.py +36 -0
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +64 -0
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.h +27 -0
- esphome/components/bme68x_bsec2/__init__.py +1 -1
- esphome/components/bytebuffer/__init__.py +5 -0
- esphome/components/bytebuffer/bytebuffer.h +421 -0
- esphome/components/climate/__init__.py +14 -13
- esphome/components/datetime/__init__.py +3 -3
- esphome/components/debug/debug_esp32.cpp +16 -8
- esphome/components/dfplayer/dfplayer.cpp +132 -6
- esphome/components/dfplayer/dfplayer.h +19 -53
- esphome/components/display/display.cpp +142 -0
- esphome/components/display/display.h +7 -0
- esphome/components/es8311/__init__.py +0 -0
- esphome/components/es8311/audio_dac.py +70 -0
- esphome/components/es8311/es8311.cpp +227 -0
- esphome/components/es8311/es8311.h +135 -0
- esphome/components/es8311/es8311_const.h +195 -0
- esphome/components/esp32/boards.py +199 -1
- esphome/components/esp32/gpio.py +3 -1
- esphome/components/esp32_ble/const_esp32c6.h +7 -0
- esphome/components/esp32_ble_client/ble_client_base.h +1 -1
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +2 -2
- esphome/components/esp32_rmt_led_strip/led_strip.h +2 -0
- esphome/components/esp32_rmt_led_strip/light.py +3 -1
- esphome/components/esp8266/gpio.py +7 -5
- esphome/components/ethernet/__init__.py +55 -1
- esphome/components/ethernet/ethernet_component.cpp +14 -1
- esphome/components/ethernet/ethernet_component.h +7 -1
- esphome/components/font/__init__.py +213 -108
- esphome/components/gp8403/output/__init__.py +1 -1
- esphome/components/host/gpio.py +6 -4
- esphome/components/http_request/__init__.py +12 -0
- esphome/components/http_request/http_request.h +65 -3
- esphome/components/http_request/http_request_arduino.cpp +2 -3
- esphome/components/http_request/http_request_idf.cpp +6 -14
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +1 -1
- esphome/components/i2c_device/__init__.py +26 -0
- esphome/components/i2c_device/i2c_device.cpp +17 -0
- esphome/components/i2c_device/i2c_device.h +18 -0
- esphome/components/i2s_audio/__init__.py +1 -3
- esphome/components/i2s_audio/speaker/__init__.py +12 -4
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +432 -197
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +91 -32
- esphome/components/ili9xxx/display.py +5 -1
- esphome/components/image/__init__.py +5 -8
- esphome/components/image/image.cpp +14 -14
- esphome/components/image/image.h +20 -24
- esphome/components/internal_temperature/internal_temperature.cpp +51 -2
- esphome/components/internal_temperature/internal_temperature.h +1 -0
- esphome/components/libretiny/gpio.py +4 -2
- esphome/components/light/__init__.py +32 -1
- esphome/components/light/automation.py +39 -32
- esphome/components/light/effects.py +36 -36
- esphome/components/light/light_state.cpp +6 -16
- esphome/components/light/light_state.h +34 -0
- esphome/components/light/types.py +3 -1
- esphome/components/logger/logger_esp32.cpp +15 -0
- esphome/components/lvgl/__init__.py +202 -95
- esphome/components/lvgl/automation.py +42 -40
- esphome/components/lvgl/binary_sensor/__init__.py +8 -15
- esphome/components/lvgl/defines.py +14 -8
- esphome/components/lvgl/encoders.py +11 -8
- esphome/components/lvgl/keypads.py +77 -0
- esphome/components/lvgl/light/__init__.py +6 -8
- esphome/components/lvgl/lv_validation.py +2 -4
- esphome/components/lvgl/lvcode.py +3 -9
- esphome/components/lvgl/lvgl_esphome.cpp +210 -89
- esphome/components/lvgl/lvgl_esphome.h +113 -30
- esphome/components/lvgl/lvgl_proxy.h +17 -0
- esphome/components/lvgl/number/__init__.py +10 -15
- esphome/components/lvgl/schemas.py +4 -2
- esphome/components/lvgl/select/__init__.py +12 -37
- esphome/components/lvgl/select/lvgl_select.h +27 -33
- esphome/components/lvgl/sensor/__init__.py +8 -14
- esphome/components/lvgl/styles.py +3 -4
- esphome/components/lvgl/switch/__init__.py +8 -13
- esphome/components/lvgl/text/__init__.py +5 -6
- esphome/components/lvgl/text_sensor/__init__.py +15 -15
- esphome/components/lvgl/touchscreens.py +2 -3
- esphome/components/lvgl/trigger.py +7 -9
- esphome/components/lvgl/types.py +9 -3
- esphome/components/lvgl/widgets/__init__.py +32 -21
- esphome/components/lvgl/widgets/dropdown.py +22 -10
- esphome/components/lvgl/widgets/msgbox.py +6 -5
- esphome/components/lvgl/widgets/obj.py +4 -2
- esphome/components/lvgl/widgets/page.py +3 -2
- esphome/components/lvgl/widgets/qrcode.py +54 -0
- esphome/components/lvgl/widgets/roller.py +21 -14
- esphome/components/lvgl/widgets/tileview.py +2 -1
- esphome/components/max17043/__init__.py +1 -0
- esphome/components/max17043/automation.h +20 -0
- esphome/components/max17043/max17043.cpp +98 -0
- esphome/components/max17043/max17043.h +29 -0
- esphome/components/max17043/sensor.py +77 -0
- esphome/components/media_player/__init__.py +11 -0
- esphome/components/media_player/automation.h +10 -0
- esphome/components/media_player/media_player.cpp +4 -0
- esphome/components/midea/air_conditioner.cpp +17 -1
- esphome/components/mlx90393/sensor.py +1 -1
- esphome/components/modbus_controller/__init__.py +31 -1
- esphome/components/modbus_controller/automation.h +16 -0
- esphome/components/modbus_controller/const.py +2 -0
- esphome/components/modbus_controller/modbus_controller.cpp +14 -2
- esphome/components/modbus_controller/modbus_controller.h +9 -0
- esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +40 -21
- esphome/components/mopeka_pro_check/mopeka_pro_check.h +9 -2
- esphome/components/mopeka_pro_check/sensor.py +41 -0
- esphome/components/mqtt/__init__.py +36 -0
- esphome/components/mqtt/mqtt_client.cpp +27 -3
- esphome/components/mqtt/mqtt_client.h +27 -2
- esphome/components/mqtt/mqtt_climate.cpp +4 -2
- esphome/components/mqtt/mqtt_component.cpp +6 -0
- esphome/components/mqtt/mqtt_component.h +4 -0
- esphome/components/mqtt/mqtt_const.h +6 -0
- esphome/components/online_image/online_image.cpp +2 -8
- esphome/components/online_image/online_image.h +2 -6
- esphome/components/opentherm/__init__.py +35 -9
- esphome/components/opentherm/binary_sensor/__init__.py +33 -0
- esphome/components/opentherm/const.py +11 -0
- esphome/components/opentherm/generate.py +142 -0
- esphome/components/opentherm/hub.cpp +130 -24
- esphome/components/opentherm/hub.h +62 -9
- esphome/components/opentherm/input.h +18 -0
- esphome/components/opentherm/input.py +51 -0
- esphome/components/opentherm/number/__init__.py +74 -0
- esphome/components/opentherm/number/number.cpp +40 -0
- esphome/components/opentherm/number/number.h +31 -0
- esphome/components/opentherm/opentherm.cpp +30 -0
- esphome/components/opentherm/opentherm.h +34 -2
- esphome/components/opentherm/opentherm_macros.h +151 -0
- esphome/components/opentherm/output/__init__.py +47 -0
- esphome/components/opentherm/output/output.cpp +18 -0
- esphome/components/opentherm/output/output.h +33 -0
- esphome/components/opentherm/schema.py +814 -0
- esphome/components/opentherm/sensor/__init__.py +51 -0
- esphome/components/opentherm/switch/__init__.py +43 -0
- esphome/components/opentherm/switch/switch.cpp +28 -0
- esphome/components/opentherm/switch/switch.h +20 -0
- esphome/components/opentherm/validate.py +31 -0
- esphome/components/pcd8544/display.py +8 -4
- esphome/components/prometheus/prometheus_handler.cpp +176 -14
- esphome/components/prometheus/prometheus_handler.h +25 -7
- esphome/components/qspi_amoled/display.py +1 -141
- esphome/components/qspi_dbi/display.py +185 -0
- esphome/components/qspi_dbi/models.py +64 -0
- esphome/components/{qspi_amoled/qspi_amoled.cpp → qspi_dbi/qspi_dbi.cpp} +95 -46
- esphome/components/{qspi_amoled/qspi_amoled.h → qspi_dbi/qspi_dbi.h} +26 -15
- esphome/components/rp2040/__init__.py +6 -3
- esphome/components/rp2040/gpio.py +5 -3
- esphome/components/rtttl/rtttl.cpp +4 -1
- esphome/components/rtttl/rtttl.h +1 -0
- esphome/components/sdl/sdl_esphome.cpp +22 -5
- esphome/components/sdl/sdl_esphome.h +1 -0
- esphome/components/sensor/__init__.py +18 -8
- esphome/components/sensor/filter.cpp +19 -18
- esphome/components/sensor/filter.h +9 -10
- esphome/components/sgp4x/sgp4x.cpp +40 -74
- esphome/components/sgp4x/sgp4x.h +5 -3
- esphome/components/speaker/__init__.py +51 -5
- esphome/components/speaker/automation.h +25 -0
- esphome/components/speaker/speaker.h +72 -1
- esphome/components/spi/__init__.py +15 -14
- esphome/components/spi_device/__init__.py +4 -15
- esphome/components/ssd1306_spi/display.py +6 -2
- esphome/components/ssd1322_spi/display.py +6 -2
- esphome/components/ssd1325_spi/display.py +6 -2
- esphome/components/ssd1327_spi/display.py +6 -2
- esphome/components/ssd1331_spi/display.py +6 -2
- esphome/components/ssd1351_spi/display.py +6 -2
- esphome/components/st7567_spi/display.py +6 -2
- esphome/components/st7701s/display.py +5 -1
- esphome/components/st7735/display.py +10 -5
- esphome/components/st7789v/display.py +12 -7
- esphome/components/statsd/statsd.cpp +2 -0
- esphome/components/statsd/statsd.h +2 -0
- esphome/components/sun/sun.h +3 -0
- esphome/components/tc74/__init__.py +1 -0
- esphome/components/tc74/sensor.py +32 -0
- esphome/components/tc74/tc74.cpp +68 -0
- esphome/components/tc74/tc74.h +28 -0
- esphome/components/touchscreen/__init__.py +41 -50
- esphome/components/touchscreen/touchscreen.h +4 -8
- esphome/components/udp/udp_component.cpp +6 -3
- esphome/components/udp/udp_component.h +4 -2
- esphome/components/waveshare_epaper/display.py +6 -2
- esphome/components/web_server/web_server.cpp +22 -0
- esphome/components/web_server/web_server.h +3 -0
- esphome/components/weikai/weikai.h +2 -2
- esphome/components/wifi/wifi_component.cpp +2 -2
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +4 -4
- esphome/components/wifi/wifi_component_esp_idf.cpp +2 -2
- esphome/components/xpt2046/touchscreen/__init__.py +7 -32
- esphome/config_validation.py +3 -1
- esphome/const.py +8 -1
- esphome/core/defines.h +8 -2
- esphome/core/helpers.cpp +32 -17
- esphome/core/helpers.h +32 -16
- esphome/core/ring_buffer.cpp +2 -2
- esphome/core/ring_buffer.h +2 -2
- esphome/dashboard/core.py +25 -0
- esphome/dashboard/status/mdns.py +3 -4
- esphome/dashboard/web_server.py +54 -19
- esphome/espota2.py +36 -35
- esphome/helpers.py +68 -16
- esphome/mqtt.py +9 -2
- esphome/storage_json.py +4 -0
- esphome/writer.py +7 -18
- esphome/zeroconf.py +8 -6
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/METADATA +7 -5
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/RECORD +226 -180
- esphome/core/bytebuffer.cpp +0 -167
- esphome/core/bytebuffer.h +0 -144
- /esphome/components/{qspi_amoled → qspi_dbi}/__init__.py +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/LICENSE +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/WHEEL +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/top_level.txt +0 -0
@@ -215,16 +215,10 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) {
|
|
215
215
|
}
|
216
216
|
case ImageType::IMAGE_TYPE_RGB565: {
|
217
217
|
uint16_t col565 = display::ColorUtil::color_to_565(color);
|
218
|
-
if (this->has_transparency()) {
|
219
|
-
if (col565 == 0x0020) {
|
220
|
-
col565 = 0;
|
221
|
-
}
|
222
|
-
if (color.w < 0x80) {
|
223
|
-
col565 = 0x0020;
|
224
|
-
}
|
225
|
-
}
|
226
218
|
this->buffer_[pos + 0] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
|
227
219
|
this->buffer_[pos + 1] = static_cast<uint8_t>(col565 & 0xFF);
|
220
|
+
if (this->has_transparency())
|
221
|
+
this->buffer_[pos + 2] = color.w;
|
228
222
|
break;
|
229
223
|
}
|
230
224
|
case ImageType::IMAGE_TYPE_RGBA: {
|
@@ -86,13 +86,9 @@ class OnlineImage : public PollingComponent,
|
|
86
86
|
Allocator allocator_{Allocator::Flags::ALLOW_FAILURE};
|
87
87
|
|
88
88
|
uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); }
|
89
|
-
int get_buffer_size_(int width, int height) const {
|
90
|
-
return std::ceil(image::image_type_to_bpp(this->type_) * width * height / 8.0);
|
91
|
-
}
|
89
|
+
int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; }
|
92
90
|
|
93
|
-
int get_position_(int x, int y) const {
|
94
|
-
return ((x + y * this->buffer_width_) * image::image_type_to_bpp(this->type_)) / 8;
|
95
|
-
}
|
91
|
+
int get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; }
|
96
92
|
|
97
93
|
ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; }
|
98
94
|
|
@@ -1,9 +1,11 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
|
-
from esphome import pins
|
4
3
|
import esphome.codegen as cg
|
5
4
|
import esphome.config_validation as cv
|
5
|
+
from esphome import pins
|
6
|
+
from esphome.components import sensor
|
6
7
|
from esphome.const import CONF_ID, PLATFORM_ESP32, PLATFORM_ESP8266
|
8
|
+
from . import const, schema, validate, generate
|
7
9
|
|
8
10
|
CODEOWNERS = ["@olegtarasov"]
|
9
11
|
MULTI_CONF = True
|
@@ -15,15 +17,15 @@ CONF_DHW_ENABLE = "dhw_enable"
|
|
15
17
|
CONF_COOLING_ENABLE = "cooling_enable"
|
16
18
|
CONF_OTC_ACTIVE = "otc_active"
|
17
19
|
CONF_CH2_ACTIVE = "ch2_active"
|
20
|
+
CONF_SUMMER_MODE_ACTIVE = "summer_mode_active"
|
21
|
+
CONF_DHW_BLOCK = "dhw_block"
|
18
22
|
CONF_SYNC_MODE = "sync_mode"
|
19
|
-
|
20
|
-
opentherm_ns = cg.esphome_ns.namespace("opentherm")
|
21
|
-
OpenthermHub = opentherm_ns.class_("OpenthermHub", cg.Component)
|
23
|
+
CONF_OPENTHERM_VERSION = "opentherm_version"
|
22
24
|
|
23
25
|
CONFIG_SCHEMA = cv.All(
|
24
26
|
cv.Schema(
|
25
27
|
{
|
26
|
-
cv.GenerateID(): cv.declare_id(OpenthermHub),
|
28
|
+
cv.GenerateID(): cv.declare_id(generate.OpenthermHub),
|
27
29
|
cv.Required(CONF_IN_PIN): pins.internal_gpio_input_pin_schema,
|
28
30
|
cv.Required(CONF_OUT_PIN): pins.internal_gpio_output_pin_schema,
|
29
31
|
cv.Optional(CONF_CH_ENABLE, True): cv.boolean,
|
@@ -31,16 +33,23 @@ CONFIG_SCHEMA = cv.All(
|
|
31
33
|
cv.Optional(CONF_COOLING_ENABLE, False): cv.boolean,
|
32
34
|
cv.Optional(CONF_OTC_ACTIVE, False): cv.boolean,
|
33
35
|
cv.Optional(CONF_CH2_ACTIVE, False): cv.boolean,
|
36
|
+
cv.Optional(CONF_SUMMER_MODE_ACTIVE, False): cv.boolean,
|
37
|
+
cv.Optional(CONF_DHW_BLOCK, False): cv.boolean,
|
34
38
|
cv.Optional(CONF_SYNC_MODE, False): cv.boolean,
|
39
|
+
cv.Optional(CONF_OPENTHERM_VERSION): cv.positive_float,
|
35
40
|
}
|
36
|
-
)
|
41
|
+
)
|
42
|
+
.extend(
|
43
|
+
validate.create_entities_schema(
|
44
|
+
schema.INPUTS, (lambda _: cv.use_id(sensor.Sensor))
|
45
|
+
)
|
46
|
+
)
|
47
|
+
.extend(cv.COMPONENT_SCHEMA),
|
37
48
|
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]),
|
38
49
|
)
|
39
50
|
|
40
51
|
|
41
52
|
async def to_code(config: dict[str, Any]) -> None:
|
42
|
-
# Create the hub, passing the two callbacks defined below
|
43
|
-
# Since the hub is used in the callbacks, we need to define it first
|
44
53
|
var = cg.new_Pvariable(config[CONF_ID])
|
45
54
|
await cg.register_component(var, config)
|
46
55
|
|
@@ -52,6 +61,23 @@ async def to_code(config: dict[str, Any]) -> None:
|
|
52
61
|
cg.add(var.set_out_pin(out_pin))
|
53
62
|
|
54
63
|
non_sensors = {CONF_ID, CONF_IN_PIN, CONF_OUT_PIN}
|
64
|
+
input_sensors = []
|
55
65
|
for key, value in config.items():
|
56
|
-
if key
|
66
|
+
if key in non_sensors:
|
67
|
+
continue
|
68
|
+
if key in schema.INPUTS:
|
69
|
+
input_sensor = await cg.get_variable(value)
|
70
|
+
cg.add(
|
71
|
+
getattr(var, f"set_{key}_{const.INPUT_SENSOR.lower()}")(input_sensor)
|
72
|
+
)
|
73
|
+
input_sensors.append(key)
|
74
|
+
else:
|
57
75
|
cg.add(getattr(var, f"set_{key}")(value))
|
76
|
+
|
77
|
+
if len(input_sensors) > 0:
|
78
|
+
generate.define_has_component(const.INPUT_SENSOR, input_sensors)
|
79
|
+
generate.define_message_handler(
|
80
|
+
const.INPUT_SENSOR, input_sensors, schema.INPUTS
|
81
|
+
)
|
82
|
+
generate.define_readers(const.INPUT_SENSOR, input_sensors)
|
83
|
+
generate.add_messages(var, input_sensors, schema.INPUTS)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
import esphome.config_validation as cv
|
4
|
+
from esphome.components import binary_sensor
|
5
|
+
from .. import const, schema, validate, generate
|
6
|
+
|
7
|
+
DEPENDENCIES = [const.OPENTHERM]
|
8
|
+
COMPONENT_TYPE = const.BINARY_SENSOR
|
9
|
+
|
10
|
+
|
11
|
+
def get_entity_validation_schema(entity: schema.BinarySensorSchema) -> cv.Schema:
|
12
|
+
return binary_sensor.binary_sensor_schema(
|
13
|
+
device_class=(
|
14
|
+
entity.device_class
|
15
|
+
or binary_sensor._UNDEF # pylint: disable=protected-access
|
16
|
+
),
|
17
|
+
icon=(entity.icon or binary_sensor._UNDEF), # pylint: disable=protected-access
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
CONFIG_SCHEMA = validate.create_component_schema(
|
22
|
+
schema.BINARY_SENSORS, get_entity_validation_schema
|
23
|
+
)
|
24
|
+
|
25
|
+
|
26
|
+
async def to_code(config: dict[str, Any]) -> None:
|
27
|
+
await generate.component_to_code(
|
28
|
+
COMPONENT_TYPE,
|
29
|
+
schema.BINARY_SENSORS,
|
30
|
+
binary_sensor.BinarySensor,
|
31
|
+
generate.create_only_conf(binary_sensor.new_binary_sensor),
|
32
|
+
config,
|
33
|
+
)
|
@@ -0,0 +1,142 @@
|
|
1
|
+
from collections.abc import Awaitable
|
2
|
+
from typing import Any, Callable
|
3
|
+
|
4
|
+
import esphome.codegen as cg
|
5
|
+
from esphome.const import CONF_ID
|
6
|
+
from . import const
|
7
|
+
from .schema import TSchema
|
8
|
+
|
9
|
+
opentherm_ns = cg.esphome_ns.namespace("opentherm")
|
10
|
+
OpenthermHub = opentherm_ns.class_("OpenthermHub", cg.Component)
|
11
|
+
|
12
|
+
|
13
|
+
def define_has_component(component_type: str, keys: list[str]) -> None:
|
14
|
+
cg.add_define(
|
15
|
+
f"OPENTHERM_{component_type.upper()}_LIST(F, sep)",
|
16
|
+
cg.RawExpression(
|
17
|
+
" sep ".join(map(lambda key: f"F({key}_{component_type.lower()})", keys))
|
18
|
+
),
|
19
|
+
)
|
20
|
+
for key in keys:
|
21
|
+
cg.add_define(f"OPENTHERM_HAS_{component_type.upper()}_{key}")
|
22
|
+
|
23
|
+
|
24
|
+
def define_message_handler(
|
25
|
+
component_type: str, keys: list[str], schemas: dict[str, TSchema]
|
26
|
+
) -> None:
|
27
|
+
# The macros defined here should be able to generate things like this:
|
28
|
+
# // Parsing a message and publishing to sensors
|
29
|
+
# case MessageId::Message:
|
30
|
+
# // Can have multiple sensors here, for example for a Status message with multiple flags
|
31
|
+
# this->thing_binary_sensor->publish_state(parse_flag8_lb_0(response));
|
32
|
+
# this->other_binary_sensor->publish_state(parse_flag8_lb_1(response));
|
33
|
+
# break;
|
34
|
+
# // Building a message for a write request
|
35
|
+
# case MessageId::Message: {
|
36
|
+
# unsigned int data = 0;
|
37
|
+
# data = write_flag8_lb_0(some_input_switch->state, data); // Where input_sensor can also be a number/output/switch
|
38
|
+
# data = write_u8_hb(some_number->state, data);
|
39
|
+
# return opentherm_->build_request_(MessageType::WriteData, MessageId::Message, data);
|
40
|
+
# }
|
41
|
+
|
42
|
+
messages: dict[str, list[tuple[str, str]]] = {}
|
43
|
+
for key in keys:
|
44
|
+
msg = schemas[key].message
|
45
|
+
if msg not in messages:
|
46
|
+
messages[msg] = []
|
47
|
+
messages[msg].append((key, schemas[key].message_data))
|
48
|
+
|
49
|
+
cg.add_define(
|
50
|
+
f"OPENTHERM_{component_type.upper()}_MESSAGE_HANDLERS(MESSAGE, ENTITY, entity_sep, postscript, msg_sep)",
|
51
|
+
cg.RawExpression(
|
52
|
+
" msg_sep ".join(
|
53
|
+
[
|
54
|
+
f"MESSAGE({msg}) "
|
55
|
+
+ " entity_sep ".join(
|
56
|
+
[
|
57
|
+
f"ENTITY({key}_{component_type.lower()}, {msg_data})"
|
58
|
+
for key, msg_data in keys
|
59
|
+
]
|
60
|
+
)
|
61
|
+
+ " postscript"
|
62
|
+
for msg, keys in messages.items()
|
63
|
+
]
|
64
|
+
)
|
65
|
+
),
|
66
|
+
)
|
67
|
+
|
68
|
+
|
69
|
+
def define_readers(component_type: str, keys: list[str]) -> None:
|
70
|
+
for key in keys:
|
71
|
+
cg.add_define(
|
72
|
+
f"OPENTHERM_READ_{key}",
|
73
|
+
cg.RawExpression(f"this->{key}_{component_type.lower()}->state"),
|
74
|
+
)
|
75
|
+
|
76
|
+
|
77
|
+
def add_messages(hub: cg.MockObj, keys: list[str], schemas: dict[str, TSchema]):
|
78
|
+
messages: set[tuple[str, bool]] = set()
|
79
|
+
for key in keys:
|
80
|
+
messages.add((schemas[key].message, schemas[key].keep_updated))
|
81
|
+
for msg, keep_updated in messages:
|
82
|
+
msg_expr = cg.RawExpression(f"esphome::opentherm::MessageId::{msg}")
|
83
|
+
if keep_updated:
|
84
|
+
cg.add(hub.add_repeating_message(msg_expr))
|
85
|
+
else:
|
86
|
+
cg.add(hub.add_initial_message(msg_expr))
|
87
|
+
|
88
|
+
|
89
|
+
def add_property_set(var: cg.MockObj, config_key: str, config: dict[str, Any]) -> None:
|
90
|
+
if config_key in config:
|
91
|
+
cg.add(getattr(var, f"set_{config_key}")(config[config_key]))
|
92
|
+
|
93
|
+
|
94
|
+
Create = Callable[[dict[str, Any], str, cg.MockObj], Awaitable[cg.Pvariable]]
|
95
|
+
|
96
|
+
|
97
|
+
def create_only_conf(
|
98
|
+
create: Callable[[dict[str, Any]], Awaitable[cg.Pvariable]]
|
99
|
+
) -> Create:
|
100
|
+
return lambda conf, _key, _hub: create(conf)
|
101
|
+
|
102
|
+
|
103
|
+
async def component_to_code(
|
104
|
+
component_type: str,
|
105
|
+
schemas: dict[str, TSchema],
|
106
|
+
type: cg.MockObjClass,
|
107
|
+
create: Create,
|
108
|
+
config: dict[str, Any],
|
109
|
+
) -> list[str]:
|
110
|
+
"""Generate the code for each configured component in the schema of a component type.
|
111
|
+
|
112
|
+
Parameters:
|
113
|
+
- component_type: The type of component, e.g. "sensor" or "binary_sensor"
|
114
|
+
- schema_: The schema for that component type, a list of available components
|
115
|
+
- type: The type of the component, e.g. sensor.Sensor or OpenthermOutput
|
116
|
+
- create: A constructor function for the component, which receives the config,
|
117
|
+
the key and the hub and should asynchronously return the new component
|
118
|
+
- config: The configuration for this component type
|
119
|
+
|
120
|
+
Returns: The list of keys for the created components
|
121
|
+
"""
|
122
|
+
cg.add_define(f"OPENTHERM_USE_{component_type.upper()}")
|
123
|
+
|
124
|
+
hub = await cg.get_variable(config[const.CONF_OPENTHERM_ID])
|
125
|
+
|
126
|
+
keys: list[str] = []
|
127
|
+
for key, conf in config.items():
|
128
|
+
if not isinstance(conf, dict):
|
129
|
+
continue
|
130
|
+
id = conf[CONF_ID]
|
131
|
+
if id and id.type == type:
|
132
|
+
entity = await create(conf, key, hub)
|
133
|
+
if const.CONF_DATA_TYPE in conf:
|
134
|
+
schemas[key].message_data = conf[const.CONF_DATA_TYPE]
|
135
|
+
cg.add(getattr(hub, f"set_{key}_{component_type.lower()}")(entity))
|
136
|
+
keys.append(key)
|
137
|
+
|
138
|
+
define_has_component(component_type, keys)
|
139
|
+
define_message_handler(component_type, keys, schemas)
|
140
|
+
add_messages(hub, keys, schemas)
|
141
|
+
|
142
|
+
return keys
|
@@ -7,50 +7,147 @@ namespace esphome {
|
|
7
7
|
namespace opentherm {
|
8
8
|
|
9
9
|
static const char *const TAG = "opentherm";
|
10
|
-
|
11
|
-
OpenthermData
|
10
|
+
namespace message_data {
|
11
|
+
bool parse_flag8_lb_0(OpenthermData &data) { return read_bit(data.valueLB, 0); }
|
12
|
+
bool parse_flag8_lb_1(OpenthermData &data) { return read_bit(data.valueLB, 1); }
|
13
|
+
bool parse_flag8_lb_2(OpenthermData &data) { return read_bit(data.valueLB, 2); }
|
14
|
+
bool parse_flag8_lb_3(OpenthermData &data) { return read_bit(data.valueLB, 3); }
|
15
|
+
bool parse_flag8_lb_4(OpenthermData &data) { return read_bit(data.valueLB, 4); }
|
16
|
+
bool parse_flag8_lb_5(OpenthermData &data) { return read_bit(data.valueLB, 5); }
|
17
|
+
bool parse_flag8_lb_6(OpenthermData &data) { return read_bit(data.valueLB, 6); }
|
18
|
+
bool parse_flag8_lb_7(OpenthermData &data) { return read_bit(data.valueLB, 7); }
|
19
|
+
bool parse_flag8_hb_0(OpenthermData &data) { return read_bit(data.valueHB, 0); }
|
20
|
+
bool parse_flag8_hb_1(OpenthermData &data) { return read_bit(data.valueHB, 1); }
|
21
|
+
bool parse_flag8_hb_2(OpenthermData &data) { return read_bit(data.valueHB, 2); }
|
22
|
+
bool parse_flag8_hb_3(OpenthermData &data) { return read_bit(data.valueHB, 3); }
|
23
|
+
bool parse_flag8_hb_4(OpenthermData &data) { return read_bit(data.valueHB, 4); }
|
24
|
+
bool parse_flag8_hb_5(OpenthermData &data) { return read_bit(data.valueHB, 5); }
|
25
|
+
bool parse_flag8_hb_6(OpenthermData &data) { return read_bit(data.valueHB, 6); }
|
26
|
+
bool parse_flag8_hb_7(OpenthermData &data) { return read_bit(data.valueHB, 7); }
|
27
|
+
uint8_t parse_u8_lb(OpenthermData &data) { return data.valueLB; }
|
28
|
+
uint8_t parse_u8_hb(OpenthermData &data) { return data.valueHB; }
|
29
|
+
int8_t parse_s8_lb(OpenthermData &data) { return (int8_t) data.valueLB; }
|
30
|
+
int8_t parse_s8_hb(OpenthermData &data) { return (int8_t) data.valueHB; }
|
31
|
+
uint16_t parse_u16(OpenthermData &data) { return data.u16(); }
|
32
|
+
uint16_t parse_u8_lb_60(OpenthermData &data) { return data.valueLB * 60; }
|
33
|
+
uint16_t parse_u8_hb_60(OpenthermData &data) { return data.valueHB * 60; }
|
34
|
+
int16_t parse_s16(OpenthermData &data) { return data.s16(); }
|
35
|
+
float parse_f88(OpenthermData &data) { return data.f88(); }
|
36
|
+
|
37
|
+
void write_flag8_lb_0(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 0, value); }
|
38
|
+
void write_flag8_lb_1(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 1, value); }
|
39
|
+
void write_flag8_lb_2(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 2, value); }
|
40
|
+
void write_flag8_lb_3(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 3, value); }
|
41
|
+
void write_flag8_lb_4(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 4, value); }
|
42
|
+
void write_flag8_lb_5(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 5, value); }
|
43
|
+
void write_flag8_lb_6(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 6, value); }
|
44
|
+
void write_flag8_lb_7(const bool value, OpenthermData &data) { data.valueLB = write_bit(data.valueLB, 7, value); }
|
45
|
+
void write_flag8_hb_0(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 0, value); }
|
46
|
+
void write_flag8_hb_1(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 1, value); }
|
47
|
+
void write_flag8_hb_2(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 2, value); }
|
48
|
+
void write_flag8_hb_3(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 3, value); }
|
49
|
+
void write_flag8_hb_4(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 4, value); }
|
50
|
+
void write_flag8_hb_5(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 5, value); }
|
51
|
+
void write_flag8_hb_6(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 6, value); }
|
52
|
+
void write_flag8_hb_7(const bool value, OpenthermData &data) { data.valueHB = write_bit(data.valueHB, 7, value); }
|
53
|
+
void write_u8_lb(const uint8_t value, OpenthermData &data) { data.valueLB = value; }
|
54
|
+
void write_u8_hb(const uint8_t value, OpenthermData &data) { data.valueHB = value; }
|
55
|
+
void write_s8_lb(const int8_t value, OpenthermData &data) { data.valueLB = (uint8_t) value; }
|
56
|
+
void write_s8_hb(const int8_t value, OpenthermData &data) { data.valueHB = (uint8_t) value; }
|
57
|
+
void write_u16(const uint16_t value, OpenthermData &data) { data.u16(value); }
|
58
|
+
void write_s16(const int16_t value, OpenthermData &data) { data.s16(value); }
|
59
|
+
void write_f88(const float value, OpenthermData &data) { data.f88(value); }
|
60
|
+
|
61
|
+
} // namespace message_data
|
62
|
+
|
63
|
+
OpenthermData OpenthermHub::build_request_(MessageId request_id) const {
|
12
64
|
OpenthermData data;
|
13
65
|
data.type = 0;
|
14
66
|
data.id = 0;
|
15
67
|
data.valueHB = 0;
|
16
68
|
data.valueLB = 0;
|
17
69
|
|
18
|
-
//
|
19
|
-
//
|
20
|
-
// It is also included in the macro-generated code below, but that will
|
21
|
-
// never be executed, because we short-circuit it here.
|
70
|
+
// We need this special logic for STATUS message because we have two options for specifying boiler modes:
|
71
|
+
// with static config values in the hub, or with separate switches.
|
22
72
|
if (request_id == MessageId::STATUS) {
|
23
|
-
|
24
|
-
bool
|
25
|
-
bool
|
26
|
-
bool
|
27
|
-
|
73
|
+
// NOLINTBEGIN
|
74
|
+
bool const ch_enabled = this->ch_enable && OPENTHERM_READ_ch_enable && OPENTHERM_READ_t_set > 0.0;
|
75
|
+
bool const dhw_enabled = this->dhw_enable && OPENTHERM_READ_dhw_enable;
|
76
|
+
bool const cooling_enabled =
|
77
|
+
this->cooling_enable && OPENTHERM_READ_cooling_enable && OPENTHERM_READ_cooling_control > 0.0;
|
78
|
+
bool const otc_enabled = this->otc_active && OPENTHERM_READ_otc_active;
|
79
|
+
bool const ch2_enabled = this->ch2_active && OPENTHERM_READ_ch2_active && OPENTHERM_READ_t_set_ch2 > 0.0;
|
80
|
+
bool const summer_mode_is_active = this->summer_mode_active && OPENTHERM_READ_summer_mode_active;
|
81
|
+
bool const dhw_blocked = this->dhw_block && OPENTHERM_READ_dhw_block;
|
82
|
+
// NOLINTEND
|
28
83
|
|
29
84
|
data.type = MessageType::READ_DATA;
|
30
85
|
data.id = MessageId::STATUS;
|
31
|
-
data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4)
|
86
|
+
data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4) |
|
87
|
+
(summer_mode_is_active << 5) | (dhw_blocked << 6);
|
88
|
+
|
89
|
+
return data;
|
90
|
+
}
|
91
|
+
|
92
|
+
// Another special case is OpenTherm version number which is configured at hub level as a constant
|
93
|
+
if (request_id == MessageId::OT_VERSION_CONTROLLER) {
|
94
|
+
data.type = MessageType::WRITE_DATA;
|
95
|
+
data.id = MessageId::OT_VERSION_CONTROLLER;
|
96
|
+
data.f88(this->opentherm_version_);
|
97
|
+
|
98
|
+
return data;
|
99
|
+
}
|
32
100
|
|
33
101
|
// Disable incomplete switch statement warnings, because the cases in each
|
34
102
|
// switch are generated based on the configured sensors and inputs.
|
35
103
|
#pragma GCC diagnostic push
|
36
104
|
#pragma GCC diagnostic ignored "-Wswitch"
|
37
105
|
|
38
|
-
|
39
|
-
|
106
|
+
// Next, we start with the write requests from switches and other inputs,
|
107
|
+
// because we would want to write that data if it is available, rather than
|
108
|
+
// request a read for that type (in the case that both read and write are
|
109
|
+
// supported).
|
110
|
+
switch (request_id) {
|
111
|
+
OPENTHERM_SWITCH_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_WRITE_MESSAGE, OPENTHERM_MESSAGE_WRITE_ENTITY, ,
|
112
|
+
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
113
|
+
OPENTHERM_NUMBER_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_WRITE_MESSAGE, OPENTHERM_MESSAGE_WRITE_ENTITY, ,
|
114
|
+
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
115
|
+
OPENTHERM_OUTPUT_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_WRITE_MESSAGE, OPENTHERM_MESSAGE_WRITE_ENTITY, ,
|
116
|
+
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
117
|
+
OPENTHERM_INPUT_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_WRITE_MESSAGE, OPENTHERM_MESSAGE_WRITE_ENTITY, ,
|
118
|
+
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
119
|
+
}
|
40
120
|
|
121
|
+
// Finally, handle the simple read requests, which only change with the message id.
|
122
|
+
switch (request_id) { OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_READ_MESSAGE, OPENTHERM_IGNORE, , , ) }
|
123
|
+
switch (request_id) {
|
124
|
+
OPENTHERM_BINARY_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_READ_MESSAGE, OPENTHERM_IGNORE, , , )
|
125
|
+
}
|
41
126
|
#pragma GCC diagnostic pop
|
42
127
|
|
43
|
-
|
44
|
-
|
45
|
-
return
|
128
|
+
// And if we get here, a message was requested which somehow wasn't handled.
|
129
|
+
// This shouldn't happen due to the way the defines are configured, so we
|
130
|
+
// log an error and just return a 0 message.
|
131
|
+
ESP_LOGE(TAG, "Tried to create a request with unknown id %d. This should never happen, so please open an issue.",
|
132
|
+
request_id);
|
133
|
+
return {};
|
46
134
|
}
|
47
135
|
|
48
|
-
OpenthermHub::OpenthermHub() : Component() {}
|
136
|
+
OpenthermHub::OpenthermHub() : Component(), in_pin_{}, out_pin_{} {}
|
49
137
|
|
50
138
|
void OpenthermHub::process_response(OpenthermData &data) {
|
51
139
|
ESP_LOGD(TAG, "Received OpenTherm response with id %d (%s)", data.id,
|
52
140
|
this->opentherm_->message_id_to_str((MessageId) data.id));
|
53
141
|
ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(data).c_str());
|
142
|
+
|
143
|
+
switch (data.id) {
|
144
|
+
OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_RESPONSE_MESSAGE, OPENTHERM_MESSAGE_RESPONSE_ENTITY, ,
|
145
|
+
OPENTHERM_MESSAGE_RESPONSE_POSTSCRIPT, )
|
146
|
+
}
|
147
|
+
switch (data.id) {
|
148
|
+
OPENTHERM_BINARY_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_RESPONSE_MESSAGE, OPENTHERM_MESSAGE_RESPONSE_ENTITY, ,
|
149
|
+
OPENTHERM_MESSAGE_RESPONSE_POSTSCRIPT, )
|
150
|
+
}
|
54
151
|
}
|
55
152
|
|
56
153
|
void OpenthermHub::setup() {
|
@@ -67,6 +164,13 @@ void OpenthermHub::setup() {
|
|
67
164
|
// good practice anyway.
|
68
165
|
this->add_repeating_message(MessageId::STATUS);
|
69
166
|
|
167
|
+
// Also ensure that we start communication with the STATUS message
|
168
|
+
this->initial_messages_.insert(this->initial_messages_.begin(), MessageId::STATUS);
|
169
|
+
|
170
|
+
if (this->opentherm_version_ > 0.0f) {
|
171
|
+
this->initial_messages_.insert(this->initial_messages_.begin(), MessageId::OT_VERSION_CONTROLLER);
|
172
|
+
}
|
173
|
+
|
70
174
|
this->current_message_iterator_ = this->initial_messages_.begin();
|
71
175
|
}
|
72
176
|
|
@@ -254,22 +358,24 @@ void OpenthermHub::handle_timeout_error_() {
|
|
254
358
|
this->stop_opentherm_();
|
255
359
|
}
|
256
360
|
|
257
|
-
#define ID(x) x
|
258
|
-
#define SHOW2(x) #x
|
259
|
-
#define SHOW(x) SHOW2(x)
|
260
|
-
|
261
361
|
void OpenthermHub::dump_config() {
|
262
362
|
ESP_LOGCONFIG(TAG, "OpenTherm:");
|
263
363
|
LOG_PIN(" In: ", this->in_pin_);
|
264
364
|
LOG_PIN(" Out: ", this->out_pin_);
|
265
365
|
ESP_LOGCONFIG(TAG, " Sync mode: %d", this->sync_mode_);
|
366
|
+
ESP_LOGCONFIG(TAG, " Sensors: %s", SHOW(OPENTHERM_SENSOR_LIST(ID, )));
|
367
|
+
ESP_LOGCONFIG(TAG, " Binary sensors: %s", SHOW(OPENTHERM_BINARY_SENSOR_LIST(ID, )));
|
368
|
+
ESP_LOGCONFIG(TAG, " Switches: %s", SHOW(OPENTHERM_SWITCH_LIST(ID, )));
|
369
|
+
ESP_LOGCONFIG(TAG, " Input sensors: %s", SHOW(OPENTHERM_INPUT_SENSOR_LIST(ID, )));
|
370
|
+
ESP_LOGCONFIG(TAG, " Outputs: %s", SHOW(OPENTHERM_OUTPUT_LIST(ID, )));
|
371
|
+
ESP_LOGCONFIG(TAG, " Numbers: %s", SHOW(OPENTHERM_NUMBER_LIST(ID, )));
|
266
372
|
ESP_LOGCONFIG(TAG, " Initial requests:");
|
267
373
|
for (auto type : this->initial_messages_) {
|
268
|
-
ESP_LOGCONFIG(TAG, " - %d", type);
|
374
|
+
ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str((type)));
|
269
375
|
}
|
270
376
|
ESP_LOGCONFIG(TAG, " Repeating requests:");
|
271
377
|
for (auto type : this->repeating_messages_) {
|
272
|
-
ESP_LOGCONFIG(TAG, " - %d", type);
|
378
|
+
ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str((type)));
|
273
379
|
}
|
274
380
|
}
|
275
381
|
|
@@ -4,14 +4,37 @@
|
|
4
4
|
#include "esphome/core/hal.h"
|
5
5
|
#include "esphome/core/component.h"
|
6
6
|
#include "esphome/core/log.h"
|
7
|
+
#include <vector>
|
7
8
|
|
8
9
|
#include "opentherm.h"
|
9
10
|
|
11
|
+
#ifdef OPENTHERM_USE_SENSOR
|
12
|
+
#include "esphome/components/sensor/sensor.h"
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifdef OPENTHERM_USE_BINARY_SENSOR
|
16
|
+
#include "esphome/components/binary_sensor/binary_sensor.h"
|
17
|
+
#endif
|
18
|
+
|
19
|
+
#ifdef OPENTHERM_USE_SWITCH
|
20
|
+
#include "esphome/components/opentherm/switch/switch.h"
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#ifdef OPENTHERM_USE_OUTPUT
|
24
|
+
#include "esphome/components/opentherm/output/output.h"
|
25
|
+
#endif
|
26
|
+
|
27
|
+
#ifdef OPENTHERM_USE_NUMBER
|
28
|
+
#include "esphome/components/opentherm/number/number.h"
|
29
|
+
#endif
|
30
|
+
|
10
31
|
#include <memory>
|
11
32
|
#include <unordered_map>
|
12
33
|
#include <unordered_set>
|
13
34
|
#include <functional>
|
14
35
|
|
36
|
+
#include "opentherm_macros.h"
|
37
|
+
|
15
38
|
namespace esphome {
|
16
39
|
namespace opentherm {
|
17
40
|
|
@@ -23,15 +46,27 @@ class OpenthermHub : public Component {
|
|
23
46
|
// The OpenTherm interface
|
24
47
|
std::unique_ptr<OpenTherm> opentherm_;
|
25
48
|
|
49
|
+
OPENTHERM_SENSOR_LIST(OPENTHERM_DECLARE_SENSOR, )
|
50
|
+
|
51
|
+
OPENTHERM_BINARY_SENSOR_LIST(OPENTHERM_DECLARE_BINARY_SENSOR, )
|
52
|
+
|
53
|
+
OPENTHERM_SWITCH_LIST(OPENTHERM_DECLARE_SWITCH, )
|
54
|
+
|
55
|
+
OPENTHERM_NUMBER_LIST(OPENTHERM_DECLARE_NUMBER, )
|
56
|
+
|
57
|
+
OPENTHERM_OUTPUT_LIST(OPENTHERM_DECLARE_OUTPUT, )
|
58
|
+
|
59
|
+
OPENTHERM_INPUT_SENSOR_LIST(OPENTHERM_DECLARE_INPUT_SENSOR, )
|
60
|
+
|
26
61
|
// The set of initial messages to send on starting communication with the boiler
|
27
|
-
std::
|
62
|
+
std::vector<MessageId> initial_messages_;
|
28
63
|
// and the repeating messages which are sent repeatedly to update various sensors
|
29
64
|
// and boiler parameters (like the setpoint).
|
30
|
-
std::
|
65
|
+
std::vector<MessageId> repeating_messages_;
|
31
66
|
// Indicates if we are still working on the initial requests or not
|
32
67
|
bool sending_initial_ = true;
|
33
68
|
// Index for the current request in one of the _requests sets.
|
34
|
-
std::
|
69
|
+
std::vector<MessageId>::const_iterator current_message_iterator_;
|
35
70
|
|
36
71
|
uint32_t last_conversation_start_ = 0;
|
37
72
|
uint32_t last_conversation_end_ = 0;
|
@@ -43,8 +78,10 @@ class OpenthermHub : public Component {
|
|
43
78
|
// Very likely to happen while using Dallas temperature sensors.
|
44
79
|
bool sync_mode_ = false;
|
45
80
|
|
81
|
+
float opentherm_version_ = 0.0f;
|
82
|
+
|
46
83
|
// Create OpenTherm messages based on the message id
|
47
|
-
OpenthermData build_request_(MessageId request_id);
|
84
|
+
OpenthermData build_request_(MessageId request_id) const;
|
48
85
|
void handle_protocol_write_error_();
|
49
86
|
void handle_protocol_read_error_();
|
50
87
|
void handle_timeout_error_();
|
@@ -78,17 +115,30 @@ class OpenthermHub : public Component {
|
|
78
115
|
void set_in_pin(InternalGPIOPin *in_pin) { this->in_pin_ = in_pin; }
|
79
116
|
void set_out_pin(InternalGPIOPin *out_pin) { this->out_pin_ = out_pin; }
|
80
117
|
|
81
|
-
|
82
|
-
|
118
|
+
OPENTHERM_SENSOR_LIST(OPENTHERM_SET_SENSOR, )
|
119
|
+
|
120
|
+
OPENTHERM_BINARY_SENSOR_LIST(OPENTHERM_SET_BINARY_SENSOR, )
|
121
|
+
|
122
|
+
OPENTHERM_SWITCH_LIST(OPENTHERM_SET_SWITCH, )
|
123
|
+
|
124
|
+
OPENTHERM_NUMBER_LIST(OPENTHERM_SET_NUMBER, )
|
125
|
+
|
126
|
+
OPENTHERM_OUTPUT_LIST(OPENTHERM_SET_OUTPUT, )
|
127
|
+
|
128
|
+
OPENTHERM_INPUT_SENSOR_LIST(OPENTHERM_SET_INPUT_SENSOR, )
|
129
|
+
|
130
|
+
// Add a request to the vector of initial requests
|
131
|
+
void add_initial_message(MessageId message_id) { this->initial_messages_.push_back(message_id); }
|
83
132
|
// Add a request to the set of repeating requests. Note that a large number of repeating
|
84
133
|
// requests will slow down communication with the boiler. Each request may take up to 1 second,
|
85
134
|
// so with all sensors enabled, it may take about half a minute before a change in setpoint
|
86
135
|
// will be processed.
|
87
|
-
void add_repeating_message(MessageId message_id) { this->repeating_messages_.
|
136
|
+
void add_repeating_message(MessageId message_id) { this->repeating_messages_.push_back(message_id); }
|
88
137
|
|
89
|
-
// There are
|
138
|
+
// There are seven status variables, which can either be set as a simple variable,
|
90
139
|
// or using a switch. ch_enable and dhw_enable default to true, the others to false.
|
91
|
-
bool ch_enable = true, dhw_enable = true, cooling_enable = false, otc_active = false, ch2_active = false
|
140
|
+
bool ch_enable = true, dhw_enable = true, cooling_enable = false, otc_active = false, ch2_active = false,
|
141
|
+
summer_mode_active = false, dhw_block = false;
|
92
142
|
|
93
143
|
// Setters for the status variables
|
94
144
|
void set_ch_enable(bool value) { this->ch_enable = value; }
|
@@ -96,7 +146,10 @@ class OpenthermHub : public Component {
|
|
96
146
|
void set_cooling_enable(bool value) { this->cooling_enable = value; }
|
97
147
|
void set_otc_active(bool value) { this->otc_active = value; }
|
98
148
|
void set_ch2_active(bool value) { this->ch2_active = value; }
|
149
|
+
void set_summer_mode_active(bool value) { this->summer_mode_active = value; }
|
150
|
+
void set_dhw_block(bool value) { this->dhw_block = value; }
|
99
151
|
void set_sync_mode(bool sync_mode) { this->sync_mode_ = sync_mode; }
|
152
|
+
void set_opentherm_version(float value) { this->opentherm_version_ = value; }
|
100
153
|
|
101
154
|
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
102
155
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
namespace esphome {
|
4
|
+
namespace opentherm {
|
5
|
+
|
6
|
+
class OpenthermInput {
|
7
|
+
public:
|
8
|
+
bool auto_min_value, auto_max_value;
|
9
|
+
|
10
|
+
virtual void set_min_value(float min_value) = 0;
|
11
|
+
virtual void set_max_value(float max_value) = 0;
|
12
|
+
|
13
|
+
virtual void set_auto_min_value(bool auto_min_value) { this->auto_min_value = auto_min_value; }
|
14
|
+
virtual void set_auto_max_value(bool auto_max_value) { this->auto_max_value = auto_max_value; }
|
15
|
+
};
|
16
|
+
|
17
|
+
} // namespace opentherm
|
18
|
+
} // namespace esphome
|