esphome 2025.5.0b2__py3-none-any.whl → 2025.5.0b3__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 +16 -14
- esphome/components/api/api_connection.cpp +4 -3
- esphome/components/api/api_connection.h +8 -1
- esphome/components/api/api_frame_helper.cpp +136 -49
- esphome/components/api/api_frame_helper.h +49 -6
- esphome/components/api/proto.h +48 -8
- esphome/components/ballu/climate.py +1 -1
- esphome/components/bedjet/bedjet_hub.cpp +1 -0
- esphome/components/binary_sensor/binary_sensor.cpp +10 -6
- esphome/components/binary_sensor/binary_sensor.h +1 -1
- esphome/components/binary_sensor/filter.cpp +21 -21
- esphome/components/binary_sensor/filter.h +10 -10
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -1
- esphome/components/ccs811/sensor.py +9 -6
- esphome/components/climate_ir/__init__.py +3 -3
- esphome/components/climate_ir_lg/climate.py +1 -1
- esphome/components/coolix/climate.py +1 -1
- esphome/components/cse7766/cse7766.cpp +2 -1
- esphome/components/current_based/current_based_cover.cpp +2 -1
- esphome/components/daikin/climate.py +1 -1
- esphome/components/daikin_arc/climate.py +1 -1
- esphome/components/daikin_brc/climate.py +1 -1
- esphome/components/daly_bms/daly_bms.cpp +2 -1
- esphome/components/debug/debug_component.cpp +1 -1
- esphome/components/delonghi/climate.py +1 -1
- esphome/components/dps310/sensor.py +6 -6
- esphome/components/ee895/sensor.py +9 -9
- esphome/components/emmeti/climate.py +1 -1
- esphome/components/endstop/endstop_cover.cpp +2 -1
- esphome/components/ens160_base/__init__.py +12 -9
- esphome/components/esp32_ble/ble_advertising.cpp +2 -1
- esphome/components/esp32_camera/esp32_camera.cpp +2 -1
- esphome/components/esp32_camera/esp32_camera.h +1 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
- esphome/components/esp32_touch/esp32_touch.cpp +1 -1
- esphome/components/ethernet/ethernet_component.cpp +1 -1
- esphome/components/feedback/feedback_cover.cpp +2 -1
- esphome/components/fujitsu_general/climate.py +1 -1
- esphome/components/gcja5/gcja5.cpp +2 -1
- esphome/components/gps/__init__.py +37 -16
- esphome/components/gps/gps.cpp +33 -17
- esphome/components/gps/gps.h +16 -15
- esphome/components/gree/climate.py +1 -1
- esphome/components/growatt_solar/growatt_solar.cpp +2 -1
- esphome/components/heatpumpir/climate.py +1 -1
- esphome/components/hitachi_ac344/climate.py +1 -1
- esphome/components/hitachi_ac424/climate.py +1 -1
- esphome/components/hte501/sensor.py +6 -6
- esphome/components/hyt271/sensor.py +6 -6
- esphome/components/kuntze/kuntze.cpp +2 -1
- esphome/components/logger/__init__.py +1 -0
- esphome/components/logger/logger.cpp +53 -32
- esphome/components/logger/logger.h +55 -5
- esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
- esphome/components/max7219digit/max7219digit.cpp +2 -1
- esphome/components/mhz19/sensor.py +11 -7
- esphome/components/midea_ir/climate.py +1 -1
- esphome/components/mitsubishi/climate.py +1 -1
- esphome/components/modbus/modbus.cpp +2 -1
- esphome/components/mqtt/mqtt_client.cpp +1 -1
- esphome/components/ms5611/sensor.py +6 -6
- esphome/components/ms8607/sensor.py +3 -3
- esphome/components/noblex/climate.py +1 -1
- esphome/components/pmsx003/pmsx003.cpp +2 -1
- esphome/components/pzem004t/pzem004t.cpp +2 -1
- esphome/components/rf_bridge/rf_bridge.cpp +2 -1
- esphome/components/sds011/sds011.cpp +2 -1
- esphome/components/sen5x/sen5x.cpp +55 -36
- esphome/components/senseair/sensor.py +3 -3
- esphome/components/sgp30/sensor.py +14 -16
- esphome/components/shtcx/sensor.py +6 -6
- esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
- esphome/components/sprinkler/sprinkler.cpp +6 -5
- esphome/components/t6615/sensor.py +3 -3
- esphome/components/t6615/t6615.cpp +2 -1
- esphome/components/tcl112/climate.py +1 -1
- esphome/components/time_based/time_based_cover.cpp +2 -1
- esphome/components/toshiba/climate.py +1 -1
- esphome/components/uart/switch/uart_switch.cpp +2 -1
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
- esphome/components/whirlpool/climate.py +1 -1
- esphome/components/whynter/climate.py +1 -1
- esphome/components/zhlt01/climate.py +1 -1
- esphome/config.py +13 -13
- esphome/const.py +1 -1
- esphome/core/application.cpp +22 -10
- esphome/core/application.h +5 -1
- esphome/core/component.cpp +10 -5
- esphome/core/component.h +5 -1
- esphome/core/scheduler.cpp +4 -1
- esphome/log.py +15 -19
- esphome/mqtt.py +2 -2
- esphome/voluptuous_schema.py +3 -1
- esphome/wizard.py +45 -35
- {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b3.dist-info}/METADATA +1 -1
- {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b3.dist-info}/RECORD +101 -101
- {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b3.dist-info}/WHEEL +0 -0
- {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b3.dist-info}/entry_points.txt +0 -0
- {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b3.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.5.0b2.dist-info → esphome-2025.5.0b3.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
#include <cstdarg>
|
4
4
|
#include <map>
|
5
5
|
#ifdef USE_ESP32
|
6
|
-
#include <
|
6
|
+
#include <pthread.h>
|
7
7
|
#endif
|
8
8
|
#include "esphome/core/automation.h"
|
9
9
|
#include "esphome/core/component.h"
|
@@ -84,6 +84,23 @@ enum UARTSelection {
|
|
84
84
|
};
|
85
85
|
#endif // USE_ESP32 || USE_ESP8266 || USE_RP2040 || USE_LIBRETINY
|
86
86
|
|
87
|
+
/**
|
88
|
+
* @brief Logger component for all ESPHome logging.
|
89
|
+
*
|
90
|
+
* This class implements a multi-platform logging system with protection against recursion.
|
91
|
+
*
|
92
|
+
* Recursion Protection Strategy:
|
93
|
+
* - On ESP32: Uses task-specific recursion guards
|
94
|
+
* * Main task: Uses a dedicated boolean member variable for efficiency
|
95
|
+
* * Other tasks: Uses pthread TLS with a dynamically allocated key for task-specific state
|
96
|
+
* - On other platforms: Uses a simple global recursion guard
|
97
|
+
*
|
98
|
+
* We use pthread TLS via pthread_key_create to create a unique key for storing
|
99
|
+
* task-specific recursion state, which:
|
100
|
+
* 1. Efficiently handles multiple tasks without locks or mutexes
|
101
|
+
* 2. Works with ESP-IDF's pthread implementation that uses a linked list for TLS variables
|
102
|
+
* 3. Avoids the limitations of the fixed FreeRTOS task local storage slots
|
103
|
+
*/
|
87
104
|
class Logger : public Component {
|
88
105
|
public:
|
89
106
|
explicit Logger(uint32_t baud_rate, size_t tx_buffer_size);
|
@@ -102,6 +119,9 @@ class Logger : public Component {
|
|
102
119
|
#ifdef USE_ESP_IDF
|
103
120
|
uart_port_t get_uart_num() const { return uart_num_; }
|
104
121
|
#endif
|
122
|
+
#ifdef USE_ESP32
|
123
|
+
void create_pthread_key() { pthread_key_create(&log_recursion_key_, nullptr); }
|
124
|
+
#endif
|
105
125
|
#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY)
|
106
126
|
void set_uart_selection(UARTSelection uart_selection) { uart_ = uart_selection; }
|
107
127
|
/// Get the UART used by the logger.
|
@@ -222,18 +242,22 @@ class Logger : public Component {
|
|
222
242
|
std::map<std::string, int> log_levels_{};
|
223
243
|
CallbackManager<void(int, const char *, const char *)> log_callback_{};
|
224
244
|
int current_level_{ESPHOME_LOG_LEVEL_VERY_VERBOSE};
|
225
|
-
#ifdef USE_ESP32
|
226
|
-
std::atomic<bool> recursion_guard_{false};
|
227
245
|
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
|
228
246
|
std::unique_ptr<logger::TaskLogBuffer> log_buffer_; // Will be initialized with init_log_buffer
|
229
247
|
#endif
|
248
|
+
#ifdef USE_ESP32
|
249
|
+
// Task-specific recursion guards:
|
250
|
+
// - Main task uses a dedicated member variable for efficiency
|
251
|
+
// - Other tasks use pthread TLS with a dynamically created key via pthread_key_create
|
252
|
+
bool main_task_recursion_guard_{false};
|
253
|
+
pthread_key_t log_recursion_key_;
|
230
254
|
#else
|
231
|
-
bool
|
255
|
+
bool global_recursion_guard_{false}; // Simple global recursion guard for single-task platforms
|
232
256
|
#endif
|
233
|
-
void *main_task_ = nullptr;
|
234
257
|
CallbackManager<void(int)> level_callback_{};
|
235
258
|
|
236
259
|
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
260
|
+
void *main_task_ = nullptr; // Only used for thread name identification
|
237
261
|
const char *HOT get_thread_name_() {
|
238
262
|
TaskHandle_t current_task = xTaskGetCurrentTaskHandle();
|
239
263
|
if (current_task == main_task_) {
|
@@ -248,6 +272,32 @@ class Logger : public Component {
|
|
248
272
|
}
|
249
273
|
#endif
|
250
274
|
|
275
|
+
#ifdef USE_ESP32
|
276
|
+
inline bool HOT check_and_set_task_log_recursion_(bool is_main_task) {
|
277
|
+
if (is_main_task) {
|
278
|
+
const bool was_recursive = main_task_recursion_guard_;
|
279
|
+
main_task_recursion_guard_ = true;
|
280
|
+
return was_recursive;
|
281
|
+
}
|
282
|
+
|
283
|
+
intptr_t current = (intptr_t) pthread_getspecific(log_recursion_key_);
|
284
|
+
if (current != 0)
|
285
|
+
return true;
|
286
|
+
|
287
|
+
pthread_setspecific(log_recursion_key_, (void *) 1);
|
288
|
+
return false;
|
289
|
+
}
|
290
|
+
|
291
|
+
inline void HOT reset_task_log_recursion_(bool is_main_task) {
|
292
|
+
if (is_main_task) {
|
293
|
+
main_task_recursion_guard_ = false;
|
294
|
+
return;
|
295
|
+
}
|
296
|
+
|
297
|
+
pthread_setspecific(log_recursion_key_, (void *) 0);
|
298
|
+
}
|
299
|
+
#endif
|
300
|
+
|
251
301
|
inline void HOT write_header_to_buffer_(int level, const char *tag, int line, const char *thread_name, char *buffer,
|
252
302
|
int *buffer_at, int buffer_size) {
|
253
303
|
// Format header
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "matrix_keypad.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
|
+
#include "esphome/core/application.h"
|
3
4
|
|
4
5
|
namespace esphome {
|
5
6
|
namespace matrix_keypad {
|
@@ -28,7 +29,7 @@ void MatrixKeypad::setup() {
|
|
28
29
|
void MatrixKeypad::loop() {
|
29
30
|
static uint32_t active_start = 0;
|
30
31
|
static int active_key = -1;
|
31
|
-
uint32_t now =
|
32
|
+
uint32_t now = App.get_loop_component_start_time();
|
32
33
|
int key = -1;
|
33
34
|
bool error = false;
|
34
35
|
int pos = 0, row, col;
|
@@ -2,6 +2,7 @@
|
|
2
2
|
#include "esphome/core/log.h"
|
3
3
|
#include "esphome/core/helpers.h"
|
4
4
|
#include "esphome/core/hal.h"
|
5
|
+
#include "esphome/core/application.h"
|
5
6
|
#include "max7219font.h"
|
6
7
|
|
7
8
|
#include <algorithm>
|
@@ -63,7 +64,7 @@ void MAX7219Component::dump_config() {
|
|
63
64
|
}
|
64
65
|
|
65
66
|
void MAX7219Component::loop() {
|
66
|
-
const uint32_t now =
|
67
|
+
const uint32_t now = App.get_loop_component_start_time();
|
67
68
|
const uint32_t millis_since_last_scroll = now - this->last_scroll_;
|
68
69
|
const size_t first_line_size = this->max_displaybuffer_[0].size();
|
69
70
|
// check if the buffer has shrunk past the current position since last update
|
@@ -32,7 +32,7 @@ CONFIG_SCHEMA = (
|
|
32
32
|
cv.Schema(
|
33
33
|
{
|
34
34
|
cv.GenerateID(): cv.declare_id(MHZ19Component),
|
35
|
-
cv.
|
35
|
+
cv.Optional(CONF_CO2): sensor.sensor_schema(
|
36
36
|
unit_of_measurement=UNIT_PARTS_PER_MILLION,
|
37
37
|
icon=ICON_MOLECULE_CO2,
|
38
38
|
accuracy_decimals=0,
|
@@ -61,16 +61,20 @@ async def to_code(config):
|
|
61
61
|
await cg.register_component(var, config)
|
62
62
|
await uart.register_uart_device(var, config)
|
63
63
|
|
64
|
-
if
|
65
|
-
sens = await sensor.new_sensor(
|
64
|
+
if co2 := config.get(CONF_CO2):
|
65
|
+
sens = await sensor.new_sensor(co2)
|
66
66
|
cg.add(var.set_co2_sensor(sens))
|
67
67
|
|
68
|
-
if
|
69
|
-
sens = await sensor.new_sensor(
|
68
|
+
if temperature := config.get(CONF_TEMPERATURE):
|
69
|
+
sens = await sensor.new_sensor(temperature)
|
70
70
|
cg.add(var.set_temperature_sensor(sens))
|
71
71
|
|
72
|
-
if
|
73
|
-
|
72
|
+
if (
|
73
|
+
automatic_baseline_calibration := config.get(
|
74
|
+
CONF_AUTOMATIC_BASELINE_CALIBRATION
|
75
|
+
)
|
76
|
+
) is not None:
|
77
|
+
cg.add(var.set_abc_enabled(automatic_baseline_calibration))
|
74
78
|
|
75
79
|
cg.add(var.set_warmup_seconds(config[CONF_WARMUP_TIME]))
|
76
80
|
|
@@ -10,7 +10,7 @@ midea_ir_ns = cg.esphome_ns.namespace("midea_ir")
|
|
10
10
|
MideaIR = midea_ir_ns.class_("MideaIR", climate_ir.ClimateIR)
|
11
11
|
|
12
12
|
|
13
|
-
CONFIG_SCHEMA = climate_ir.
|
13
|
+
CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(MideaIR).extend(
|
14
14
|
{
|
15
15
|
cv.Optional(CONF_USE_FAHRENHEIT, default=False): cv.boolean,
|
16
16
|
}
|
@@ -43,7 +43,7 @@ VERTICAL_DIRECTIONS = {
|
|
43
43
|
}
|
44
44
|
|
45
45
|
|
46
|
-
CONFIG_SCHEMA = climate_ir.
|
46
|
+
CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(MitsubishiClimate).extend(
|
47
47
|
{
|
48
48
|
cv.Optional(CONF_SET_FAN_MODE, default="3levels"): cv.enum(SETFANMODE),
|
49
49
|
cv.Optional(CONF_SUPPORTS_DRY, default=False): cv.boolean,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#include "modbus.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
3
|
#include "esphome/core/helpers.h"
|
4
|
+
#include "esphome/core/application.h"
|
4
5
|
|
5
6
|
namespace esphome {
|
6
7
|
namespace modbus {
|
@@ -13,7 +14,7 @@ void Modbus::setup() {
|
|
13
14
|
}
|
14
15
|
}
|
15
16
|
void Modbus::loop() {
|
16
|
-
const uint32_t now =
|
17
|
+
const uint32_t now = App.get_loop_component_start_time();
|
17
18
|
|
18
19
|
while (this->available()) {
|
19
20
|
uint8_t byte;
|
@@ -24,13 +24,13 @@ CONFIG_SCHEMA = (
|
|
24
24
|
cv.Schema(
|
25
25
|
{
|
26
26
|
cv.GenerateID(): cv.declare_id(MS5611Component),
|
27
|
-
cv.
|
27
|
+
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
28
28
|
unit_of_measurement=UNIT_CELSIUS,
|
29
29
|
accuracy_decimals=1,
|
30
30
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
31
31
|
state_class=STATE_CLASS_MEASUREMENT,
|
32
32
|
),
|
33
|
-
cv.
|
33
|
+
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
34
34
|
unit_of_measurement=UNIT_HECTOPASCAL,
|
35
35
|
icon=ICON_GAUGE,
|
36
36
|
accuracy_decimals=1,
|
@@ -49,10 +49,10 @@ async def to_code(config):
|
|
49
49
|
await cg.register_component(var, config)
|
50
50
|
await i2c.register_i2c_device(var, config)
|
51
51
|
|
52
|
-
if
|
53
|
-
sens = await sensor.new_sensor(
|
52
|
+
if temperature := config.get(CONF_TEMPERATURE):
|
53
|
+
sens = await sensor.new_sensor(temperature)
|
54
54
|
cg.add(var.set_temperature_sensor(sens))
|
55
55
|
|
56
|
-
if
|
57
|
-
sens = await sensor.new_sensor(
|
56
|
+
if pressure := config.get(CONF_PRESSURE):
|
57
|
+
sens = await sensor.new_sensor(pressure)
|
58
58
|
cg.add(var.set_pressure_sensor(sens))
|
@@ -29,19 +29,19 @@ CONFIG_SCHEMA = (
|
|
29
29
|
cv.Schema(
|
30
30
|
{
|
31
31
|
cv.GenerateID(): cv.declare_id(MS8607Component),
|
32
|
-
cv.
|
32
|
+
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
33
33
|
unit_of_measurement=UNIT_CELSIUS,
|
34
34
|
accuracy_decimals=2, # Resolution: 0.01
|
35
35
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
36
36
|
state_class=STATE_CLASS_MEASUREMENT,
|
37
37
|
),
|
38
|
-
cv.
|
38
|
+
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
39
39
|
unit_of_measurement=UNIT_HECTOPASCAL,
|
40
40
|
accuracy_decimals=2, # Resolution: 0.016
|
41
41
|
device_class=DEVICE_CLASS_PRESSURE,
|
42
42
|
state_class=STATE_CLASS_MEASUREMENT,
|
43
43
|
),
|
44
|
-
cv.
|
44
|
+
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
45
45
|
unit_of_measurement=UNIT_PERCENT,
|
46
46
|
accuracy_decimals=2, # Resolution: 0.04
|
47
47
|
device_class=DEVICE_CLASS_HUMIDITY,
|
@@ -6,7 +6,7 @@ AUTO_LOAD = ["climate_ir"]
|
|
6
6
|
noblex_ns = cg.esphome_ns.namespace("noblex")
|
7
7
|
NoblexClimate = noblex_ns.class_("NoblexClimate", climate_ir.ClimateIR)
|
8
8
|
|
9
|
-
CONFIG_SCHEMA = climate_ir.
|
9
|
+
CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(NoblexClimate)
|
10
10
|
|
11
11
|
|
12
12
|
async def to_code(config):
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "pmsx003.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
|
+
#include "esphome/core/application.h"
|
3
4
|
|
4
5
|
namespace esphome {
|
5
6
|
namespace pmsx003 {
|
@@ -42,7 +43,7 @@ void PMSX003Component::dump_config() {
|
|
42
43
|
}
|
43
44
|
|
44
45
|
void PMSX003Component::loop() {
|
45
|
-
const uint32_t now =
|
46
|
+
const uint32_t now = App.get_loop_component_start_time();
|
46
47
|
|
47
48
|
// If we update less often than it takes the device to stabilise, spin the fan down
|
48
49
|
// rather than running it constantly. It does take some time to stabilise, so we
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "pzem004t.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
|
+
#include "esphome/core/application.h"
|
3
4
|
#include <cinttypes>
|
4
5
|
|
5
6
|
namespace esphome {
|
@@ -16,7 +17,7 @@ void PZEM004T::setup() {
|
|
16
17
|
}
|
17
18
|
|
18
19
|
void PZEM004T::loop() {
|
19
|
-
const uint32_t now =
|
20
|
+
const uint32_t now = App.get_loop_component_start_time();
|
20
21
|
if (now - this->last_read_ > 500 && this->available() < 7) {
|
21
22
|
while (this->available())
|
22
23
|
this->read();
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "rf_bridge.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
|
+
#include "esphome/core/application.h"
|
3
4
|
#include <cinttypes>
|
4
5
|
#include <cstring>
|
5
6
|
|
@@ -128,7 +129,7 @@ void RFBridgeComponent::write_byte_str_(const std::string &codes) {
|
|
128
129
|
}
|
129
130
|
|
130
131
|
void RFBridgeComponent::loop() {
|
131
|
-
const uint32_t now =
|
132
|
+
const uint32_t now = App.get_loop_component_start_time();
|
132
133
|
if (now - this->last_bridge_byte_ > 50) {
|
133
134
|
this->rx_buffer_.clear();
|
134
135
|
this->last_bridge_byte_ = now;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "sds011.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
|
+
#include "esphome/core/application.h"
|
3
4
|
|
4
5
|
namespace esphome {
|
5
6
|
namespace sds011 {
|
@@ -75,7 +76,7 @@ void SDS011Component::dump_config() {
|
|
75
76
|
}
|
76
77
|
|
77
78
|
void SDS011Component::loop() {
|
78
|
-
const uint32_t now =
|
79
|
+
const uint32_t now = App.get_loop_component_start_time();
|
79
80
|
if ((now - this->last_transmission_ >= 500) && this->data_index_) {
|
80
81
|
// last transmission too long ago. Reset RX index.
|
81
82
|
ESP_LOGV(TAG, "Last transmission too long ago. Reset RX index.");
|
@@ -25,6 +25,10 @@ static const uint16_t SEN5X_CMD_TEMPERATURE_COMPENSATION = 0x60B2;
|
|
25
25
|
static const uint16_t SEN5X_CMD_VOC_ALGORITHM_STATE = 0x6181;
|
26
26
|
static const uint16_t SEN5X_CMD_VOC_ALGORITHM_TUNING = 0x60D0;
|
27
27
|
|
28
|
+
static const int8_t SEN5X_INDEX_SCALE_FACTOR = 10; // used for VOC and NOx index values
|
29
|
+
static const int8_t SEN5X_MIN_INDEX_VALUE = 1 * SEN5X_INDEX_SCALE_FACTOR; // must be adjusted by the scale factor
|
30
|
+
static const int16_t SEN5X_MAX_INDEX_VALUE = 500 * SEN5X_INDEX_SCALE_FACTOR; // must be adjusted by the scale factor
|
31
|
+
|
28
32
|
void SEN5XComponent::setup() {
|
29
33
|
ESP_LOGCONFIG(TAG, "Setting up sen5x...");
|
30
34
|
|
@@ -88,8 +92,9 @@ void SEN5XComponent::setup() {
|
|
88
92
|
product_name_.push_back(current_char);
|
89
93
|
// second char
|
90
94
|
current_char = *current_int & 0xFF;
|
91
|
-
if (current_char)
|
95
|
+
if (current_char) {
|
92
96
|
product_name_.push_back(current_char);
|
97
|
+
}
|
93
98
|
}
|
94
99
|
current_int++;
|
95
100
|
} while (current_char && --max);
|
@@ -271,10 +276,10 @@ void SEN5XComponent::dump_config() {
|
|
271
276
|
ESP_LOGCONFIG(TAG, " Low RH/T acceleration mode");
|
272
277
|
break;
|
273
278
|
case MEDIUM_ACCELERATION:
|
274
|
-
ESP_LOGCONFIG(TAG, " Medium RH/T
|
279
|
+
ESP_LOGCONFIG(TAG, " Medium RH/T acceleration mode");
|
275
280
|
break;
|
276
281
|
case HIGH_ACCELERATION:
|
277
|
-
ESP_LOGCONFIG(TAG, " High RH/T
|
282
|
+
ESP_LOGCONFIG(TAG, " High RH/T acceleration mode");
|
278
283
|
break;
|
279
284
|
}
|
280
285
|
}
|
@@ -337,47 +342,61 @@ void SEN5XComponent::update() {
|
|
337
342
|
ESP_LOGD(TAG, "read data error (%d)", this->last_error_);
|
338
343
|
return;
|
339
344
|
}
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
float
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
345
|
+
|
346
|
+
ESP_LOGVV(TAG, "pm_1_0 = 0x%.4x", measurements[0]);
|
347
|
+
float pm_1_0 = measurements[0] == UINT16_MAX ? NAN : measurements[0] / 10.0f;
|
348
|
+
|
349
|
+
ESP_LOGVV(TAG, "pm_2_5 = 0x%.4x", measurements[1]);
|
350
|
+
float pm_2_5 = measurements[1] == UINT16_MAX ? NAN : measurements[1] / 10.0f;
|
351
|
+
|
352
|
+
ESP_LOGVV(TAG, "pm_4_0 = 0x%.4x", measurements[2]);
|
353
|
+
float pm_4_0 = measurements[2] == UINT16_MAX ? NAN : measurements[2] / 10.0f;
|
354
|
+
|
355
|
+
ESP_LOGVV(TAG, "pm_10_0 = 0x%.4x", measurements[3]);
|
356
|
+
float pm_10_0 = measurements[3] == UINT16_MAX ? NAN : measurements[3] / 10.0f;
|
357
|
+
|
358
|
+
ESP_LOGVV(TAG, "humidity = 0x%.4x", measurements[4]);
|
359
|
+
float humidity = measurements[4] == INT16_MAX ? NAN : static_cast<int16_t>(measurements[4]) / 100.0f;
|
360
|
+
|
361
|
+
ESP_LOGVV(TAG, "temperature = 0x%.4x", measurements[5]);
|
362
|
+
float temperature = measurements[5] == INT16_MAX ? NAN : static_cast<int16_t>(measurements[5]) / 200.0f;
|
363
|
+
|
364
|
+
ESP_LOGVV(TAG, "voc = 0x%.4x", measurements[6]);
|
365
|
+
int16_t voc_idx = static_cast<int16_t>(measurements[6]);
|
366
|
+
float voc = (voc_idx < SEN5X_MIN_INDEX_VALUE || voc_idx > SEN5X_MAX_INDEX_VALUE)
|
367
|
+
? NAN
|
368
|
+
: static_cast<float>(voc_idx) / 10.0f;
|
369
|
+
|
370
|
+
ESP_LOGVV(TAG, "nox = 0x%.4x", measurements[7]);
|
371
|
+
int16_t nox_idx = static_cast<int16_t>(measurements[7]);
|
372
|
+
float nox = (nox_idx < SEN5X_MIN_INDEX_VALUE || nox_idx > SEN5X_MAX_INDEX_VALUE)
|
373
|
+
? NAN
|
374
|
+
: static_cast<float>(nox_idx) / 10.0f;
|
375
|
+
|
376
|
+
if (this->pm_1_0_sensor_ != nullptr) {
|
366
377
|
this->pm_1_0_sensor_->publish_state(pm_1_0);
|
367
|
-
|
378
|
+
}
|
379
|
+
if (this->pm_2_5_sensor_ != nullptr) {
|
368
380
|
this->pm_2_5_sensor_->publish_state(pm_2_5);
|
369
|
-
|
381
|
+
}
|
382
|
+
if (this->pm_4_0_sensor_ != nullptr) {
|
370
383
|
this->pm_4_0_sensor_->publish_state(pm_4_0);
|
371
|
-
|
384
|
+
}
|
385
|
+
if (this->pm_10_0_sensor_ != nullptr) {
|
372
386
|
this->pm_10_0_sensor_->publish_state(pm_10_0);
|
373
|
-
|
387
|
+
}
|
388
|
+
if (this->temperature_sensor_ != nullptr) {
|
374
389
|
this->temperature_sensor_->publish_state(temperature);
|
375
|
-
|
390
|
+
}
|
391
|
+
if (this->humidity_sensor_ != nullptr) {
|
376
392
|
this->humidity_sensor_->publish_state(humidity);
|
377
|
-
|
393
|
+
}
|
394
|
+
if (this->voc_sensor_ != nullptr) {
|
378
395
|
this->voc_sensor_->publish_state(voc);
|
379
|
-
|
396
|
+
}
|
397
|
+
if (this->nox_sensor_ != nullptr) {
|
380
398
|
this->nox_sensor_->publish_state(nox);
|
399
|
+
}
|
381
400
|
this->status_clear_warning();
|
382
401
|
});
|
383
402
|
}
|
@@ -38,7 +38,7 @@ CONFIG_SCHEMA = (
|
|
38
38
|
cv.Schema(
|
39
39
|
{
|
40
40
|
cv.GenerateID(): cv.declare_id(SenseAirComponent),
|
41
|
-
cv.
|
41
|
+
cv.Optional(CONF_CO2): sensor.sensor_schema(
|
42
42
|
unit_of_measurement=UNIT_PARTS_PER_MILLION,
|
43
43
|
icon=ICON_MOLECULE_CO2,
|
44
44
|
accuracy_decimals=0,
|
@@ -57,8 +57,8 @@ async def to_code(config):
|
|
57
57
|
await cg.register_component(var, config)
|
58
58
|
await uart.register_uart_device(var, config)
|
59
59
|
|
60
|
-
if
|
61
|
-
sens = await sensor.new_sensor(
|
60
|
+
if co2 := config.get(CONF_CO2):
|
61
|
+
sens = await sensor.new_sensor(co2)
|
62
62
|
cg.add(var.set_co2_sensor(sens))
|
63
63
|
|
64
64
|
|
@@ -37,14 +37,14 @@ CONFIG_SCHEMA = (
|
|
37
37
|
cv.Schema(
|
38
38
|
{
|
39
39
|
cv.GenerateID(): cv.declare_id(SGP30Component),
|
40
|
-
cv.
|
40
|
+
cv.Optional(CONF_ECO2): sensor.sensor_schema(
|
41
41
|
unit_of_measurement=UNIT_PARTS_PER_MILLION,
|
42
42
|
icon=ICON_MOLECULE_CO2,
|
43
43
|
accuracy_decimals=0,
|
44
44
|
device_class=DEVICE_CLASS_CARBON_DIOXIDE,
|
45
45
|
state_class=STATE_CLASS_MEASUREMENT,
|
46
46
|
),
|
47
|
-
cv.
|
47
|
+
cv.Optional(CONF_TVOC): sensor.sensor_schema(
|
48
48
|
unit_of_measurement=UNIT_PARTS_PER_BILLION,
|
49
49
|
icon=ICON_RADIATOR,
|
50
50
|
accuracy_decimals=0,
|
@@ -86,32 +86,30 @@ async def to_code(config):
|
|
86
86
|
await cg.register_component(var, config)
|
87
87
|
await i2c.register_i2c_device(var, config)
|
88
88
|
|
89
|
-
if
|
90
|
-
sens = await sensor.new_sensor(
|
89
|
+
if eco2_config := config.get(CONF_ECO2):
|
90
|
+
sens = await sensor.new_sensor(eco2_config)
|
91
91
|
cg.add(var.set_eco2_sensor(sens))
|
92
92
|
|
93
|
-
if
|
94
|
-
sens = await sensor.new_sensor(
|
93
|
+
if tvoc_config := config.get(CONF_TVOC):
|
94
|
+
sens = await sensor.new_sensor(tvoc_config)
|
95
95
|
cg.add(var.set_tvoc_sensor(sens))
|
96
96
|
|
97
|
-
if
|
98
|
-
sens = await sensor.new_sensor(
|
97
|
+
if eco2_baseline_config := config.get(CONF_ECO2_BASELINE):
|
98
|
+
sens = await sensor.new_sensor(eco2_baseline_config)
|
99
99
|
cg.add(var.set_eco2_baseline_sensor(sens))
|
100
100
|
|
101
|
-
if
|
102
|
-
sens = await sensor.new_sensor(
|
101
|
+
if tvoc_baseline_config := config.get(CONF_TVOC_BASELINE):
|
102
|
+
sens = await sensor.new_sensor(tvoc_baseline_config)
|
103
103
|
cg.add(var.set_tvoc_baseline_sensor(sens))
|
104
104
|
|
105
|
-
if CONF_STORE_BASELINE
|
106
|
-
cg.add(var.set_store_baseline(
|
105
|
+
if (store_baseline := config.get(CONF_STORE_BASELINE)) is not None:
|
106
|
+
cg.add(var.set_store_baseline(store_baseline))
|
107
107
|
|
108
|
-
if
|
109
|
-
baseline_config = config[CONF_BASELINE]
|
108
|
+
if baseline_config := config.get(CONF_BASELINE):
|
110
109
|
cg.add(var.set_eco2_baseline(baseline_config[CONF_ECO2_BASELINE]))
|
111
110
|
cg.add(var.set_tvoc_baseline(baseline_config[CONF_TVOC_BASELINE]))
|
112
111
|
|
113
|
-
if
|
114
|
-
compensation_config = config[CONF_COMPENSATION]
|
112
|
+
if compensation_config := config.get(CONF_COMPENSATION):
|
115
113
|
sens = await cg.get_variable(compensation_config[CONF_HUMIDITY_SOURCE])
|
116
114
|
cg.add(var.set_humidity_sensor(sens))
|
117
115
|
sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE_SOURCE])
|
@@ -26,13 +26,13 @@ CONFIG_SCHEMA = (
|
|
26
26
|
cv.Schema(
|
27
27
|
{
|
28
28
|
cv.GenerateID(): cv.declare_id(SHTCXComponent),
|
29
|
-
cv.
|
29
|
+
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
30
30
|
unit_of_measurement=UNIT_CELSIUS,
|
31
31
|
accuracy_decimals=1,
|
32
32
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
33
33
|
state_class=STATE_CLASS_MEASUREMENT,
|
34
34
|
),
|
35
|
-
cv.
|
35
|
+
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
|
36
36
|
unit_of_measurement=UNIT_PERCENT,
|
37
37
|
accuracy_decimals=1,
|
38
38
|
device_class=DEVICE_CLASS_HUMIDITY,
|
@@ -50,10 +50,10 @@ async def to_code(config):
|
|
50
50
|
await cg.register_component(var, config)
|
51
51
|
await i2c.register_i2c_device(var, config)
|
52
52
|
|
53
|
-
if
|
54
|
-
sens = await sensor.new_sensor(
|
53
|
+
if temperature := config.get(CONF_TEMPERATURE):
|
54
|
+
sens = await sensor.new_sensor(temperature)
|
55
55
|
cg.add(var.set_temperature_sensor(sens))
|
56
56
|
|
57
|
-
if
|
58
|
-
sens = await sensor.new_sensor(
|
57
|
+
if humidity := config.get(CONF_HUMIDITY):
|
58
|
+
sens = await sensor.new_sensor(humidity)
|
59
59
|
cg.add(var.set_humidity_sensor(sens))
|
@@ -1,5 +1,6 @@
|
|
1
1
|
#include "slow_pwm_output.h"
|
2
2
|
#include "esphome/core/log.h"
|
3
|
+
#include "esphome/core/application.h"
|
3
4
|
|
4
5
|
namespace esphome {
|
5
6
|
namespace slow_pwm {
|
@@ -39,7 +40,7 @@ void SlowPWMOutput::set_output_state_(bool new_state) {
|
|
39
40
|
}
|
40
41
|
|
41
42
|
void SlowPWMOutput::loop() {
|
42
|
-
uint32_t now =
|
43
|
+
uint32_t now = App.get_loop_component_start_time();
|
43
44
|
float scaled_state = this->state_ * this->period_;
|
44
45
|
|
45
46
|
if (now - this->period_start_time_ >= this->period_) {
|
@@ -20,7 +20,7 @@ SprinklerSwitch::SprinklerSwitch(switch_::Switch *off_switch, switch_::Switch *o
|
|
20
20
|
bool SprinklerSwitch::is_latching_valve() { return (this->off_switch_ != nullptr) && (this->on_switch_ != nullptr); }
|
21
21
|
|
22
22
|
void SprinklerSwitch::loop() {
|
23
|
-
if ((this->pinned_millis_) && (
|
23
|
+
if ((this->pinned_millis_) && (App.get_loop_component_start_time() > this->pinned_millis_ + this->pulse_duration_)) {
|
24
24
|
this->pinned_millis_ = 0; // reset tracker
|
25
25
|
if (this->off_switch_->state) {
|
26
26
|
this->off_switch_->turn_off();
|
@@ -148,22 +148,23 @@ SprinklerValveOperator::SprinklerValveOperator(SprinklerValve *valve, Sprinkler
|
|
148
148
|
: controller_(controller), valve_(valve) {}
|
149
149
|
|
150
150
|
void SprinklerValveOperator::loop() {
|
151
|
-
|
151
|
+
uint32_t now = App.get_loop_component_start_time();
|
152
|
+
if (now >= this->start_millis_) { // dummy check
|
152
153
|
switch (this->state_) {
|
153
154
|
case STARTING:
|
154
|
-
if (
|
155
|
+
if (now > (this->start_millis_ + this->start_delay_)) {
|
155
156
|
this->run_(); // start_delay_ has been exceeded, so ensure both valves are on and update the state
|
156
157
|
}
|
157
158
|
break;
|
158
159
|
|
159
160
|
case ACTIVE:
|
160
|
-
if (
|
161
|
+
if (now > (this->start_millis_ + this->start_delay_ + this->run_duration_)) {
|
161
162
|
this->stop(); // start_delay_ + run_duration_ has been exceeded, start shutting down
|
162
163
|
}
|
163
164
|
break;
|
164
165
|
|
165
166
|
case STOPPING:
|
166
|
-
if (
|
167
|
+
if (now > (this->stop_millis_ + this->stop_delay_)) {
|
167
168
|
this->kill_(); // stop_delay_has been exceeded, ensure all valves are off
|
168
169
|
}
|
169
170
|
break;
|