esphome 2025.2.2__py3-none-any.whl → 2025.3.0b2__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 +9 -1
- esphome/components/api/api_connection.cpp +426 -70
- esphome/components/api/api_connection.h +117 -25
- esphome/components/api/api_pb2.cpp +33 -0
- esphome/components/api/api_pb2.h +4 -0
- esphome/components/api/api_server.cpp +2 -2
- esphome/components/api/list_entities.cpp +76 -22
- esphome/components/api/list_entities.h +1 -0
- esphome/components/api/subscribe_state.h +2 -0
- esphome/components/audio/__init__.py +1 -1
- esphome/components/audio/audio_decoder.cpp +43 -11
- esphome/components/audio/audio_reader.cpp +2 -2
- esphome/components/audio/audio_resampler.cpp +4 -2
- esphome/components/audio/audio_transfer_buffer.cpp +19 -9
- esphome/components/audio/audio_transfer_buffer.h +7 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -0
- esphome/components/bmp085/bmp085.cpp +1 -1
- esphome/components/chsc6x/__init__.py +2 -0
- esphome/components/chsc6x/chsc6x_touchscreen.cpp +47 -0
- esphome/components/chsc6x/chsc6x_touchscreen.h +34 -0
- esphome/components/chsc6x/touchscreen.py +33 -0
- esphome/components/climate/__init__.py +0 -1
- esphome/components/cst816/binary_sensor/__init__.py +2 -25
- esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +3 -14
- esphome/components/cst816/touchscreen/cst816_touchscreen.h +0 -4
- esphome/components/esp32_ble_beacon/__init__.py +3 -1
- esphome/components/esp8266/gpio.py +1 -2
- esphome/components/font/__init__.py +185 -185
- esphome/components/font/font.cpp +4 -4
- esphome/components/font/font.h +1 -0
- esphome/components/haier/climate.py +11 -10
- esphome/components/hbridge/switch/hbridge_switch.cpp +2 -2
- esphome/components/heatpumpir/climate.py +2 -1
- esphome/components/heatpumpir/heatpumpir.cpp +1 -0
- esphome/components/heatpumpir/heatpumpir.h +1 -0
- esphome/components/i2c/__init__.py +6 -6
- esphome/components/i2c/i2c_bus_esp_idf.cpp +6 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/ili9xxx/display.py +1 -0
- esphome/components/ili9xxx/ili9xxx_display.h +5 -0
- esphome/components/ili9xxx/ili9xxx_init.h +59 -0
- esphome/components/ld2450/__init__.py +51 -0
- esphome/components/ld2450/binary_sensor.py +47 -0
- esphome/components/ld2450/button/__init__.py +45 -0
- esphome/components/ld2450/button/reset_button.cpp +9 -0
- esphome/components/ld2450/button/reset_button.h +18 -0
- esphome/components/ld2450/button/restart_button.cpp +9 -0
- esphome/components/ld2450/button/restart_button.h +18 -0
- esphome/components/ld2450/ld2450.cpp +876 -0
- esphome/components/ld2450/ld2450.h +234 -0
- esphome/components/ld2450/number/__init__.py +121 -0
- esphome/components/ld2450/number/presence_timeout_number.cpp +12 -0
- esphome/components/ld2450/number/presence_timeout_number.h +18 -0
- esphome/components/ld2450/number/zone_coordinate_number.cpp +14 -0
- esphome/components/ld2450/number/zone_coordinate_number.h +19 -0
- esphome/components/ld2450/select/__init__.py +56 -0
- esphome/components/ld2450/select/baud_rate_select.cpp +12 -0
- esphome/components/ld2450/select/baud_rate_select.h +18 -0
- esphome/components/ld2450/select/zone_type_select.cpp +12 -0
- esphome/components/ld2450/select/zone_type_select.h +18 -0
- esphome/components/ld2450/sensor.py +156 -0
- esphome/components/ld2450/switch/__init__.py +45 -0
- esphome/components/ld2450/switch/bluetooth_switch.cpp +12 -0
- esphome/components/ld2450/switch/bluetooth_switch.h +18 -0
- esphome/components/ld2450/switch/multi_target_switch.cpp +12 -0
- esphome/components/ld2450/switch/multi_target_switch.h +18 -0
- esphome/components/ld2450/text_sensor.py +62 -0
- esphome/components/lvgl/defines.py +0 -2
- esphome/components/lvgl/font.cpp +1 -1
- esphome/components/lvgl/lvgl_esphome.cpp +27 -19
- esphome/components/lvgl/widgets/img.py +1 -3
- esphome/components/mcp2515/mcp2515.cpp +1 -0
- esphome/components/mdns/__init__.py +1 -1
- esphome/components/mixer/speaker/mixer_speaker.cpp +6 -1
- esphome/components/mixer/speaker/mixer_speaker.h +2 -0
- esphome/components/mlx90393/sensor.py +53 -33
- esphome/components/mlx90393/sensor_mlx90393.cpp +4 -0
- esphome/components/mlx90393/sensor_mlx90393.h +8 -3
- esphome/components/mqtt/__init__.py +2 -2
- esphome/components/msa3xx/__init__.py +189 -0
- esphome/components/msa3xx/binary_sensor.py +40 -0
- esphome/components/msa3xx/msa3xx.cpp +417 -0
- esphome/components/msa3xx/msa3xx.h +311 -0
- esphome/components/msa3xx/sensor.py +42 -0
- esphome/components/msa3xx/text_sensor.py +38 -0
- esphome/components/nfc/binary_sensor/__init__.py +4 -4
- esphome/components/opentherm/binary_sensor/__init__.py +4 -4
- esphome/components/opentherm/generate.py +6 -6
- esphome/components/opentherm/sensor/__init__.py +5 -6
- esphome/components/packages/__init__.py +35 -11
- esphome/components/pn532/binary_sensor.py +4 -4
- esphome/components/rc522/binary_sensor.py +4 -4
- esphome/components/resampler/speaker/resampler_speaker.h +2 -0
- esphome/components/socket/bsd_sockets_impl.cpp +1 -0
- esphome/components/socket/lwip_sockets_impl.cpp +1 -0
- esphome/components/socket/socket.h +3 -1
- esphome/components/speaker/speaker.h +2 -2
- esphome/components/ssd1306_base/__init__.py +7 -7
- esphome/components/thermostat/climate.py +1 -1
- esphome/components/tmp1075/tmp1075.cpp +7 -11
- esphome/components/tmp1075/tmp1075.h +1 -2
- esphome/components/tormatic/__init__.py +1 -0
- esphome/components/tormatic/cover.py +47 -0
- esphome/components/tormatic/tormatic_cover.cpp +355 -0
- esphome/components/tormatic/tormatic_cover.h +60 -0
- esphome/components/tormatic/tormatic_protocol.h +211 -0
- esphome/components/touchscreen/binary_sensor/__init__.py +3 -0
- esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +7 -1
- esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +3 -1
- esphome/components/touchscreen/touchscreen.cpp +3 -4
- esphome/components/udp/udp_component.h +4 -1
- esphome/components/web_server/list_entities.cpp +70 -66
- esphome/components/web_server/list_entities.h +43 -22
- esphome/components/web_server/web_server.cpp +345 -68
- esphome/components/web_server/web_server.h +138 -6
- esphome/components/web_server_base/__init__.py +1 -1
- esphome/components/web_server_idf/__init__.py +2 -0
- esphome/components/web_server_idf/web_server_idf.cpp +177 -30
- esphome/components/web_server_idf/web_server_idf.h +53 -4
- esphome/config_validation.py +23 -125
- esphome/const.py +5 -1
- esphome/core/config.py +12 -4
- esphome/core/defines.h +1 -1
- esphome/core/helpers.h +24 -3
- esphome/core/time.cpp +1 -0
- esphome/cpp_generator.py +3 -3
- esphome/dashboard/core.py +30 -21
- esphome/dashboard/dns.py +7 -1
- esphome/dashboard/entries.py +83 -16
- esphome/dashboard/settings.py +0 -4
- esphome/dashboard/status/mdns.py +43 -14
- esphome/dashboard/status/mqtt.py +22 -9
- esphome/dashboard/status/ping.py +54 -10
- esphome/dashboard/web_server.py +56 -24
- esphome/storage_json.py +4 -0
- esphome/wizard.py +13 -17
- esphome/writer.py +1 -3
- esphome/yaml_util.py +36 -33
- esphome/zeroconf.py +9 -21
- {esphome-2025.2.2.dist-info → esphome-2025.3.0b2.dist-info}/METADATA +7 -7
- {esphome-2025.2.2.dist-info → esphome-2025.3.0b2.dist-info}/RECORD +145 -105
- esphome/components/cst816/binary_sensor/cst816_button.h +0 -27
- {esphome-2025.2.2.dist-info → esphome-2025.3.0b2.dist-info}/LICENSE +0 -0
- {esphome-2025.2.2.dist-info → esphome-2025.3.0b2.dist-info}/WHEEL +0 -0
- {esphome-2025.2.2.dist-info → esphome-2025.3.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.2.2.dist-info → esphome-2025.3.0b2.dist-info}/top_level.txt +0 -0
@@ -14,6 +14,46 @@
|
|
14
14
|
namespace esphome {
|
15
15
|
namespace api {
|
16
16
|
|
17
|
+
using send_message_t = bool(APIConnection *, void *);
|
18
|
+
|
19
|
+
/*
|
20
|
+
This class holds a pointer to the source component that wants to publish a message, and a pointer to a function that
|
21
|
+
will lazily publish that message. The two pointers allow dedup in the deferred queue if multiple publishes for the
|
22
|
+
same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a std::vector) is
|
23
|
+
the DeferredMessage instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per entry. Even
|
24
|
+
100 backed up messages (you'd have to have at least 100 sensors publishing because of dedup) would take up only 0.8
|
25
|
+
kB.
|
26
|
+
*/
|
27
|
+
class DeferredMessageQueue {
|
28
|
+
struct DeferredMessage {
|
29
|
+
friend class DeferredMessageQueue;
|
30
|
+
|
31
|
+
protected:
|
32
|
+
void *source_;
|
33
|
+
send_message_t *send_message_;
|
34
|
+
|
35
|
+
public:
|
36
|
+
DeferredMessage(void *source, send_message_t *send_message) : source_(source), send_message_(send_message) {}
|
37
|
+
bool operator==(const DeferredMessage &test) const {
|
38
|
+
return (source_ == test.source_ && send_message_ == test.send_message_);
|
39
|
+
}
|
40
|
+
} __attribute__((packed));
|
41
|
+
|
42
|
+
protected:
|
43
|
+
// vector is used very specifically for its zero memory overhead even though items are popped from the front (memory
|
44
|
+
// footprint is more important than speed here)
|
45
|
+
std::vector<DeferredMessage> deferred_queue_;
|
46
|
+
APIConnection *api_connection_;
|
47
|
+
|
48
|
+
// helper for allowing only unique entries in the queue
|
49
|
+
void dmq_push_back_with_dedup_(void *source, send_message_t *send_message);
|
50
|
+
|
51
|
+
public:
|
52
|
+
DeferredMessageQueue(APIConnection *api_connection) : api_connection_(api_connection) {}
|
53
|
+
void process_queue();
|
54
|
+
void defer(void *source, send_message_t *send_message);
|
55
|
+
};
|
56
|
+
|
17
57
|
class APIConnection : public APIServerConnection {
|
18
58
|
public:
|
19
59
|
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
|
@@ -28,96 +68,140 @@ class APIConnection : public APIServerConnection {
|
|
28
68
|
}
|
29
69
|
#ifdef USE_BINARY_SENSOR
|
30
70
|
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state);
|
31
|
-
|
71
|
+
void send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor);
|
72
|
+
static bool try_send_binary_sensor_state(APIConnection *api, void *v_binary_sensor);
|
73
|
+
static bool try_send_binary_sensor_state(APIConnection *api, binary_sensor::BinarySensor *binary_sensor, bool state);
|
74
|
+
static bool try_send_binary_sensor_info(APIConnection *api, void *v_binary_sensor);
|
32
75
|
#endif
|
33
76
|
#ifdef USE_COVER
|
34
77
|
bool send_cover_state(cover::Cover *cover);
|
35
|
-
|
78
|
+
void send_cover_info(cover::Cover *cover);
|
79
|
+
static bool try_send_cover_state(APIConnection *api, void *v_cover);
|
80
|
+
static bool try_send_cover_info(APIConnection *api, void *v_cover);
|
36
81
|
void cover_command(const CoverCommandRequest &msg) override;
|
37
82
|
#endif
|
38
83
|
#ifdef USE_FAN
|
39
84
|
bool send_fan_state(fan::Fan *fan);
|
40
|
-
|
85
|
+
void send_fan_info(fan::Fan *fan);
|
86
|
+
static bool try_send_fan_state(APIConnection *api, void *v_fan);
|
87
|
+
static bool try_send_fan_info(APIConnection *api, void *v_fan);
|
41
88
|
void fan_command(const FanCommandRequest &msg) override;
|
42
89
|
#endif
|
43
90
|
#ifdef USE_LIGHT
|
44
91
|
bool send_light_state(light::LightState *light);
|
45
|
-
|
92
|
+
void send_light_info(light::LightState *light);
|
93
|
+
static bool try_send_light_state(APIConnection *api, void *v_light);
|
94
|
+
static bool try_send_light_info(APIConnection *api, void *v_light);
|
46
95
|
void light_command(const LightCommandRequest &msg) override;
|
47
96
|
#endif
|
48
97
|
#ifdef USE_SENSOR
|
49
98
|
bool send_sensor_state(sensor::Sensor *sensor, float state);
|
50
|
-
|
99
|
+
void send_sensor_info(sensor::Sensor *sensor);
|
100
|
+
static bool try_send_sensor_state(APIConnection *api, void *v_sensor);
|
101
|
+
static bool try_send_sensor_state(APIConnection *api, sensor::Sensor *sensor, float state);
|
102
|
+
static bool try_send_sensor_info(APIConnection *api, void *v_sensor);
|
51
103
|
#endif
|
52
104
|
#ifdef USE_SWITCH
|
53
105
|
bool send_switch_state(switch_::Switch *a_switch, bool state);
|
54
|
-
|
106
|
+
void send_switch_info(switch_::Switch *a_switch);
|
107
|
+
static bool try_send_switch_state(APIConnection *api, void *v_a_switch);
|
108
|
+
static bool try_send_switch_state(APIConnection *api, switch_::Switch *a_switch, bool state);
|
109
|
+
static bool try_send_switch_info(APIConnection *api, void *v_a_switch);
|
55
110
|
void switch_command(const SwitchCommandRequest &msg) override;
|
56
111
|
#endif
|
57
112
|
#ifdef USE_TEXT_SENSOR
|
58
113
|
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor, std::string state);
|
59
|
-
|
114
|
+
void send_text_sensor_info(text_sensor::TextSensor *text_sensor);
|
115
|
+
static bool try_send_text_sensor_state(APIConnection *api, void *v_text_sensor);
|
116
|
+
static bool try_send_text_sensor_state(APIConnection *api, text_sensor::TextSensor *text_sensor, std::string state);
|
117
|
+
static bool try_send_text_sensor_info(APIConnection *api, void *v_text_sensor);
|
60
118
|
#endif
|
61
119
|
#ifdef USE_ESP32_CAMERA
|
62
|
-
void
|
63
|
-
|
120
|
+
void set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
|
121
|
+
void send_camera_info(esp32_camera::ESP32Camera *camera);
|
122
|
+
static bool try_send_camera_info(APIConnection *api, void *v_camera);
|
64
123
|
void camera_image(const CameraImageRequest &msg) override;
|
65
124
|
#endif
|
66
125
|
#ifdef USE_CLIMATE
|
67
126
|
bool send_climate_state(climate::Climate *climate);
|
68
|
-
|
127
|
+
void send_climate_info(climate::Climate *climate);
|
128
|
+
static bool try_send_climate_state(APIConnection *api, void *v_climate);
|
129
|
+
static bool try_send_climate_info(APIConnection *api, void *v_climate);
|
69
130
|
void climate_command(const ClimateCommandRequest &msg) override;
|
70
131
|
#endif
|
71
132
|
#ifdef USE_NUMBER
|
72
133
|
bool send_number_state(number::Number *number, float state);
|
73
|
-
|
134
|
+
void send_number_info(number::Number *number);
|
135
|
+
static bool try_send_number_state(APIConnection *api, void *v_number);
|
136
|
+
static bool try_send_number_state(APIConnection *api, number::Number *number, float state);
|
137
|
+
static bool try_send_number_info(APIConnection *api, void *v_number);
|
74
138
|
void number_command(const NumberCommandRequest &msg) override;
|
75
139
|
#endif
|
76
140
|
#ifdef USE_DATETIME_DATE
|
77
141
|
bool send_date_state(datetime::DateEntity *date);
|
78
|
-
|
142
|
+
void send_date_info(datetime::DateEntity *date);
|
143
|
+
static bool try_send_date_state(APIConnection *api, void *v_date);
|
144
|
+
static bool try_send_date_info(APIConnection *api, void *v_date);
|
79
145
|
void date_command(const DateCommandRequest &msg) override;
|
80
146
|
#endif
|
81
147
|
#ifdef USE_DATETIME_TIME
|
82
148
|
bool send_time_state(datetime::TimeEntity *time);
|
83
|
-
|
149
|
+
void send_time_info(datetime::TimeEntity *time);
|
150
|
+
static bool try_send_time_state(APIConnection *api, void *v_time);
|
151
|
+
static bool try_send_time_info(APIConnection *api, void *v_time);
|
84
152
|
void time_command(const TimeCommandRequest &msg) override;
|
85
153
|
#endif
|
86
154
|
#ifdef USE_DATETIME_DATETIME
|
87
155
|
bool send_datetime_state(datetime::DateTimeEntity *datetime);
|
88
|
-
|
156
|
+
void send_datetime_info(datetime::DateTimeEntity *datetime);
|
157
|
+
static bool try_send_datetime_state(APIConnection *api, void *v_datetime);
|
158
|
+
static bool try_send_datetime_info(APIConnection *api, void *v_datetime);
|
89
159
|
void datetime_command(const DateTimeCommandRequest &msg) override;
|
90
160
|
#endif
|
91
161
|
#ifdef USE_TEXT
|
92
162
|
bool send_text_state(text::Text *text, std::string state);
|
93
|
-
|
163
|
+
void send_text_info(text::Text *text);
|
164
|
+
static bool try_send_text_state(APIConnection *api, void *v_text);
|
165
|
+
static bool try_send_text_state(APIConnection *api, text::Text *text, std::string state);
|
166
|
+
static bool try_send_text_info(APIConnection *api, void *v_text);
|
94
167
|
void text_command(const TextCommandRequest &msg) override;
|
95
168
|
#endif
|
96
169
|
#ifdef USE_SELECT
|
97
170
|
bool send_select_state(select::Select *select, std::string state);
|
98
|
-
|
171
|
+
void send_select_info(select::Select *select);
|
172
|
+
static bool try_send_select_state(APIConnection *api, void *v_select);
|
173
|
+
static bool try_send_select_state(APIConnection *api, select::Select *select, std::string state);
|
174
|
+
static bool try_send_select_info(APIConnection *api, void *v_select);
|
99
175
|
void select_command(const SelectCommandRequest &msg) override;
|
100
176
|
#endif
|
101
177
|
#ifdef USE_BUTTON
|
102
|
-
|
178
|
+
void send_button_info(button::Button *button);
|
179
|
+
static bool try_send_button_info(APIConnection *api, void *v_button);
|
103
180
|
void button_command(const ButtonCommandRequest &msg) override;
|
104
181
|
#endif
|
105
182
|
#ifdef USE_LOCK
|
106
183
|
bool send_lock_state(lock::Lock *a_lock, lock::LockState state);
|
107
|
-
|
184
|
+
void send_lock_info(lock::Lock *a_lock);
|
185
|
+
static bool try_send_lock_state(APIConnection *api, void *v_a_lock);
|
186
|
+
static bool try_send_lock_state(APIConnection *api, lock::Lock *a_lock, lock::LockState state);
|
187
|
+
static bool try_send_lock_info(APIConnection *api, void *v_a_lock);
|
108
188
|
void lock_command(const LockCommandRequest &msg) override;
|
109
189
|
#endif
|
110
190
|
#ifdef USE_VALVE
|
111
191
|
bool send_valve_state(valve::Valve *valve);
|
112
|
-
|
192
|
+
void send_valve_info(valve::Valve *valve);
|
193
|
+
static bool try_send_valve_state(APIConnection *api, void *v_valve);
|
194
|
+
static bool try_send_valve_info(APIConnection *api, void *v_valve);
|
113
195
|
void valve_command(const ValveCommandRequest &msg) override;
|
114
196
|
#endif
|
115
197
|
#ifdef USE_MEDIA_PLAYER
|
116
198
|
bool send_media_player_state(media_player::MediaPlayer *media_player);
|
117
|
-
|
199
|
+
void send_media_player_info(media_player::MediaPlayer *media_player);
|
200
|
+
static bool try_send_media_player_state(APIConnection *api, void *v_media_player);
|
201
|
+
static bool try_send_media_player_info(APIConnection *api, void *v_media_player);
|
118
202
|
void media_player_command(const MediaPlayerCommandRequest &msg) override;
|
119
203
|
#endif
|
120
|
-
bool
|
204
|
+
bool try_send_log_message(int level, const char *tag, const char *line);
|
121
205
|
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
|
122
206
|
if (!this->service_call_subscription_)
|
123
207
|
return;
|
@@ -160,18 +244,25 @@ class APIConnection : public APIServerConnection {
|
|
160
244
|
|
161
245
|
#ifdef USE_ALARM_CONTROL_PANEL
|
162
246
|
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
|
163
|
-
|
247
|
+
void send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
|
248
|
+
static bool try_send_alarm_control_panel_state(APIConnection *api, void *v_a_alarm_control_panel);
|
249
|
+
static bool try_send_alarm_control_panel_info(APIConnection *api, void *v_a_alarm_control_panel);
|
164
250
|
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
|
165
251
|
#endif
|
166
252
|
|
167
253
|
#ifdef USE_EVENT
|
168
|
-
|
169
|
-
|
254
|
+
void send_event(event::Event *event, std::string event_type);
|
255
|
+
void send_event_info(event::Event *event);
|
256
|
+
static bool try_send_event(APIConnection *api, void *v_event);
|
257
|
+
static bool try_send_event(APIConnection *api, event::Event *event, std::string event_type);
|
258
|
+
static bool try_send_event_info(APIConnection *api, void *v_event);
|
170
259
|
#endif
|
171
260
|
|
172
261
|
#ifdef USE_UPDATE
|
173
262
|
bool send_update_state(update::UpdateEntity *update);
|
174
|
-
|
263
|
+
void send_update_info(update::UpdateEntity *update);
|
264
|
+
static bool try_send_update_state(APIConnection *api, void *v_update);
|
265
|
+
static bool try_send_update_info(APIConnection *api, void *v_update);
|
175
266
|
void update_command(const UpdateCommandRequest &msg) override;
|
176
267
|
#endif
|
177
268
|
|
@@ -262,6 +353,7 @@ class APIConnection : public APIServerConnection {
|
|
262
353
|
bool service_call_subscription_{false};
|
263
354
|
bool next_close_ = false;
|
264
355
|
APIServer *parent_;
|
356
|
+
DeferredMessageQueue deferred_message_queue_;
|
265
357
|
InitialStateIterator initial_state_iterator_;
|
266
358
|
ListEntitiesIterator list_entities_iterator_;
|
267
359
|
int state_subs_at_ = -1;
|
@@ -838,6 +838,10 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
|
|
838
838
|
this->suggested_area = value.as_string();
|
839
839
|
return true;
|
840
840
|
}
|
841
|
+
case 18: {
|
842
|
+
this->bluetooth_mac_address = value.as_string();
|
843
|
+
return true;
|
844
|
+
}
|
841
845
|
default:
|
842
846
|
return false;
|
843
847
|
}
|
@@ -860,6 +864,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
|
|
860
864
|
buffer.encode_uint32(14, this->legacy_voice_assistant_version);
|
861
865
|
buffer.encode_uint32(17, this->voice_assistant_feature_flags);
|
862
866
|
buffer.encode_string(16, this->suggested_area);
|
867
|
+
buffer.encode_string(18, this->bluetooth_mac_address);
|
863
868
|
}
|
864
869
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
865
870
|
void DeviceInfoResponse::dump_to(std::string &out) const {
|
@@ -937,6 +942,10 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
|
|
937
942
|
out.append(" suggested_area: ");
|
938
943
|
out.append("'").append(this->suggested_area).append("'");
|
939
944
|
out.append("\n");
|
945
|
+
|
946
|
+
out.append(" bluetooth_mac_address: ");
|
947
|
+
out.append("'").append(this->bluetooth_mac_address).append("'");
|
948
|
+
out.append("\n");
|
940
949
|
out.append("}");
|
941
950
|
}
|
942
951
|
#endif
|
@@ -7085,6 +7094,16 @@ void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
|
|
7085
7094
|
out.append("}");
|
7086
7095
|
}
|
7087
7096
|
#endif
|
7097
|
+
bool VoiceAssistantAnnounceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
7098
|
+
switch (field_id) {
|
7099
|
+
case 4: {
|
7100
|
+
this->start_conversation = value.as_bool();
|
7101
|
+
return true;
|
7102
|
+
}
|
7103
|
+
default:
|
7104
|
+
return false;
|
7105
|
+
}
|
7106
|
+
}
|
7088
7107
|
bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
7089
7108
|
switch (field_id) {
|
7090
7109
|
case 1: {
|
@@ -7095,6 +7114,10 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength
|
|
7095
7114
|
this->text = value.as_string();
|
7096
7115
|
return true;
|
7097
7116
|
}
|
7117
|
+
case 3: {
|
7118
|
+
this->preannounce_media_id = value.as_string();
|
7119
|
+
return true;
|
7120
|
+
}
|
7098
7121
|
default:
|
7099
7122
|
return false;
|
7100
7123
|
}
|
@@ -7102,6 +7125,8 @@ bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLength
|
|
7102
7125
|
void VoiceAssistantAnnounceRequest::encode(ProtoWriteBuffer buffer) const {
|
7103
7126
|
buffer.encode_string(1, this->media_id);
|
7104
7127
|
buffer.encode_string(2, this->text);
|
7128
|
+
buffer.encode_string(3, this->preannounce_media_id);
|
7129
|
+
buffer.encode_bool(4, this->start_conversation);
|
7105
7130
|
}
|
7106
7131
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
7107
7132
|
void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const {
|
@@ -7114,6 +7139,14 @@ void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const {
|
|
7114
7139
|
out.append(" text: ");
|
7115
7140
|
out.append("'").append(this->text).append("'");
|
7116
7141
|
out.append("\n");
|
7142
|
+
|
7143
|
+
out.append(" preannounce_media_id: ");
|
7144
|
+
out.append("'").append(this->preannounce_media_id).append("'");
|
7145
|
+
out.append("\n");
|
7146
|
+
|
7147
|
+
out.append(" start_conversation: ");
|
7148
|
+
out.append(YESNO(this->start_conversation));
|
7149
|
+
out.append("\n");
|
7117
7150
|
out.append("}");
|
7118
7151
|
}
|
7119
7152
|
#endif
|
esphome/components/api/api_pb2.h
CHANGED
@@ -354,6 +354,7 @@ class DeviceInfoResponse : public ProtoMessage {
|
|
354
354
|
uint32_t legacy_voice_assistant_version{0};
|
355
355
|
uint32_t voice_assistant_feature_flags{0};
|
356
356
|
std::string suggested_area{};
|
357
|
+
std::string bluetooth_mac_address{};
|
357
358
|
void encode(ProtoWriteBuffer buffer) const override;
|
358
359
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
359
360
|
void dump_to(std::string &out) const override;
|
@@ -1831,6 +1832,8 @@ class VoiceAssistantAnnounceRequest : public ProtoMessage {
|
|
1831
1832
|
public:
|
1832
1833
|
std::string media_id{};
|
1833
1834
|
std::string text{};
|
1835
|
+
std::string preannounce_media_id{};
|
1836
|
+
bool start_conversation{false};
|
1834
1837
|
void encode(ProtoWriteBuffer buffer) const override;
|
1835
1838
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
1836
1839
|
void dump_to(std::string &out) const override;
|
@@ -1838,6 +1841,7 @@ class VoiceAssistantAnnounceRequest : public ProtoMessage {
|
|
1838
1841
|
|
1839
1842
|
protected:
|
1840
1843
|
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
1844
|
+
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
1841
1845
|
};
|
1842
1846
|
class VoiceAssistantAnnounceFinished : public ProtoMessage {
|
1843
1847
|
public:
|
@@ -72,7 +72,7 @@ void APIServer::setup() {
|
|
72
72
|
logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) {
|
73
73
|
for (auto &c : this->clients_) {
|
74
74
|
if (!c->remove_)
|
75
|
-
c->
|
75
|
+
c->try_send_log_message(level, tag, message);
|
76
76
|
}
|
77
77
|
});
|
78
78
|
}
|
@@ -86,7 +86,7 @@ void APIServer::setup() {
|
|
86
86
|
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
|
87
87
|
for (auto &c : this->clients_) {
|
88
88
|
if (!c->remove_)
|
89
|
-
c->
|
89
|
+
c->set_camera_state(image);
|
90
90
|
}
|
91
91
|
});
|
92
92
|
}
|
@@ -10,37 +10,63 @@ namespace api {
|
|
10
10
|
|
11
11
|
#ifdef USE_BINARY_SENSOR
|
12
12
|
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
|
13
|
-
|
13
|
+
this->client_->send_binary_sensor_info(binary_sensor);
|
14
|
+
return true;
|
14
15
|
}
|
15
16
|
#endif
|
16
17
|
#ifdef USE_COVER
|
17
|
-
bool ListEntitiesIterator::on_cover(cover::Cover *cover) {
|
18
|
+
bool ListEntitiesIterator::on_cover(cover::Cover *cover) {
|
19
|
+
this->client_->send_cover_info(cover);
|
20
|
+
return true;
|
21
|
+
}
|
18
22
|
#endif
|
19
23
|
#ifdef USE_FAN
|
20
|
-
bool ListEntitiesIterator::on_fan(fan::Fan *fan) {
|
24
|
+
bool ListEntitiesIterator::on_fan(fan::Fan *fan) {
|
25
|
+
this->client_->send_fan_info(fan);
|
26
|
+
return true;
|
27
|
+
}
|
21
28
|
#endif
|
22
29
|
#ifdef USE_LIGHT
|
23
|
-
bool ListEntitiesIterator::on_light(light::LightState *light) {
|
30
|
+
bool ListEntitiesIterator::on_light(light::LightState *light) {
|
31
|
+
this->client_->send_light_info(light);
|
32
|
+
return true;
|
33
|
+
}
|
24
34
|
#endif
|
25
35
|
#ifdef USE_SENSOR
|
26
|
-
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) {
|
36
|
+
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) {
|
37
|
+
this->client_->send_sensor_info(sensor);
|
38
|
+
return true;
|
39
|
+
}
|
27
40
|
#endif
|
28
41
|
#ifdef USE_SWITCH
|
29
|
-
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) {
|
42
|
+
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) {
|
43
|
+
this->client_->send_switch_info(a_switch);
|
44
|
+
return true;
|
45
|
+
}
|
30
46
|
#endif
|
31
47
|
#ifdef USE_BUTTON
|
32
|
-
bool ListEntitiesIterator::on_button(button::Button *button) {
|
48
|
+
bool ListEntitiesIterator::on_button(button::Button *button) {
|
49
|
+
this->client_->send_button_info(button);
|
50
|
+
return true;
|
51
|
+
}
|
33
52
|
#endif
|
34
53
|
#ifdef USE_TEXT_SENSOR
|
35
54
|
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
|
36
|
-
|
55
|
+
this->client_->send_text_sensor_info(text_sensor);
|
56
|
+
return true;
|
37
57
|
}
|
38
58
|
#endif
|
39
59
|
#ifdef USE_LOCK
|
40
|
-
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) {
|
60
|
+
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) {
|
61
|
+
this->client_->send_lock_info(a_lock);
|
62
|
+
return true;
|
63
|
+
}
|
41
64
|
#endif
|
42
65
|
#ifdef USE_VALVE
|
43
|
-
bool ListEntitiesIterator::on_valve(valve::Valve *valve) {
|
66
|
+
bool ListEntitiesIterator::on_valve(valve::Valve *valve) {
|
67
|
+
this->client_->send_valve_info(valve);
|
68
|
+
return true;
|
69
|
+
}
|
44
70
|
#endif
|
45
71
|
|
46
72
|
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
|
@@ -52,55 +78,83 @@ bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
|
|
52
78
|
|
53
79
|
#ifdef USE_ESP32_CAMERA
|
54
80
|
bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
|
55
|
-
|
81
|
+
this->client_->send_camera_info(camera);
|
82
|
+
return true;
|
56
83
|
}
|
57
84
|
#endif
|
58
85
|
|
59
86
|
#ifdef USE_CLIMATE
|
60
|
-
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
|
87
|
+
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
|
88
|
+
this->client_->send_climate_info(climate);
|
89
|
+
return true;
|
90
|
+
}
|
61
91
|
#endif
|
62
92
|
|
63
93
|
#ifdef USE_NUMBER
|
64
|
-
bool ListEntitiesIterator::on_number(number::Number *number) {
|
94
|
+
bool ListEntitiesIterator::on_number(number::Number *number) {
|
95
|
+
this->client_->send_number_info(number);
|
96
|
+
return true;
|
97
|
+
}
|
65
98
|
#endif
|
66
99
|
|
67
100
|
#ifdef USE_DATETIME_DATE
|
68
|
-
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) {
|
101
|
+
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) {
|
102
|
+
this->client_->send_date_info(date);
|
103
|
+
return true;
|
104
|
+
}
|
69
105
|
#endif
|
70
106
|
|
71
107
|
#ifdef USE_DATETIME_TIME
|
72
|
-
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) {
|
108
|
+
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) {
|
109
|
+
this->client_->send_time_info(time);
|
110
|
+
return true;
|
111
|
+
}
|
73
112
|
#endif
|
74
113
|
|
75
114
|
#ifdef USE_DATETIME_DATETIME
|
76
115
|
bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) {
|
77
|
-
|
116
|
+
this->client_->send_datetime_info(datetime);
|
117
|
+
return true;
|
78
118
|
}
|
79
119
|
#endif
|
80
120
|
|
81
121
|
#ifdef USE_TEXT
|
82
|
-
bool ListEntitiesIterator::on_text(text::Text *text) {
|
122
|
+
bool ListEntitiesIterator::on_text(text::Text *text) {
|
123
|
+
this->client_->send_text_info(text);
|
124
|
+
return true;
|
125
|
+
}
|
83
126
|
#endif
|
84
127
|
|
85
128
|
#ifdef USE_SELECT
|
86
|
-
bool ListEntitiesIterator::on_select(select::Select *select) {
|
129
|
+
bool ListEntitiesIterator::on_select(select::Select *select) {
|
130
|
+
this->client_->send_select_info(select);
|
131
|
+
return true;
|
132
|
+
}
|
87
133
|
#endif
|
88
134
|
|
89
135
|
#ifdef USE_MEDIA_PLAYER
|
90
136
|
bool ListEntitiesIterator::on_media_player(media_player::MediaPlayer *media_player) {
|
91
|
-
|
137
|
+
this->client_->send_media_player_info(media_player);
|
138
|
+
return true;
|
92
139
|
}
|
93
140
|
#endif
|
94
141
|
#ifdef USE_ALARM_CONTROL_PANEL
|
95
142
|
bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
|
96
|
-
|
143
|
+
this->client_->send_alarm_control_panel_info(a_alarm_control_panel);
|
144
|
+
return true;
|
97
145
|
}
|
98
146
|
#endif
|
99
147
|
#ifdef USE_EVENT
|
100
|
-
bool ListEntitiesIterator::on_event(event::Event *event) {
|
148
|
+
bool ListEntitiesIterator::on_event(event::Event *event) {
|
149
|
+
this->client_->send_event_info(event);
|
150
|
+
return true;
|
151
|
+
}
|
101
152
|
#endif
|
102
153
|
#ifdef USE_UPDATE
|
103
|
-
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) {
|
154
|
+
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) {
|
155
|
+
this->client_->send_update_info(update);
|
156
|
+
return true;
|
157
|
+
}
|
104
158
|
#endif
|
105
159
|
|
106
160
|
} // namespace api
|
@@ -80,6 +80,7 @@ class ListEntitiesIterator : public ComponentIterator {
|
|
80
80
|
bool on_update(update::UpdateEntity *update) override;
|
81
81
|
#endif
|
82
82
|
bool on_end() override;
|
83
|
+
bool completed() { return this->state_ == IteratorState::NONE; }
|
83
84
|
|
84
85
|
protected:
|
85
86
|
APIConnection *client_;
|
@@ -76,6 +76,8 @@ class InitialStateIterator : public ComponentIterator {
|
|
76
76
|
#ifdef USE_UPDATE
|
77
77
|
bool on_update(update::UpdateEntity *update) override;
|
78
78
|
#endif
|
79
|
+
bool completed() { return this->state_ == IteratorState::NONE; }
|
80
|
+
|
79
81
|
protected:
|
80
82
|
APIConnection *client_;
|
81
83
|
};
|
@@ -66,19 +66,30 @@ esp_err_t AudioDecoder::start(AudioFileType audio_file_type) {
|
|
66
66
|
case AudioFileType::FLAC:
|
67
67
|
this->flac_decoder_ = make_unique<esp_audio_libs::flac::FLACDecoder>();
|
68
68
|
this->free_buffer_required_ =
|
69
|
-
this->output_transfer_buffer_->capacity(); //
|
69
|
+
this->output_transfer_buffer_->capacity(); // Adjusted and reallocated after reading the header
|
70
70
|
break;
|
71
71
|
#endif
|
72
72
|
#ifdef USE_AUDIO_MP3_SUPPORT
|
73
73
|
case AudioFileType::MP3:
|
74
74
|
this->mp3_decoder_ = esp_audio_libs::helix_decoder::MP3InitDecoder();
|
75
|
+
|
76
|
+
// MP3 always has 1152 samples per chunk
|
75
77
|
this->free_buffer_required_ = 1152 * sizeof(int16_t) * 2; // samples * size per sample * channels
|
78
|
+
|
79
|
+
// Always reallocate the output transfer buffer to the smallest necessary size
|
80
|
+
this->output_transfer_buffer_->reallocate(this->free_buffer_required_);
|
76
81
|
break;
|
77
82
|
#endif
|
78
83
|
case AudioFileType::WAV:
|
79
84
|
this->wav_decoder_ = make_unique<esp_audio_libs::wav_decoder::WAVDecoder>();
|
80
85
|
this->wav_decoder_->reset();
|
86
|
+
|
87
|
+
// Processing WAVs doesn't actually require a specific amount of buffer size, as it is already in PCM format.
|
88
|
+
// Thus, we don't reallocate to a minimum size.
|
81
89
|
this->free_buffer_required_ = 1024;
|
90
|
+
if (this->output_transfer_buffer_->capacity() < this->free_buffer_required_) {
|
91
|
+
this->output_transfer_buffer_->reallocate(this->free_buffer_required_);
|
92
|
+
}
|
82
93
|
break;
|
83
94
|
case AudioFileType::NONE:
|
84
95
|
default:
|
@@ -116,10 +127,18 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
|
|
116
127
|
|
117
128
|
uint32_t decoding_start = millis();
|
118
129
|
|
130
|
+
bool first_loop_iteration = true;
|
131
|
+
|
132
|
+
size_t bytes_processed = 0;
|
133
|
+
size_t bytes_available_before_processing = 0;
|
134
|
+
|
119
135
|
while (state == FileDecoderState::MORE_TO_PROCESS) {
|
120
136
|
// Transfer decoded out
|
121
137
|
if (!this->pause_output_) {
|
122
|
-
|
138
|
+
// Never shift the data in the output transfer buffer to avoid unnecessary, slow data moves
|
139
|
+
size_t bytes_written =
|
140
|
+
this->output_transfer_buffer_->transfer_data_to_sink(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS), false);
|
141
|
+
|
123
142
|
if (this->audio_stream_info_.has_value()) {
|
124
143
|
this->accumulated_frames_written_ += this->audio_stream_info_.value().bytes_to_frames(bytes_written);
|
125
144
|
this->playback_ms_ +=
|
@@ -138,12 +157,24 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
|
|
138
157
|
|
139
158
|
// Decode more audio
|
140
159
|
|
141
|
-
|
160
|
+
// Only shift data on the first loop iteration to avoid unnecessary, slow moves
|
161
|
+
size_t bytes_read = this->input_transfer_buffer_->transfer_data_from_source(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS),
|
162
|
+
first_loop_iteration);
|
142
163
|
|
143
|
-
if ((this->
|
164
|
+
if (!first_loop_iteration && (this->input_transfer_buffer_->available() < bytes_processed)) {
|
165
|
+
// Less data is available than what was processed in last iteration, so don't attempt to decode.
|
166
|
+
// This attempts to avoid the decoder from consistently trying to decode an incomplete frame. The transfer buffer
|
167
|
+
// will shift the remaining data to the start and copy more from the source the next time the decode function is
|
168
|
+
// called
|
169
|
+
break;
|
170
|
+
}
|
171
|
+
|
172
|
+
bytes_available_before_processing = this->input_transfer_buffer_->available();
|
173
|
+
|
174
|
+
if ((this->potentially_failed_count_ > 10) && (bytes_read == 0)) {
|
144
175
|
// Failed to decode in last attempt and there is no new data
|
145
176
|
|
146
|
-
if (this->input_transfer_buffer_->free() == 0) {
|
177
|
+
if ((this->input_transfer_buffer_->free() == 0) && first_loop_iteration) {
|
147
178
|
// The input buffer is full. Since it previously failed on the exact same data, we can never recover
|
148
179
|
state = FileDecoderState::FAILED;
|
149
180
|
} else {
|
@@ -175,6 +206,9 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
|
|
175
206
|
}
|
176
207
|
}
|
177
208
|
|
209
|
+
first_loop_iteration = false;
|
210
|
+
bytes_processed = bytes_available_before_processing - this->input_transfer_buffer_->available();
|
211
|
+
|
178
212
|
if (state == FileDecoderState::POTENTIALLY_FAILED) {
|
179
213
|
++this->potentially_failed_count_;
|
180
214
|
} else if (state == FileDecoderState::END_OF_FILE) {
|
@@ -207,13 +241,11 @@ FileDecoderState AudioDecoder::decode_flac_() {
|
|
207
241
|
size_t bytes_consumed = this->flac_decoder_->get_bytes_index();
|
208
242
|
this->input_transfer_buffer_->decrease_buffer_length(bytes_consumed);
|
209
243
|
|
244
|
+
// Reallocate the output transfer buffer to the smallest necessary size
|
210
245
|
this->free_buffer_required_ = flac_decoder_->get_output_buffer_size_bytes();
|
211
|
-
if (this->output_transfer_buffer_->
|
212
|
-
//
|
213
|
-
|
214
|
-
// Couldn't reallocate output buffer
|
215
|
-
return FileDecoderState::FAILED;
|
216
|
-
}
|
246
|
+
if (!this->output_transfer_buffer_->reallocate(this->free_buffer_required_)) {
|
247
|
+
// Couldn't reallocate output buffer
|
248
|
+
return FileDecoderState::FAILED;
|
217
249
|
}
|
218
250
|
|
219
251
|
this->audio_stream_info_ =
|