esphome 2024.9.2__py3-none-any.whl → 2024.10.0__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/components/aic3204/__init__.py +0 -0
- esphome/components/aic3204/aic3204.cpp +173 -0
- esphome/components/aic3204/aic3204.h +88 -0
- esphome/components/aic3204/audio_dac.py +52 -0
- esphome/components/aic3204/automation.h +23 -0
- esphome/components/alarm_control_panel/__init__.py +3 -4
- esphome/components/animation/__init__.py +16 -12
- esphome/components/api/api_connection.cpp +2 -0
- esphome/components/api/api_connection.h +3 -1
- esphome/components/api/api_frame_helper.cpp +2 -1
- esphome/components/api/api_frame_helper.h +2 -1
- esphome/components/api/api_server.cpp +2 -0
- esphome/components/api/api_server.h +3 -1
- esphome/components/api/custom_api_device.h +3 -2
- esphome/components/api/homeassistant_service.h +4 -3
- esphome/components/api/list_entities.cpp +2 -0
- esphome/components/api/list_entities.h +3 -2
- esphome/components/api/subscribe_state.cpp +2 -0
- esphome/components/api/subscribe_state.h +3 -2
- esphome/components/audio_dac/__init__.py +57 -0
- esphome/components/audio_dac/audio_dac.h +23 -0
- esphome/components/audio_dac/automation.h +43 -0
- esphome/components/bang_bang/bang_bang_climate.cpp +5 -2
- esphome/components/bedjet/bedjet_codec.cpp +4 -2
- esphome/components/binary_sensor/__init__.py +3 -4
- esphome/components/button/__init__.py +3 -4
- esphome/components/ch422g/__init__.py +26 -17
- esphome/components/ch422g/ch422g.cpp +66 -49
- esphome/components/ch422g/ch422g.h +17 -19
- esphome/components/climate/__init__.py +3 -4
- esphome/components/cover/__init__.py +4 -5
- esphome/components/cse7766/cse7766.cpp +12 -1
- esphome/components/cse7766/cse7766.h +4 -0
- esphome/components/cse7766/sensor.py +13 -1
- esphome/components/cst816/touchscreen/__init__.py +7 -4
- esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +20 -19
- esphome/components/cst816/touchscreen/cst816_touchscreen.h +2 -0
- esphome/components/datetime/__init__.py +21 -14
- esphome/components/datetime/datetime_base.h +8 -1
- esphome/components/datetime/datetime_entity.cpp +2 -0
- esphome/components/datetime/datetime_entity.h +2 -0
- esphome/components/datetime/time_entity.cpp +2 -0
- esphome/components/datetime/time_entity.h +2 -0
- esphome/components/esp32/__init__.py +20 -4
- esphome/components/esp32_improv/__init__.py +82 -1
- esphome/components/esp32_improv/automation.h +72 -0
- esphome/components/esp32_improv/esp32_improv_component.cpp +13 -5
- esphome/components/esp32_improv/esp32_improv_component.h +15 -0
- esphome/components/ethernet/__init__.py +5 -0
- esphome/components/ethernet/ethernet_component.cpp +13 -0
- esphome/components/ethernet/ethernet_component.h +1 -0
- esphome/components/event/__init__.py +20 -12
- esphome/components/fan/__init__.py +3 -4
- esphome/components/gp2y1010au0f/__init__.py +0 -0
- esphome/components/gp2y1010au0f/gp2y1010au0f.cpp +67 -0
- esphome/components/gp2y1010au0f/gp2y1010au0f.h +52 -0
- esphome/components/gp2y1010au0f/sensor.py +61 -0
- esphome/components/gpio_expander/__init__.py +0 -0
- esphome/components/gpio_expander/cached_gpio.h +38 -0
- esphome/components/grove_gas_mc_v2/__init__.py +0 -0
- esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +88 -0
- esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +39 -0
- esphome/components/grove_gas_mc_v2/sensor.py +77 -0
- esphome/components/haier/climate.py +4 -3
- esphome/components/haier/haier_base.cpp +63 -8
- esphome/components/haier/haier_base.h +29 -3
- esphome/components/haier/hon_climate.cpp +122 -65
- esphome/components/haier/hon_climate.h +18 -2
- esphome/components/haier/smartair2_climate.cpp +21 -21
- esphome/components/haier/switch/__init__.py +91 -0
- esphome/components/haier/switch/beeper.cpp +14 -0
- esphome/components/haier/switch/beeper.h +18 -0
- esphome/components/haier/switch/display.cpp +14 -0
- esphome/components/haier/switch/display.h +18 -0
- esphome/components/haier/switch/health_mode.cpp +14 -0
- esphome/components/haier/switch/health_mode.h +18 -0
- esphome/components/haier/switch/quiet_mode.cpp +14 -0
- esphome/components/haier/switch/quiet_mode.h +18 -0
- esphome/components/hmac_md5/hmac_md5.cpp +2 -0
- esphome/components/hmac_md5/hmac_md5.h +2 -1
- esphome/components/i2s_audio/speaker/__init__.py +19 -0
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
- esphome/components/ili9xxx/ili9xxx_display.h +1 -0
- esphome/components/image/__init__.py +12 -12
- esphome/components/image/image.cpp +44 -0
- esphome/components/image/image.h +17 -2
- esphome/components/inkplate6/display.py +2 -0
- esphome/components/inkplate6/inkplate.h +30 -2
- esphome/components/light/__init__.py +3 -4
- esphome/components/lock/__init__.py +3 -4
- esphome/components/lvgl/__init__.py +16 -5
- esphome/components/lvgl/defines.py +1 -0
- esphome/components/lvgl/hello_world.py +64 -0
- esphome/components/lvgl/lv_validation.py +159 -3
- esphome/components/lvgl/lvgl_esphome.cpp +0 -43
- esphome/components/lvgl/lvgl_esphome.h +0 -4
- esphome/components/lvgl/styles.py +3 -2
- esphome/components/lvgl/text/__init__.py +3 -3
- esphome/components/lvgl/widgets/__init__.py +2 -0
- esphome/components/lvgl/widgets/animimg.py +3 -4
- esphome/components/lvgl/widgets/dropdown.py +5 -1
- esphome/components/lvgl/widgets/meter.py +16 -11
- esphome/components/md5/__init__.py +6 -0
- esphome/components/md5/md5.cpp +2 -0
- esphome/components/md5/md5.h +2 -0
- esphome/components/micro_wake_word/__init__.py +7 -0
- esphome/components/mics_4514/sensor.py +11 -26
- esphome/components/modbus_controller/__init__.py +7 -5
- esphome/components/modbus_controller/binary_sensor/__init__.py +6 -6
- esphome/components/modbus_controller/number/__init__.py +5 -6
- esphome/components/modbus_controller/output/__init__.py +10 -14
- esphome/components/modbus_controller/select/__init__.py +1 -1
- esphome/components/modbus_controller/sensor/__init__.py +7 -7
- esphome/components/modbus_controller/switch/__init__.py +6 -7
- esphome/components/modbus_controller/text_sensor/__init__.py +8 -9
- esphome/components/mqtt/__init__.py +3 -0
- esphome/components/mqtt/mqtt_client.cpp +2 -0
- esphome/components/mqtt/mqtt_client.h +2 -0
- esphome/components/nau7802/__init__.py +0 -0
- esphome/components/nau7802/nau7802.cpp +323 -0
- esphome/components/nau7802/nau7802.h +121 -0
- esphome/components/nau7802/sensor.py +134 -0
- esphome/components/nextion/base_component.py +1 -0
- esphome/components/nextion/display.py +4 -0
- esphome/components/nextion/nextion.cpp +19 -4
- esphome/components/nextion/nextion.h +16 -0
- esphome/components/npi19/__init__.py +0 -0
- esphome/components/npi19/npi19.cpp +111 -0
- esphome/components/npi19/npi19.h +30 -0
- esphome/components/npi19/sensor.py +52 -0
- esphome/components/number/__init__.py +3 -5
- esphome/components/online_image/__init__.py +1 -1
- esphome/components/online_image/online_image.h +1 -2
- esphome/components/opentherm/__init__.py +57 -0
- esphome/components/opentherm/hub.cpp +277 -0
- esphome/components/opentherm/hub.h +110 -0
- esphome/components/opentherm/opentherm.cpp +568 -0
- esphome/components/opentherm/opentherm.h +347 -0
- esphome/components/pulse_counter/pulse_counter_sensor.cpp +8 -1
- esphome/components/pulse_counter/pulse_counter_sensor.h +1 -0
- esphome/components/radon_eye_ble/radon_eye_listener.cpp +10 -3
- esphome/components/remote_transmitter/__init__.py +18 -2
- esphome/components/remote_transmitter/remote_transmitter.h +6 -0
- esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +2 -0
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
- esphome/components/select/__init__.py +3 -4
- esphome/components/sensor/__init__.py +3 -4
- esphome/components/shelly_dimmer/shelly_dimmer.cpp +32 -32
- esphome/components/shelly_dimmer/shelly_dimmer.h +2 -0
- esphome/components/st7701s/st7701s.cpp +21 -8
- esphome/components/st7701s/st7701s.h +2 -0
- esphome/components/switch/__init__.py +3 -4
- esphome/components/tca9555/__init__.py +72 -0
- esphome/components/tca9555/tca9555.cpp +140 -0
- esphome/components/tca9555/tca9555.h +64 -0
- esphome/components/tcs34725/tcs34725.cpp +62 -64
- esphome/components/tem3200/__init__.py +0 -0
- esphome/components/tem3200/sensor.py +55 -0
- esphome/components/tem3200/tem3200.cpp +151 -0
- esphome/components/tem3200/tem3200.h +30 -0
- esphome/components/template/binary_sensor/__init__.py +19 -6
- esphome/components/text/__init__.py +3 -4
- esphome/components/text_sensor/__init__.py +3 -4
- esphome/components/thermostat/climate.py +11 -9
- esphome/components/thermostat/thermostat_climate.cpp +21 -15
- esphome/components/tm1638/binary_sensor/__init__.py +3 -2
- esphome/components/tm1638/display.py +5 -5
- esphome/components/tm1638/output/__init__.py +3 -2
- esphome/components/tm1638/switch/__init__.py +3 -2
- esphome/components/touchscreen/touchscreen.cpp +2 -2
- esphome/components/update/__init__.py +3 -4
- esphome/components/valve/__init__.py +3 -4
- esphome/components/web_server/__init__.py +78 -22
- esphome/components/web_server/server_index_v3.h +3989 -3979
- esphome/components/web_server/web_server.cpp +219 -34
- esphome/components/web_server/web_server.h +10 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +4 -5
- esphome/config_validation.py +1 -0
- esphome/const.py +12 -2
- esphome/core/defines.h +4 -2
- esphome/core/helpers.cpp +46 -10
- esphome/core/helpers.h +8 -0
- esphome/core/ring_buffer.cpp +12 -2
- esphome/core/ring_buffer.h +3 -0
- {esphome-2024.9.2.dist-info → esphome-2024.10.0.dist-info}/METADATA +5 -3
- {esphome-2024.9.2.dist-info → esphome-2024.10.0.dist-info}/RECORD +192 -143
- {esphome-2024.9.2.dist-info → esphome-2024.10.0.dist-info}/LICENSE +0 -0
- {esphome-2024.9.2.dist-info → esphome-2024.10.0.dist-info}/WHEEL +0 -0
- {esphome-2024.9.2.dist-info → esphome-2024.10.0.dist-info}/entry_points.txt +0 -0
- {esphome-2024.9.2.dist-info → esphome-2024.10.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
#include "hub.h"
|
2
|
+
#include "esphome/core/helpers.h"
|
3
|
+
|
4
|
+
#include <string>
|
5
|
+
|
6
|
+
namespace esphome {
|
7
|
+
namespace opentherm {
|
8
|
+
|
9
|
+
static const char *const TAG = "opentherm";
|
10
|
+
|
11
|
+
OpenthermData OpenthermHub::build_request_(MessageId request_id) {
|
12
|
+
OpenthermData data;
|
13
|
+
data.type = 0;
|
14
|
+
data.id = 0;
|
15
|
+
data.valueHB = 0;
|
16
|
+
data.valueLB = 0;
|
17
|
+
|
18
|
+
// First, handle the status request. This requires special logic, because we
|
19
|
+
// wouldn't want to inadvertently disable domestic hot water, for example.
|
20
|
+
// It is also included in the macro-generated code below, but that will
|
21
|
+
// never be executed, because we short-circuit it here.
|
22
|
+
if (request_id == MessageId::STATUS) {
|
23
|
+
bool const ch_enabled = this->ch_enable;
|
24
|
+
bool dhw_enabled = this->dhw_enable;
|
25
|
+
bool cooling_enabled = this->cooling_enable;
|
26
|
+
bool otc_enabled = this->otc_active;
|
27
|
+
bool ch2_enabled = this->ch2_active;
|
28
|
+
|
29
|
+
data.type = MessageType::READ_DATA;
|
30
|
+
data.id = MessageId::STATUS;
|
31
|
+
data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4);
|
32
|
+
|
33
|
+
// Disable incomplete switch statement warnings, because the cases in each
|
34
|
+
// switch are generated based on the configured sensors and inputs.
|
35
|
+
#pragma GCC diagnostic push
|
36
|
+
#pragma GCC diagnostic ignored "-Wswitch"
|
37
|
+
|
38
|
+
// TODO: This is a placeholder for an auto-generated switch statement which builds request structure based on
|
39
|
+
// which sensors are enabled in config.
|
40
|
+
|
41
|
+
#pragma GCC diagnostic pop
|
42
|
+
|
43
|
+
return data;
|
44
|
+
}
|
45
|
+
return OpenthermData();
|
46
|
+
}
|
47
|
+
|
48
|
+
OpenthermHub::OpenthermHub() : Component() {}
|
49
|
+
|
50
|
+
void OpenthermHub::process_response(OpenthermData &data) {
|
51
|
+
ESP_LOGD(TAG, "Received OpenTherm response with id %d (%s)", data.id,
|
52
|
+
this->opentherm_->message_id_to_str((MessageId) data.id));
|
53
|
+
ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(data).c_str());
|
54
|
+
}
|
55
|
+
|
56
|
+
void OpenthermHub::setup() {
|
57
|
+
ESP_LOGD(TAG, "Setting up OpenTherm component");
|
58
|
+
this->opentherm_ = make_unique<OpenTherm>(this->in_pin_, this->out_pin_);
|
59
|
+
if (!this->opentherm_->initialize()) {
|
60
|
+
ESP_LOGE(TAG, "Failed to initialize OpenTherm protocol. See previous log messages for details.");
|
61
|
+
this->mark_failed();
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
|
65
|
+
// Ensure that there is at least one request, as we are required to
|
66
|
+
// communicate at least once every second. Sending the status request is
|
67
|
+
// good practice anyway.
|
68
|
+
this->add_repeating_message(MessageId::STATUS);
|
69
|
+
|
70
|
+
this->current_message_iterator_ = this->initial_messages_.begin();
|
71
|
+
}
|
72
|
+
|
73
|
+
void OpenthermHub::on_shutdown() { this->opentherm_->stop(); }
|
74
|
+
|
75
|
+
void OpenthermHub::loop() {
|
76
|
+
if (this->sync_mode_) {
|
77
|
+
this->sync_loop_();
|
78
|
+
return;
|
79
|
+
}
|
80
|
+
|
81
|
+
auto cur_time = millis();
|
82
|
+
auto const cur_mode = this->opentherm_->get_mode();
|
83
|
+
switch (cur_mode) {
|
84
|
+
case OperationMode::WRITE:
|
85
|
+
case OperationMode::READ:
|
86
|
+
case OperationMode::LISTEN:
|
87
|
+
if (!this->check_timings_(cur_time)) {
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
this->last_mode_ = cur_mode;
|
91
|
+
break;
|
92
|
+
case OperationMode::ERROR_PROTOCOL:
|
93
|
+
if (this->last_mode_ == OperationMode::WRITE) {
|
94
|
+
this->handle_protocol_write_error_();
|
95
|
+
} else if (this->last_mode_ == OperationMode::READ) {
|
96
|
+
this->handle_protocol_read_error_();
|
97
|
+
}
|
98
|
+
|
99
|
+
this->stop_opentherm_();
|
100
|
+
break;
|
101
|
+
case OperationMode::ERROR_TIMEOUT:
|
102
|
+
this->handle_timeout_error_();
|
103
|
+
this->stop_opentherm_();
|
104
|
+
break;
|
105
|
+
case OperationMode::IDLE:
|
106
|
+
if (this->should_skip_loop_(cur_time)) {
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
this->start_conversation_();
|
110
|
+
break;
|
111
|
+
case OperationMode::SENT:
|
112
|
+
// Message sent, now listen for the response.
|
113
|
+
this->opentherm_->listen();
|
114
|
+
break;
|
115
|
+
case OperationMode::RECEIVED:
|
116
|
+
this->read_response_();
|
117
|
+
break;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
void OpenthermHub::sync_loop_() {
|
122
|
+
if (!this->opentherm_->is_idle()) {
|
123
|
+
ESP_LOGE(TAG, "OpenTherm is not idle at the start of the loop");
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
|
127
|
+
auto cur_time = millis();
|
128
|
+
|
129
|
+
this->check_timings_(cur_time);
|
130
|
+
|
131
|
+
if (this->should_skip_loop_(cur_time)) {
|
132
|
+
return;
|
133
|
+
}
|
134
|
+
|
135
|
+
this->start_conversation_();
|
136
|
+
|
137
|
+
if (!this->spin_wait_(1150, [&] { return this->opentherm_->is_active(); })) {
|
138
|
+
ESP_LOGE(TAG, "Hub timeout triggered during send");
|
139
|
+
this->stop_opentherm_();
|
140
|
+
return;
|
141
|
+
}
|
142
|
+
|
143
|
+
if (this->opentherm_->is_error()) {
|
144
|
+
this->handle_protocol_write_error_();
|
145
|
+
this->stop_opentherm_();
|
146
|
+
return;
|
147
|
+
} else if (!this->opentherm_->is_sent()) {
|
148
|
+
ESP_LOGW(TAG, "Unexpected state after sending request: %s",
|
149
|
+
this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode()));
|
150
|
+
this->stop_opentherm_();
|
151
|
+
return;
|
152
|
+
}
|
153
|
+
|
154
|
+
// Listen for the response
|
155
|
+
this->opentherm_->listen();
|
156
|
+
if (!this->spin_wait_(1150, [&] { return this->opentherm_->is_active(); })) {
|
157
|
+
ESP_LOGE(TAG, "Hub timeout triggered during receive");
|
158
|
+
this->stop_opentherm_();
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
|
162
|
+
if (this->opentherm_->is_timeout()) {
|
163
|
+
this->handle_timeout_error_();
|
164
|
+
this->stop_opentherm_();
|
165
|
+
return;
|
166
|
+
} else if (this->opentherm_->is_protocol_error()) {
|
167
|
+
this->handle_protocol_read_error_();
|
168
|
+
this->stop_opentherm_();
|
169
|
+
return;
|
170
|
+
} else if (!this->opentherm_->has_message()) {
|
171
|
+
ESP_LOGW(TAG, "Unexpected state after receiving response: %s",
|
172
|
+
this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode()));
|
173
|
+
this->stop_opentherm_();
|
174
|
+
return;
|
175
|
+
}
|
176
|
+
|
177
|
+
this->read_response_();
|
178
|
+
}
|
179
|
+
|
180
|
+
bool OpenthermHub::check_timings_(uint32_t cur_time) {
|
181
|
+
if (this->last_conversation_start_ > 0 && (cur_time - this->last_conversation_start_) > 1150) {
|
182
|
+
ESP_LOGW(TAG,
|
183
|
+
"%d ms elapsed since the start of the last convo, but 1150 ms are allowed at maximum. Look at other "
|
184
|
+
"components that might slow the loop down.",
|
185
|
+
(int) (cur_time - this->last_conversation_start_));
|
186
|
+
this->stop_opentherm_();
|
187
|
+
return false;
|
188
|
+
}
|
189
|
+
|
190
|
+
return true;
|
191
|
+
}
|
192
|
+
|
193
|
+
bool OpenthermHub::should_skip_loop_(uint32_t cur_time) const {
|
194
|
+
if (this->last_conversation_end_ > 0 && (cur_time - this->last_conversation_end_) < 100) {
|
195
|
+
ESP_LOGV(TAG, "Less than 100 ms elapsed since last convo, skipping this iteration");
|
196
|
+
return true;
|
197
|
+
}
|
198
|
+
|
199
|
+
return false;
|
200
|
+
}
|
201
|
+
|
202
|
+
void OpenthermHub::start_conversation_() {
|
203
|
+
if (this->sending_initial_ && this->current_message_iterator_ == this->initial_messages_.end()) {
|
204
|
+
this->sending_initial_ = false;
|
205
|
+
this->current_message_iterator_ = this->repeating_messages_.begin();
|
206
|
+
} else if (this->current_message_iterator_ == this->repeating_messages_.end()) {
|
207
|
+
this->current_message_iterator_ = this->repeating_messages_.begin();
|
208
|
+
}
|
209
|
+
|
210
|
+
auto request = this->build_request_(*this->current_message_iterator_);
|
211
|
+
|
212
|
+
ESP_LOGD(TAG, "Sending request with id %d (%s)", request.id,
|
213
|
+
this->opentherm_->message_id_to_str((MessageId) request.id));
|
214
|
+
ESP_LOGD(TAG, "%s", this->opentherm_->debug_data(request).c_str());
|
215
|
+
// Send the request
|
216
|
+
this->last_conversation_start_ = millis();
|
217
|
+
this->opentherm_->send(request);
|
218
|
+
}
|
219
|
+
|
220
|
+
void OpenthermHub::read_response_() {
|
221
|
+
OpenthermData response;
|
222
|
+
if (!this->opentherm_->get_message(response)) {
|
223
|
+
ESP_LOGW(TAG, "Couldn't get the response, but flags indicated success. This is a bug.");
|
224
|
+
this->stop_opentherm_();
|
225
|
+
return;
|
226
|
+
}
|
227
|
+
|
228
|
+
this->stop_opentherm_();
|
229
|
+
|
230
|
+
this->process_response(response);
|
231
|
+
|
232
|
+
this->current_message_iterator_++;
|
233
|
+
}
|
234
|
+
|
235
|
+
void OpenthermHub::stop_opentherm_() {
|
236
|
+
this->opentherm_->stop();
|
237
|
+
this->last_conversation_end_ = millis();
|
238
|
+
}
|
239
|
+
|
240
|
+
void OpenthermHub::handle_protocol_write_error_() {
|
241
|
+
ESP_LOGW(TAG, "Error while sending request: %s",
|
242
|
+
this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode()));
|
243
|
+
ESP_LOGW(TAG, "%s", this->opentherm_->debug_data(this->last_request_).c_str());
|
244
|
+
}
|
245
|
+
|
246
|
+
void OpenthermHub::handle_protocol_read_error_() {
|
247
|
+
OpenThermError error;
|
248
|
+
this->opentherm_->get_protocol_error(error);
|
249
|
+
ESP_LOGW(TAG, "Protocol error occured while receiving response: %s", this->opentherm_->debug_error(error).c_str());
|
250
|
+
}
|
251
|
+
|
252
|
+
void OpenthermHub::handle_timeout_error_() {
|
253
|
+
ESP_LOGW(TAG, "Receive response timed out at a protocol level");
|
254
|
+
this->stop_opentherm_();
|
255
|
+
}
|
256
|
+
|
257
|
+
#define ID(x) x
|
258
|
+
#define SHOW2(x) #x
|
259
|
+
#define SHOW(x) SHOW2(x)
|
260
|
+
|
261
|
+
void OpenthermHub::dump_config() {
|
262
|
+
ESP_LOGCONFIG(TAG, "OpenTherm:");
|
263
|
+
LOG_PIN(" In: ", this->in_pin_);
|
264
|
+
LOG_PIN(" Out: ", this->out_pin_);
|
265
|
+
ESP_LOGCONFIG(TAG, " Sync mode: %d", this->sync_mode_);
|
266
|
+
ESP_LOGCONFIG(TAG, " Initial requests:");
|
267
|
+
for (auto type : this->initial_messages_) {
|
268
|
+
ESP_LOGCONFIG(TAG, " - %d", type);
|
269
|
+
}
|
270
|
+
ESP_LOGCONFIG(TAG, " Repeating requests:");
|
271
|
+
for (auto type : this->repeating_messages_) {
|
272
|
+
ESP_LOGCONFIG(TAG, " - %d", type);
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
} // namespace opentherm
|
277
|
+
} // namespace esphome
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "esphome/core/defines.h"
|
4
|
+
#include "esphome/core/hal.h"
|
5
|
+
#include "esphome/core/component.h"
|
6
|
+
#include "esphome/core/log.h"
|
7
|
+
|
8
|
+
#include "opentherm.h"
|
9
|
+
|
10
|
+
#include <memory>
|
11
|
+
#include <unordered_map>
|
12
|
+
#include <unordered_set>
|
13
|
+
#include <functional>
|
14
|
+
|
15
|
+
namespace esphome {
|
16
|
+
namespace opentherm {
|
17
|
+
|
18
|
+
// OpenTherm component for ESPHome
|
19
|
+
class OpenthermHub : public Component {
|
20
|
+
protected:
|
21
|
+
// Communication pins for the OpenTherm interface
|
22
|
+
InternalGPIOPin *in_pin_, *out_pin_;
|
23
|
+
// The OpenTherm interface
|
24
|
+
std::unique_ptr<OpenTherm> opentherm_;
|
25
|
+
|
26
|
+
// The set of initial messages to send on starting communication with the boiler
|
27
|
+
std::unordered_set<MessageId> initial_messages_;
|
28
|
+
// and the repeating messages which are sent repeatedly to update various sensors
|
29
|
+
// and boiler parameters (like the setpoint).
|
30
|
+
std::unordered_set<MessageId> repeating_messages_;
|
31
|
+
// Indicates if we are still working on the initial requests or not
|
32
|
+
bool sending_initial_ = true;
|
33
|
+
// Index for the current request in one of the _requests sets.
|
34
|
+
std::unordered_set<MessageId>::const_iterator current_message_iterator_;
|
35
|
+
|
36
|
+
uint32_t last_conversation_start_ = 0;
|
37
|
+
uint32_t last_conversation_end_ = 0;
|
38
|
+
OperationMode last_mode_ = IDLE;
|
39
|
+
OpenthermData last_request_;
|
40
|
+
|
41
|
+
// Synchronous communication mode prevents other components from disabling interrupts while
|
42
|
+
// we are talking to the boiler. Enable if you experience random intermittent invalid response errors.
|
43
|
+
// Very likely to happen while using Dallas temperature sensors.
|
44
|
+
bool sync_mode_ = false;
|
45
|
+
|
46
|
+
// Create OpenTherm messages based on the message id
|
47
|
+
OpenthermData build_request_(MessageId request_id);
|
48
|
+
void handle_protocol_write_error_();
|
49
|
+
void handle_protocol_read_error_();
|
50
|
+
void handle_timeout_error_();
|
51
|
+
void stop_opentherm_();
|
52
|
+
void start_conversation_();
|
53
|
+
void read_response_();
|
54
|
+
bool check_timings_(uint32_t cur_time);
|
55
|
+
bool should_skip_loop_(uint32_t cur_time) const;
|
56
|
+
void sync_loop_();
|
57
|
+
|
58
|
+
template<typename F> bool spin_wait_(uint32_t timeout, F func) {
|
59
|
+
auto start_time = millis();
|
60
|
+
while (func()) {
|
61
|
+
yield();
|
62
|
+
auto cur_time = millis();
|
63
|
+
if (cur_time - start_time >= timeout) {
|
64
|
+
return false;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
return true;
|
68
|
+
}
|
69
|
+
|
70
|
+
public:
|
71
|
+
// Constructor with references to the global interrupt handlers
|
72
|
+
OpenthermHub();
|
73
|
+
|
74
|
+
// Handle responses from the OpenTherm interface
|
75
|
+
void process_response(OpenthermData &data);
|
76
|
+
|
77
|
+
// Setters for the input and output OpenTherm interface pins
|
78
|
+
void set_in_pin(InternalGPIOPin *in_pin) { this->in_pin_ = in_pin; }
|
79
|
+
void set_out_pin(InternalGPIOPin *out_pin) { this->out_pin_ = out_pin; }
|
80
|
+
|
81
|
+
// Add a request to the set of initial requests
|
82
|
+
void add_initial_message(MessageId message_id) { this->initial_messages_.insert(message_id); }
|
83
|
+
// Add a request to the set of repeating requests. Note that a large number of repeating
|
84
|
+
// requests will slow down communication with the boiler. Each request may take up to 1 second,
|
85
|
+
// so with all sensors enabled, it may take about half a minute before a change in setpoint
|
86
|
+
// will be processed.
|
87
|
+
void add_repeating_message(MessageId message_id) { this->repeating_messages_.insert(message_id); }
|
88
|
+
|
89
|
+
// There are five status variables, which can either be set as a simple variable,
|
90
|
+
// 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;
|
92
|
+
|
93
|
+
// Setters for the status variables
|
94
|
+
void set_ch_enable(bool value) { this->ch_enable = value; }
|
95
|
+
void set_dhw_enable(bool value) { this->dhw_enable = value; }
|
96
|
+
void set_cooling_enable(bool value) { this->cooling_enable = value; }
|
97
|
+
void set_otc_active(bool value) { this->otc_active = value; }
|
98
|
+
void set_ch2_active(bool value) { this->ch2_active = value; }
|
99
|
+
void set_sync_mode(bool sync_mode) { this->sync_mode_ = sync_mode; }
|
100
|
+
|
101
|
+
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
102
|
+
|
103
|
+
void setup() override;
|
104
|
+
void on_shutdown() override;
|
105
|
+
void loop() override;
|
106
|
+
void dump_config() override;
|
107
|
+
};
|
108
|
+
|
109
|
+
} // namespace opentherm
|
110
|
+
} // namespace esphome
|