esphome 2024.9.1__py3-none-any.whl → 2024.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. esphome/components/aic3204/__init__.py +0 -0
  2. esphome/components/aic3204/aic3204.cpp +173 -0
  3. esphome/components/aic3204/aic3204.h +88 -0
  4. esphome/components/aic3204/audio_dac.py +52 -0
  5. esphome/components/aic3204/automation.h +23 -0
  6. esphome/components/alarm_control_panel/__init__.py +3 -4
  7. esphome/components/animation/__init__.py +16 -12
  8. esphome/components/api/api_connection.cpp +2 -0
  9. esphome/components/api/api_connection.h +3 -1
  10. esphome/components/api/api_frame_helper.cpp +2 -1
  11. esphome/components/api/api_frame_helper.h +2 -1
  12. esphome/components/api/api_server.cpp +2 -0
  13. esphome/components/api/api_server.h +3 -1
  14. esphome/components/api/custom_api_device.h +3 -2
  15. esphome/components/api/homeassistant_service.h +4 -3
  16. esphome/components/api/list_entities.cpp +2 -0
  17. esphome/components/api/list_entities.h +3 -2
  18. esphome/components/api/subscribe_state.cpp +2 -0
  19. esphome/components/api/subscribe_state.h +3 -2
  20. esphome/components/audio_dac/__init__.py +57 -0
  21. esphome/components/audio_dac/audio_dac.h +23 -0
  22. esphome/components/audio_dac/automation.h +43 -0
  23. esphome/components/bang_bang/bang_bang_climate.cpp +5 -2
  24. esphome/components/bedjet/bedjet_codec.cpp +4 -2
  25. esphome/components/binary_sensor/__init__.py +3 -4
  26. esphome/components/bl0906/sensor.py +3 -2
  27. esphome/components/button/__init__.py +3 -4
  28. esphome/components/ch422g/__init__.py +26 -17
  29. esphome/components/ch422g/ch422g.cpp +66 -49
  30. esphome/components/ch422g/ch422g.h +17 -19
  31. esphome/components/climate/__init__.py +3 -4
  32. esphome/components/cover/__init__.py +4 -5
  33. esphome/components/cse7766/cse7766.cpp +12 -1
  34. esphome/components/cse7766/cse7766.h +4 -0
  35. esphome/components/cse7766/sensor.py +13 -1
  36. esphome/components/cst816/touchscreen/__init__.py +7 -4
  37. esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +20 -19
  38. esphome/components/cst816/touchscreen/cst816_touchscreen.h +2 -0
  39. esphome/components/datetime/__init__.py +21 -14
  40. esphome/components/datetime/datetime_base.h +8 -1
  41. esphome/components/datetime/datetime_entity.cpp +2 -0
  42. esphome/components/datetime/datetime_entity.h +2 -0
  43. esphome/components/datetime/time_entity.cpp +2 -0
  44. esphome/components/datetime/time_entity.h +2 -0
  45. esphome/components/esp32/__init__.py +20 -4
  46. esphome/components/esp32_improv/__init__.py +82 -1
  47. esphome/components/esp32_improv/automation.h +72 -0
  48. esphome/components/esp32_improv/esp32_improv_component.cpp +13 -5
  49. esphome/components/esp32_improv/esp32_improv_component.h +15 -0
  50. esphome/components/ethernet/__init__.py +5 -0
  51. esphome/components/ethernet/ethernet_component.cpp +13 -0
  52. esphome/components/ethernet/ethernet_component.h +1 -0
  53. esphome/components/event/__init__.py +20 -12
  54. esphome/components/fan/__init__.py +3 -4
  55. esphome/components/gp2y1010au0f/__init__.py +0 -0
  56. esphome/components/gp2y1010au0f/gp2y1010au0f.cpp +67 -0
  57. esphome/components/gp2y1010au0f/gp2y1010au0f.h +52 -0
  58. esphome/components/gp2y1010au0f/sensor.py +61 -0
  59. esphome/components/gpio_expander/__init__.py +0 -0
  60. esphome/components/gpio_expander/cached_gpio.h +38 -0
  61. esphome/components/grove_gas_mc_v2/__init__.py +0 -0
  62. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +88 -0
  63. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +39 -0
  64. esphome/components/grove_gas_mc_v2/sensor.py +77 -0
  65. esphome/components/haier/climate.py +4 -3
  66. esphome/components/haier/haier_base.cpp +63 -8
  67. esphome/components/haier/haier_base.h +29 -3
  68. esphome/components/haier/hon_climate.cpp +122 -65
  69. esphome/components/haier/hon_climate.h +18 -2
  70. esphome/components/haier/smartair2_climate.cpp +21 -21
  71. esphome/components/haier/switch/__init__.py +91 -0
  72. esphome/components/haier/switch/beeper.cpp +14 -0
  73. esphome/components/haier/switch/beeper.h +18 -0
  74. esphome/components/haier/switch/display.cpp +14 -0
  75. esphome/components/haier/switch/display.h +18 -0
  76. esphome/components/haier/switch/health_mode.cpp +14 -0
  77. esphome/components/haier/switch/health_mode.h +18 -0
  78. esphome/components/haier/switch/quiet_mode.cpp +14 -0
  79. esphome/components/haier/switch/quiet_mode.h +18 -0
  80. esphome/components/hmac_md5/hmac_md5.cpp +2 -0
  81. esphome/components/hmac_md5/hmac_md5.h +2 -1
  82. esphome/components/i2s_audio/speaker/__init__.py +19 -0
  83. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  84. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
  85. esphome/components/ili9xxx/ili9xxx_display.h +1 -0
  86. esphome/components/image/__init__.py +12 -12
  87. esphome/components/image/image.cpp +44 -0
  88. esphome/components/image/image.h +17 -2
  89. esphome/components/inkplate6/display.py +2 -0
  90. esphome/components/inkplate6/inkplate.h +30 -2
  91. esphome/components/light/__init__.py +3 -4
  92. esphome/components/lock/__init__.py +3 -4
  93. esphome/components/lvgl/__init__.py +16 -5
  94. esphome/components/lvgl/defines.py +1 -0
  95. esphome/components/lvgl/hello_world.py +64 -0
  96. esphome/components/lvgl/lv_validation.py +159 -3
  97. esphome/components/lvgl/lvgl_esphome.cpp +0 -43
  98. esphome/components/lvgl/lvgl_esphome.h +0 -4
  99. esphome/components/lvgl/styles.py +3 -2
  100. esphome/components/lvgl/text/__init__.py +3 -3
  101. esphome/components/lvgl/widgets/__init__.py +2 -0
  102. esphome/components/lvgl/widgets/animimg.py +3 -4
  103. esphome/components/lvgl/widgets/dropdown.py +5 -1
  104. esphome/components/lvgl/widgets/meter.py +16 -11
  105. esphome/components/md5/__init__.py +6 -0
  106. esphome/components/md5/md5.cpp +2 -0
  107. esphome/components/md5/md5.h +2 -0
  108. esphome/components/micro_wake_word/__init__.py +7 -0
  109. esphome/components/mics_4514/sensor.py +11 -26
  110. esphome/components/modbus_controller/__init__.py +7 -5
  111. esphome/components/modbus_controller/binary_sensor/__init__.py +6 -6
  112. esphome/components/modbus_controller/number/__init__.py +5 -6
  113. esphome/components/modbus_controller/output/__init__.py +10 -14
  114. esphome/components/modbus_controller/select/__init__.py +1 -1
  115. esphome/components/modbus_controller/sensor/__init__.py +7 -7
  116. esphome/components/modbus_controller/switch/__init__.py +6 -7
  117. esphome/components/modbus_controller/text_sensor/__init__.py +8 -9
  118. esphome/components/mqtt/__init__.py +3 -0
  119. esphome/components/mqtt/mqtt_client.cpp +2 -0
  120. esphome/components/mqtt/mqtt_client.h +2 -0
  121. esphome/components/nau7802/__init__.py +0 -0
  122. esphome/components/nau7802/nau7802.cpp +323 -0
  123. esphome/components/nau7802/nau7802.h +121 -0
  124. esphome/components/nau7802/sensor.py +134 -0
  125. esphome/components/nextion/base_component.py +1 -0
  126. esphome/components/nextion/display.py +4 -0
  127. esphome/components/nextion/nextion.cpp +19 -4
  128. esphome/components/nextion/nextion.h +16 -0
  129. esphome/components/npi19/__init__.py +0 -0
  130. esphome/components/npi19/npi19.cpp +111 -0
  131. esphome/components/npi19/npi19.h +30 -0
  132. esphome/components/npi19/sensor.py +52 -0
  133. esphome/components/number/__init__.py +3 -5
  134. esphome/components/online_image/__init__.py +1 -1
  135. esphome/components/online_image/online_image.h +1 -2
  136. esphome/components/opentherm/__init__.py +57 -0
  137. esphome/components/opentherm/hub.cpp +277 -0
  138. esphome/components/opentherm/hub.h +110 -0
  139. esphome/components/opentherm/opentherm.cpp +568 -0
  140. esphome/components/opentherm/opentherm.h +347 -0
  141. esphome/components/pulse_counter/pulse_counter_sensor.cpp +8 -1
  142. esphome/components/pulse_counter/pulse_counter_sensor.h +1 -0
  143. esphome/components/radon_eye_ble/radon_eye_listener.cpp +10 -3
  144. esphome/components/remote_transmitter/__init__.py +18 -2
  145. esphome/components/remote_transmitter/remote_transmitter.h +6 -0
  146. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +2 -0
  147. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
  148. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
  149. esphome/components/rp2040/__init__.py +13 -14
  150. esphome/components/select/__init__.py +3 -4
  151. esphome/components/sensor/__init__.py +3 -4
  152. esphome/components/shelly_dimmer/shelly_dimmer.cpp +32 -32
  153. esphome/components/shelly_dimmer/shelly_dimmer.h +2 -0
  154. esphome/components/st7701s/st7701s.cpp +21 -8
  155. esphome/components/st7701s/st7701s.h +2 -0
  156. esphome/components/switch/__init__.py +3 -4
  157. esphome/components/tca9555/__init__.py +72 -0
  158. esphome/components/tca9555/tca9555.cpp +140 -0
  159. esphome/components/tca9555/tca9555.h +64 -0
  160. esphome/components/tcs34725/tcs34725.cpp +62 -64
  161. esphome/components/tem3200/__init__.py +0 -0
  162. esphome/components/tem3200/sensor.py +55 -0
  163. esphome/components/tem3200/tem3200.cpp +151 -0
  164. esphome/components/tem3200/tem3200.h +30 -0
  165. esphome/components/template/binary_sensor/__init__.py +19 -6
  166. esphome/components/text/__init__.py +3 -4
  167. esphome/components/text_sensor/__init__.py +3 -4
  168. esphome/components/thermostat/climate.py +11 -9
  169. esphome/components/thermostat/thermostat_climate.cpp +21 -15
  170. esphome/components/tm1638/binary_sensor/__init__.py +3 -2
  171. esphome/components/tm1638/display.py +5 -5
  172. esphome/components/tm1638/output/__init__.py +3 -2
  173. esphome/components/tm1638/switch/__init__.py +3 -2
  174. esphome/components/touchscreen/touchscreen.cpp +2 -2
  175. esphome/components/update/__init__.py +3 -4
  176. esphome/components/valve/__init__.py +3 -4
  177. esphome/components/web_server/__init__.py +78 -22
  178. esphome/components/web_server/server_index_v3.h +3989 -3979
  179. esphome/components/web_server/web_server.cpp +219 -34
  180. esphome/components/web_server/web_server.h +10 -1
  181. esphome/components/wifi/wifi_component_esp_idf.cpp +4 -5
  182. esphome/config_validation.py +1 -0
  183. esphome/const.py +12 -2
  184. esphome/core/defines.h +4 -2
  185. esphome/core/helpers.cpp +46 -10
  186. esphome/core/helpers.h +8 -0
  187. esphome/core/ring_buffer.cpp +12 -2
  188. esphome/core/ring_buffer.h +3 -0
  189. esphome/voluptuous_schema.py +3 -1
  190. esphome/wizard.py +0 -3
  191. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/METADATA +5 -3
  192. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/RECORD +196 -147
  193. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/LICENSE +0 -0
  194. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/WHEEL +0 -0
  195. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/entry_points.txt +0 -0
  196. {esphome-2024.9.1.dist-info → esphome-2024.10.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,347 @@
1
+ /*
2
+ * OpenTherm protocol implementation. Originally taken from https://github.com/jpraus/arduino-opentherm, but
3
+ * heavily modified to comply with ESPHome coding standards and provide better logging.
4
+ * Original code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
5
+ * Public License, which is compatible with GPLv3 license, which covers C++ part of ESPHome project.
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #include <string>
11
+ #include <sstream>
12
+ #include <iomanip>
13
+ #include "esphome/core/hal.h"
14
+ #include "esphome/core/log.h"
15
+
16
+ #if defined(ESP32) || defined(USE_ESP_IDF)
17
+ #include "driver/timer.h"
18
+ #endif
19
+
20
+ namespace esphome {
21
+ namespace opentherm {
22
+
23
+ // TODO: Account for immutable semantics change in hub.cpp when doing later installments of OpenTherm PR
24
+ template<class T> constexpr T read_bit(T value, uint8_t bit) { return (value >> bit) & 0x01; }
25
+
26
+ template<class T> constexpr T set_bit(T value, uint8_t bit) { return value |= (1UL << bit); }
27
+
28
+ template<class T> constexpr T clear_bit(T value, uint8_t bit) { return value &= ~(1UL << bit); }
29
+
30
+ template<class T> constexpr T write_bit(T value, uint8_t bit, uint8_t bit_value) {
31
+ return bit_value ? setBit(value, bit) : clearBit(value, bit);
32
+ }
33
+
34
+ enum OperationMode {
35
+ IDLE = 0, // no operation
36
+
37
+ LISTEN = 1, // waiting for transmission to start
38
+ READ = 2, // reading 32-bit data frame
39
+ RECEIVED = 3, // data frame received with valid start and stop bit
40
+
41
+ WRITE = 4, // writing data with timer_
42
+ SENT = 5, // all data written to output
43
+
44
+ ERROR_PROTOCOL = 8, // manchester protocol data transfer error
45
+ ERROR_TIMEOUT = 9 // read timeout
46
+ };
47
+
48
+ enum ProtocolErrorType {
49
+ NO_ERROR = 0, // No error
50
+ NO_TRANSITION = 1, // No transition in the middle of the bit
51
+ INVALID_STOP_BIT = 2, // Stop bit wasn't present when expected
52
+ PARITY_ERROR = 3, // Parity check didn't pass
53
+ NO_CHANGE_TOO_LONG = 4, // No level change for too much timer ticks
54
+ };
55
+
56
+ enum MessageType {
57
+ READ_DATA = 0,
58
+ READ_ACK = 4,
59
+ WRITE_DATA = 1,
60
+ WRITE_ACK = 5,
61
+ INVALID_DATA = 2,
62
+ DATA_INVALID = 6,
63
+ UNKNOWN_DATAID = 7
64
+ };
65
+
66
+ enum MessageId {
67
+ STATUS = 0,
68
+ CH_SETPOINT = 1,
69
+ CONTROLLER_CONFIG = 2,
70
+ DEVICE_CONFIG = 3,
71
+ COMMAND_CODE = 4,
72
+ FAULT_FLAGS = 5,
73
+ REMOTE = 6,
74
+ COOLING_CONTROL = 7,
75
+ CH2_SETPOINT = 8,
76
+ CH_SETPOINT_OVERRIDE = 9,
77
+ TSP_COUNT = 10,
78
+ TSP_COMMAND = 11,
79
+ FHB_SIZE = 12,
80
+ FHB_COMMAND = 13,
81
+ MAX_MODULATION_LEVEL = 14,
82
+ MAX_BOILER_CAPACITY = 15, // u8_hb - u8_lb gives min modulation level
83
+ ROOM_SETPOINT = 16,
84
+ MODULATION_LEVEL = 17,
85
+ CH_WATER_PRESSURE = 18,
86
+ DHW_FLOW_RATE = 19,
87
+ DAY_TIME = 20,
88
+ DATE = 21,
89
+ YEAR = 22,
90
+ ROOM_SETPOINT_CH2 = 23,
91
+ ROOM_TEMP = 24,
92
+ FEED_TEMP = 25,
93
+ DHW_TEMP = 26,
94
+ OUTSIDE_TEMP = 27,
95
+ RETURN_WATER_TEMP = 28,
96
+ SOLAR_STORE_TEMP = 29,
97
+ SOLAR_COLLECT_TEMP = 30,
98
+ FEED_TEMP_CH2 = 31,
99
+ DHW2_TEMP = 32,
100
+ EXHAUST_TEMP = 33,
101
+ FAN_SPEED = 35,
102
+ FLAME_CURRENT = 36,
103
+ DHW_BOUNDS = 48,
104
+ CH_BOUNDS = 49,
105
+ OTC_CURVE_BOUNDS = 50,
106
+ DHW_SETPOINT = 56,
107
+ MAX_CH_SETPOINT = 57,
108
+ OTC_CURVE_RATIO = 58,
109
+
110
+ // HVAC Specific Message IDs
111
+ HVAC_STATUS = 70,
112
+ REL_VENT_SETPOINT = 71,
113
+ DEVICE_VENT = 74,
114
+ REL_VENTILATION = 77,
115
+ REL_HUMID_EXHAUST = 78,
116
+ SUPPLY_INLET_TEMP = 80,
117
+ SUPPLY_OUTLET_TEMP = 81,
118
+ EXHAUST_INLET_TEMP = 82,
119
+ EXHAUST_OUTLET_TEMP = 83,
120
+ NOM_REL_VENTILATION = 87,
121
+
122
+ OVERRIDE_FUNC = 100,
123
+ OEM_DIAGNOSTIC = 115,
124
+ BURNER_STARTS = 116,
125
+ CH_PUMP_STARTS = 117,
126
+ DHW_PUMP_STARTS = 118,
127
+ DHW_BURNER_STARTS = 119,
128
+ BURNER_HOURS = 120,
129
+ CH_PUMP_HOURS = 121,
130
+ DHW_PUMP_HOURS = 122,
131
+ DHW_BURNER_HOURS = 123,
132
+ OT_VERSION_CONTROLLER = 124,
133
+ OT_VERSION_DEVICE = 125,
134
+ VERSION_CONTROLLER = 126,
135
+ VERSION_DEVICE = 127
136
+ };
137
+
138
+ enum BitPositions { STOP_BIT = 33 };
139
+
140
+ /**
141
+ * Structure to hold Opentherm data packet content.
142
+ * Use f88(), u16() or s16() functions to get appropriate value of data packet accoridng to id of message.
143
+ */
144
+ struct OpenthermData {
145
+ uint8_t type;
146
+ uint8_t id;
147
+ uint8_t valueHB;
148
+ uint8_t valueLB;
149
+
150
+ OpenthermData() : type(0), id(0), valueHB(0), valueLB(0) {}
151
+
152
+ /**
153
+ * @return float representation of data packet value
154
+ */
155
+ float f88();
156
+
157
+ /**
158
+ * @param float number to set as value of this data packet
159
+ */
160
+ void f88(float value);
161
+
162
+ /**
163
+ * @return unsigned 16b integer representation of data packet value
164
+ */
165
+ uint16_t u16();
166
+
167
+ /**
168
+ * @param unsigned 16b integer number to set as value of this data packet
169
+ */
170
+ void u16(uint16_t value);
171
+
172
+ /**
173
+ * @return signed 16b integer representation of data packet value
174
+ */
175
+ int16_t s16();
176
+
177
+ /**
178
+ * @param signed 16b integer number to set as value of this data packet
179
+ */
180
+ void s16(int16_t value);
181
+ };
182
+
183
+ struct OpenThermError {
184
+ ProtocolErrorType error_type;
185
+ uint32_t capture;
186
+ uint8_t clock;
187
+ uint32_t data;
188
+ uint8_t bit_pos;
189
+ };
190
+
191
+ /**
192
+ * Opentherm static class that supports either listening or sending Opentherm data packets in the same time
193
+ */
194
+ class OpenTherm {
195
+ public:
196
+ OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout = 800);
197
+
198
+ /**
199
+ * Setup pins.
200
+ */
201
+ bool initialize();
202
+
203
+ /**
204
+ * Start listening for Opentherm data packet comming from line connected to given pin.
205
+ * If data packet is received then has_message() function returns true and data packet can be retrieved by calling
206
+ * get_message() function. If timeout > 0 then this function waits for incomming data package for timeout millis and
207
+ * if no data packet is recevived, error state is indicated by is_error() function. If either data packet is received
208
+ * or timeout is reached listening is stopped.
209
+ */
210
+ void listen();
211
+
212
+ /**
213
+ * Use this function to check whether listen() function already captured a valid data packet.
214
+ *
215
+ * @return true if data packet has been captured from line by listen() function.
216
+ */
217
+ bool has_message() { return mode_ == OperationMode::RECEIVED; }
218
+
219
+ /**
220
+ * Use this to retrive data packed captured by listen() function. Data packet is ready when has_message() function
221
+ * returns true. This function can be called multiple times until stop() is called.
222
+ *
223
+ * @param data reference to data structure to which fill the data packet data.
224
+ * @return true if packet was ready and was filled into data structure passed, false otherwise.
225
+ */
226
+ bool get_message(OpenthermData &data);
227
+
228
+ /**
229
+ * Immediately send out Opentherm data packet to line connected on given pin.
230
+ * Completed data transfer is indicated by is_sent() function.
231
+ * Error state is indicated by is_error() function.
232
+ *
233
+ * @param data Opentherm data packet.
234
+ */
235
+ void send(OpenthermData &data);
236
+
237
+ /**
238
+ * Stops listening for data packet or sending out data packet and resets internal state of this class.
239
+ * Stops all timers and unattaches all interrupts.
240
+ */
241
+ void stop();
242
+
243
+ /**
244
+ * Get protocol error details in case a protocol error occured.
245
+ * @param error reference to data structure to which fill the error details
246
+ * @return true if protocol error occured during last conversation, false otherwise.
247
+ */
248
+ bool get_protocol_error(OpenThermError &error);
249
+
250
+ /**
251
+ * Use this function to check whether send() function already finished sending data packed to line.
252
+ *
253
+ * @return true if data packet has been sent, false otherwise.
254
+ */
255
+ bool is_sent() { return mode_ == OperationMode::SENT; }
256
+
257
+ /**
258
+ * Indicates whether listinig or sending is not in progress.
259
+ * That also means that no timers are running and no interrupts are attached.
260
+ *
261
+ * @return true if listening nor sending is in progress.
262
+ */
263
+ bool is_idle() { return mode_ == OperationMode::IDLE; }
264
+
265
+ /**
266
+ * Indicates whether last listen() or send() operation ends up with an error. Includes both timeout and
267
+ * protocol errors.
268
+ *
269
+ * @return true if last listen() or send() operation ends up with an error.
270
+ */
271
+ bool is_error() { return mode_ == OperationMode::ERROR_TIMEOUT || mode_ == OperationMode::ERROR_PROTOCOL; }
272
+
273
+ /**
274
+ * Indicates whether last listen() or send() operation ends up with a *timeout* error
275
+ * @return true if last listen() or send() operation ends up with a *timeout* error.
276
+ */
277
+ bool is_timeout() { return mode_ == OperationMode::ERROR_TIMEOUT; }
278
+
279
+ /**
280
+ * Indicates whether last listen() or send() operation ends up with a *protocol* error
281
+ * @return true if last listen() or send() operation ends up with a *protocol* error.
282
+ */
283
+ bool is_protocol_error() { return mode_ == OperationMode::ERROR_PROTOCOL; }
284
+
285
+ bool is_active() { return mode_ == LISTEN || mode_ == READ || mode_ == WRITE; }
286
+
287
+ OperationMode get_mode() { return mode_; }
288
+
289
+ std::string debug_data(OpenthermData &data);
290
+ std::string debug_error(OpenThermError &error);
291
+
292
+ const char *protocol_error_to_to_str(ProtocolErrorType error_type);
293
+ const char *message_type_to_str(MessageType message_type);
294
+ const char *operation_mode_to_str(OperationMode mode);
295
+ const char *message_id_to_str(MessageId id);
296
+
297
+ static bool timer_isr(OpenTherm *arg);
298
+
299
+ #ifdef ESP8266
300
+ static void esp8266_timer_isr();
301
+ #endif
302
+
303
+ private:
304
+ InternalGPIOPin *in_pin_;
305
+ InternalGPIOPin *out_pin_;
306
+ ISRInternalGPIOPin isr_in_pin_;
307
+ ISRInternalGPIOPin isr_out_pin_;
308
+
309
+ #if defined(ESP32) || defined(USE_ESP_IDF)
310
+ timer_group_t timer_group_;
311
+ timer_idx_t timer_idx_;
312
+ #endif
313
+
314
+ OperationMode mode_;
315
+ ProtocolErrorType error_type_;
316
+ uint32_t capture_;
317
+ uint8_t clock_;
318
+ uint32_t data_;
319
+ uint8_t bit_pos_;
320
+ int32_t timeout_counter_; // <0 no timeout
321
+
322
+ int32_t device_timeout_;
323
+
324
+ #if defined(ESP32) || defined(USE_ESP_IDF)
325
+ bool init_esp32_timer_();
326
+ void start_esp32_timer_(uint64_t alarm_value);
327
+ #endif
328
+
329
+ void stop_timer_();
330
+
331
+ void read_(); // data detected start reading
332
+ void start_read_timer_(); // reading timer_ to sample at 1/5 of manchester code bit length (at 5kHz)
333
+ void start_write_timer_(); // writing timer_ to send manchester code (at 2kHz)
334
+ bool check_parity_(uint32_t val);
335
+
336
+ void bit_read_(uint8_t value);
337
+ ProtocolErrorType verify_stop_bit_(uint8_t value);
338
+ void write_bit_(uint8_t high, uint8_t clock);
339
+
340
+ #ifdef ESP8266
341
+ // ESP8266 timer can accept callback with no parameters, so we have this hack to save a static instance of OpenTherm
342
+ static OpenTherm *instance_;
343
+ #endif
344
+ };
345
+
346
+ } // namespace opentherm
347
+ } // namespace esphome
@@ -53,12 +53,19 @@ pulse_counter_t BasicPulseCounterStorage::read_raw_value() {
53
53
  #ifdef HAS_PCNT
54
54
  bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
55
55
  static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0;
56
+ static pcnt_channel_t next_pcnt_channel = PCNT_CHANNEL_0;
56
57
  this->pin = pin;
57
58
  this->pin->setup();
58
59
  this->pcnt_unit = next_pcnt_unit;
60
+ this->pcnt_channel = next_pcnt_channel;
59
61
  next_pcnt_unit = pcnt_unit_t(int(next_pcnt_unit) + 1);
62
+ if (int(next_pcnt_unit) >= PCNT_UNIT_0 + PCNT_UNIT_MAX) {
63
+ next_pcnt_unit = PCNT_UNIT_0;
64
+ next_pcnt_channel = pcnt_channel_t(int(next_pcnt_channel) + 1);
65
+ }
60
66
 
61
67
  ESP_LOGCONFIG(TAG, " PCNT Unit Number: %u", this->pcnt_unit);
68
+ ESP_LOGCONFIG(TAG, " PCNT Channel Number: %u", this->pcnt_channel);
62
69
 
63
70
  pcnt_count_mode_t rising = PCNT_COUNT_DIS, falling = PCNT_COUNT_DIS;
64
71
  switch (this->rising_edge_mode) {
@@ -94,7 +101,7 @@ bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
94
101
  .counter_h_lim = 0,
95
102
  .counter_l_lim = 0,
96
103
  .unit = this->pcnt_unit,
97
- .channel = PCNT_CHANNEL_0,
104
+ .channel = this->pcnt_channel,
98
105
  };
99
106
  esp_err_t error = pcnt_unit_config(&pcnt_config);
100
107
  if (error != ESP_OK) {
@@ -55,6 +55,7 @@ struct HwPulseCounterStorage : public PulseCounterStorageBase {
55
55
  pulse_counter_t read_raw_value() override;
56
56
 
57
57
  pcnt_unit_t pcnt_unit;
58
+ pcnt_channel_t pcnt_channel;
58
59
  };
59
60
  #endif
60
61
 
@@ -1,5 +1,7 @@
1
1
  #include "radon_eye_listener.h"
2
2
  #include "esphome/core/log.h"
3
+ #include <algorithm>
4
+ #include <vector>
3
5
 
4
6
  #ifdef USE_ESP32
5
7
 
@@ -10,9 +12,14 @@ static const char *const TAG = "radon_eye_ble";
10
12
 
11
13
  bool RadonEyeListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
12
14
  if (not device.get_name().empty()) {
13
- if (device.get_name().rfind("FR:R", 0) == 0) {
14
- // This is an RD200, I think
15
- ESP_LOGD(TAG, "Found Radon Eye RD200 device Name: %s (MAC: %s)", device.get_name().c_str(),
15
+ // Vector containing the prefixes to search for
16
+ std::vector<std::string> prefixes = {"FR:R", "FR:I", "FR:H"};
17
+
18
+ // Check if the device name starts with any of the prefixes
19
+ if (std::any_of(prefixes.begin(), prefixes.end(),
20
+ [&](const std::string &prefix) { return device.get_name().rfind(prefix, 0) == 0; })) {
21
+ // Device found
22
+ ESP_LOGD(TAG, "Found Radon Eye device Name: %s (MAC: %s)", device.get_name().c_str(),
16
23
  device.address_str().c_str());
17
24
  }
18
25
  }
@@ -1,10 +1,14 @@
1
+ from esphome import automation, pins
1
2
  import esphome.codegen as cg
3
+ from esphome.components import esp32_rmt, remote_base
2
4
  import esphome.config_validation as cv
3
- from esphome import pins
4
- from esphome.components import remote_base, esp32_rmt
5
5
  from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN, CONF_RMT_CHANNEL
6
6
 
7
7
  AUTO_LOAD = ["remote_base"]
8
+
9
+ CONF_ON_TRANSMIT = "on_transmit"
10
+ CONF_ON_COMPLETE = "on_complete"
11
+
8
12
  remote_transmitter_ns = cg.esphome_ns.namespace("remote_transmitter")
9
13
  RemoteTransmitterComponent = remote_transmitter_ns.class_(
10
14
  "RemoteTransmitterComponent", remote_base.RemoteTransmitterBase, cg.Component
@@ -19,6 +23,8 @@ CONFIG_SCHEMA = cv.Schema(
19
23
  cv.percentage_int, cv.Range(min=1, max=100)
20
24
  ),
21
25
  cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=True),
26
+ cv.Optional(CONF_ON_TRANSMIT): automation.validate_automation(single=True),
27
+ cv.Optional(CONF_ON_COMPLETE): automation.validate_automation(single=True),
22
28
  }
23
29
  ).extend(cv.COMPONENT_SCHEMA)
24
30
 
@@ -32,3 +38,13 @@ async def to_code(config):
32
38
  await cg.register_component(var, config)
33
39
 
34
40
  cg.add(var.set_carrier_duty_percent(config[CONF_CARRIER_DUTY_PERCENT]))
41
+
42
+ if on_transmit_config := config.get(CONF_ON_TRANSMIT):
43
+ await automation.build_automation(
44
+ var.get_transmit_trigger(), [], on_transmit_config
45
+ )
46
+
47
+ if on_complete_config := config.get(CONF_ON_COMPLETE):
48
+ await automation.build_automation(
49
+ var.get_complete_trigger(), [], on_complete_config
50
+ )
@@ -33,6 +33,9 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase,
33
33
 
34
34
  void set_carrier_duty_percent(uint8_t carrier_duty_percent) { this->carrier_duty_percent_ = carrier_duty_percent; }
35
35
 
36
+ Trigger<> *get_transmit_trigger() const { return this->transmit_trigger_; };
37
+ Trigger<> *get_complete_trigger() const { return this->complete_trigger_; };
38
+
36
39
  protected:
37
40
  void send_internal(uint32_t send_times, uint32_t send_wait) override;
38
41
  #if defined(USE_ESP8266) || defined(USE_LIBRETINY)
@@ -57,6 +60,9 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase,
57
60
  bool inverted_{false};
58
61
  #endif
59
62
  uint8_t carrier_duty_percent_;
63
+
64
+ Trigger<> *transmit_trigger_{new Trigger<>()};
65
+ Trigger<> *complete_trigger_{new Trigger<>()};
60
66
  };
61
67
 
62
68
  } // namespace remote_transmitter
