esphome 2024.8.2__py3-none-any.whl → 2024.9.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.
Files changed (204) hide show
  1. esphome/__main__.py +6 -2
  2. esphome/components/api/api_connection.cpp +53 -0
  3. esphome/components/api/api_connection.h +4 -0
  4. esphome/components/api/api_pb2.cpp +280 -0
  5. esphome/components/api/api_pb2.h +91 -0
  6. esphome/components/api/api_pb2_service.cpp +85 -0
  7. esphome/components/api/api_pb2_service.h +28 -0
  8. esphome/components/async_tcp/__init__.py +3 -3
  9. esphome/components/atm90e26/sensor.py +10 -10
  10. esphome/components/atm90e32/sensor.py +1 -1
  11. esphome/components/bl0906/__init__.py +1 -0
  12. esphome/components/bl0906/bl0906.cpp +238 -0
  13. esphome/components/bl0906/bl0906.h +96 -0
  14. esphome/components/bl0906/const.py +4 -0
  15. esphome/components/bl0906/constants.h +122 -0
  16. esphome/components/bl0906/sensor.py +184 -0
  17. esphome/components/bl0942/__init__.py +1 -1
  18. esphome/components/bl0942/bl0942.cpp +127 -34
  19. esphome/components/bl0942/bl0942.h +87 -3
  20. esphome/components/bl0942/sensor.py +46 -8
  21. esphome/components/ble_client/__init__.py +1 -3
  22. esphome/components/ble_presence/binary_sensor.py +2 -2
  23. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
  24. esphome/components/bmp280/sensor.py +2 -93
  25. esphome/components/bmp280_base/__init__.py +88 -0
  26. esphome/components/{bmp280/bmp280.cpp → bmp280_base/bmp280_base.cpp} +11 -4
  27. esphome/components/{bmp280/bmp280.h → bmp280_base/bmp280_base.h} +9 -5
  28. esphome/components/bmp280_i2c/__init__.py +0 -0
  29. esphome/components/bmp280_i2c/bmp280_i2c.cpp +27 -0
  30. esphome/components/bmp280_i2c/bmp280_i2c.h +22 -0
  31. esphome/components/bmp280_i2c/sensor.py +22 -0
  32. esphome/components/bmp280_spi/__init__.py +0 -0
  33. esphome/components/bmp280_spi/bmp280_spi.cpp +65 -0
  34. esphome/components/bmp280_spi/bmp280_spi.h +20 -0
  35. esphome/components/bmp280_spi/sensor.py +22 -0
  36. esphome/components/captive_portal/captive_portal.cpp +2 -0
  37. esphome/components/captive_portal/captive_portal.h +3 -1
  38. esphome/components/ch422g/__init__.py +67 -0
  39. esphome/components/ch422g/ch422g.cpp +122 -0
  40. esphome/components/ch422g/ch422g.h +70 -0
  41. esphome/components/debug/debug_esp32.cpp +3 -1
  42. esphome/components/display/__init__.py +5 -4
  43. esphome/components/dsmr/dsmr.cpp +6 -0
  44. esphome/components/dsmr/dsmr.h +6 -0
  45. esphome/components/dsmr/text_sensor.py +7 -2
  46. esphome/components/e131/e131.cpp +2 -0
  47. esphome/components/e131/e131.h +3 -1
  48. esphome/components/e131/e131_addressable_light_effect.cpp +2 -0
  49. esphome/components/e131/e131_addressable_light_effect.h +2 -1
  50. esphome/components/e131/e131_packet.cpp +2 -0
  51. esphome/components/esp32_ble/ble_uuid.cpp +7 -0
  52. esphome/components/esp32_ble/ble_uuid.h +1 -0
  53. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +11 -9
  54. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +3 -3
  55. esphome/components/esp32_camera/__init__.py +4 -0
  56. esphome/components/esp32_camera/esp32_camera.cpp +9 -1
  57. esphome/components/esp32_camera/esp32_camera.h +3 -0
  58. esphome/components/esp32_can/canbus.py +18 -7
  59. esphome/components/esp32_can/esp32_can.cpp +8 -0
  60. esphome/components/esp32_can/esp32_can.h +4 -0
  61. esphome/components/esp32_rmt_led_strip/led_strip.cpp +14 -2
  62. esphome/components/esp32_rmt_led_strip/led_strip.h +3 -2
  63. esphome/components/esp32_rmt_led_strip/light.py +21 -4
  64. esphome/components/esphome/ota/ota_esphome.cpp +2 -1
  65. esphome/components/esphome/ota/ota_esphome.h +2 -0
  66. esphome/components/font/__init__.py +11 -22
  67. esphome/components/font/font.cpp +3 -2
  68. esphome/components/font/font.h +12 -3
  69. esphome/components/gree/climate.py +2 -1
  70. esphome/components/gree/gree.cpp +54 -3
  71. esphome/components/gree/gree.h +10 -2
  72. esphome/components/gt911/touchscreen/__init__.py +6 -4
  73. esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +17 -0
  74. esphome/components/gt911/touchscreen/gt911_touchscreen.h +2 -0
  75. esphome/components/hmac_md5/__init__.py +2 -0
  76. esphome/components/hmac_md5/hmac_md5.cpp +56 -0
  77. esphome/components/hmac_md5/hmac_md5.h +48 -0
  78. esphome/components/homeassistant/__init__.py +13 -0
  79. esphome/components/homeassistant/switch/__init__.py +15 -2
  80. esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
  81. esphome/components/i2s_audio/__init__.py +88 -9
  82. esphome/components/i2s_audio/i2s_audio.h +20 -2
  83. esphome/components/i2s_audio/media_player/__init__.py +8 -4
  84. esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +1 -1
  85. esphome/components/i2s_audio/microphone/__init__.py +19 -51
  86. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +18 -15
  87. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +0 -12
  88. esphome/components/i2s_audio/speaker/__init__.py +39 -27
  89. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +49 -37
  90. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +3 -4
  91. esphome/components/ili9xxx/display.py +16 -17
  92. esphome/components/ili9xxx/ili9xxx_display.cpp +1 -1
  93. esphome/components/ili9xxx/ili9xxx_display.h +18 -18
  94. esphome/components/ili9xxx/ili9xxx_init.h +0 -3
  95. esphome/components/improv_serial/improv_serial_component.cpp +2 -1
  96. esphome/components/improv_serial/improv_serial_component.h +2 -1
  97. esphome/components/ledc/ledc_output.cpp +11 -7
  98. esphome/components/libretiny/__init__.py +8 -13
  99. esphome/components/ltr501/__init__.py +1 -0
  100. esphome/components/ltr501/ltr501.cpp +542 -0
  101. esphome/components/ltr501/ltr501.h +184 -0
  102. esphome/components/ltr501/ltr_definitions_501.h +260 -0
  103. esphome/components/ltr501/sensor.py +274 -0
  104. esphome/components/ltr_als_ps/sensor.py +2 -2
  105. esphome/components/lvgl/__init__.py +19 -16
  106. esphome/components/lvgl/automation.py +90 -9
  107. esphome/components/lvgl/defines.py +29 -2
  108. esphome/components/lvgl/gradient.py +61 -0
  109. esphome/components/lvgl/lv_validation.py +45 -27
  110. esphome/components/lvgl/lvcode.py +8 -3
  111. esphome/components/lvgl/lvgl_esphome.cpp +54 -0
  112. esphome/components/lvgl/lvgl_esphome.h +9 -3
  113. esphome/components/lvgl/number/__init__.py +1 -0
  114. esphome/components/lvgl/number/lvgl_number.h +3 -1
  115. esphome/components/lvgl/schemas.py +16 -11
  116. esphome/components/lvgl/select/__init__.py +1 -0
  117. esphome/components/lvgl/select/lvgl_select.h +3 -1
  118. esphome/components/lvgl/switch/__init__.py +2 -1
  119. esphome/components/lvgl/switch/lvgl_switch.h +3 -1
  120. esphome/components/lvgl/text/__init__.py +1 -0
  121. esphome/components/lvgl/text/lvgl_text.h +3 -1
  122. esphome/components/lvgl/trigger.py +3 -2
  123. esphome/components/lvgl/types.py +2 -1
  124. esphome/components/lvgl/widgets/__init__.py +23 -8
  125. esphome/components/lvgl/widgets/arc.py +5 -1
  126. esphome/components/lvgl/widgets/buttonmatrix.py +5 -1
  127. esphome/components/lvgl/widgets/checkbox.py +8 -3
  128. esphome/components/lvgl/widgets/meter.py +8 -1
  129. esphome/components/lvgl/widgets/msgbox.py +26 -15
  130. esphome/components/lvgl/widgets/page.py +51 -7
  131. esphome/components/lvgl/widgets/tileview.py +2 -8
  132. esphome/components/max31856/max31856.cpp +12 -1
  133. esphome/components/max31856/max31856.h +5 -2
  134. esphome/components/max31856/sensor.py +20 -0
  135. esphome/components/mcp9600/sensor.py +2 -2
  136. esphome/components/mdns/__init__.py +6 -6
  137. esphome/components/media_player/media_player.h +16 -0
  138. esphome/components/micro_wake_word/__init__.py +2 -25
  139. esphome/components/microphone/microphone.h +1 -1
  140. esphome/components/mics_4514/mics_4514.cpp +26 -36
  141. esphome/components/modbus_controller/__init__.py +6 -0
  142. esphome/components/modbus_controller/const.py +2 -0
  143. esphome/components/modbus_controller/modbus_controller.cpp +30 -27
  144. esphome/components/modbus_controller/modbus_controller.h +22 -4
  145. esphome/components/network/__init__.py +11 -8
  146. esphome/components/pipsolar/pipsolar.cpp +3 -0
  147. esphome/components/pipsolar/pipsolar.h +1 -0
  148. esphome/components/pipsolar/switch/__init__.py +2 -0
  149. esphome/components/prometheus/prometheus_handler.cpp +2 -0
  150. esphome/components/prometheus/prometheus_handler.h +3 -1
  151. esphome/components/rp2040/__init__.py +7 -8
  152. esphome/components/rpi_dpi_rgb/display.py +20 -17
  153. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +36 -6
  154. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h +4 -0
  155. esphome/components/socket/socket.cpp +2 -0
  156. esphome/components/socket/socket.h +2 -0
  157. esphome/components/speaker/speaker.h +1 -1
  158. esphome/components/st7701s/display.py +35 -37
  159. esphome/components/st7701s/st7701s.cpp +11 -6
  160. esphome/components/st7701s/st7701s.h +1 -0
  161. esphome/components/statsd/__init__.py +65 -0
  162. esphome/components/statsd/statsd.cpp +156 -0
  163. esphome/components/statsd/statsd.h +86 -0
  164. esphome/components/tuya/__init__.py +1 -0
  165. esphome/components/tuya/number/__init__.py +39 -2
  166. esphome/components/tuya/number/tuya_number.cpp +58 -2
  167. esphome/components/tuya/number/tuya_number.h +12 -3
  168. esphome/components/udp/__init__.py +158 -0
  169. esphome/components/udp/binary_sensor.py +27 -0
  170. esphome/components/udp/sensor.py +27 -0
  171. esphome/components/udp/udp_component.cpp +616 -0
  172. esphome/components/udp/udp_component.h +158 -0
  173. esphome/components/uponor_smatrix/uponor_smatrix.cpp +4 -6
  174. esphome/components/uponor_smatrix/uponor_smatrix.h +0 -1
  175. esphome/components/veml7700/sensor.py +2 -2
  176. esphome/components/voice_assistant/__init__.py +6 -0
  177. esphome/components/voice_assistant/voice_assistant.cpp +24 -2
  178. esphome/components/voice_assistant/voice_assistant.h +20 -0
  179. esphome/components/web_server/__init__.py +11 -11
  180. esphome/components/web_server/list_entities.cpp +2 -0
  181. esphome/components/web_server/list_entities.h +3 -1
  182. esphome/components/web_server/web_server.cpp +2 -1
  183. esphome/components/web_server/web_server.h +2 -0
  184. esphome/components/web_server_base/web_server_base.cpp +2 -0
  185. esphome/components/web_server_base/web_server_base.h +3 -1
  186. esphome/components/wifi/wifi_component_libretiny.cpp +15 -1
  187. esphome/components/wireguard/__init__.py +9 -6
  188. esphome/components/wireguard/wireguard.cpp +2 -1
  189. esphome/components/wireguard/wireguard.h +3 -1
  190. esphome/config_validation.py +8 -0
  191. esphome/const.py +8 -1
  192. esphome/core/bytebuffer.cpp +117 -84
  193. esphome/core/bytebuffer.h +69 -21
  194. esphome/core/config.py +0 -3
  195. esphome/core/defines.h +2 -0
  196. esphome/core/ring_buffer.cpp +13 -2
  197. esphome/core/ring_buffer.h +56 -0
  198. esphome/external_files.py +5 -3
  199. {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/METADATA +1 -1
  200. {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/RECORD +204 -169
  201. {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/LICENSE +0 -0
  202. {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/WHEEL +0 -0
  203. {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/entry_points.txt +0 -0
  204. {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,616 @@
1
+ #include "esphome/core/log.h"
2
+ #include "esphome/core/application.h"
3
+ #include "esphome/components/network/util.h"
4
+ #include "udp_component.h"
5
+
6
+ namespace esphome {
7
+ namespace udp {
8
+
9
+ /**
10
+ * Structure of a data packet; everything is little-endian
11
+ *
12
+ * --- In clear text ---
13
+ * MAGIC_NUMBER: 16 bits
14
+ * host name length: 1 byte
15
+ * host name: (length) bytes
16
+ * padding: 0 or more null bytes to a 4 byte boundary
17
+ *
18
+ * --- Encrypted (if key set) ----
19
+ * DATA_KEY: 1 byte: OR ROLLING_CODE_KEY:
20
+ * Rolling code (if enabled): 8 bytes
21
+ * Ping keys: if any
22
+ * repeat:
23
+ * PING_KEY: 1 byte
24
+ * ping code: 4 bytes
25
+ * Sensors:
26
+ * repeat:
27
+ * SENSOR_KEY: 1 byte
28
+ * float value: 4 bytes
29
+ * name length: 1 byte
30
+ * name
31
+ * Binary Sensors:
32
+ * repeat:
33
+ * BINARY_SENSOR_KEY: 1 byte
34
+ * bool value: 1 bytes
35
+ * name length: 1 byte
36
+ * name
37
+ *
38
+ * Padded to a 4 byte boundary with nulls
39
+ *
40
+ * Structure of a ping request packet:
41
+ * --- In clear text ---
42
+ * MAGIC_PING: 16 bits
43
+ * host name length: 1 byte
44
+ * host name: (length) bytes
45
+ * Ping key (4 bytes)
46
+ *
47
+ */
48
+ static const char *const TAG = "udp";
49
+
50
+ /**
51
+ * XXTEA implementation, using 256 bit key.
52
+ */
53
+
54
+ static const uint32_t DELTA = 0x9e3779b9;
55
+ #define MX ((((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (k[(p ^ e) & 7] ^ z)))
56
+
57
+ /**
58
+ * Encrypt a block of data in-place
59
+ */
60
+
61
+ static void xxtea_encrypt(uint32_t *v, size_t n, const uint32_t *k) {
62
+ uint32_t z, y, sum, e;
63
+ size_t p;
64
+ size_t q = 6 + 52 / n;
65
+ sum = 0;
66
+ z = v[n - 1];
67
+ while (q-- != 0) {
68
+ sum += DELTA;
69
+ e = (sum >> 2);
70
+ for (p = 0; p != n - 1; p++) {
71
+ y = v[p + 1];
72
+ z = v[p] += MX;
73
+ }
74
+ y = v[0];
75
+ z = v[n - 1] += MX;
76
+ }
77
+ }
78
+
79
+ static void xxtea_decrypt(uint32_t *v, size_t n, const uint32_t *k) {
80
+ uint32_t z, y, sum, e;
81
+ size_t p;
82
+ size_t q = 6 + 52 / n;
83
+ sum = q * DELTA;
84
+ y = v[0];
85
+ while (q-- != 0) {
86
+ e = (sum >> 2);
87
+ for (p = n - 1; p != 0; p--) {
88
+ z = v[p - 1];
89
+ y = v[p] -= MX;
90
+ }
91
+ z = v[n - 1];
92
+ y = v[0] -= MX;
93
+ sum -= DELTA;
94
+ }
95
+ }
96
+
97
+ inline static size_t round4(size_t value) { return (value + 3) & ~3; }
98
+
99
+ union FuData {
100
+ uint32_t u32;
101
+ float f32;
102
+ };
103
+
104
+ static const size_t MAX_PACKET_SIZE = 508;
105
+ static const uint16_t MAGIC_NUMBER = 0x4553;
106
+ static const uint16_t MAGIC_PING = 0x5048;
107
+ static const uint32_t PREF_HASH = 0x45535043;
108
+ enum DataKey {
109
+ ZERO_FILL_KEY,
110
+ DATA_KEY,
111
+ SENSOR_KEY,
112
+ BINARY_SENSOR_KEY,
113
+ PING_KEY,
114
+ ROLLING_CODE_KEY,
115
+ };
116
+
117
+ static const size_t MAX_PING_KEYS = 4;
118
+
119
+ static inline void add(std::vector<uint8_t> &vec, uint32_t data) {
120
+ vec.push_back(data & 0xFF);
121
+ vec.push_back((data >> 8) & 0xFF);
122
+ vec.push_back((data >> 16) & 0xFF);
123
+ vec.push_back((data >> 24) & 0xFF);
124
+ }
125
+
126
+ static inline uint32_t get_uint32(uint8_t *&buf) {
127
+ uint32_t data = *buf++;
128
+ data += *buf++ << 8;
129
+ data += *buf++ << 16;
130
+ data += *buf++ << 24;
131
+ return data;
132
+ }
133
+
134
+ static inline uint16_t get_uint16(uint8_t *&buf) {
135
+ uint16_t data = *buf++;
136
+ data += *buf++ << 8;
137
+ return data;
138
+ }
139
+
140
+ static inline void add(std::vector<uint8_t> &vec, uint8_t data) { vec.push_back(data); }
141
+ static inline void add(std::vector<uint8_t> &vec, uint16_t data) {
142
+ vec.push_back((uint8_t) data);
143
+ vec.push_back((uint8_t) (data >> 8));
144
+ }
145
+ static inline void add(std::vector<uint8_t> &vec, DataKey data) { vec.push_back(data); }
146
+ static void add(std::vector<uint8_t> &vec, const char *str) {
147
+ auto len = strlen(str);
148
+ vec.push_back(len);
149
+ for (size_t i = 0; i != len; i++) {
150
+ vec.push_back(*str++);
151
+ }
152
+ }
153
+
154
+ void UDPComponent::setup() {
155
+ this->name_ = App.get_name().c_str();
156
+ if (strlen(this->name_) > 255) {
157
+ this->mark_failed();
158
+ this->status_set_error("Device name exceeds 255 chars");
159
+ return;
160
+ }
161
+ this->resend_ping_key_ = this->ping_pong_enable_;
162
+ // restore the upper 32 bits of the rolling code, increment and save.
163
+ this->pref_ = global_preferences->make_preference<uint32_t>(PREF_HASH, true);
164
+ this->pref_.load(&this->rolling_code_[1]);
165
+ this->rolling_code_[1]++;
166
+ this->pref_.save(&this->rolling_code_[1]);
167
+ this->ping_key_ = random_uint32();
168
+ ESP_LOGV(TAG, "Rolling code incremented, upper part now %u", (unsigned) this->rolling_code_[1]);
169
+ #ifdef USE_SENSOR
170
+ for (auto &sensor : this->sensors_) {
171
+ sensor.sensor->add_on_state_callback([this, &sensor](float x) {
172
+ this->updated_ = true;
173
+ sensor.updated = true;
174
+ });
175
+ }
176
+ #endif
177
+ #ifdef USE_BINARY_SENSOR
178
+ for (auto &sensor : this->binary_sensors_) {
179
+ sensor.sensor->add_on_state_callback([this, &sensor](bool value) {
180
+ this->updated_ = true;
181
+ sensor.updated = true;
182
+ });
183
+ }
184
+ #endif
185
+ this->should_send_ = this->ping_pong_enable_;
186
+ #ifdef USE_SENSOR
187
+ this->should_send_ |= !this->sensors_.empty();
188
+ #endif
189
+ #ifdef USE_BINARY_SENSOR
190
+ this->should_send_ |= !this->binary_sensors_.empty();
191
+ #endif
192
+ this->should_listen_ = !this->providers_.empty() || this->is_encrypted_();
193
+ // initialise the header. This is invariant.
194
+ add(this->header_, MAGIC_NUMBER);
195
+ add(this->header_, this->name_);
196
+ // pad to a multiple of 4 bytes
197
+ while (this->header_.size() & 0x3)
198
+ this->header_.push_back(0);
199
+ #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
200
+ for (const auto &address : this->addresses_) {
201
+ struct sockaddr saddr {};
202
+ socket::set_sockaddr(&saddr, sizeof(saddr), address, this->port_);
203
+ this->sockaddrs_.push_back(saddr);
204
+ }
205
+ // set up broadcast socket
206
+ if (this->should_send_) {
207
+ this->broadcast_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
208
+ if (this->broadcast_socket_ == nullptr) {
209
+ this->mark_failed();
210
+ this->status_set_error("Could not create socket");
211
+ return;
212
+ }
213
+ int enable = 1;
214
+ auto err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
215
+ if (err != 0) {
216
+ this->status_set_warning("Socket unable to set reuseaddr");
217
+ // we can still continue
218
+ }
219
+ err = this->broadcast_socket_->setsockopt(SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int));
220
+ if (err != 0) {
221
+ this->status_set_warning("Socket unable to set broadcast");
222
+ }
223
+ }
224
+ // create listening socket if we either want to subscribe to providers, or need to listen
225
+ // for ping key broadcasts.
226
+ if (this->should_listen_) {
227
+ this->listen_socket_ = socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
228
+ if (this->listen_socket_ == nullptr) {
229
+ this->mark_failed();
230
+ this->status_set_error("Could not create socket");
231
+ return;
232
+ }
233
+ auto err = this->listen_socket_->setblocking(false);
234
+ if (err < 0) {
235
+ ESP_LOGE(TAG, "Unable to set nonblocking: errno %d", errno);
236
+ this->mark_failed();
237
+ this->status_set_error("Unable to set nonblocking");
238
+ return;
239
+ }
240
+ int enable = 1;
241
+ err = this->listen_socket_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
242
+ if (err != 0) {
243
+ this->status_set_warning("Socket unable to set reuseaddr");
244
+ // we can still continue
245
+ }
246
+ struct sockaddr_in server {};
247
+
248
+ socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_);
249
+ if (sl == 0) {
250
+ ESP_LOGE(TAG, "Socket unable to set sockaddr: errno %d", errno);
251
+ this->mark_failed();
252
+ this->status_set_error("Unable to set sockaddr");
253
+ return;
254
+ }
255
+
256
+ err = this->listen_socket_->bind((struct sockaddr *) &server, sizeof(server));
257
+ if (err != 0) {
258
+ ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
259
+ this->mark_failed();
260
+ this->status_set_error("Unable to bind socket");
261
+ return;
262
+ }
263
+ }
264
+ #else
265
+ // 8266 and RP2040 `Duino
266
+ for (const auto &address : this->addresses_) {
267
+ auto ipaddr = IPAddress();
268
+ ipaddr.fromString(address.c_str());
269
+ this->ipaddrs_.push_back(ipaddr);
270
+ }
271
+ if (this->should_listen_)
272
+ this->udp_client_.begin(this->port_);
273
+ #endif
274
+ }
275
+
276
+ void UDPComponent::init_data_() {
277
+ this->data_.clear();
278
+ if (this->rolling_code_enable_) {
279
+ add(this->data_, ROLLING_CODE_KEY);
280
+ add(this->data_, this->rolling_code_[0]);
281
+ add(this->data_, this->rolling_code_[1]);
282
+ this->increment_code_();
283
+ } else {
284
+ add(this->data_, DATA_KEY);
285
+ }
286
+ for (auto pkey : this->ping_keys_) {
287
+ add(this->data_, PING_KEY);
288
+ add(this->data_, pkey.second);
289
+ }
290
+ }
291
+
292
+ void UDPComponent::flush_() {
293
+ if (!network::is_connected() || this->data_.empty())
294
+ return;
295
+ uint32_t buffer[MAX_PACKET_SIZE / 4];
296
+ memset(buffer, 0, sizeof buffer);
297
+ // len must be a multiple of 4
298
+ auto header_len = round4(this->header_.size()) / 4;
299
+ auto len = round4(data_.size()) / 4;
300
+ memcpy(buffer, this->header_.data(), this->header_.size());
301
+ memcpy(buffer + header_len, this->data_.data(), this->data_.size());
302
+ if (this->is_encrypted_()) {
303
+ xxtea_encrypt(buffer + header_len, len, (uint32_t *) this->encryption_key_.data());
304
+ }
305
+ auto total_len = (header_len + len) * 4;
306
+ this->send_packet_(buffer, total_len);
307
+ }
308
+
309
+ void UDPComponent::add_binary_data_(uint8_t key, const char *id, bool data) {
310
+ auto len = 1 + 1 + 1 + strlen(id);
311
+ if (len + this->header_.size() + this->data_.size() > MAX_PACKET_SIZE) {
312
+ this->flush_();
313
+ }
314
+ add(this->data_, key);
315
+ add(this->data_, (uint8_t) data);
316
+ add(this->data_, id);
317
+ }
318
+ void UDPComponent::add_data_(uint8_t key, const char *id, float data) {
319
+ FuData udata{.f32 = data};
320
+ this->add_data_(key, id, udata.u32);
321
+ }
322
+
323
+ void UDPComponent::add_data_(uint8_t key, const char *id, uint32_t data) {
324
+ auto len = 4 + 1 + 1 + strlen(id);
325
+ if (len + this->header_.size() + this->data_.size() > MAX_PACKET_SIZE) {
326
+ this->flush_();
327
+ }
328
+ add(this->data_, key);
329
+ add(this->data_, data);
330
+ add(this->data_, id);
331
+ }
332
+ void UDPComponent::send_data_(bool all) {
333
+ if (!this->should_send_ || !network::is_connected())
334
+ return;
335
+ this->init_data_();
336
+ #ifdef USE_SENSOR
337
+ for (auto &sensor : this->sensors_) {
338
+ if (all || sensor.updated) {
339
+ sensor.updated = false;
340
+ this->add_data_(SENSOR_KEY, sensor.id, sensor.sensor->get_state());
341
+ }
342
+ }
343
+ #endif
344
+ #ifdef USE_BINARY_SENSOR
345
+ for (auto &sensor : this->binary_sensors_) {
346
+ if (all || sensor.updated) {
347
+ sensor.updated = false;
348
+ this->add_binary_data_(BINARY_SENSOR_KEY, sensor.id, sensor.sensor->state);
349
+ }
350
+ }
351
+ #endif
352
+ this->flush_();
353
+ this->updated_ = false;
354
+ this->resend_data_ = false;
355
+ }
356
+
357
+ void UDPComponent::update() {
358
+ this->updated_ = true;
359
+ this->resend_data_ = this->should_send_;
360
+ auto now = millis() / 1000;
361
+ if (this->last_key_time_ + this->ping_pong_recyle_time_ < now) {
362
+ this->resend_ping_key_ = this->ping_pong_enable_;
363
+ this->last_key_time_ = now;
364
+ }
365
+ }
366
+
367
+ void UDPComponent::loop() {
368
+ uint8_t buf[MAX_PACKET_SIZE];
369
+ if (this->should_listen_) {
370
+ for (;;) {
371
+ #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
372
+ auto len = this->listen_socket_->read(buf, sizeof(buf));
373
+ #else
374
+ auto len = this->udp_client_.parsePacket();
375
+ if (len > 0)
376
+ len = this->udp_client_.read(buf, sizeof(buf));
377
+ #endif
378
+ if (len > 0) {
379
+ this->process_(buf, len);
380
+ continue;
381
+ }
382
+ break;
383
+ }
384
+ }
385
+ if (this->resend_ping_key_)
386
+ this->send_ping_pong_request_();
387
+ if (this->updated_) {
388
+ this->send_data_(this->resend_data_);
389
+ }
390
+ }
391
+
392
+ void UDPComponent::add_key_(const char *name, uint32_t key) {
393
+ if (!this->is_encrypted_())
394
+ return;
395
+ if (this->ping_keys_.count(name) == 0 && this->ping_keys_.size() == MAX_PING_KEYS) {
396
+ ESP_LOGW(TAG, "Ping key from %s discarded", name);
397
+ return;
398
+ }
399
+ this->ping_keys_[name] = key;
400
+ this->resend_data_ = true;
401
+ ESP_LOGV(TAG, "Ping key from %s now %X", name, (unsigned) key);
402
+ }
403
+
404
+ void UDPComponent::process_ping_request_(const char *name, uint8_t *ptr, size_t len) {
405
+ if (len != 4) {
406
+ ESP_LOGW(TAG, "Bad ping request");
407
+ return;
408
+ }
409
+ auto key = get_uint32(ptr);
410
+ this->add_key_(name, key);
411
+ ESP_LOGV(TAG, "Updated ping key for %s to %08X", name, (unsigned) key);
412
+ }
413
+
414
+ static bool process_rolling_code(Provider &provider, uint8_t *&buf, const uint8_t *end) {
415
+ if (end - buf < 8)
416
+ return false;
417
+ auto code0 = get_uint32(buf);
418
+ auto code1 = get_uint32(buf);
419
+ if (code1 < provider.last_code[1] || (code1 == provider.last_code[1] && code0 <= provider.last_code[0])) {
420
+ ESP_LOGW(TAG, "Rolling code for %s %08lX:%08lX is old", provider.name, (unsigned long) code1,
421
+ (unsigned long) code0);
422
+ return false;
423
+ }
424
+ provider.last_code[0] = code0;
425
+ provider.last_code[1] = code1;
426
+ return true;
427
+ }
428
+
429
+ /**
430
+ * Process a received packet
431
+ */
432
+ void UDPComponent::process_(uint8_t *buf, const size_t len) {
433
+ auto ping_key_seen = !this->ping_pong_enable_;
434
+ if (len < 8) {
435
+ return ESP_LOGV(TAG, "Bad length %zu", len);
436
+ }
437
+ char namebuf[256]{};
438
+ uint8_t byte;
439
+ uint8_t *start_ptr = buf;
440
+ const uint8_t *end = buf + len;
441
+ FuData rdata{};
442
+ auto magic = get_uint16(buf);
443
+ if (magic != MAGIC_NUMBER && magic != MAGIC_PING)
444
+ return ESP_LOGV(TAG, "Bad magic %X", magic);
445
+
446
+ auto hlen = *buf++;
447
+ if (hlen > len - 3) {
448
+ return ESP_LOGV(TAG, "Bad hostname length %u > %zu", hlen, len - 3);
449
+ }
450
+ memcpy(namebuf, buf, hlen);
451
+ if (strcmp(this->name_, namebuf) == 0) {
452
+ return ESP_LOGV(TAG, "Ignoring our own data");
453
+ }
454
+ buf += hlen;
455
+ if (magic == MAGIC_PING)
456
+ return this->process_ping_request_(namebuf, buf, end - buf);
457
+ if (round4(len) != len) {
458
+ return ESP_LOGW(TAG, "Bad length %zu", len);
459
+ }
460
+ hlen = round4(hlen + 3);
461
+ buf = start_ptr + hlen;
462
+ if (buf == end) {
463
+ return ESP_LOGV(TAG, "No data after header");
464
+ }
465
+
466
+ if (this->providers_.count(namebuf) == 0) {
467
+ return ESP_LOGVV(TAG, "Unknown hostname %s", namebuf);
468
+ }
469
+ auto &provider = this->providers_[namebuf];
470
+ // if encryption not used with this host, ping check is pointless since it would be easily spoofed.
471
+ if (provider.encryption_key.empty())
472
+ ping_key_seen = true;
473
+
474
+ ESP_LOGV(TAG, "Found hostname %s", namebuf);
475
+ #ifdef USE_SENSOR
476
+ auto &sensors = this->remote_sensors_[namebuf];
477
+ #endif
478
+ #ifdef USE_BINARY_SENSOR
479
+ auto &binary_sensors = this->remote_binary_sensors_[namebuf];
480
+ #endif
481
+
482
+ if (!provider.encryption_key.empty()) {
483
+ xxtea_decrypt((uint32_t *) buf, (end - buf) / 4, (uint32_t *) provider.encryption_key.data());
484
+ }
485
+ byte = *buf++;
486
+ if (byte == ROLLING_CODE_KEY) {
487
+ if (!process_rolling_code(provider, buf, end))
488
+ return;
489
+ } else if (byte != DATA_KEY) {
490
+ return ESP_LOGV(TAG, "Expected rolling_key or data_key, got %X", byte);
491
+ }
492
+ while (buf < end) {
493
+ byte = *buf++;
494
+ if (byte == ZERO_FILL_KEY)
495
+ continue;
496
+ if (byte == PING_KEY) {
497
+ if (end - buf < 4) {
498
+ return ESP_LOGV(TAG, "PING_KEY requires 4 more bytes");
499
+ }
500
+ auto key = get_uint32(buf);
501
+ if (key == this->ping_key_) {
502
+ ping_key_seen = true;
503
+ ESP_LOGV(TAG, "Found good ping key %X", (unsigned) key);
504
+ } else {
505
+ ESP_LOGV(TAG, "Unknown ping key %X", (unsigned) key);
506
+ }
507
+ continue;
508
+ }
509
+ if (!ping_key_seen) {
510
+ ESP_LOGW(TAG, "Ping key not seen");
511
+ this->resend_ping_key_ = true;
512
+ break;
513
+ }
514
+ if (byte == BINARY_SENSOR_KEY) {
515
+ if (end - buf < 3) {
516
+ return ESP_LOGV(TAG, "Binary sensor key requires at least 3 more bytes");
517
+ }
518
+ rdata.u32 = *buf++;
519
+ } else if (byte == SENSOR_KEY) {
520
+ if (end - buf < 6) {
521
+ return ESP_LOGV(TAG, "Sensor key requires at least 6 more bytes");
522
+ }
523
+ rdata.u32 = get_uint32(buf);
524
+ } else {
525
+ return ESP_LOGW(TAG, "Unknown key byte %X", byte);
526
+ }
527
+
528
+ hlen = *buf++;
529
+ if (end - buf < hlen) {
530
+ return ESP_LOGV(TAG, "Name length of %u not available", hlen);
531
+ }
532
+ memset(namebuf, 0, sizeof namebuf);
533
+ memcpy(namebuf, buf, hlen);
534
+ ESP_LOGV(TAG, "Found sensor key %d, id %s, data %lX", byte, namebuf, (unsigned long) rdata.u32);
535
+ buf += hlen;
536
+ #ifdef USE_SENSOR
537
+ if (byte == SENSOR_KEY && sensors.count(namebuf) != 0)
538
+ sensors[namebuf]->publish_state(rdata.f32);
539
+ #endif
540
+ #ifdef USE_BINARY_SENSOR
541
+ if (byte == BINARY_SENSOR_KEY && binary_sensors.count(namebuf) != 0)
542
+ binary_sensors[namebuf]->publish_state(rdata.u32 != 0);
543
+ #endif
544
+ }
545
+ }
546
+
547
+ void UDPComponent::dump_config() {
548
+ ESP_LOGCONFIG(TAG, "UDP:");
549
+ ESP_LOGCONFIG(TAG, " Port: %u", this->port_);
550
+ ESP_LOGCONFIG(TAG, " Encrypted: %s", YESNO(this->is_encrypted_()));
551
+ ESP_LOGCONFIG(TAG, " Ping-pong: %s", YESNO(this->ping_pong_enable_));
552
+ for (const auto &address : this->addresses_)
553
+ ESP_LOGCONFIG(TAG, " Address: %s", address.c_str());
554
+ #ifdef USE_SENSOR
555
+ for (auto sensor : this->sensors_)
556
+ ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id);
557
+ #endif
558
+ #ifdef USE_BINARY_SENSOR
559
+ for (auto sensor : this->binary_sensors_)
560
+ ESP_LOGCONFIG(TAG, " Binary Sensor: %s", sensor.id);
561
+ #endif
562
+ for (const auto &host : this->providers_) {
563
+ ESP_LOGCONFIG(TAG, " Remote host: %s", host.first.c_str());
564
+ ESP_LOGCONFIG(TAG, " Encrypted: %s", YESNO(!host.second.encryption_key.empty()));
565
+ #ifdef USE_SENSOR
566
+ for (const auto &sensor : this->remote_sensors_[host.first.c_str()])
567
+ ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.first.c_str());
568
+ #endif
569
+ #ifdef USE_BINARY_SENSOR
570
+ for (const auto &sensor : this->remote_binary_sensors_[host.first.c_str()])
571
+ ESP_LOGCONFIG(TAG, " Binary Sensor: %s", sensor.first.c_str());
572
+ #endif
573
+ }
574
+ }
575
+ void UDPComponent::increment_code_() {
576
+ if (this->rolling_code_enable_) {
577
+ if (++this->rolling_code_[0] == 0) {
578
+ this->rolling_code_[1]++;
579
+ this->pref_.save(&this->rolling_code_[1]);
580
+ }
581
+ }
582
+ }
583
+ void UDPComponent::send_packet_(void *data, size_t len) {
584
+ #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
585
+ for (const auto &saddr : this->sockaddrs_) {
586
+ auto result = this->broadcast_socket_->sendto(data, len, 0, &saddr, sizeof(saddr));
587
+ if (result < 0)
588
+ ESP_LOGW(TAG, "sendto() error %d", errno);
589
+ }
590
+ #else
591
+ auto iface = IPAddress(0, 0, 0, 0);
592
+ for (const auto &saddr : this->ipaddrs_) {
593
+ if (this->udp_client_.beginPacketMulticast(saddr, this->port_, iface, 128) != 0) {
594
+ this->udp_client_.write((const uint8_t *) data, len);
595
+ auto result = this->udp_client_.endPacket();
596
+ if (result == 0)
597
+ ESP_LOGW(TAG, "udp.write() error");
598
+ }
599
+ }
600
+ #endif
601
+ }
602
+
603
+ void UDPComponent::send_ping_pong_request_() {
604
+ if (!this->ping_pong_enable_ || !network::is_connected())
605
+ return;
606
+ this->ping_key_ = random_uint32();
607
+ this->ping_header_.clear();
608
+ add(this->ping_header_, MAGIC_PING);
609
+ add(this->ping_header_, this->name_);
610
+ add(this->ping_header_, this->ping_key_);
611
+ this->send_packet_(this->ping_header_.data(), this->ping_header_.size());
612
+ this->resend_ping_key_ = false;
613
+ ESP_LOGV(TAG, "Sent new ping request %08X", (unsigned) this->ping_key_);
614
+ }
615
+ } // namespace udp
616
+ } // namespace esphome