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.
- esphome/__main__.py +6 -2
- esphome/components/api/api_connection.cpp +53 -0
- esphome/components/api/api_connection.h +4 -0
- esphome/components/api/api_pb2.cpp +280 -0
- esphome/components/api/api_pb2.h +91 -0
- esphome/components/api/api_pb2_service.cpp +85 -0
- esphome/components/api/api_pb2_service.h +28 -0
- esphome/components/async_tcp/__init__.py +3 -3
- esphome/components/atm90e26/sensor.py +10 -10
- esphome/components/atm90e32/sensor.py +1 -1
- esphome/components/bl0906/__init__.py +1 -0
- esphome/components/bl0906/bl0906.cpp +238 -0
- esphome/components/bl0906/bl0906.h +96 -0
- esphome/components/bl0906/const.py +4 -0
- esphome/components/bl0906/constants.h +122 -0
- esphome/components/bl0906/sensor.py +184 -0
- esphome/components/bl0942/__init__.py +1 -1
- esphome/components/bl0942/bl0942.cpp +127 -34
- esphome/components/bl0942/bl0942.h +87 -3
- esphome/components/bl0942/sensor.py +46 -8
- esphome/components/ble_client/__init__.py +1 -3
- esphome/components/ble_presence/binary_sensor.py +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
- esphome/components/bmp280/sensor.py +2 -93
- esphome/components/bmp280_base/__init__.py +88 -0
- esphome/components/{bmp280/bmp280.cpp → bmp280_base/bmp280_base.cpp} +11 -4
- esphome/components/{bmp280/bmp280.h → bmp280_base/bmp280_base.h} +9 -5
- esphome/components/bmp280_i2c/__init__.py +0 -0
- esphome/components/bmp280_i2c/bmp280_i2c.cpp +27 -0
- esphome/components/bmp280_i2c/bmp280_i2c.h +22 -0
- esphome/components/bmp280_i2c/sensor.py +22 -0
- esphome/components/bmp280_spi/__init__.py +0 -0
- esphome/components/bmp280_spi/bmp280_spi.cpp +65 -0
- esphome/components/bmp280_spi/bmp280_spi.h +20 -0
- esphome/components/bmp280_spi/sensor.py +22 -0
- esphome/components/captive_portal/captive_portal.cpp +2 -0
- esphome/components/captive_portal/captive_portal.h +3 -1
- esphome/components/ch422g/__init__.py +67 -0
- esphome/components/ch422g/ch422g.cpp +122 -0
- esphome/components/ch422g/ch422g.h +70 -0
- esphome/components/debug/debug_esp32.cpp +3 -1
- esphome/components/display/__init__.py +5 -4
- esphome/components/dsmr/dsmr.cpp +6 -0
- esphome/components/dsmr/dsmr.h +6 -0
- esphome/components/dsmr/text_sensor.py +7 -2
- esphome/components/e131/e131.cpp +2 -0
- esphome/components/e131/e131.h +3 -1
- esphome/components/e131/e131_addressable_light_effect.cpp +2 -0
- esphome/components/e131/e131_addressable_light_effect.h +2 -1
- esphome/components/e131/e131_packet.cpp +2 -0
- esphome/components/esp32_ble/ble_uuid.cpp +7 -0
- esphome/components/esp32_ble/ble_uuid.h +1 -0
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +11 -9
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +3 -3
- esphome/components/esp32_camera/__init__.py +4 -0
- esphome/components/esp32_camera/esp32_camera.cpp +9 -1
- esphome/components/esp32_camera/esp32_camera.h +3 -0
- esphome/components/esp32_can/canbus.py +18 -7
- esphome/components/esp32_can/esp32_can.cpp +8 -0
- esphome/components/esp32_can/esp32_can.h +4 -0
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +14 -2
- esphome/components/esp32_rmt_led_strip/led_strip.h +3 -2
- esphome/components/esp32_rmt_led_strip/light.py +21 -4
- esphome/components/esphome/ota/ota_esphome.cpp +2 -1
- esphome/components/esphome/ota/ota_esphome.h +2 -0
- esphome/components/font/__init__.py +11 -22
- esphome/components/font/font.cpp +3 -2
- esphome/components/font/font.h +12 -3
- esphome/components/gree/climate.py +2 -1
- esphome/components/gree/gree.cpp +54 -3
- esphome/components/gree/gree.h +10 -2
- esphome/components/gt911/touchscreen/__init__.py +6 -4
- esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +17 -0
- esphome/components/gt911/touchscreen/gt911_touchscreen.h +2 -0
- esphome/components/hmac_md5/__init__.py +2 -0
- esphome/components/hmac_md5/hmac_md5.cpp +56 -0
- esphome/components/hmac_md5/hmac_md5.h +48 -0
- esphome/components/homeassistant/__init__.py +13 -0
- esphome/components/homeassistant/switch/__init__.py +15 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/i2s_audio/__init__.py +88 -9
- esphome/components/i2s_audio/i2s_audio.h +20 -2
- esphome/components/i2s_audio/media_player/__init__.py +8 -4
- esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +1 -1
- esphome/components/i2s_audio/microphone/__init__.py +19 -51
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +18 -15
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +0 -12
- esphome/components/i2s_audio/speaker/__init__.py +39 -27
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +49 -37
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +3 -4
- esphome/components/ili9xxx/display.py +16 -17
- esphome/components/ili9xxx/ili9xxx_display.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.h +18 -18
- esphome/components/ili9xxx/ili9xxx_init.h +0 -3
- esphome/components/improv_serial/improv_serial_component.cpp +2 -1
- esphome/components/improv_serial/improv_serial_component.h +2 -1
- esphome/components/ledc/ledc_output.cpp +11 -7
- esphome/components/libretiny/__init__.py +8 -13
- esphome/components/ltr501/__init__.py +1 -0
- esphome/components/ltr501/ltr501.cpp +542 -0
- esphome/components/ltr501/ltr501.h +184 -0
- esphome/components/ltr501/ltr_definitions_501.h +260 -0
- esphome/components/ltr501/sensor.py +274 -0
- esphome/components/ltr_als_ps/sensor.py +2 -2
- esphome/components/lvgl/__init__.py +19 -16
- esphome/components/lvgl/automation.py +90 -9
- esphome/components/lvgl/defines.py +29 -2
- esphome/components/lvgl/gradient.py +61 -0
- esphome/components/lvgl/lv_validation.py +45 -27
- esphome/components/lvgl/lvcode.py +8 -3
- esphome/components/lvgl/lvgl_esphome.cpp +54 -0
- esphome/components/lvgl/lvgl_esphome.h +9 -3
- esphome/components/lvgl/number/__init__.py +1 -0
- esphome/components/lvgl/number/lvgl_number.h +3 -1
- esphome/components/lvgl/schemas.py +16 -11
- esphome/components/lvgl/select/__init__.py +1 -0
- esphome/components/lvgl/select/lvgl_select.h +3 -1
- esphome/components/lvgl/switch/__init__.py +2 -1
- esphome/components/lvgl/switch/lvgl_switch.h +3 -1
- esphome/components/lvgl/text/__init__.py +1 -0
- esphome/components/lvgl/text/lvgl_text.h +3 -1
- esphome/components/lvgl/trigger.py +3 -2
- esphome/components/lvgl/types.py +2 -1
- esphome/components/lvgl/widgets/__init__.py +23 -8
- esphome/components/lvgl/widgets/arc.py +5 -1
- esphome/components/lvgl/widgets/buttonmatrix.py +5 -1
- esphome/components/lvgl/widgets/checkbox.py +8 -3
- esphome/components/lvgl/widgets/meter.py +8 -1
- esphome/components/lvgl/widgets/msgbox.py +26 -15
- esphome/components/lvgl/widgets/page.py +51 -7
- esphome/components/lvgl/widgets/tileview.py +2 -8
- esphome/components/max31856/max31856.cpp +12 -1
- esphome/components/max31856/max31856.h +5 -2
- esphome/components/max31856/sensor.py +20 -0
- esphome/components/mcp9600/sensor.py +2 -2
- esphome/components/mdns/__init__.py +6 -6
- esphome/components/media_player/media_player.h +16 -0
- esphome/components/micro_wake_word/__init__.py +2 -25
- esphome/components/microphone/microphone.h +1 -1
- esphome/components/mics_4514/mics_4514.cpp +26 -36
- esphome/components/modbus_controller/__init__.py +6 -0
- esphome/components/modbus_controller/const.py +2 -0
- esphome/components/modbus_controller/modbus_controller.cpp +30 -27
- esphome/components/modbus_controller/modbus_controller.h +22 -4
- esphome/components/network/__init__.py +11 -8
- esphome/components/pipsolar/pipsolar.cpp +3 -0
- esphome/components/pipsolar/pipsolar.h +1 -0
- esphome/components/pipsolar/switch/__init__.py +2 -0
- esphome/components/prometheus/prometheus_handler.cpp +2 -0
- esphome/components/prometheus/prometheus_handler.h +3 -1
- esphome/components/rp2040/__init__.py +7 -8
- esphome/components/rpi_dpi_rgb/display.py +20 -17
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +36 -6
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h +4 -0
- esphome/components/socket/socket.cpp +2 -0
- esphome/components/socket/socket.h +2 -0
- esphome/components/speaker/speaker.h +1 -1
- esphome/components/st7701s/display.py +35 -37
- esphome/components/st7701s/st7701s.cpp +11 -6
- esphome/components/st7701s/st7701s.h +1 -0
- esphome/components/statsd/__init__.py +65 -0
- esphome/components/statsd/statsd.cpp +156 -0
- esphome/components/statsd/statsd.h +86 -0
- esphome/components/tuya/__init__.py +1 -0
- esphome/components/tuya/number/__init__.py +39 -2
- esphome/components/tuya/number/tuya_number.cpp +58 -2
- esphome/components/tuya/number/tuya_number.h +12 -3
- esphome/components/udp/__init__.py +158 -0
- esphome/components/udp/binary_sensor.py +27 -0
- esphome/components/udp/sensor.py +27 -0
- esphome/components/udp/udp_component.cpp +616 -0
- esphome/components/udp/udp_component.h +158 -0
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +4 -6
- esphome/components/uponor_smatrix/uponor_smatrix.h +0 -1
- esphome/components/veml7700/sensor.py +2 -2
- esphome/components/voice_assistant/__init__.py +6 -0
- esphome/components/voice_assistant/voice_assistant.cpp +24 -2
- esphome/components/voice_assistant/voice_assistant.h +20 -0
- esphome/components/web_server/__init__.py +11 -11
- esphome/components/web_server/list_entities.cpp +2 -0
- esphome/components/web_server/list_entities.h +3 -1
- esphome/components/web_server/web_server.cpp +2 -1
- esphome/components/web_server/web_server.h +2 -0
- esphome/components/web_server_base/web_server_base.cpp +2 -0
- esphome/components/web_server_base/web_server_base.h +3 -1
- esphome/components/wifi/wifi_component_libretiny.cpp +15 -1
- esphome/components/wireguard/__init__.py +9 -6
- esphome/components/wireguard/wireguard.cpp +2 -1
- esphome/components/wireguard/wireguard.h +3 -1
- esphome/config_validation.py +8 -0
- esphome/const.py +8 -1
- esphome/core/bytebuffer.cpp +117 -84
- esphome/core/bytebuffer.h +69 -21
- esphome/core/config.py +0 -3
- esphome/core/defines.h +2 -0
- esphome/core/ring_buffer.cpp +13 -2
- esphome/core/ring_buffer.h +56 -0
- esphome/external_files.py +5 -3
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/METADATA +1 -1
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/RECORD +204 -169
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/LICENSE +0 -0
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/WHEEL +0 -0
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/entry_points.txt +0 -0
- {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
|