@@ -124,6 +124,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
124
124
  ESP_LOGE(TAG, "Empty data");
125
125
  return;
126
126
  }
127
+ this->transmit_trigger_->trigger();
127
128
  for (uint32_t i = 0; i < send_times; i++) {
128
129
  esp_err_t error = rmt_write_items(this->channel_, this->rmt_temp_.data(), this->rmt_temp_.size(), true);
129
130
  if (error != ESP_OK) {
@@ -135,6 +136,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
135
136
  if (i + 1 < send_times)
136
137
  delayMicroseconds(send_wait);
137
138
  }
139
+ this->complete_trigger_->trigger();
138
140
  }
139
141
 
140
142
  } // namespace remote_transmitter
@@ -76,6 +76,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
76
76
  uint32_t on_time, off_time;
77
77
  this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time);
78
78
  this->target_time_ = 0;
79
+ this->transmit_trigger_->trigger();
79
80
  for (uint32_t i = 0; i < send_times; i++) {
80
81
  for (int32_t item : this->temp_.get_data()) {
81
82
  if (item > 0) {
@@ -93,6 +94,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
93
94
  if (i + 1 < send_times)
94
95
  this->target_time_ += send_wait;
95
96
  }
97
+ this->complete_trigger_->trigger();
96
98
  }
97
99
 
98
100
  } // namespace remote_transmitter
