esphome 2025.7.0b2__py3-none-any.whl → 2025.7.0b4__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/components/async_tcp/__init__.py +1 -1
- esphome/components/esp_ldo/__init__.py +10 -8
- esphome/components/esp_ldo/esp_ldo.h +3 -0
- esphome/components/fan/fan.cpp +4 -0
- esphome/components/gpio/binary_sensor/__init__.py +24 -3
- esphome/components/http_request/update/http_request_update.cpp +7 -7
- esphome/components/i2s_audio/speaker/__init__.py +1 -1
- esphome/components/json/__init__.py +1 -1
- esphome/components/json/json_util.cpp +56 -63
- esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
- esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
- esphome/components/ld2420/ld2420.cpp +66 -57
- esphome/components/ld2420/ld2420.h +9 -11
- esphome/components/ld2420/number/gate_config_number.cpp +1 -1
- esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
- esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
- esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
- esphome/components/light/light_json_schema.cpp +17 -16
- esphome/components/lvgl/widgets/meter.py +20 -13
- esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -1
- esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
- esphome/components/mqtt/mqtt_button.cpp +4 -1
- esphome/components/mqtt/mqtt_client.cpp +2 -0
- esphome/components/mqtt/mqtt_climate.cpp +6 -4
- esphome/components/mqtt/mqtt_component.cpp +3 -1
- esphome/components/mqtt/mqtt_cover.cpp +1 -0
- esphome/components/mqtt/mqtt_date.cpp +4 -3
- esphome/components/mqtt/mqtt_datetime.cpp +7 -6
- esphome/components/mqtt/mqtt_event.cpp +6 -3
- esphome/components/mqtt/mqtt_fan.cpp +1 -0
- esphome/components/mqtt/mqtt_light.cpp +8 -4
- esphome/components/mqtt/mqtt_lock.cpp +3 -1
- esphome/components/mqtt/mqtt_number.cpp +1 -0
- esphome/components/mqtt/mqtt_select.cpp +2 -1
- esphome/components/mqtt/mqtt_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_switch.cpp +3 -1
- esphome/components/mqtt/mqtt_text.cpp +1 -0
- esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_time.cpp +4 -3
- esphome/components/mqtt/mqtt_update.cpp +1 -0
- esphome/components/mqtt/mqtt_valve.cpp +3 -1
- esphome/components/ms8607/ms8607.cpp +1 -1
- esphome/components/online_image/__init__.py +4 -1
- esphome/components/online_image/online_image.cpp +11 -5
- esphome/components/online_image/online_image.h +6 -1
- esphome/components/opentherm/output/output.cpp +1 -1
- esphome/components/servo/servo.cpp +2 -2
- esphome/components/substitutions/__init__.py +5 -2
- esphome/components/web_server/web_server.cpp +13 -9
- esphome/components/web_server_base/__init__.py +1 -1
- esphome/components/web_server_idf/web_server_idf.cpp +2 -0
- esphome/const.py +1 -1
- esphome/core/component.cpp +9 -8
- esphome/core/helpers.h +1 -1
- esphome/platformio_api.py +2 -0
- esphome/writer.py +23 -0
- {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/METADATA +1 -1
- {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/RECORD +62 -62
- {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/WHEEL +0 -0
- {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/entry_points.txt +0 -0
- {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.7.0b2.dist-info → esphome-2025.7.0b4.dist-info}/top_level.txt +0 -0
|
@@ -31,7 +31,7 @@ CONFIG_SCHEMA = cv.All(
|
|
|
31
31
|
async def to_code(config):
|
|
32
32
|
if CORE.is_esp32 or CORE.is_libretiny:
|
|
33
33
|
# https://github.com/ESP32Async/AsyncTCP
|
|
34
|
-
cg.add_library("ESP32Async/AsyncTCP", "3.4.
|
|
34
|
+
cg.add_library("ESP32Async/AsyncTCP", "3.4.5")
|
|
35
35
|
elif CORE.is_esp8266:
|
|
36
36
|
# https://github.com/ESP32Async/ESPAsyncTCP
|
|
37
37
|
cg.add_library("ESP32Async/ESPAsyncTCP", "2.0.0")
|
|
@@ -20,14 +20,16 @@ adjusted_ids = set()
|
|
|
20
20
|
|
|
21
21
|
CONFIG_SCHEMA = cv.All(
|
|
22
22
|
cv.ensure_list(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
cv.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
cv.COMPONENT_SCHEMA.extend(
|
|
24
|
+
{
|
|
25
|
+
cv.GenerateID(): cv.declare_id(EspLdo),
|
|
26
|
+
cv.Required(CONF_VOLTAGE): cv.All(
|
|
27
|
+
cv.voltage, cv.float_range(min=0.5, max=2.7)
|
|
28
|
+
),
|
|
29
|
+
cv.Required(CONF_CHANNEL): cv.one_of(*CHANNELS, int=True),
|
|
30
|
+
cv.Optional(CONF_ADJUSTABLE, default=False): cv.boolean,
|
|
31
|
+
}
|
|
32
|
+
)
|
|
31
33
|
),
|
|
32
34
|
cv.only_with_esp_idf,
|
|
33
35
|
only_on_variant(supported=[VARIANT_ESP32P4]),
|
|
@@ -17,6 +17,9 @@ class EspLdo : public Component {
|
|
|
17
17
|
void set_adjustable(bool adjustable) { this->adjustable_ = adjustable; }
|
|
18
18
|
void set_voltage(float voltage) { this->voltage_ = voltage; }
|
|
19
19
|
void adjust_voltage(float voltage);
|
|
20
|
+
float get_setup_priority() const override {
|
|
21
|
+
return setup_priority::BUS; // LDO setup should be done early
|
|
22
|
+
}
|
|
20
23
|
|
|
21
24
|
protected:
|
|
22
25
|
int channel_;
|
esphome/components/fan/fan.cpp
CHANGED
|
@@ -177,6 +177,10 @@ optional<FanRestoreState> Fan::restore_state_() {
|
|
|
177
177
|
return {};
|
|
178
178
|
}
|
|
179
179
|
void Fan::save_state_() {
|
|
180
|
+
if (this->restore_mode_ == FanRestoreMode::NO_RESTORE) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
180
184
|
FanRestoreState state{};
|
|
181
185
|
state.state = this->state;
|
|
182
186
|
state.oscillating = this->oscillating;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
1
3
|
from esphome import pins
|
|
2
4
|
import esphome.codegen as cg
|
|
3
5
|
from esphome.components import binary_sensor
|
|
4
6
|
import esphome.config_validation as cv
|
|
5
|
-
from esphome.const import CONF_PIN
|
|
7
|
+
from esphome.const import CONF_ID, CONF_NAME, CONF_NUMBER, CONF_PIN
|
|
8
|
+
from esphome.core import CORE
|
|
6
9
|
|
|
7
10
|
from .. import gpio_ns
|
|
8
11
|
|
|
12
|
+
_LOGGER = logging.getLogger(__name__)
|
|
13
|
+
|
|
9
14
|
GPIOBinarySensor = gpio_ns.class_(
|
|
10
15
|
"GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component
|
|
11
16
|
)
|
|
@@ -41,6 +46,22 @@ async def to_code(config):
|
|
|
41
46
|
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
|
42
47
|
cg.add(var.set_pin(pin))
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
# Check for ESP8266 GPIO16 interrupt limitation
|
|
50
|
+
# GPIO16 on ESP8266 is a special pin that doesn't support interrupts through
|
|
51
|
+
# the Arduino attachInterrupt() function. This is the only known GPIO pin
|
|
52
|
+
# across all supported platforms that has this limitation, so we handle it
|
|
53
|
+
# here instead of in the platform-specific code.
|
|
54
|
+
use_interrupt = config[CONF_USE_INTERRUPT]
|
|
55
|
+
if use_interrupt and CORE.is_esp8266 and config[CONF_PIN][CONF_NUMBER] == 16:
|
|
56
|
+
_LOGGER.warning(
|
|
57
|
+
"GPIO binary_sensor '%s': GPIO16 on ESP8266 doesn't support interrupts. "
|
|
58
|
+
"Falling back to polling mode (same as in ESPHome <2025.7). "
|
|
59
|
+
"The sensor will work exactly as before, but other pins have better "
|
|
60
|
+
"performance with interrupts.",
|
|
61
|
+
config.get(CONF_NAME, config[CONF_ID]),
|
|
62
|
+
)
|
|
63
|
+
use_interrupt = False
|
|
64
|
+
|
|
65
|
+
cg.add(var.set_use_interrupt(use_interrupt))
|
|
66
|
+
if use_interrupt:
|
|
46
67
|
cg.add(var.set_interrupt_type(config[CONF_INTERRUPT_TYPE]))
|
|
@@ -83,7 +83,7 @@ void HttpRequestUpdate::update_task(void *params) {
|
|
|
83
83
|
container.reset(); // Release ownership of the container's shared_ptr
|
|
84
84
|
|
|
85
85
|
valid = json::parse_json(response, [this_update](JsonObject root) -> bool {
|
|
86
|
-
if (!root
|
|
86
|
+
if (!root["name"].is<const char *>() || !root["version"].is<const char *>() || !root["builds"].is<JsonArray>()) {
|
|
87
87
|
ESP_LOGE(TAG, "Manifest does not contain required fields");
|
|
88
88
|
return false;
|
|
89
89
|
}
|
|
@@ -91,26 +91,26 @@ void HttpRequestUpdate::update_task(void *params) {
|
|
|
91
91
|
this_update->update_info_.latest_version = root["version"].as<std::string>();
|
|
92
92
|
|
|
93
93
|
for (auto build : root["builds"].as<JsonArray>()) {
|
|
94
|
-
if (!build
|
|
94
|
+
if (!build["chipFamily"].is<const char *>()) {
|
|
95
95
|
ESP_LOGE(TAG, "Manifest does not contain required fields");
|
|
96
96
|
return false;
|
|
97
97
|
}
|
|
98
98
|
if (build["chipFamily"] == ESPHOME_VARIANT) {
|
|
99
|
-
if (!build
|
|
99
|
+
if (!build["ota"].is<JsonObject>()) {
|
|
100
100
|
ESP_LOGE(TAG, "Manifest does not contain required fields");
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
|
-
|
|
104
|
-
if (!ota
|
|
103
|
+
JsonObject ota = build["ota"].as<JsonObject>();
|
|
104
|
+
if (!ota["path"].is<const char *>() || !ota["md5"].is<const char *>()) {
|
|
105
105
|
ESP_LOGE(TAG, "Manifest does not contain required fields");
|
|
106
106
|
return false;
|
|
107
107
|
}
|
|
108
108
|
this_update->update_info_.firmware_url = ota["path"].as<std::string>();
|
|
109
109
|
this_update->update_info_.md5 = ota["md5"].as<std::string>();
|
|
110
110
|
|
|
111
|
-
if (ota
|
|
111
|
+
if (ota["summary"].is<const char *>())
|
|
112
112
|
this_update->update_info_.summary = ota["summary"].as<std::string>();
|
|
113
|
-
if (ota
|
|
113
|
+
if (ota["release_url"].is<const char *>())
|
|
114
114
|
this_update->update_info_.release_url = ota["release_url"].as<std::string>();
|
|
115
115
|
|
|
116
116
|
return true;
|
|
@@ -180,7 +180,7 @@ async def to_code(config):
|
|
|
180
180
|
await speaker.register_speaker(var, config)
|
|
181
181
|
|
|
182
182
|
if config[CONF_DAC_TYPE] == "internal":
|
|
183
|
-
cg.add(var.set_internal_dac_mode(config[
|
|
183
|
+
cg.add(var.set_internal_dac_mode(config[CONF_MODE]))
|
|
184
184
|
else:
|
|
185
185
|
cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN]))
|
|
186
186
|
if use_legacy():
|
|
@@ -1,83 +1,76 @@
|
|
|
1
1
|
#include "json_util.h"
|
|
2
2
|
#include "esphome/core/log.h"
|
|
3
3
|
|
|
4
|
+
// ArduinoJson::Allocator is included via ArduinoJson.h in json_util.h
|
|
5
|
+
|
|
4
6
|
namespace esphome {
|
|
5
7
|
namespace json {
|
|
6
8
|
|
|
7
9
|
static const char *const TAG = "json";
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
// Build an allocator for the JSON Library using the RAMAllocator class
|
|
12
|
+
struct SpiRamAllocator : ArduinoJson::Allocator {
|
|
13
|
+
void *allocate(size_t size) override { return this->allocator_.allocate(size); }
|
|
14
|
+
|
|
15
|
+
void deallocate(void *pointer) override {
|
|
16
|
+
// ArduinoJson's Allocator interface doesn't provide the size parameter in deallocate.
|
|
17
|
+
// RAMAllocator::deallocate() requires the size, which we don't have access to here.
|
|
18
|
+
// RAMAllocator::deallocate implementation just calls free() regardless of whether
|
|
19
|
+
// the memory was allocated with heap_caps_malloc or malloc.
|
|
20
|
+
// This is safe because ESP-IDF's heap implementation internally tracks the memory region
|
|
21
|
+
// and routes free() to the appropriate heap.
|
|
22
|
+
free(pointer); // NOLINT(cppcoreguidelines-owning-memory,cppcoreguidelines-no-malloc)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void *reallocate(void *ptr, size_t new_size) override {
|
|
26
|
+
return this->allocator_.reallocate(static_cast<uint8_t *>(ptr), new_size);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected:
|
|
30
|
+
RAMAllocator<uint8_t> allocator_{RAMAllocator<uint8_t>(RAMAllocator<uint8_t>::NONE)};
|
|
31
|
+
};
|
|
11
32
|
|
|
12
33
|
std::string build_json(const json_build_t &f) {
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return "{}";
|
|
26
|
-
}
|
|
27
|
-
JsonObject root = json_document.to<JsonObject>();
|
|
28
|
-
f(root);
|
|
29
|
-
if (json_document.overflowed()) {
|
|
30
|
-
if (request_size == free_heap) {
|
|
31
|
-
ESP_LOGE(TAG, "Could not allocate memory for document! Overflowed largest free heap block: %zu bytes",
|
|
32
|
-
free_heap);
|
|
33
|
-
return "{}";
|
|
34
|
-
}
|
|
35
|
-
request_size = std::min(request_size * 2, free_heap);
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
json_document.shrinkToFit();
|
|
39
|
-
ESP_LOGV(TAG, "Size after shrink %zu bytes", json_document.capacity());
|
|
40
|
-
std::string output;
|
|
41
|
-
serializeJson(json_document, output);
|
|
42
|
-
return output;
|
|
34
|
+
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
35
|
+
auto doc_allocator = SpiRamAllocator();
|
|
36
|
+
JsonDocument json_document(&doc_allocator);
|
|
37
|
+
if (json_document.overflowed()) {
|
|
38
|
+
ESP_LOGE(TAG, "Could not allocate memory for JSON document!");
|
|
39
|
+
return "{}";
|
|
40
|
+
}
|
|
41
|
+
JsonObject root = json_document.to<JsonObject>();
|
|
42
|
+
f(root);
|
|
43
|
+
if (json_document.overflowed()) {
|
|
44
|
+
ESP_LOGE(TAG, "Could not allocate memory for JSON document!");
|
|
45
|
+
return "{}";
|
|
43
46
|
}
|
|
47
|
+
std::string output;
|
|
48
|
+
serializeJson(json_document, output);
|
|
49
|
+
return output;
|
|
50
|
+
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
bool parse_json(const std::string &data, const json_parse_t &f) {
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (json_document.capacity() == 0) {
|
|
56
|
-
ESP_LOGE(TAG, "Could not allocate memory for document! Requested %zu bytes, free heap: %zu", request_size,
|
|
57
|
-
free_heap);
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
DeserializationError err = deserializeJson(json_document, data);
|
|
61
|
-
json_document.shrinkToFit();
|
|
54
|
+
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
55
|
+
auto doc_allocator = SpiRamAllocator();
|
|
56
|
+
JsonDocument json_document(&doc_allocator);
|
|
57
|
+
if (json_document.overflowed()) {
|
|
58
|
+
ESP_LOGE(TAG, "Could not allocate memory for JSON document!");
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
DeserializationError err = deserializeJson(json_document, data);
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
JsonObject root = json_document.as<JsonObject>();
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
ESP_LOGV(TAG, "Increasing memory allocation.");
|
|
73
|
-
request_size *= 2;
|
|
74
|
-
continue;
|
|
75
|
-
} else {
|
|
76
|
-
ESP_LOGE(TAG, "Parse error: %s", err.c_str());
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
65
|
+
if (err == DeserializationError::Ok) {
|
|
66
|
+
return f(root);
|
|
67
|
+
} else if (err == DeserializationError::NoMemory) {
|
|
68
|
+
ESP_LOGE(TAG, "Can not allocate more memory for deserialization. Consider making source string smaller");
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
ESP_LOGE(TAG, "Parse error: %s", err.c_str());
|
|
80
72
|
return false;
|
|
73
|
+
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
|
|
81
74
|
}
|
|
82
75
|
|
|
83
76
|
} // namespace json
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
namespace esphome {
|
|
6
6
|
namespace ld2420 {
|
|
7
7
|
|
|
8
|
-
static const char *const TAG = "
|
|
8
|
+
static const char *const TAG = "ld2420.binary_sensor";
|
|
9
9
|
|
|
10
10
|
void LD2420BinarySensor::dump_config() {
|
|
11
|
-
ESP_LOGCONFIG(TAG, "
|
|
11
|
+
ESP_LOGCONFIG(TAG, "Binary Sensor:");
|
|
12
12
|
LOG_BINARY_SENSOR(" ", "Presence", this->presence_bsensor_);
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -137,7 +137,7 @@ static const std::string OP_SIMPLE_MODE_STRING = "Simple";
|
|
|
137
137
|
// Memory-efficient lookup tables
|
|
138
138
|
struct StringToUint8 {
|
|
139
139
|
const char *str;
|
|
140
|
-
uint8_t value;
|
|
140
|
+
const uint8_t value;
|
|
141
141
|
};
|
|
142
142
|
|
|
143
143
|
static constexpr StringToUint8 OP_MODE_BY_STR[] = {
|
|
@@ -155,8 +155,9 @@ static constexpr const char *ERR_MESSAGE[] = {
|
|
|
155
155
|
// Helper function for lookups
|
|
156
156
|
template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) {
|
|
157
157
|
for (const auto &entry : arr) {
|
|
158
|
-
if (str == entry.str)
|
|
158
|
+
if (str == entry.str) {
|
|
159
159
|
return entry.value;
|
|
160
|
+
}
|
|
160
161
|
}
|
|
161
162
|
return 0xFF; // Not found
|
|
162
163
|
}
|
|
@@ -326,15 +327,8 @@ void LD2420Component::revert_config_action() {
|
|
|
326
327
|
|
|
327
328
|
void LD2420Component::loop() {
|
|
328
329
|
// If there is a active send command do not process it here, the send command call will handle it.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
return;
|
|
332
|
-
static uint8_t buffer[2048];
|
|
333
|
-
static uint8_t rx_data;
|
|
334
|
-
while (this->available()) {
|
|
335
|
-
rx_data = this->read();
|
|
336
|
-
this->readline_(rx_data, buffer, sizeof(buffer));
|
|
337
|
-
}
|
|
330
|
+
while (!this->cmd_active_ && this->available()) {
|
|
331
|
+
this->readline_(this->read(), this->buffer_data_, MAX_LINE_LENGTH);
|
|
338
332
|
}
|
|
339
333
|
}
|
|
340
334
|
|
|
@@ -365,8 +359,9 @@ void LD2420Component::auto_calibrate_sensitivity() {
|
|
|
365
359
|
|
|
366
360
|
// Store average and peak values
|
|
367
361
|
this->gate_avg[gate] = sum / CALIBRATE_SAMPLES;
|
|
368
|
-
if (this->gate_peak[gate] < peak)
|
|
362
|
+
if (this->gate_peak[gate] < peak) {
|
|
369
363
|
this->gate_peak[gate] = peak;
|
|
364
|
+
}
|
|
370
365
|
|
|
371
366
|
uint32_t calculated_value =
|
|
372
367
|
(static_cast<uint32_t>(this->gate_peak[gate]) + (move_factor * static_cast<uint32_t>(this->gate_peak[gate])));
|
|
@@ -403,8 +398,9 @@ void LD2420Component::set_operating_mode(const std::string &state) {
|
|
|
403
398
|
}
|
|
404
399
|
} else {
|
|
405
400
|
// Set the current data back so we don't have new data that can be applied in error.
|
|
406
|
-
if (this->get_calibration_())
|
|
401
|
+
if (this->get_calibration_()) {
|
|
407
402
|
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
|
403
|
+
}
|
|
408
404
|
this->set_calibration_(false);
|
|
409
405
|
}
|
|
410
406
|
} else {
|
|
@@ -414,30 +410,32 @@ void LD2420Component::set_operating_mode(const std::string &state) {
|
|
|
414
410
|
}
|
|
415
411
|
|
|
416
412
|
void LD2420Component::readline_(int rx_data, uint8_t *buffer, int len) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
413
|
+
if (rx_data < 0) {
|
|
414
|
+
return; // No data available
|
|
415
|
+
}
|
|
416
|
+
if (this->buffer_pos_ < len - 1) {
|
|
417
|
+
buffer[this->buffer_pos_++] = rx_data;
|
|
418
|
+
buffer[this->buffer_pos_] = 0;
|
|
419
|
+
} else {
|
|
420
|
+
// We should never get here, but just in case...
|
|
421
|
+
ESP_LOGW(TAG, "Max command length exceeded; ignoring");
|
|
422
|
+
this->buffer_pos_ = 0;
|
|
423
|
+
}
|
|
424
|
+
if (this->buffer_pos_ < 4) {
|
|
425
|
+
return; // Not enough data to process yet
|
|
426
|
+
}
|
|
427
|
+
if (memcmp(&buffer[this->buffer_pos_ - 4], &CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)) == 0) {
|
|
428
|
+
this->cmd_active_ = false; // Set command state to inactive after response
|
|
429
|
+
this->handle_ack_data_(buffer, this->buffer_pos_);
|
|
430
|
+
this->buffer_pos_ = 0;
|
|
431
|
+
} else if ((buffer[this->buffer_pos_ - 2] == 0x0D && buffer[this->buffer_pos_ - 1] == 0x0A) &&
|
|
432
|
+
(this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE)) {
|
|
433
|
+
this->handle_simple_mode_(buffer, this->buffer_pos_);
|
|
434
|
+
this->buffer_pos_ = 0;
|
|
435
|
+
} else if ((memcmp(&buffer[this->buffer_pos_ - 4], &ENERGY_FRAME_FOOTER, sizeof(ENERGY_FRAME_FOOTER)) == 0) &&
|
|
436
|
+
(this->get_mode_() == CMD_SYSTEM_MODE_ENERGY)) {
|
|
437
|
+
this->handle_energy_mode_(buffer, this->buffer_pos_);
|
|
438
|
+
this->buffer_pos_ = 0;
|
|
441
439
|
}
|
|
442
440
|
}
|
|
443
441
|
|
|
@@ -462,8 +460,9 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) {
|
|
|
462
460
|
|
|
463
461
|
// Resonable refresh rate for home assistant database size health
|
|
464
462
|
const int32_t current_millis = App.get_loop_component_start_time();
|
|
465
|
-
if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS)
|
|
463
|
+
if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS) {
|
|
466
464
|
return;
|
|
465
|
+
}
|
|
467
466
|
this->last_periodic_millis = current_millis;
|
|
468
467
|
for (auto &listener : this->listeners_) {
|
|
469
468
|
listener->on_distance(this->get_distance_());
|
|
@@ -506,14 +505,16 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
|
|
|
506
505
|
}
|
|
507
506
|
}
|
|
508
507
|
outbuf[index] = '\0';
|
|
509
|
-
if (index > 1)
|
|
508
|
+
if (index > 1) {
|
|
510
509
|
this->set_distance_(strtol(outbuf, &endptr, 10));
|
|
510
|
+
}
|
|
511
511
|
|
|
512
512
|
if (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE) {
|
|
513
513
|
// Resonable refresh rate for home assistant database size health
|
|
514
514
|
const int32_t current_millis = App.get_loop_component_start_time();
|
|
515
|
-
if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS)
|
|
515
|
+
if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS) {
|
|
516
516
|
return;
|
|
517
|
+
}
|
|
517
518
|
this->last_normal_periodic_millis = current_millis;
|
|
518
519
|
for (auto &listener : this->listeners_)
|
|
519
520
|
listener->on_distance(this->get_distance_());
|
|
@@ -593,11 +594,12 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
|
|
|
593
594
|
int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
|
|
594
595
|
uint32_t start_millis = millis();
|
|
595
596
|
uint8_t error = 0;
|
|
596
|
-
uint8_t ack_buffer[
|
|
597
|
-
uint8_t cmd_buffer[
|
|
597
|
+
uint8_t ack_buffer[MAX_LINE_LENGTH];
|
|
598
|
+
uint8_t cmd_buffer[MAX_LINE_LENGTH];
|
|
598
599
|
this->cmd_reply_.ack = false;
|
|
599
|
-
if (frame.command != CMD_RESTART)
|
|
600
|
-
this->
|
|
600
|
+
if (frame.command != CMD_RESTART) {
|
|
601
|
+
this->cmd_active_ = true;
|
|
602
|
+
} // Restart does not reply, thus no ack state required
|
|
601
603
|
uint8_t retry = 3;
|
|
602
604
|
while (retry) {
|
|
603
605
|
frame.length = 0;
|
|
@@ -619,9 +621,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
|
|
|
619
621
|
|
|
620
622
|
memcpy(cmd_buffer + frame.length, &frame.footer, sizeof(frame.footer));
|
|
621
623
|
frame.length += sizeof(frame.footer);
|
|
622
|
-
|
|
623
|
-
this->write_byte(cmd_buffer[index]);
|
|
624
|
-
}
|
|
624
|
+
this->write_array(cmd_buffer, frame.length);
|
|
625
625
|
|
|
626
626
|
error = 0;
|
|
627
627
|
if (frame.command == CMD_RESTART) {
|
|
@@ -630,7 +630,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
|
|
|
630
630
|
|
|
631
631
|
while (!this->cmd_reply_.ack) {
|
|
632
632
|
while (this->available()) {
|
|
633
|
-
this->readline_(read(), ack_buffer, sizeof(ack_buffer));
|
|
633
|
+
this->readline_(this->read(), ack_buffer, sizeof(ack_buffer));
|
|
634
634
|
}
|
|
635
635
|
delay_microseconds_safe(1450);
|
|
636
636
|
// Wait on an Rx from the LD2420 for up to 3 1 second loops, otherwise it could trigger a WDT.
|
|
@@ -641,10 +641,12 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
|
|
|
641
641
|
break;
|
|
642
642
|
}
|
|
643
643
|
}
|
|
644
|
-
if (this->cmd_reply_.ack)
|
|
644
|
+
if (this->cmd_reply_.ack) {
|
|
645
645
|
retry = 0;
|
|
646
|
-
|
|
646
|
+
}
|
|
647
|
+
if (this->cmd_reply_.error > 0) {
|
|
647
648
|
this->handle_cmd_error(error);
|
|
649
|
+
}
|
|
648
650
|
}
|
|
649
651
|
return error;
|
|
650
652
|
}
|
|
@@ -764,8 +766,9 @@ void LD2420Component::set_system_mode(uint16_t mode) {
|
|
|
764
766
|
cmd_frame.data_length += sizeof(unknown_parm);
|
|
765
767
|
cmd_frame.footer = CMD_FRAME_FOOTER;
|
|
766
768
|
ESP_LOGV(TAG, "Sending write system mode command: %2X", cmd_frame.command);
|
|
767
|
-
if (this->send_cmd_from_array(cmd_frame) == 0)
|
|
769
|
+
if (this->send_cmd_from_array(cmd_frame) == 0) {
|
|
768
770
|
this->set_mode_(mode);
|
|
771
|
+
}
|
|
769
772
|
}
|
|
770
773
|
|
|
771
774
|
void LD2420Component::get_firmware_version_() {
|
|
@@ -840,18 +843,24 @@ void LD2420Component::set_gate_threshold(uint8_t gate) {
|
|
|
840
843
|
|
|
841
844
|
#ifdef USE_NUMBER
|
|
842
845
|
void LD2420Component::init_gate_config_numbers() {
|
|
843
|
-
if (this->gate_timeout_number_ != nullptr)
|
|
846
|
+
if (this->gate_timeout_number_ != nullptr) {
|
|
844
847
|
this->gate_timeout_number_->publish_state(static_cast<uint16_t>(this->current_config.timeout));
|
|
845
|
-
|
|
848
|
+
}
|
|
849
|
+
if (this->gate_select_number_ != nullptr) {
|
|
846
850
|
this->gate_select_number_->publish_state(0);
|
|
847
|
-
|
|
851
|
+
}
|
|
852
|
+
if (this->min_gate_distance_number_ != nullptr) {
|
|
848
853
|
this->min_gate_distance_number_->publish_state(static_cast<uint16_t>(this->current_config.min_gate));
|
|
849
|
-
|
|
854
|
+
}
|
|
855
|
+
if (this->max_gate_distance_number_ != nullptr) {
|
|
850
856
|
this->max_gate_distance_number_->publish_state(static_cast<uint16_t>(this->current_config.max_gate));
|
|
851
|
-
|
|
857
|
+
}
|
|
858
|
+
if (this->gate_move_sensitivity_factor_number_ != nullptr) {
|
|
852
859
|
this->gate_move_sensitivity_factor_number_->publish_state(this->gate_move_sensitivity_factor);
|
|
853
|
-
|
|
860
|
+
}
|
|
861
|
+
if (this->gate_still_sensitivity_factor_number_ != nullptr) {
|
|
854
862
|
this->gate_still_sensitivity_factor_number_->publish_state(this->gate_still_sensitivity_factor);
|
|
863
|
+
}
|
|
855
864
|
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
|
856
865
|
if (this->gate_still_threshold_numbers_[gate] != nullptr) {
|
|
857
866
|
this->gate_still_threshold_numbers_[gate]->publish_state(
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
namespace esphome {
|
|
21
21
|
namespace ld2420 {
|
|
22
22
|
|
|
23
|
-
static const uint8_t TOTAL_GATES = 16;
|
|
24
23
|
static const uint8_t CALIBRATE_SAMPLES = 64;
|
|
24
|
+
static const uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer
|
|
25
|
+
static const uint8_t TOTAL_GATES = 16;
|
|
25
26
|
|
|
26
27
|
enum OpMode : uint8_t {
|
|
27
28
|
OP_NORMAL_MODE = 1,
|
|
@@ -118,10 +119,10 @@ class LD2420Component : public Component, public uart::UARTDevice {
|
|
|
118
119
|
|
|
119
120
|
float gate_move_sensitivity_factor{0.5};
|
|
120
121
|
float gate_still_sensitivity_factor{0.5};
|
|
121
|
-
int32_t last_periodic_millis
|
|
122
|
-
int32_t report_periodic_millis
|
|
123
|
-
int32_t monitor_periodic_millis
|
|
124
|
-
int32_t last_normal_periodic_millis
|
|
122
|
+
int32_t last_periodic_millis{0};
|
|
123
|
+
int32_t report_periodic_millis{0};
|
|
124
|
+
int32_t monitor_periodic_millis{0};
|
|
125
|
+
int32_t last_normal_periodic_millis{0};
|
|
125
126
|
uint16_t radar_data[TOTAL_GATES][CALIBRATE_SAMPLES];
|
|
126
127
|
uint16_t gate_avg[TOTAL_GATES];
|
|
127
128
|
uint16_t gate_peak[TOTAL_GATES];
|
|
@@ -161,8 +162,6 @@ class LD2420Component : public Component, public uart::UARTDevice {
|
|
|
161
162
|
void set_presence_(bool presence) { this->presence_ = presence; };
|
|
162
163
|
uint16_t get_distance_() { return this->distance_; };
|
|
163
164
|
void set_distance_(uint16_t distance) { this->distance_ = distance; };
|
|
164
|
-
bool get_cmd_active_() { return this->cmd_active_; };
|
|
165
|
-
void set_cmd_active_(bool active) { this->cmd_active_ = active; };
|
|
166
165
|
void handle_simple_mode_(const uint8_t *inbuf, int len);
|
|
167
166
|
void handle_energy_mode_(uint8_t *buffer, int len);
|
|
168
167
|
void handle_ack_data_(uint8_t *buffer, int len);
|
|
@@ -181,12 +180,11 @@ class LD2420Component : public Component, public uart::UARTDevice {
|
|
|
181
180
|
std::vector<number::Number *> gate_move_threshold_numbers_ = std::vector<number::Number *>(16);
|
|
182
181
|
#endif
|
|
183
182
|
|
|
184
|
-
|
|
185
|
-
uint32_t min_distance_gate_;
|
|
183
|
+
uint16_t distance_{0};
|
|
186
184
|
uint16_t system_mode_;
|
|
187
185
|
uint16_t gate_energy_[TOTAL_GATES];
|
|
188
|
-
|
|
189
|
-
uint8_t
|
|
186
|
+
uint8_t buffer_pos_{0}; // where to resume processing/populating buffer
|
|
187
|
+
uint8_t buffer_data_[MAX_LINE_LENGTH];
|
|
190
188
|
char firmware_ver_[8]{"v0.0.0"};
|
|
191
189
|
bool cmd_active_{false};
|
|
192
190
|
bool presence_{false};
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
namespace esphome {
|
|
6
6
|
namespace ld2420 {
|
|
7
7
|
|
|
8
|
-
static const char *const TAG = "
|
|
8
|
+
static const char *const TAG = "ld2420.sensor";
|
|
9
9
|
|
|
10
10
|
void LD2420Sensor::dump_config() {
|
|
11
|
-
ESP_LOGCONFIG(TAG, "
|
|
11
|
+
ESP_LOGCONFIG(TAG, "Sensor:");
|
|
12
12
|
LOG_SENSOR(" ", "Distance", this->distance_sensor_);
|
|
13
13
|
}
|
|
14
14
|
|