esphome 2024.6.6__py3-none-any.whl → 2024.7.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/components/cover/cover.h +2 -2
- esphome/components/esp32_camera/__init__.py +6 -3
- esphome/components/ethernet/ethernet_component.cpp +3 -2
- esphome/components/font/__init__.py +2 -28
- esphome/components/haier/binary_sensor/__init__.py +4 -4
- esphome/components/haier/button/__init__.py +1 -1
- esphome/components/haier/climate.py +43 -9
- esphome/components/haier/haier_base.cpp +4 -0
- esphome/components/haier/haier_base.h +11 -1
- esphome/components/haier/hon_climate.cpp +109 -55
- esphome/components/haier/hon_climate.h +7 -1
- esphome/components/haier/hon_packet.h +5 -0
- esphome/components/haier/sensor/__init__.py +5 -5
- esphome/components/haier/smartair2_climate.cpp +1 -0
- esphome/components/haier/text_sensor/__init__.py +4 -4
- esphome/components/heatpumpir/climate.py +8 -2
- esphome/components/heatpumpir/heatpumpir.cpp +6 -0
- esphome/components/heatpumpir/heatpumpir.h +6 -0
- esphome/components/http_request/update/http_request_update.cpp +6 -7
- esphome/components/http_request/update/http_request_update.h +0 -3
- esphome/components/image/__init__.py +2 -29
- esphome/components/improv_serial/improv_serial_component.cpp +8 -8
- esphome/components/mdns/__init__.py +3 -3
- esphome/components/mdns/mdns_component.cpp +3 -1
- esphome/components/mdns/mdns_component.h +3 -1
- esphome/components/mdns/mdns_esp32.cpp +2 -1
- esphome/components/mdns/mdns_esp8266.cpp +2 -1
- esphome/components/mdns/mdns_host.cpp +2 -1
- esphome/components/mdns/mdns_libretiny.cpp +2 -1
- esphome/components/mdns/mdns_rp2040.cpp +2 -1
- esphome/components/micro_wake_word/__init__.py +203 -56
- esphome/components/micro_wake_word/micro_wake_word.cpp +225 -275
- esphome/components/micro_wake_word/micro_wake_word.h +77 -107
- esphome/components/micro_wake_word/preprocessor_settings.h +20 -0
- esphome/components/micro_wake_word/streaming_model.cpp +189 -0
- esphome/components/micro_wake_word/streaming_model.h +84 -0
- esphome/components/modbus_controller/text_sensor/__init__.py +2 -1
- esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +4 -1
- esphome/components/modbus_controller/text_sensor/modbus_textsensor.h +1 -1
- esphome/components/number/__init__.py +2 -0
- esphome/components/qspi_amoled/display.py +16 -4
- esphome/components/qspi_amoled/qspi_amoled.cpp +16 -0
- esphome/components/qspi_amoled/qspi_amoled.h +0 -3
- esphome/components/remote_base/dooya_protocol.cpp +4 -4
- esphome/components/remote_base/rc_switch_protocol.cpp +1 -1
- esphome/components/script/__init__.py +1 -1
- esphome/components/sensor/__init__.py +2 -0
- esphome/components/tuya/tuya.cpp +8 -2
- esphome/components/tuya/tuya.h +3 -1
- esphome/components/uart/__init__.py +72 -9
- esphome/components/uart/uart_component_esp32_arduino.cpp +18 -4
- esphome/components/uart/uart_component_esp_idf.cpp +22 -2
- esphome/components/uart/uart_component_host.cpp +295 -0
- esphome/components/uart/uart_component_host.h +38 -0
- esphome/components/uptime/sensor.py +44 -11
- esphome/components/uptime/{uptime_sensor.cpp → uptime_seconds_sensor.cpp} +11 -7
- esphome/components/uptime/{uptime_sensor.h → uptime_seconds_sensor.h} +2 -2
- esphome/components/uptime/uptime_timestamp_sensor.cpp +39 -0
- esphome/components/uptime/uptime_timestamp_sensor.h +30 -0
- esphome/components/veml7700/veml7700.cpp +1 -1
- esphome/components/veml7700/veml7700.h +5 -5
- esphome/components/voice_assistant/voice_assistant.cpp +1 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +1 -1
- esphome/components/wifi/wifi_component_pico_w.cpp +18 -2
- esphome/components/wireguard/__init__.py +1 -1
- esphome/components/x9c/output.py +7 -1
- esphome/const.py +2 -1
- esphome/core/defines.h +1 -0
- esphome/core/helpers.cpp +1 -1
- esphome/core/helpers.h +1 -1
- esphome/external_files.py +26 -0
- {esphome-2024.6.6.dist-info → esphome-2024.7.0b1.dist-info}/METADATA +1 -1
- {esphome-2024.6.6.dist-info → esphome-2024.7.0b1.dist-info}/RECORD +77 -71
- esphome/components/micro_wake_word/audio_preprocessor_int8_model_data.h +0 -493
- {esphome-2024.6.6.dist-info → esphome-2024.7.0b1.dist-info}/LICENSE +0 -0
- {esphome-2024.6.6.dist-info → esphome-2024.7.0b1.dist-info}/WHEEL +0 -0
- {esphome-2024.6.6.dist-info → esphome-2024.7.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2024.6.6.dist-info → esphome-2024.7.0b1.dist-info}/top_level.txt +0 -0
esphome/components/cover/cover.h
CHANGED
@@ -129,13 +129,13 @@ class Cover : public EntityBase, public EntityBase_DeviceClass {
|
|
129
129
|
*
|
130
130
|
* This is a legacy method and may be removed later, please use `.make_call()` instead.
|
131
131
|
*/
|
132
|
-
ESPDEPRECATED("open() is deprecated, use make_call().set_command_open() instead.", "2021.9")
|
132
|
+
ESPDEPRECATED("open() is deprecated, use make_call().set_command_open().perform() instead.", "2021.9")
|
133
133
|
void open();
|
134
134
|
/** Close the cover.
|
135
135
|
*
|
136
136
|
* This is a legacy method and may be removed later, please use `.make_call()` instead.
|
137
137
|
*/
|
138
|
-
ESPDEPRECATED("close() is deprecated, use make_call().set_command_close() instead.", "2021.9")
|
138
|
+
ESPDEPRECATED("close() is deprecated, use make_call().set_command_close().perform() instead.", "2021.9")
|
139
139
|
void close();
|
140
140
|
/** Stop the cover.
|
141
141
|
*
|
@@ -17,7 +17,7 @@ from esphome.const import (
|
|
17
17
|
CONF_VSYNC_PIN,
|
18
18
|
)
|
19
19
|
from esphome.core import CORE
|
20
|
-
from esphome.components.esp32 import
|
20
|
+
from esphome.components.esp32 import add_idf_component
|
21
21
|
from esphome.cpp_helpers import setup_entity
|
22
22
|
|
23
23
|
DEPENDENCIES = ["esp32"]
|
@@ -290,8 +290,11 @@ async def to_code(config):
|
|
290
290
|
cg.add_define("USE_ESP32_CAMERA")
|
291
291
|
|
292
292
|
if CORE.using_esp_idf:
|
293
|
-
|
294
|
-
|
293
|
+
add_idf_component(
|
294
|
+
name="esp32-camera",
|
295
|
+
repo="https://github.com/espressif/esp32-camera.git",
|
296
|
+
ref="v2.0.9",
|
297
|
+
)
|
295
298
|
|
296
299
|
for conf in config.get(CONF_ON_STREAM_START, []):
|
297
300
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
@@ -65,7 +65,8 @@ void EthernetComponent::setup() {
|
|
65
65
|
.intr_flags = 0,
|
66
66
|
};
|
67
67
|
|
68
|
-
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
68
|
+
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \
|
69
|
+
defined(USE_ESP32_VARIANT_ESP32C6)
|
69
70
|
auto host = SPI2_HOST;
|
70
71
|
#else
|
71
72
|
auto host = SPI3_HOST;
|
@@ -631,7 +632,7 @@ void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister regi
|
|
631
632
|
ESPHL_ERROR_CHECK(err, "Writing PHY Register failed");
|
632
633
|
|
633
634
|
if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
|
634
|
-
ESP_LOGD(TAG, "Select PHY Register Page
|
635
|
+
ESP_LOGD(TAG, "Select PHY Register Page 0x00");
|
635
636
|
err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0);
|
636
637
|
ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed");
|
637
638
|
}
|
@@ -17,7 +17,6 @@ from esphome.helpers import (
|
|
17
17
|
cpp_string_escape,
|
18
18
|
)
|
19
19
|
from esphome.const import (
|
20
|
-
__version__,
|
21
20
|
CONF_FAMILY,
|
22
21
|
CONF_FILE,
|
23
22
|
CONF_GLYPHS,
|
@@ -185,31 +184,6 @@ def get_font_path(value, type) -> Path:
|
|
185
184
|
return None
|
186
185
|
|
187
186
|
|
188
|
-
def download_content(url: str, path: Path) -> None:
|
189
|
-
if not external_files.has_remote_file_changed(url, path):
|
190
|
-
_LOGGER.debug("Remote file has not changed %s", url)
|
191
|
-
return
|
192
|
-
|
193
|
-
_LOGGER.debug(
|
194
|
-
"Remote file has changed, downloading from %s to %s",
|
195
|
-
url,
|
196
|
-
path,
|
197
|
-
)
|
198
|
-
|
199
|
-
try:
|
200
|
-
req = requests.get(
|
201
|
-
url,
|
202
|
-
timeout=external_files.NETWORK_TIMEOUT,
|
203
|
-
headers={"User-agent": f"ESPHome/{__version__} (https://esphome.io)"},
|
204
|
-
)
|
205
|
-
req.raise_for_status()
|
206
|
-
except requests.exceptions.RequestException as e:
|
207
|
-
raise cv.Invalid(f"Could not download from {url}: {e}")
|
208
|
-
|
209
|
-
path.parent.mkdir(parents=True, exist_ok=True)
|
210
|
-
path.write_bytes(req.content)
|
211
|
-
|
212
|
-
|
213
187
|
def download_gfont(value):
|
214
188
|
name = (
|
215
189
|
f"{value[CONF_FAMILY]}:ital,wght@{int(value[CONF_ITALIC])},{value[CONF_WEIGHT]}"
|
@@ -236,7 +210,7 @@ def download_gfont(value):
|
|
236
210
|
ttf_url = match.group(1)
|
237
211
|
_LOGGER.debug("download_gfont: ttf_url=%s", ttf_url)
|
238
212
|
|
239
|
-
download_content(ttf_url, path)
|
213
|
+
external_files.download_content(ttf_url, path)
|
240
214
|
return value
|
241
215
|
|
242
216
|
|
@@ -244,7 +218,7 @@ def download_web_font(value):
|
|
244
218
|
url = value[CONF_URL]
|
245
219
|
path = get_font_path(value, TYPE_WEB)
|
246
220
|
|
247
|
-
download_content(url, path)
|
221
|
+
external_files.download_content(url, path)
|
248
222
|
_LOGGER.debug("download_web_font: path=%s", path)
|
249
223
|
return value
|
250
224
|
|
@@ -56,7 +56,7 @@ SENSOR_TYPES = {
|
|
56
56
|
|
57
57
|
CONFIG_SCHEMA = cv.Schema(
|
58
58
|
{
|
59
|
-
cv.
|
59
|
+
cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate),
|
60
60
|
}
|
61
61
|
).extend({cv.Optional(type): schema for type, schema in SENSOR_TYPES.items()})
|
62
62
|
|
@@ -64,8 +64,8 @@ CONFIG_SCHEMA = cv.Schema(
|
|
64
64
|
async def to_code(config):
|
65
65
|
paren = await cg.get_variable(config[CONF_HAIER_ID])
|
66
66
|
|
67
|
-
for
|
68
|
-
if conf := config.get(
|
67
|
+
for type_ in SENSOR_TYPES:
|
68
|
+
if conf := config.get(type_):
|
69
69
|
sens = await binary_sensor.new_binary_sensor(conf)
|
70
|
-
binary_sensor_type = getattr(BinarySensorTypeEnum,
|
70
|
+
binary_sensor_type = getattr(BinarySensorTypeEnum, type_.upper())
|
71
71
|
cg.add(paren.set_sub_binary_sensor(binary_sensor_type, sens))
|
@@ -21,7 +21,7 @@ ICON_SPRAY_BOTTLE = "mdi:spray-bottle"
|
|
21
21
|
|
22
22
|
CONFIG_SCHEMA = cv.Schema(
|
23
23
|
{
|
24
|
-
cv.
|
24
|
+
cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate),
|
25
25
|
cv.Optional(CONF_SELF_CLEANING): button.button_schema(
|
26
26
|
SelfCleaningButton,
|
27
27
|
icon=ICON_SPRAY_BOTTLE,
|
@@ -38,6 +38,9 @@ PROTOCOL_MAX_TEMPERATURE = 30.0
|
|
38
38
|
PROTOCOL_TARGET_TEMPERATURE_STEP = 1.0
|
39
39
|
PROTOCOL_CURRENT_TEMPERATURE_STEP = 0.5
|
40
40
|
PROTOCOL_CONTROL_PACKET_SIZE = 10
|
41
|
+
PROTOCOL_MIN_SENSORS_PACKET_SIZE = 18
|
42
|
+
PROTOCOL_DEFAULT_SENSORS_PACKET_SIZE = 22
|
43
|
+
PROTOCOL_STATUS_MESSAGE_HEADER_SIZE = 0
|
41
44
|
|
42
45
|
CODEOWNERS = ["@paveldn"]
|
43
46
|
DEPENDENCIES = ["climate", "uart"]
|
@@ -48,6 +51,9 @@ CONF_CONTROL_PACKET_SIZE = "control_packet_size"
|
|
48
51
|
CONF_HORIZONTAL_AIRFLOW = "horizontal_airflow"
|
49
52
|
CONF_ON_ALARM_START = "on_alarm_start"
|
50
53
|
CONF_ON_ALARM_END = "on_alarm_end"
|
54
|
+
CONF_ON_STATUS_MESSAGE = "on_status_message"
|
55
|
+
CONF_SENSORS_PACKET_SIZE = "sensors_packet_size"
|
56
|
+
CONF_STATUS_MESSAGE_HEADER_SIZE = "status_message_header_size"
|
51
57
|
CONF_VERTICAL_AIRFLOW = "vertical_airflow"
|
52
58
|
CONF_WIFI_SIGNAL = "wifi_signal"
|
53
59
|
|
@@ -129,6 +135,11 @@ HaierAlarmEndTrigger = haier_ns.class_(
|
|
129
135
|
automation.Trigger.template(cg.uint8, cg.const_char_ptr),
|
130
136
|
)
|
131
137
|
|
138
|
+
StatusMessageTrigger = haier_ns.class_(
|
139
|
+
"StatusMessageTrigger",
|
140
|
+
automation.Trigger.template(cg.const_char_ptr, cg.size_t),
|
141
|
+
)
|
142
|
+
|
132
143
|
|
133
144
|
def validate_visual(config):
|
134
145
|
if CONF_VISUAL in config:
|
@@ -183,7 +194,6 @@ BASE_CONFIG_SCHEMA = (
|
|
183
194
|
cv.Optional(
|
184
195
|
CONF_SUPPORTED_SWING_MODES,
|
185
196
|
default=[
|
186
|
-
"OFF",
|
187
197
|
"VERTICAL",
|
188
198
|
"HORIZONTAL",
|
189
199
|
"BOTH",
|
@@ -194,6 +204,11 @@ BASE_CONFIG_SCHEMA = (
|
|
194
204
|
cv.Optional(
|
195
205
|
CONF_ANSWER_TIMEOUT,
|
196
206
|
): cv.positive_time_period_milliseconds,
|
207
|
+
cv.Optional(CONF_ON_STATUS_MESSAGE): automation.validate_automation(
|
208
|
+
{
|
209
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StatusMessageTrigger),
|
210
|
+
}
|
211
|
+
),
|
197
212
|
}
|
198
213
|
)
|
199
214
|
.extend(uart.UART_DEVICE_SCHEMA)
|
@@ -211,7 +226,7 @@ CONFIG_SCHEMA = cv.All(
|
|
211
226
|
): cv.boolean,
|
212
227
|
cv.Optional(
|
213
228
|
CONF_SUPPORTED_PRESETS,
|
214
|
-
default=
|
229
|
+
default=["BOOST", "COMFORT"], # No AWAY by default
|
215
230
|
): cv.ensure_list(
|
216
231
|
cv.enum(SUPPORTED_CLIMATE_PRESETS_SMARTAIR2_OPTIONS, upper=True)
|
217
232
|
),
|
@@ -229,9 +244,17 @@ CONFIG_SCHEMA = cv.All(
|
|
229
244
|
cv.Optional(
|
230
245
|
CONF_CONTROL_PACKET_SIZE, default=PROTOCOL_CONTROL_PACKET_SIZE
|
231
246
|
): cv.int_range(min=PROTOCOL_CONTROL_PACKET_SIZE, max=50),
|
247
|
+
cv.Optional(
|
248
|
+
CONF_SENSORS_PACKET_SIZE,
|
249
|
+
default=PROTOCOL_DEFAULT_SENSORS_PACKET_SIZE,
|
250
|
+
): cv.int_range(min=PROTOCOL_MIN_SENSORS_PACKET_SIZE, max=50),
|
251
|
+
cv.Optional(
|
252
|
+
CONF_STATUS_MESSAGE_HEADER_SIZE,
|
253
|
+
default=PROTOCOL_STATUS_MESSAGE_HEADER_SIZE,
|
254
|
+
): cv.int_range(min=PROTOCOL_STATUS_MESSAGE_HEADER_SIZE),
|
232
255
|
cv.Optional(
|
233
256
|
CONF_SUPPORTED_PRESETS,
|
234
|
-
default=
|
257
|
+
default=["BOOST", "ECO", "SLEEP"], # No AWAY by default
|
235
258
|
): cv.ensure_list(
|
236
259
|
cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True)
|
237
260
|
),
|
@@ -427,11 +450,7 @@ def _final_validate(config):
|
|
427
450
|
"No logger component found, logging for Haier protocol is disabled"
|
428
451
|
)
|
429
452
|
cg.add_build_flag("-DHAIER_LOG_LEVEL=0")
|
430
|
-
if (
|
431
|
-
(CONF_WIFI_SIGNAL in config)
|
432
|
-
and (config[CONF_WIFI_SIGNAL])
|
433
|
-
and CONF_WIFI not in full_config
|
434
|
-
):
|
453
|
+
if config.get(CONF_WIFI_SIGNAL) and CONF_WIFI not in full_config:
|
435
454
|
raise cv.Invalid(
|
436
455
|
f"No WiFi configured, if you want to use haier climate without WiFi add {CONF_WIFI_SIGNAL}: false to climate configuration"
|
437
456
|
)
|
@@ -473,6 +492,16 @@ async def to_code(config):
|
|
473
492
|
config[CONF_CONTROL_PACKET_SIZE] - PROTOCOL_CONTROL_PACKET_SIZE
|
474
493
|
)
|
475
494
|
)
|
495
|
+
if CONF_SENSORS_PACKET_SIZE in config:
|
496
|
+
cg.add(
|
497
|
+
var.set_extra_sensors_packet_bytes_size(
|
498
|
+
config[CONF_SENSORS_PACKET_SIZE] - PROTOCOL_MIN_SENSORS_PACKET_SIZE
|
499
|
+
)
|
500
|
+
)
|
501
|
+
if CONF_STATUS_MESSAGE_HEADER_SIZE in config:
|
502
|
+
cg.add(
|
503
|
+
var.set_status_message_header_size(config[CONF_STATUS_MESSAGE_HEADER_SIZE])
|
504
|
+
)
|
476
505
|
for conf in config.get(CONF_ON_ALARM_START, []):
|
477
506
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
478
507
|
await automation.build_automation(
|
@@ -483,5 +512,10 @@ async def to_code(config):
|
|
483
512
|
await automation.build_automation(
|
484
513
|
trigger, [(cg.uint8, "code"), (cg.const_char_ptr, "message")], conf
|
485
514
|
)
|
515
|
+
for conf in config.get(CONF_ON_STATUS_MESSAGE, []):
|
516
|
+
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
517
|
+
await automation.build_automation(
|
518
|
+
trigger, [(cg.const_char_ptr, "data"), (cg.size_t, "data_size")], conf
|
519
|
+
)
|
486
520
|
# https://github.com/paveldn/HaierProtocol
|
487
|
-
cg.add_library("pavlodn/HaierProtocol", "0.9.
|
521
|
+
cg.add_library("pavlodn/HaierProtocol", "0.9.31")
|
@@ -186,6 +186,10 @@ void HaierClimateBase::send_custom_command(const haier_protocol::HaierMessage &m
|
|
186
186
|
this->action_request_ = PendingAction({ActionRequest::SEND_CUSTOM_COMMAND, message});
|
187
187
|
}
|
188
188
|
|
189
|
+
void HaierClimateBase::add_status_message_callback(std::function<void(const char *, size_t)> &&callback) {
|
190
|
+
this->status_message_callback_.add(std::move(callback));
|
191
|
+
}
|
192
|
+
|
189
193
|
haier_protocol::HandlerError HaierClimateBase::answer_preprocess_(
|
190
194
|
haier_protocol::FrameType request_message_type, haier_protocol::FrameType expected_request_message_type,
|
191
195
|
haier_protocol::FrameType answer_message_type, haier_protocol::FrameType expected_answer_message_type,
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#include <set>
|
5
5
|
#include "esphome/components/climate/climate.h"
|
6
6
|
#include "esphome/components/uart/uart.h"
|
7
|
+
#include "esphome/core/automation.h"
|
7
8
|
// HaierProtocol
|
8
9
|
#include <protocol/haier_protocol.h>
|
9
10
|
|
@@ -56,6 +57,7 @@ class HaierClimateBase : public esphome::Component,
|
|
56
57
|
void set_answer_timeout(uint32_t timeout);
|
57
58
|
void set_send_wifi(bool send_wifi);
|
58
59
|
void send_custom_command(const haier_protocol::HaierMessage &message);
|
60
|
+
void add_status_message_callback(std::function<void(const char *, size_t)> &&callback);
|
59
61
|
|
60
62
|
protected:
|
61
63
|
enum class ProtocolPhases {
|
@@ -140,11 +142,19 @@ class HaierClimateBase : public esphome::Component,
|
|
140
142
|
esphome::climate::ClimateTraits traits_;
|
141
143
|
HvacSettings current_hvac_settings_;
|
142
144
|
HvacSettings next_hvac_settings_;
|
143
|
-
std::unique_ptr<uint8_t[]> last_status_message_;
|
145
|
+
std::unique_ptr<uint8_t[]> last_status_message_{nullptr};
|
144
146
|
std::chrono::steady_clock::time_point last_request_timestamp_; // For interval between messages
|
145
147
|
std::chrono::steady_clock::time_point last_valid_status_timestamp_; // For protocol timeout
|
146
148
|
std::chrono::steady_clock::time_point last_status_request_; // To request AC status
|
147
149
|
std::chrono::steady_clock::time_point last_signal_request_; // To send WiFI signal level
|
150
|
+
CallbackManager<void(const char *, size_t)> status_message_callback_{};
|
151
|
+
};
|
152
|
+
|
153
|
+
class StatusMessageTrigger : public Trigger<const char *, size_t> {
|
154
|
+
public:
|
155
|
+
explicit StatusMessageTrigger(HaierClimateBase *parent) {
|
156
|
+
parent->add_status_message_callback([this](const char *data, size_t data_size) { this->trigger(data, data_size); });
|
157
|
+
}
|
148
158
|
};
|
149
159
|
|
150
160
|
} // namespace haier
|
@@ -18,12 +18,13 @@ constexpr int PROTOCOL_OUTDOOR_TEMPERATURE_OFFSET = -64;
|
|
18
18
|
constexpr uint8_t CONTROL_MESSAGE_RETRIES = 5;
|
19
19
|
constexpr std::chrono::milliseconds CONTROL_MESSAGE_RETRIES_INTERVAL = std::chrono::milliseconds(500);
|
20
20
|
constexpr size_t ALARM_STATUS_REQUEST_INTERVAL_MS = 600000;
|
21
|
+
const uint8_t ONE_BUF[] = {0x00, 0x01};
|
22
|
+
const uint8_t ZERO_BUF[] = {0x00, 0x00};
|
21
23
|
|
22
24
|
HonClimate::HonClimate()
|
23
25
|
: cleaning_status_(CleaningState::NO_CLEANING), got_valid_outdoor_temp_(false), active_alarms_{0x00, 0x00, 0x00,
|
24
26
|
0x00, 0x00, 0x00,
|
25
27
|
0x00, 0x00} {
|
26
|
-
last_status_message_ = std::unique_ptr<uint8_t[]>(new uint8_t[sizeof(hon_protocol::HaierPacketControl)]);
|
27
28
|
this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID;
|
28
29
|
this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO;
|
29
30
|
}
|
@@ -169,11 +170,18 @@ haier_protocol::HandlerError HonClimate::status_handler_(haier_protocol::FrameTy
|
|
169
170
|
this->action_request_.reset();
|
170
171
|
this->force_send_control_ = false;
|
171
172
|
} else {
|
172
|
-
if (
|
173
|
-
|
173
|
+
if (!this->last_status_message_) {
|
174
|
+
this->real_control_packet_size_ = sizeof(hon_protocol::HaierPacketControl) + this->extra_control_packet_bytes_;
|
175
|
+
this->real_sensors_packet_size_ = sizeof(hon_protocol::HaierPacketSensors) + this->extra_sensors_packet_bytes_;
|
176
|
+
this->last_status_message_.reset();
|
177
|
+
this->last_status_message_ = std::unique_ptr<uint8_t[]>(new uint8_t[this->real_control_packet_size_]);
|
178
|
+
};
|
179
|
+
if (data_size >= this->real_control_packet_size_ + 2) {
|
180
|
+
memcpy(this->last_status_message_.get(), data + 2 + this->status_message_header_size_,
|
181
|
+
this->real_control_packet_size_);
|
182
|
+
this->status_message_callback_.call((const char *) data, data_size);
|
174
183
|
} else {
|
175
|
-
ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size,
|
176
|
-
sizeof(hon_protocol::HaierPacketControl));
|
184
|
+
ESP_LOGW(TAG, "Status packet too small: %d (should be >= %d)", data_size, this->real_control_packet_size_);
|
177
185
|
}
|
178
186
|
switch (this->protocol_phase_) {
|
179
187
|
case ProtocolPhases::SENDING_FIRST_STATUS_REQUEST:
|
@@ -479,8 +487,8 @@ void HonClimate::initialization() {
|
|
479
487
|
}
|
480
488
|
|
481
489
|
haier_protocol::HaierMessage HonClimate::get_control_message() {
|
482
|
-
uint8_t control_out_buffer[
|
483
|
-
memcpy(control_out_buffer, this->last_status_message_.get(),
|
490
|
+
uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE];
|
491
|
+
memcpy(control_out_buffer, this->last_status_message_.get(), this->real_control_packet_size_);
|
484
492
|
hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer;
|
485
493
|
control_out_buffer[4] = 0; // This byte should be cleared before setting values
|
486
494
|
bool has_hvac_settings = false;
|
@@ -636,7 +644,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() {
|
|
636
644
|
out_data->health_mode = this->health_mode_ ? 1 : 0;
|
637
645
|
return haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
638
646
|
(uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS,
|
639
|
-
control_out_buffer,
|
647
|
+
control_out_buffer, this->real_control_packet_size_);
|
640
648
|
}
|
641
649
|
|
642
650
|
void HonClimate::process_alarm_message_(const uint8_t *packet, uint8_t size, bool check_new) {
|
@@ -758,15 +766,17 @@ void HonClimate::update_sub_text_sensor_(SubTextSensorType type, const std::stri
|
|
758
766
|
#endif // USE_TEXT_SENSOR
|
759
767
|
|
760
768
|
haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) {
|
761
|
-
size_t expected_size =
|
762
|
-
|
763
|
-
if (size < expected_size)
|
769
|
+
size_t expected_size =
|
770
|
+
2 + this->status_message_header_size_ + this->real_control_packet_size_ + this->real_sensors_packet_size_;
|
771
|
+
if (size < expected_size) {
|
772
|
+
ESP_LOGW(TAG, "Unexpected message size %d (expexted >= %d)", size, expected_size);
|
764
773
|
return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE;
|
774
|
+
}
|
765
775
|
uint16_t subtype = (((uint16_t) packet_buffer[0]) << 8) + packet_buffer[1];
|
766
|
-
if ((subtype == 0x7D01) && (size >= expected_size +
|
776
|
+
if ((subtype == 0x7D01) && (size >= expected_size + sizeof(hon_protocol::HaierPacketBigData))) {
|
767
777
|
// Got BigData packet
|
768
778
|
const hon_protocol::HaierPacketBigData *bd_packet =
|
769
|
-
(const hon_protocol::HaierPacketBigData *) (&packet_buffer[expected_size
|
779
|
+
(const hon_protocol::HaierPacketBigData *) (&packet_buffer[expected_size]);
|
770
780
|
#ifdef USE_SENSOR
|
771
781
|
this->update_sub_sensor_(SubSensorType::INDOOR_COIL_TEMPERATURE, bd_packet->indoor_coil_temperature / 2.0 - 20);
|
772
782
|
this->update_sub_sensor_(SubSensorType::OUTDOOR_COIL_TEMPERATURE, bd_packet->outdoor_coil_temperature - 64);
|
@@ -795,9 +805,9 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
|
|
795
805
|
hon_protocol::HaierPacketControl control;
|
796
806
|
hon_protocol::HaierPacketSensors sensors;
|
797
807
|
} packet;
|
798
|
-
memcpy(&packet.control, packet_buffer + 2,
|
799
|
-
|
800
|
-
|
808
|
+
memcpy(&packet.control, packet_buffer + 2 + this->status_message_header_size_,
|
809
|
+
sizeof(hon_protocol::HaierPacketControl));
|
810
|
+
memcpy(&packet.sensors, packet_buffer + 2 + this->status_message_header_size_ + this->real_control_packet_size_,
|
801
811
|
sizeof(hon_protocol::HaierPacketSensors));
|
802
812
|
if (packet.sensors.error_status != 0) {
|
803
813
|
ESP_LOGW(TAG, "HVAC error, code=0x%02X", packet.sensors.error_status);
|
@@ -996,8 +1006,6 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
|
|
996
1006
|
}
|
997
1007
|
|
998
1008
|
void HonClimate::fill_control_messages_queue_() {
|
999
|
-
static uint8_t one_buf[] = {0x00, 0x01};
|
1000
|
-
static uint8_t zero_buf[] = {0x00, 0x00};
|
1001
1009
|
if (!this->current_hvac_settings_.valid && !this->force_send_control_)
|
1002
1010
|
return;
|
1003
1011
|
this->clear_control_messages_queue_();
|
@@ -1009,7 +1017,7 @@ void HonClimate::fill_control_messages_queue_() {
|
|
1009
1017
|
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
1010
1018
|
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
1011
1019
|
(uint8_t) hon_protocol::DataParameters::BEEPER_STATUS,
|
1012
|
-
this->beeper_status_ ?
|
1020
|
+
this->beeper_status_ ? ZERO_BUF : ONE_BUF, 2));
|
1013
1021
|
}
|
1014
1022
|
// Health mode
|
1015
1023
|
{
|
@@ -1017,7 +1025,7 @@ void HonClimate::fill_control_messages_queue_() {
|
|
1017
1025
|
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
1018
1026
|
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
1019
1027
|
(uint8_t) hon_protocol::DataParameters::HEALTH_MODE,
|
1020
|
-
this->health_mode_ ?
|
1028
|
+
this->health_mode_ ? ONE_BUF : ZERO_BUF, 2));
|
1021
1029
|
}
|
1022
1030
|
// Climate mode
|
1023
1031
|
bool new_power = this->mode != CLIMATE_MODE_OFF;
|
@@ -1092,7 +1100,7 @@ void HonClimate::fill_control_messages_queue_() {
|
|
1092
1100
|
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
1093
1101
|
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
1094
1102
|
(uint8_t) hon_protocol::DataParameters::AC_POWER,
|
1095
|
-
new_power ?
|
1103
|
+
new_power ? ONE_BUF : ZERO_BUF, 2));
|
1096
1104
|
}
|
1097
1105
|
// CLimate preset
|
1098
1106
|
{
|
@@ -1165,6 +1173,35 @@ void HonClimate::fill_control_messages_queue_() {
|
|
1165
1173
|
(uint8_t) hon_protocol::DataParameters::SET_POINT,
|
1166
1174
|
buffer, 2));
|
1167
1175
|
}
|
1176
|
+
// Vertical swing mode
|
1177
|
+
if (climate_control.swing_mode.has_value()) {
|
1178
|
+
uint8_t vertical_swing_buf[] = {0x00, (uint8_t) hon_protocol::VerticalSwingMode::AUTO};
|
1179
|
+
uint8_t horizontal_swing_buf[] = {0x00, (uint8_t) hon_protocol::HorizontalSwingMode::AUTO};
|
1180
|
+
switch (climate_control.swing_mode.value()) {
|
1181
|
+
case CLIMATE_SWING_OFF:
|
1182
|
+
horizontal_swing_buf[1] = (uint8_t) this->settings_.last_horizontal_swing;
|
1183
|
+
vertical_swing_buf[1] = (uint8_t) this->settings_.last_vertiacal_swing;
|
1184
|
+
break;
|
1185
|
+
case CLIMATE_SWING_VERTICAL:
|
1186
|
+
horizontal_swing_buf[1] = (uint8_t) this->settings_.last_horizontal_swing;
|
1187
|
+
break;
|
1188
|
+
case CLIMATE_SWING_HORIZONTAL:
|
1189
|
+
vertical_swing_buf[1] = (uint8_t) this->settings_.last_vertiacal_swing;
|
1190
|
+
break;
|
1191
|
+
case CLIMATE_SWING_BOTH:
|
1192
|
+
break;
|
1193
|
+
}
|
1194
|
+
this->control_messages_queue_.push(
|
1195
|
+
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
1196
|
+
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
1197
|
+
(uint8_t) hon_protocol::DataParameters::HORIZONTAL_SWING_MODE,
|
1198
|
+
horizontal_swing_buf, 2));
|
1199
|
+
this->control_messages_queue_.push(
|
1200
|
+
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
1201
|
+
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
1202
|
+
(uint8_t) hon_protocol::DataParameters::VERTICAL_SWING_MODE,
|
1203
|
+
vertical_swing_buf, 2));
|
1204
|
+
}
|
1168
1205
|
// Fan mode
|
1169
1206
|
if (climate_control.fan_mode.has_value()) {
|
1170
1207
|
switch (climate_control.fan_mode.value()) {
|
@@ -1202,40 +1239,56 @@ void HonClimate::clear_control_messages_queue_() {
|
|
1202
1239
|
|
1203
1240
|
bool HonClimate::prepare_pending_action() {
|
1204
1241
|
switch (this->action_request_.value().action) {
|
1205
|
-
case ActionRequest::START_SELF_CLEAN:
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
this->
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1242
|
+
case ActionRequest::START_SELF_CLEAN:
|
1243
|
+
if (this->control_method_ == HonControlMethod::SET_GROUP_PARAMETERS) {
|
1244
|
+
uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE];
|
1245
|
+
memcpy(control_out_buffer, this->last_status_message_.get(), this->real_control_packet_size_);
|
1246
|
+
hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer;
|
1247
|
+
out_data->self_cleaning_status = 1;
|
1248
|
+
out_data->steri_clean = 0;
|
1249
|
+
out_data->set_point = 0x06;
|
1250
|
+
out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER;
|
1251
|
+
out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER;
|
1252
|
+
out_data->ac_power = 1;
|
1253
|
+
out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY;
|
1254
|
+
out_data->light_status = 0;
|
1255
|
+
this->action_request_.value().message = haier_protocol::HaierMessage(
|
1256
|
+
haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS,
|
1257
|
+
control_out_buffer, this->real_control_packet_size_);
|
1258
|
+
return true;
|
1259
|
+
} else if (this->control_method_ == HonControlMethod::SET_SINGLE_PARAMETER) {
|
1260
|
+
this->action_request_.value().message =
|
1261
|
+
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
1262
|
+
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
1263
|
+
(uint8_t) hon_protocol::DataParameters::SELF_CLEANING,
|
1264
|
+
ONE_BUF, 2);
|
1265
|
+
return true;
|
1266
|
+
} else {
|
1267
|
+
this->action_request_.reset();
|
1268
|
+
return false;
|
1269
|
+
}
|
1270
|
+
case ActionRequest::START_STERI_CLEAN:
|
1271
|
+
if (this->control_method_ == HonControlMethod::SET_GROUP_PARAMETERS) {
|
1272
|
+
uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE];
|
1273
|
+
memcpy(control_out_buffer, this->last_status_message_.get(), this->real_control_packet_size_);
|
1274
|
+
hon_protocol::HaierPacketControl *out_data = (hon_protocol::HaierPacketControl *) control_out_buffer;
|
1275
|
+
out_data->self_cleaning_status = 0;
|
1276
|
+
out_data->steri_clean = 1;
|
1277
|
+
out_data->set_point = 0x06;
|
1278
|
+
out_data->vertical_swing_mode = (uint8_t) hon_protocol::VerticalSwingMode::CENTER;
|
1279
|
+
out_data->horizontal_swing_mode = (uint8_t) hon_protocol::HorizontalSwingMode::CENTER;
|
1280
|
+
out_data->ac_power = 1;
|
1281
|
+
out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY;
|
1282
|
+
out_data->light_status = 0;
|
1283
|
+
this->action_request_.value().message = haier_protocol::HaierMessage(
|
1284
|
+
haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS,
|
1285
|
+
control_out_buffer, this->real_control_packet_size_);
|
1286
|
+
return true;
|
1287
|
+
} else {
|
1288
|
+
// No Steri clean support (yet?) in SET_SINGLE_PARAMETER
|
1289
|
+
this->action_request_.reset();
|
1290
|
+
return false;
|
1291
|
+
}
|
1239
1292
|
default:
|
1240
1293
|
return HaierClimateBase::prepare_pending_action();
|
1241
1294
|
}
|
@@ -1251,6 +1304,7 @@ void HonClimate::process_protocol_reset() {
|
|
1251
1304
|
#endif // USE_SENSOR
|
1252
1305
|
this->got_valid_outdoor_temp_ = false;
|
1253
1306
|
this->hvac_hardware_info_.reset();
|
1307
|
+
this->last_status_message_.reset(nullptr);
|
1254
1308
|
}
|
1255
1309
|
|
1256
1310
|
bool HonClimate::should_get_big_data_() {
|
@@ -104,6 +104,8 @@ class HonClimate : public HaierClimateBase {
|
|
104
104
|
void start_self_cleaning();
|
105
105
|
void start_steri_cleaning();
|
106
106
|
void set_extra_control_packet_bytes_size(size_t size) { this->extra_control_packet_bytes_ = size; };
|
107
|
+
void set_extra_sensors_packet_bytes_size(size_t size) { this->extra_sensors_packet_bytes_ = size; };
|
108
|
+
void set_status_message_header_size(size_t size) { this->status_message_header_size_ = size; };
|
107
109
|
void set_control_method(HonControlMethod method) { this->control_method_ = method; };
|
108
110
|
void add_alarm_start_callback(std::function<void(uint8_t, const char *)> &&callback);
|
109
111
|
void add_alarm_end_callback(std::function<void(uint8_t, const char *)> &&callback);
|
@@ -158,7 +160,11 @@ class HonClimate : public HaierClimateBase {
|
|
158
160
|
esphome::optional<hon_protocol::HorizontalSwingMode> pending_horizontal_direction_{};
|
159
161
|
esphome::optional<HardwareInfo> hvac_hardware_info_{};
|
160
162
|
uint8_t active_alarms_[8];
|
161
|
-
int extra_control_packet_bytes_;
|
163
|
+
int extra_control_packet_bytes_{0};
|
164
|
+
int extra_sensors_packet_bytes_{4};
|
165
|
+
int status_message_header_size_{0};
|
166
|
+
int real_control_packet_size_{sizeof(hon_protocol::HaierPacketControl)};
|
167
|
+
int real_sensors_packet_size_{sizeof(hon_protocol::HaierPacketSensors) + 4};
|
162
168
|
HonControlMethod control_method_;
|
163
169
|
std::queue<haier_protocol::HaierMessage> control_messages_queue_;
|
164
170
|
CallbackManager<void(uint8_t, const char *)> alarm_start_callback_{};
|
@@ -41,15 +41,20 @@ enum class ConditioningMode : uint8_t {
|
|
41
41
|
enum class DataParameters : uint8_t {
|
42
42
|
AC_POWER = 0x01,
|
43
43
|
SET_POINT = 0x02,
|
44
|
+
VERTICAL_SWING_MODE = 0x03,
|
44
45
|
AC_MODE = 0x04,
|
45
46
|
FAN_MODE = 0x05,
|
46
47
|
USE_FAHRENHEIT = 0x07,
|
48
|
+
DISPLAY_STATUS = 0x09,
|
47
49
|
TEN_DEGREE = 0x0A,
|
48
50
|
HEALTH_MODE = 0x0B,
|
51
|
+
HORIZONTAL_SWING_MODE = 0x0C,
|
52
|
+
SELF_CLEANING = 0x0D,
|
49
53
|
BEEPER_STATUS = 0x16,
|
50
54
|
LOCK_REMOTE = 0x17,
|
51
55
|
QUIET_MODE = 0x19,
|
52
56
|
FAST_MODE = 0x1A,
|
57
|
+
SLEEP_MODE = 0x1B,
|
53
58
|
};
|
54
59
|
|
55
60
|
enum class SpecialMode : uint8_t { NONE = 0x00, ELDERLY = 0x01, CHILDREN = 0x02, PREGNANT = 0x03 };
|
@@ -137,16 +137,16 @@ SENSOR_TYPES = {
|
|
137
137
|
|
138
138
|
CONFIG_SCHEMA = cv.Schema(
|
139
139
|
{
|
140
|
-
cv.
|
140
|
+
cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate),
|
141
141
|
}
|
142
|
-
).extend({cv.Optional(
|
142
|
+
).extend({cv.Optional(type_): schema for type_, schema in SENSOR_TYPES.items()})
|
143
143
|
|
144
144
|
|
145
145
|
async def to_code(config):
|
146
146
|
paren = await cg.get_variable(config[CONF_HAIER_ID])
|
147
147
|
|
148
|
-
for
|
149
|
-
if conf := config.get(
|
148
|
+
for type_ in SENSOR_TYPES:
|
149
|
+
if conf := config.get(type_):
|
150
150
|
sens = await sensor.new_sensor(conf)
|
151
|
-
sensor_type = getattr(SensorTypeEnum,
|
151
|
+
sensor_type = getattr(SensorTypeEnum, type_.upper())
|
152
152
|
cg.add(paren.set_sub_sensor(sensor_type, sens))
|