@@ -78,6 +78,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
78
78
  uint32_t on_time, off_time;
79
79
  this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time);
80
80
  this->target_time_ = 0;
81
+ this->transmit_trigger_->trigger();
81
82
  for (uint32_t i = 0; i < send_times; i++) {
82
83
  InterruptLock lock;
83
84
  for (int32_t item : this->temp_.get_data()) {
@@ -96,6 +97,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
96
97
  if (i + 1 < send_times)
97
98
  this->target_time_ += send_wait;
98
99
  }
100
+ this->complete_trigger_->trigger();
99
101
  }
100
102
 
101
103
  } // namespace remote_transmitter
@@ -71,6 +71,14 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
71
71
  # return f"~1.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
72
72
 
73
73
 
74
+ def _parse_platform_version(value):
75
+ value = cv.string(value)
76
+ if value.startswith("http"):
77
+ return value
78
+
79
+ return f"https://github.com/maxgerhardt/platform-raspberrypi.git#{value}"
80
+
81
+
74
82
  # NOTE: Keep this in mind when updating the recommended version:
75
83
  # * The new version needs to be thoroughly validated before changing the
76
84
  # recommended version as otherwise a bunch of devices could be bricked
@@ -82,10 +90,9 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
82
90
  # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico
83
91
  RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4)
84
92
 
85
- # The platformio/raspberrypi version to use for arduino frameworks
86
- # - https://github.com/platformio/platform-raspberrypi/releases
87
- # - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi
88
- ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0)
93
+ # The raspberrypi platform version to use for arduino frameworks
94
+ # - https://github.com/maxgerhardt/platform-raspberrypi/tags
95
+ RECOMMENDED_ARDUINO_PLATFORM_VERSION = "v1.2.0-gcc12"
89
96
 
90
97
 
91
98
  def _arduino_check_versions(value):
@@ -111,7 +118,8 @@ def _arduino_check_versions(value):
111
118
  value[CONF_SOURCE] = source or _format_framework_arduino_version(version)
112
119
 
113
120
  value[CONF_PLATFORM_VERSION] = value.get(
114
- CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION))
121
+ CONF_PLATFORM_VERSION,
122
+ _parse_platform_version(RECOMMENDED_ARDUINO_PLATFORM_VERSION),
115
123
  )
116
124
 
117
125
  if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION:
@@ -122,15 +130,6 @@ def _arduino_check_versions(value):
122
130
  return value
123
131
 
124
132
 
125
- def _parse_platform_version(value):
126
- try:
127
- # if platform version is a valid version constraint, prefix the default package
128
- cv.platformio_version_constraint(value)
129
- return f"platformio/raspberrypi@{value}"
130
- except cv.Invalid:
131
- return value
132
-
133
-
134
133
  ARDUINO_FRAMEWORK_SCHEMA = cv.All(
135
134
  cv.Schema(
136
135
  {
@@ -14,7 +14,7 @@ from esphome.const import (
14
14
  CONF_OPERATION,
15
15
  CONF_OPTION,
16
16
  CONF_TRIGGER_ID,
17
- CONF_WEB_SERVER_ID,
17
+ CONF_WEB_SERVER,
18
18
  )
19
19
  from esphome.core import CORE, coroutine_with_priority
20
20
  from esphome.cpp_generator import MockObjClass
@@ -104,9 +104,8 @@ async def setup_select_core_(var, config, *, options: list[str]):
104
104
  mqtt_ = cg.new_Pvariable(mqtt_id, var)
105
105
  await mqtt.register_mqtt_component(mqtt_, config)
106
106
 
107
- if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
108
- web_server_ = await cg.get_variable(webserver_id)
109
- web_server.add_entity_to_sorting_list(web_server_, var, config)
107
+ if web_server_config := config.get(CONF_WEB_SERVER):
108
+ await web_server.add_entity_config(var, web_server_config)
110
109
 
111
110
 
112
111
  async def register_select(var, config, *, options: list[str]):
@@ -36,7 +36,7 @@ from esphome.const import (
36
36
  CONF_TYPE,
37
37
  CONF_UNIT_OF_MEASUREMENT,
38
38
  CONF_VALUE,
39
- CONF_WEB_SERVER_ID,
39
+ CONF_WEB_SERVER,
40
40
  CONF_WINDOW_SIZE,
41
41
  DEVICE_CLASS_APPARENT_POWER,
42
42
  DEVICE_CLASS_AQI,
@@ -800,9 +800,8 @@ async def setup_sensor_core_(var, config):
800
800
  else:
801
801
  cg.add(mqtt_.set_expire_after(expire_after))
802
802
 
803
- if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
804
- web_server_ = await cg.get_variable(webserver_id)
805
- web_server.add_entity_to_sorting_list(web_server_, var, config)
803
+ if web_server_config := config.get(CONF_WEB_SERVER):
804
+ await web_server.add_entity_config(var, web_server_config)
806
805
 
807
806
 
808
807
  async def register_sensor(var, config):