mirror of
https://github.com/esphome/esphome.git
synced 2025-08-10 12:27:46 +00:00
Merge branch 'sensor_memory' into integration
This commit is contained in:
@@ -148,6 +148,7 @@ BinarySensorCondition = binary_sensor_ns.class_("BinarySensorCondition", Conditi
|
||||
|
||||
# Filters
|
||||
Filter = binary_sensor_ns.class_("Filter")
|
||||
TimeoutFilter = binary_sensor_ns.class_("TimeoutFilter", Filter, cg.Component)
|
||||
DelayedOnOffFilter = binary_sensor_ns.class_("DelayedOnOffFilter", Filter, cg.Component)
|
||||
DelayedOnFilter = binary_sensor_ns.class_("DelayedOnFilter", Filter, cg.Component)
|
||||
DelayedOffFilter = binary_sensor_ns.class_("DelayedOffFilter", Filter, cg.Component)
|
||||
@@ -171,6 +172,19 @@ async def invert_filter_to_code(config, filter_id):
|
||||
return cg.new_Pvariable(filter_id)
|
||||
|
||||
|
||||
@register_filter(
|
||||
"timeout",
|
||||
TimeoutFilter,
|
||||
cv.templatable(cv.positive_time_period_milliseconds),
|
||||
)
|
||||
async def timeout_filter_to_code(config, filter_id):
|
||||
var = cg.new_Pvariable(filter_id)
|
||||
await cg.register_component(var, {})
|
||||
template_ = await cg.templatable(config, [], cg.uint32)
|
||||
cg.add(var.set_timeout_value(template_))
|
||||
return var
|
||||
|
||||
|
||||
@register_filter(
|
||||
"delayed_on_off",
|
||||
DelayedOnOffFilter,
|
||||
|
@@ -25,6 +25,12 @@ void Filter::input(bool value) {
|
||||
}
|
||||
}
|
||||
|
||||
void TimeoutFilter::input(bool value) {
|
||||
this->set_timeout("timeout", this->timeout_delay_.value(), [this]() { this->parent_->invalidate_state(); });
|
||||
// we do not de-dup here otherwise changes from invalid to valid state will not be output
|
||||
this->output(value);
|
||||
}
|
||||
|
||||
optional<bool> DelayedOnOffFilter::new_value(bool value) {
|
||||
if (value) {
|
||||
this->set_timeout("ON_OFF", this->on_delay_.value(), [this]() { this->output(true); });
|
||||
|
@@ -16,7 +16,7 @@ class Filter {
|
||||
public:
|
||||
virtual optional<bool> new_value(bool value) = 0;
|
||||
|
||||
void input(bool value);
|
||||
virtual void input(bool value);
|
||||
|
||||
void output(bool value);
|
||||
|
||||
@@ -28,6 +28,16 @@ class Filter {
|
||||
Deduplicator<bool> dedup_;
|
||||
};
|
||||
|
||||
class TimeoutFilter : public Filter, public Component {
|
||||
public:
|
||||
optional<bool> new_value(bool value) override { return value; }
|
||||
void input(bool value) override;
|
||||
template<typename T> void set_timeout_value(T timeout) { this->timeout_delay_ = timeout; }
|
||||
|
||||
protected:
|
||||
TemplatableValue<uint32_t> timeout_delay_{};
|
||||
};
|
||||
|
||||
class DelayedOnOffFilter : public Filter, public Component {
|
||||
public:
|
||||
optional<bool> new_value(bool value) override;
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "ble_event_pool.h"
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <esp_bt.h>
|
||||
@@ -516,13 +517,12 @@ void ESP32BLE::dump_config() {
|
||||
break;
|
||||
}
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"ESP32 BLE:\n"
|
||||
" MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n"
|
||||
"BLE:\n"
|
||||
" MAC address: %s\n"
|
||||
" IO Capability: %s",
|
||||
mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5],
|
||||
io_capability_s);
|
||||
format_mac_address_pretty(mac_address).c_str(), io_capability_s);
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
|
||||
ESP_LOGCONFIG(TAG, "Bluetooth stack is not enabled");
|
||||
}
|
||||
}
|
||||
|
||||
|
0
esphome/components/esp32_hall/__init__.py
Normal file
0
esphome/components/esp32_hall/__init__.py
Normal file
5
esphome/components/esp32_hall/sensor.py
Normal file
5
esphome/components/esp32_hall/sensor.py
Normal file
@@ -0,0 +1,5 @@
|
||||
import esphome.config_validation as cv
|
||||
|
||||
CONFIG_SCHEMA = cv.invalid(
|
||||
"The esp32_hall component has been removed as of ESPHome 2025.7.0. See https://github.com/esphome/esphome/pull/9117 for details."
|
||||
)
|
@@ -8,6 +8,8 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#endif
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
#define highbyte(val) (uint8_t)((val) >> 8)
|
||||
#define lowbyte(val) (uint8_t)((val) &0xff)
|
||||
|
||||
@@ -73,9 +75,9 @@ void LD2410Component::dump_config() {
|
||||
#endif
|
||||
this->read_all_info();
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Throttle_ : %ums\n"
|
||||
" MAC Address : %s\n"
|
||||
" Firmware Version : %s",
|
||||
" Throttle: %ums\n"
|
||||
" MAC address: %s\n"
|
||||
" Firmware version: %s",
|
||||
this->throttle_, const_cast<char *>(this->mac_.c_str()), const_cast<char *>(this->version_.c_str()));
|
||||
}
|
||||
|
||||
@@ -153,7 +155,7 @@ void LD2410Component::handle_periodic_data_(uint8_t *buffer, int len) {
|
||||
/*
|
||||
Reduce data update rate to prevent home assistant database size grow fast
|
||||
*/
|
||||
int32_t current_millis = millis();
|
||||
int32_t current_millis = App.get_loop_component_start_time();
|
||||
if (current_millis - last_periodic_millis_ < this->throttle_)
|
||||
return;
|
||||
last_periodic_millis_ = current_millis;
|
||||
@@ -299,21 +301,6 @@ const char MAC_FMT[] = "%02X:%02X:%02X:%02X:%02X:%02X";
|
||||
const std::string UNKNOWN_MAC("unknown");
|
||||
const std::string NO_MAC("08:05:04:03:02:01");
|
||||
|
||||
std::string format_mac(uint8_t *buffer) {
|
||||
std::string::size_type mac_size = 256;
|
||||
std::string mac;
|
||||
do {
|
||||
mac.resize(mac_size + 1);
|
||||
mac_size = std::snprintf(&mac[0], mac.size(), MAC_FMT, buffer[10], buffer[11], buffer[12], buffer[13], buffer[14],
|
||||
buffer[15]);
|
||||
} while (mac_size + 1 > mac.size());
|
||||
mac.resize(mac_size);
|
||||
if (mac == NO_MAC) {
|
||||
return UNKNOWN_MAC;
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
#ifdef USE_NUMBER
|
||||
std::function<void(void)> set_number_value(number::Number *n, float value) {
|
||||
float normalized_value = value * 1.0;
|
||||
@@ -328,40 +315,40 @@ std::function<void(void)> set_number_value(number::Number *n, float value) {
|
||||
bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
ESP_LOGV(TAG, "Handling ACK DATA for COMMAND %02X", buffer[COMMAND]);
|
||||
if (len < 10) {
|
||||
ESP_LOGE(TAG, "Error with last command : incorrect length");
|
||||
ESP_LOGE(TAG, "Invalid length");
|
||||
return true;
|
||||
}
|
||||
if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // check 4 frame start bytes
|
||||
ESP_LOGE(TAG, "Error with last command : incorrect Header");
|
||||
ESP_LOGE(TAG, "Invalid header");
|
||||
return true;
|
||||
}
|
||||
if (buffer[COMMAND_STATUS] != 0x01) {
|
||||
ESP_LOGE(TAG, "Error with last command : status != 0x01");
|
||||
ESP_LOGE(TAG, "Invalid status");
|
||||
return true;
|
||||
}
|
||||
if (this->two_byte_to_int_(buffer[8], buffer[9]) != 0x00) {
|
||||
ESP_LOGE(TAG, "Error with last command , last buffer was: %u , %u", buffer[8], buffer[9]);
|
||||
ESP_LOGE(TAG, "Invalid command: %u, %u", buffer[8], buffer[9]);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (buffer[COMMAND]) {
|
||||
case lowbyte(CMD_ENABLE_CONF):
|
||||
ESP_LOGV(TAG, "Handled Enable conf command");
|
||||
ESP_LOGV(TAG, "Enable conf");
|
||||
break;
|
||||
case lowbyte(CMD_DISABLE_CONF):
|
||||
ESP_LOGV(TAG, "Handled Disabled conf command");
|
||||
ESP_LOGV(TAG, "Disabled conf");
|
||||
break;
|
||||
case lowbyte(CMD_SET_BAUD_RATE):
|
||||
ESP_LOGV(TAG, "Handled baud rate change command");
|
||||
ESP_LOGV(TAG, "Baud rate change");
|
||||
#ifdef USE_SELECT
|
||||
if (this->baud_rate_select_ != nullptr) {
|
||||
ESP_LOGE(TAG, "Change baud rate component config to %s and reinstall", this->baud_rate_select_->state.c_str());
|
||||
ESP_LOGE(TAG, "Configure baud rate to %s and reinstall", this->baud_rate_select_->state.c_str());
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case lowbyte(CMD_VERSION):
|
||||
this->version_ = format_version(buffer);
|
||||
ESP_LOGV(TAG, "FW Version is: %s", const_cast<char *>(this->version_.c_str()));
|
||||
ESP_LOGV(TAG, "Firmware version: %s", const_cast<char *>(this->version_.c_str()));
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->version_text_sensor_ != nullptr) {
|
||||
this->version_text_sensor_->publish_state(this->version_);
|
||||
@@ -371,7 +358,7 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
case lowbyte(CMD_QUERY_DISTANCE_RESOLUTION): {
|
||||
std::string distance_resolution =
|
||||
DISTANCE_RESOLUTION_INT_TO_ENUM.at(this->two_byte_to_int_(buffer[10], buffer[11]));
|
||||
ESP_LOGV(TAG, "Distance resolution is: %s", const_cast<char *>(distance_resolution.c_str()));
|
||||
ESP_LOGV(TAG, "Distance resolution: %s", const_cast<char *>(distance_resolution.c_str()));
|
||||
#ifdef USE_SELECT
|
||||
if (this->distance_resolution_select_ != nullptr &&
|
||||
this->distance_resolution_select_->state != distance_resolution) {
|
||||
@@ -383,9 +370,9 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
this->light_function_ = LIGHT_FUNCTION_INT_TO_ENUM.at(buffer[10]);
|
||||
this->light_threshold_ = buffer[11] * 1.0;
|
||||
this->out_pin_level_ = OUT_PIN_LEVEL_INT_TO_ENUM.at(buffer[12]);
|
||||
ESP_LOGV(TAG, "Light function is: %s", const_cast<char *>(this->light_function_.c_str()));
|
||||
ESP_LOGV(TAG, "Light threshold is: %f", this->light_threshold_);
|
||||
ESP_LOGV(TAG, "Out pin level is: %s", const_cast<char *>(this->out_pin_level_.c_str()));
|
||||
ESP_LOGV(TAG, "Light function: %s", const_cast<char *>(this->light_function_.c_str()));
|
||||
ESP_LOGV(TAG, "Light threshold: %f", this->light_threshold_);
|
||||
ESP_LOGV(TAG, "Out pin level: %s", const_cast<char *>(this->out_pin_level_.c_str()));
|
||||
#ifdef USE_SELECT
|
||||
if (this->light_function_select_ != nullptr && this->light_function_select_->state != this->light_function_) {
|
||||
this->light_function_select_->publish_state(this->light_function_);
|
||||
@@ -406,11 +393,11 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
if (len < 20) {
|
||||
return false;
|
||||
}
|
||||
this->mac_ = format_mac(buffer);
|
||||
ESP_LOGV(TAG, "MAC Address is: %s", const_cast<char *>(this->mac_.c_str()));
|
||||
this->mac_ = format_mac_address_pretty(&buffer[10]);
|
||||
ESP_LOGV(TAG, "MAC address: %s", this->mac_.c_str());
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->mac_text_sensor_ != nullptr) {
|
||||
this->mac_text_sensor_->publish_state(this->mac_);
|
||||
this->mac_text_sensor_->publish_state(this->mac_ == NO_MAC ? UNKNOWN_MAC : this->mac_);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
@@ -420,19 +407,19 @@ bool LD2410Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
#endif
|
||||
break;
|
||||
case lowbyte(CMD_GATE_SENS):
|
||||
ESP_LOGV(TAG, "Handled sensitivity command");
|
||||
ESP_LOGV(TAG, "Sensitivity");
|
||||
break;
|
||||
case lowbyte(CMD_BLUETOOTH):
|
||||
ESP_LOGV(TAG, "Handled bluetooth command");
|
||||
ESP_LOGV(TAG, "Bluetooth");
|
||||
break;
|
||||
case lowbyte(CMD_SET_DISTANCE_RESOLUTION):
|
||||
ESP_LOGV(TAG, "Handled set distance resolution command");
|
||||
ESP_LOGV(TAG, "Set distance resolution");
|
||||
break;
|
||||
case lowbyte(CMD_SET_LIGHT_CONTROL):
|
||||
ESP_LOGV(TAG, "Handled set light control command");
|
||||
ESP_LOGV(TAG, "Set light control");
|
||||
break;
|
||||
case lowbyte(CMD_BT_PASSWORD):
|
||||
ESP_LOGV(TAG, "Handled set bluetooth password command");
|
||||
ESP_LOGV(TAG, "Set bluetooth password");
|
||||
break;
|
||||
case lowbyte(CMD_QUERY): // Query parameters response
|
||||
{
|
||||
@@ -532,7 +519,7 @@ void LD2410Component::set_baud_rate(const std::string &state) {
|
||||
|
||||
void LD2410Component::set_bluetooth_password(const std::string &password) {
|
||||
if (password.length() != 6) {
|
||||
ESP_LOGE(TAG, "set_bluetooth_password(): invalid password length, must be exactly 6 chars '%s'", password.c_str());
|
||||
ESP_LOGE(TAG, "Password must be exactly 6 chars");
|
||||
return;
|
||||
}
|
||||
this->set_config_mode_(true);
|
||||
@@ -544,7 +531,7 @@ void LD2410Component::set_bluetooth_password(const std::string &password) {
|
||||
|
||||
void LD2410Component::set_engineering_mode(bool enable) {
|
||||
this->set_config_mode_(true);
|
||||
last_engineering_mode_change_millis_ = millis();
|
||||
last_engineering_mode_change_millis_ = App.get_loop_component_start_time();
|
||||
uint8_t cmd = enable ? CMD_ENABLE_ENG : CMD_DISABLE_ENG;
|
||||
this->send_command_(cmd, nullptr, 0);
|
||||
this->set_config_mode_(false);
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "ld2420.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
/*
|
||||
@@ -40,7 +41,7 @@ There are three documented parameters for modes:
|
||||
00 04 = Energy output mode
|
||||
This mode outputs detailed signal energy values for each gate and the target distance.
|
||||
The data format consist of the following.
|
||||
Header HH, Length LL, Persence PP, Distance DD, 16 Gate Energies EE, Footer FF
|
||||
Header HH, Length LL, Presence PP, Distance DD, 16 Gate Energies EE, Footer FF
|
||||
HH HH HH HH LL LL PP DD DD EE EE .. 16x .. FF FF FF FF
|
||||
F4 F3 F2 F1 23 00 00 00 00 00 00 .. .. .. .. F8 F7 F6 F5
|
||||
00 00 = debug output mode
|
||||
@@ -67,10 +68,10 @@ float LD2420Component::get_setup_priority() const { return setup_priority::BUS;
|
||||
void LD2420Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"LD2420:\n"
|
||||
" Firmware Version : %7s\n"
|
||||
"LD2420 Number:",
|
||||
" Firmware version: %7s",
|
||||
this->ld2420_firmware_ver_);
|
||||
#ifdef USE_NUMBER
|
||||
ESP_LOGCONFIG(TAG, "Number:");
|
||||
LOG_NUMBER(TAG, " Gate Timeout:", this->gate_timeout_number_);
|
||||
LOG_NUMBER(TAG, " Gate Max Distance:", this->max_gate_distance_number_);
|
||||
LOG_NUMBER(TAG, " Gate Min Distance:", this->min_gate_distance_number_);
|
||||
@@ -86,10 +87,10 @@ void LD2420Component::dump_config() {
|
||||
LOG_BUTTON(TAG, " Factory Reset:", this->factory_reset_button_);
|
||||
LOG_BUTTON(TAG, " Restart Module:", this->restart_module_button_);
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG, "LD2420 Select:");
|
||||
ESP_LOGCONFIG(TAG, "Select:");
|
||||
LOG_SELECT(TAG, " Operating Mode", this->operating_selector_);
|
||||
if (this->get_firmware_int_(ld2420_firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
ESP_LOGW(TAG, "LD2420 Firmware Version %s and older are only supported in Simple Mode", ld2420_firmware_ver_);
|
||||
if (LD2420Component::get_firmware_int(this->ld2420_firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
ESP_LOGW(TAG, "Firmware version %s and older supports Simple Mode only", this->ld2420_firmware_ver_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +103,7 @@ uint8_t LD2420Component::calc_checksum(void *data, size_t size) {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
int LD2420Component::get_firmware_int_(const char *version_string) {
|
||||
int LD2420Component::get_firmware_int(const char *version_string) {
|
||||
std::string version_str = version_string;
|
||||
if (version_str[0] == 'v') {
|
||||
version_str = version_str.substr(1);
|
||||
@@ -115,7 +116,7 @@ int LD2420Component::get_firmware_int_(const char *version_string) {
|
||||
void LD2420Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Running setup");
|
||||
if (this->set_config_mode(true) == LD2420_ERROR_TIMEOUT) {
|
||||
ESP_LOGE(TAG, "LD2420 module has failed to respond, check baud rate and serial connections.");
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@@ -127,7 +128,7 @@ void LD2420Component::setup() {
|
||||
const char *pfw = this->ld2420_firmware_ver_;
|
||||
std::string fw_str(pfw);
|
||||
|
||||
for (auto &listener : listeners_) {
|
||||
for (auto &listener : this->listeners_) {
|
||||
listener->on_fw_version(fw_str);
|
||||
}
|
||||
|
||||
@@ -137,11 +138,11 @@ void LD2420Component::setup() {
|
||||
}
|
||||
|
||||
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
||||
if (get_firmware_int_(ld2420_firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
if (LD2420Component::get_firmware_int(this->ld2420_firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
this->set_operating_mode(OP_SIMPLE_MODE_STRING);
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
this->set_mode_(CMD_SYSTEM_MODE_SIMPLE);
|
||||
ESP_LOGW(TAG, "LD2420 Frimware Version %s and older are only supported in Simple Mode", ld2420_firmware_ver_);
|
||||
ESP_LOGW(TAG, "Firmware version %s and older supports Simple Mode only", this->ld2420_firmware_ver_);
|
||||
} else {
|
||||
this->set_mode_(CMD_SYSTEM_MODE_ENERGY);
|
||||
this->operating_selector_->publish_state(OP_NORMAL_MODE_STRING);
|
||||
@@ -151,18 +152,17 @@ void LD2420Component::setup() {
|
||||
#endif
|
||||
this->set_system_mode(this->system_mode_);
|
||||
this->set_config_mode(false);
|
||||
ESP_LOGCONFIG(TAG, "LD2420 setup complete.");
|
||||
}
|
||||
|
||||
void LD2420Component::apply_config_action() {
|
||||
const uint8_t checksum = calc_checksum(&this->new_config, sizeof(this->new_config));
|
||||
if (checksum == calc_checksum(&this->current_config, sizeof(this->current_config))) {
|
||||
ESP_LOGCONFIG(TAG, "No configuration change detected");
|
||||
ESP_LOGD(TAG, "No configuration change detected");
|
||||
return;
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, "Reconfiguring LD2420");
|
||||
ESP_LOGD(TAG, "Reconfiguring");
|
||||
if (this->set_config_mode(true) == LD2420_ERROR_TIMEOUT) {
|
||||
ESP_LOGE(TAG, "LD2420 module has failed to respond, check baud rate and serial connections.");
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@@ -178,13 +178,12 @@ void LD2420Component::apply_config_action() {
|
||||
this->set_system_mode(this->system_mode_);
|
||||
this->set_config_mode(false); // Disable config mode to save new values in LD2420 nvm
|
||||
this->set_operating_mode(OP_NORMAL_MODE_STRING);
|
||||
ESP_LOGCONFIG(TAG, "LD2420 reconfig complete.");
|
||||
}
|
||||
|
||||
void LD2420Component::factory_reset_action() {
|
||||
ESP_LOGCONFIG(TAG, "Setting factory defaults");
|
||||
ESP_LOGD(TAG, "Setting factory defaults");
|
||||
if (this->set_config_mode(true) == LD2420_ERROR_TIMEOUT) {
|
||||
ESP_LOGE(TAG, "LD2420 module has failed to respond, check baud rate and serial connections.");
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
@@ -207,18 +206,16 @@ void LD2420Component::factory_reset_action() {
|
||||
this->init_gate_config_numbers();
|
||||
this->refresh_gate_config_numbers();
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG, "LD2420 factory reset complete.");
|
||||
}
|
||||
|
||||
void LD2420Component::restart_module_action() {
|
||||
ESP_LOGCONFIG(TAG, "Restarting LD2420 module");
|
||||
ESP_LOGD(TAG, "Restarting");
|
||||
this->send_module_restart();
|
||||
this->set_timeout(250, [this]() {
|
||||
this->set_config_mode(true);
|
||||
this->set_system_mode(system_mode_);
|
||||
this->set_system_mode(this->system_mode_);
|
||||
this->set_config_mode(false);
|
||||
});
|
||||
ESP_LOGCONFIG(TAG, "LD2420 Restarted.");
|
||||
}
|
||||
|
||||
void LD2420Component::revert_config_action() {
|
||||
@@ -226,18 +223,18 @@ void LD2420Component::revert_config_action() {
|
||||
#ifdef USE_NUMBER
|
||||
this->init_gate_config_numbers();
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG, "Reverted config number edits.");
|
||||
ESP_LOGD(TAG, "Reverted config number edits");
|
||||
}
|
||||
|
||||
void LD2420Component::loop() {
|
||||
// If there is a active send command do not process it here, the send command call will handle it.
|
||||
if (!get_cmd_active_()) {
|
||||
if (!available())
|
||||
if (!this->get_cmd_active_()) {
|
||||
if (!this->available())
|
||||
return;
|
||||
static uint8_t buffer[2048];
|
||||
static uint8_t rx_data;
|
||||
while (available()) {
|
||||
rx_data = read();
|
||||
while (this->available()) {
|
||||
rx_data = this->read();
|
||||
this->readline_(rx_data, buffer, sizeof(buffer));
|
||||
}
|
||||
}
|
||||
@@ -292,7 +289,7 @@ void LD2420Component::report_gate_data() {
|
||||
|
||||
void LD2420Component::set_operating_mode(const std::string &state) {
|
||||
// If unsupported firmware ignore mode select
|
||||
if (get_firmware_int_(ld2420_firmware_ver_) >= CALIBRATE_VERSION_MIN) {
|
||||
if (LD2420Component::get_firmware_int(ld2420_firmware_ver_) >= CALIBRATE_VERSION_MIN) {
|
||||
this->current_operating_mode = OP_MODE_TO_UINT.at(state);
|
||||
// Entering Auto Calibrate we need to clear the privoiuos data collection
|
||||
this->operating_selector_->publish_state(state);
|
||||
@@ -365,13 +362,13 @@ void LD2420Component::handle_energy_mode_(uint8_t *buffer, int len) {
|
||||
}
|
||||
|
||||
// Resonable refresh rate for home assistant database size health
|
||||
const int32_t current_millis = millis();
|
||||
const int32_t current_millis = App.get_loop_component_start_time();
|
||||
if (current_millis - this->last_periodic_millis < REFRESH_RATE_MS)
|
||||
return;
|
||||
this->last_periodic_millis = current_millis;
|
||||
for (auto &listener : this->listeners_) {
|
||||
listener->on_distance(get_distance_());
|
||||
listener->on_presence(get_presence_());
|
||||
listener->on_distance(this->get_distance_());
|
||||
listener->on_presence(this->get_presence_());
|
||||
listener->on_energy(this->gate_energy_, sizeof(this->gate_energy_) / sizeof(this->gate_energy_[0]));
|
||||
}
|
||||
|
||||
@@ -392,9 +389,9 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
|
||||
char outbuf[bufsize]{0};
|
||||
while (true) {
|
||||
if (inbuf[pos - 2] == 'O' && inbuf[pos - 1] == 'F' && inbuf[pos] == 'F') {
|
||||
set_presence_(false);
|
||||
this->set_presence_(false);
|
||||
} else if (inbuf[pos - 1] == 'O' && inbuf[pos] == 'N') {
|
||||
set_presence_(true);
|
||||
this->set_presence_(true);
|
||||
}
|
||||
if (inbuf[pos] >= '0' && inbuf[pos] <= '9') {
|
||||
if (index < bufsize - 1) {
|
||||
@@ -411,18 +408,18 @@ void LD2420Component::handle_simple_mode_(const uint8_t *inbuf, int len) {
|
||||
}
|
||||
outbuf[index] = '\0';
|
||||
if (index > 1)
|
||||
set_distance_(strtol(outbuf, &endptr, 10));
|
||||
this->set_distance_(strtol(outbuf, &endptr, 10));
|
||||
|
||||
if (get_mode_() == CMD_SYSTEM_MODE_SIMPLE) {
|
||||
if (this->get_mode_() == CMD_SYSTEM_MODE_SIMPLE) {
|
||||
// Resonable refresh rate for home assistant database size health
|
||||
const int32_t current_millis = millis();
|
||||
const int32_t current_millis = App.get_loop_component_start_time();
|
||||
if (current_millis - this->last_normal_periodic_millis < REFRESH_RATE_MS)
|
||||
return;
|
||||
this->last_normal_periodic_millis = current_millis;
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->on_distance(get_distance_());
|
||||
listener->on_distance(this->get_distance_());
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->on_presence(get_presence_());
|
||||
listener->on_presence(this->get_presence_());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,10 +430,10 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
uint8_t data_element = 0;
|
||||
uint16_t data_pos = 0;
|
||||
if (this->cmd_reply_.length > CMD_MAX_BYTES) {
|
||||
ESP_LOGW(TAG, "LD2420 reply - received command reply frame is corrupt, length exceeds %d bytes.", CMD_MAX_BYTES);
|
||||
ESP_LOGW(TAG, "Reply frame too long");
|
||||
return;
|
||||
} else if (this->cmd_reply_.length < 2) {
|
||||
ESP_LOGW(TAG, "LD2420 reply - received command frame is corrupt, length is less than 2 bytes.");
|
||||
ESP_LOGW(TAG, "Command frame too short");
|
||||
return;
|
||||
}
|
||||
memcpy(&this->cmd_reply_.error, &buffer[CMD_ERROR_WORD], sizeof(this->cmd_reply_.error));
|
||||
@@ -447,13 +444,13 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
this->cmd_reply_.ack = true;
|
||||
switch ((uint16_t) this->cmd_reply_.command) {
|
||||
case (CMD_ENABLE_CONF):
|
||||
ESP_LOGD(TAG, "LD2420 reply - set config enable: CMD = %2X %s", CMD_ENABLE_CONF, result);
|
||||
ESP_LOGV(TAG, "Set config enable: CMD = %2X %s", CMD_ENABLE_CONF, result);
|
||||
break;
|
||||
case (CMD_DISABLE_CONF):
|
||||
ESP_LOGD(TAG, "LD2420 reply - set config disable: CMD = %2X %s", CMD_DISABLE_CONF, result);
|
||||
ESP_LOGV(TAG, "Set config disable: CMD = %2X %s", CMD_DISABLE_CONF, result);
|
||||
break;
|
||||
case (CMD_READ_REGISTER):
|
||||
ESP_LOGD(TAG, "LD2420 reply - read register: CMD = %2X %s", CMD_READ_REGISTER, result);
|
||||
ESP_LOGV(TAG, "Read register: CMD = %2X %s", CMD_READ_REGISTER, result);
|
||||
// TODO Read/Write register is not implemented yet, this will get flushed out to a proper header file
|
||||
data_pos = 0x0A;
|
||||
for (uint16_t index = 0; index < (CMD_REG_DATA_REPLY_SIZE * // NOLINT
|
||||
@@ -465,13 +462,13 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
}
|
||||
break;
|
||||
case (CMD_WRITE_REGISTER):
|
||||
ESP_LOGD(TAG, "LD2420 reply - write register: CMD = %2X %s", CMD_WRITE_REGISTER, result);
|
||||
ESP_LOGV(TAG, "Write register: CMD = %2X %s", CMD_WRITE_REGISTER, result);
|
||||
break;
|
||||
case (CMD_WRITE_ABD_PARAM):
|
||||
ESP_LOGD(TAG, "LD2420 reply - write gate parameter(s): %2X %s", CMD_WRITE_ABD_PARAM, result);
|
||||
ESP_LOGV(TAG, "Write gate parameter(s): %2X %s", CMD_WRITE_ABD_PARAM, result);
|
||||
break;
|
||||
case (CMD_READ_ABD_PARAM):
|
||||
ESP_LOGD(TAG, "LD2420 reply - read gate parameter(s): %2X %s", CMD_READ_ABD_PARAM, result);
|
||||
ESP_LOGV(TAG, "Read gate parameter(s): %2X %s", CMD_READ_ABD_PARAM, result);
|
||||
data_pos = CMD_ABD_DATA_REPLY_START;
|
||||
for (uint16_t index = 0; index < (CMD_ABD_DATA_REPLY_SIZE * // NOLINT
|
||||
((buffer[CMD_FRAME_DATA_LENGTH] - 4) / CMD_ABD_DATA_REPLY_SIZE));
|
||||
@@ -483,11 +480,11 @@ void LD2420Component::handle_ack_data_(uint8_t *buffer, int len) {
|
||||
}
|
||||
break;
|
||||
case (CMD_WRITE_SYS_PARAM):
|
||||
ESP_LOGD(TAG, "LD2420 reply - set system parameter(s): %2X %s", CMD_WRITE_SYS_PARAM, result);
|
||||
ESP_LOGV(TAG, "Set system parameter(s): %2X %s", CMD_WRITE_SYS_PARAM, result);
|
||||
break;
|
||||
case (CMD_READ_VERSION):
|
||||
memcpy(this->ld2420_firmware_ver_, &buffer[12], buffer[10]);
|
||||
ESP_LOGD(TAG, "LD2420 reply - module firmware version: %7s %s", this->ld2420_firmware_ver_, result);
|
||||
ESP_LOGV(TAG, "Firmware version: %7s %s", this->ld2420_firmware_ver_, result);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -533,7 +530,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
|
||||
}
|
||||
|
||||
while (!this->cmd_reply_.ack) {
|
||||
while (available()) {
|
||||
while (this->available()) {
|
||||
this->readline_(read(), ack_buffer, sizeof(ack_buffer));
|
||||
}
|
||||
delay_microseconds_safe(1450);
|
||||
@@ -548,7 +545,7 @@ int LD2420Component::send_cmd_from_array(CmdFrameT frame) {
|
||||
if (this->cmd_reply_.ack)
|
||||
retry = 0;
|
||||
if (this->cmd_reply_.error > 0)
|
||||
handle_cmd_error(error);
|
||||
this->handle_cmd_error(error);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@@ -563,7 +560,7 @@ uint8_t LD2420Component::set_config_mode(bool enable) {
|
||||
cmd_frame.data_length += sizeof(CMD_PROTOCOL_VER);
|
||||
}
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending set config %s command: %2X", enable ? "enable" : "disable", cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending set config %s command: %2X", enable ? "enable" : "disable", cmd_frame.command);
|
||||
return this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
@@ -576,7 +573,7 @@ void LD2420Component::ld2420_restart() {
|
||||
cmd_frame.header = CMD_FRAME_HEADER;
|
||||
cmd_frame.command = CMD_RESTART;
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending restart command: %2X", cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending restart command: %2X", cmd_frame.command);
|
||||
this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
@@ -588,7 +585,7 @@ void LD2420Component::get_reg_value_(uint16_t reg) {
|
||||
cmd_frame.data[1] = reg;
|
||||
cmd_frame.data_length += 2;
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending read register %4X command: %2X", reg, cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending read register %4X command: %2X", reg, cmd_frame.command);
|
||||
this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
@@ -602,11 +599,11 @@ void LD2420Component::set_reg_value(uint16_t reg, uint16_t value) {
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &value, sizeof(CMD_REG_DATA_REPLY_SIZE));
|
||||
cmd_frame.data_length += 2;
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending write register %4X command: %2X data = %4X", reg, cmd_frame.command, value);
|
||||
ESP_LOGV(TAG, "Sending write register %4X command: %2X data = %4X", reg, cmd_frame.command, value);
|
||||
this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
void LD2420Component::handle_cmd_error(uint8_t error) { ESP_LOGI(TAG, "Command failed: %s", ERR_MESSAGE[error]); }
|
||||
void LD2420Component::handle_cmd_error(uint8_t error) { ESP_LOGE(TAG, "Command failed: %s", ERR_MESSAGE[error]); }
|
||||
|
||||
int LD2420Component::get_gate_threshold_(uint8_t gate) {
|
||||
uint8_t error;
|
||||
@@ -619,7 +616,7 @@ int LD2420Component::get_gate_threshold_(uint8_t gate) {
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &CMD_GATE_STILL_THRESH[gate], sizeof(CMD_GATE_STILL_THRESH[gate]));
|
||||
cmd_frame.data_length += 2;
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending read gate %d high/low theshold command: %2X", gate, cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending read gate %d high/low threshold command: %2X", gate, cmd_frame.command);
|
||||
error = this->send_cmd_from_array(cmd_frame);
|
||||
if (error == 0) {
|
||||
this->current_config.move_thresh[gate] = cmd_reply_.data[0];
|
||||
@@ -644,7 +641,7 @@ int LD2420Component::get_min_max_distances_timeout_() {
|
||||
sizeof(CMD_TIMEOUT_REG)); // Register: global delay time
|
||||
cmd_frame.data_length += sizeof(CMD_TIMEOUT_REG);
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending read gate min max and timeout command: %2X", cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending read gate min max and timeout command: %2X", cmd_frame.command);
|
||||
error = this->send_cmd_from_array(cmd_frame);
|
||||
if (error == 0) {
|
||||
this->current_config.min_gate = (uint16_t) cmd_reply_.data[0];
|
||||
@@ -667,9 +664,9 @@ void LD2420Component::set_system_mode(uint16_t mode) {
|
||||
memcpy(&cmd_frame.data[cmd_frame.data_length], &unknown_parm, sizeof(unknown_parm));
|
||||
cmd_frame.data_length += sizeof(unknown_parm);
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending write system mode command: %2X", cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending write system mode command: %2X", cmd_frame.command);
|
||||
if (this->send_cmd_from_array(cmd_frame) == 0)
|
||||
set_mode_(mode);
|
||||
this->set_mode_(mode);
|
||||
}
|
||||
|
||||
void LD2420Component::get_firmware_version_() {
|
||||
@@ -679,7 +676,7 @@ void LD2420Component::get_firmware_version_() {
|
||||
cmd_frame.command = CMD_READ_VERSION;
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
|
||||
ESP_LOGD(TAG, "Sending read firmware version command: %2X", cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending read firmware version command: %2X", cmd_frame.command);
|
||||
this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
@@ -712,7 +709,7 @@ void LD2420Component::set_min_max_distances_timeout(uint32_t max_gate_distance,
|
||||
cmd_frame.data_length += sizeof(timeout);
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
|
||||
ESP_LOGD(TAG, "Sending write gate min max and timeout command: %2X", cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending write gate min max and timeout command: %2X", cmd_frame.command);
|
||||
this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
@@ -738,7 +735,7 @@ void LD2420Component::set_gate_threshold(uint8_t gate) {
|
||||
sizeof(this->new_config.still_thresh[gate]));
|
||||
cmd_frame.data_length += sizeof(this->new_config.still_thresh[gate]);
|
||||
cmd_frame.footer = CMD_FRAME_FOOTER;
|
||||
ESP_LOGD(TAG, "Sending set gate %4X sensitivity command: %2X", gate, cmd_frame.command);
|
||||
ESP_LOGV(TAG, "Sending set gate %4X sensitivity command: %2X", gate, cmd_frame.command);
|
||||
this->send_cmd_from_array(cmd_frame);
|
||||
}
|
||||
|
||||
|
@@ -179,7 +179,7 @@ class LD2420Component : public Component, public uart::UARTDevice {
|
||||
void set_operating_mode(const std::string &state);
|
||||
void auto_calibrate_sensitivity();
|
||||
void update_radar_data(uint16_t const *gate_energy, uint8_t sample_number);
|
||||
uint8_t calc_checksum(void *data, size_t size);
|
||||
static uint8_t calc_checksum(void *data, size_t size);
|
||||
|
||||
RegConfigT current_config;
|
||||
RegConfigT new_config;
|
||||
@@ -222,7 +222,7 @@ class LD2420Component : public Component, public uart::UARTDevice {
|
||||
volatile bool ack;
|
||||
};
|
||||
|
||||
int get_firmware_int_(const char *version_string);
|
||||
static int get_firmware_int(const char *version_string);
|
||||
void get_firmware_version_();
|
||||
int get_gate_threshold_(uint8_t gate);
|
||||
void get_reg_value_(uint16_t reg);
|
||||
|
@@ -6,7 +6,9 @@
|
||||
#ifdef USE_SENSOR
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#endif
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#define highbyte(val) (uint8_t)((val) >> 8)
|
||||
#define lowbyte(val) (uint8_t)((val) &0xff)
|
||||
@@ -96,11 +98,6 @@ static inline std::string get_direction(int16_t speed) {
|
||||
return STATIONARY;
|
||||
}
|
||||
|
||||
static inline std::string format_mac(uint8_t *buffer) {
|
||||
return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, buffer[10], buffer[11], buffer[12], buffer[13], buffer[14],
|
||||
buffer[15]);
|
||||
}
|
||||
|
||||
static inline std::string format_version(uint8_t *buffer) {
|
||||
return str_sprintf("%u.%02X.%02X%02X%02X%02X", buffer[13], buffer[12], buffer[17], buffer[16], buffer[15],
|
||||
buffer[14]);
|
||||
@@ -120,7 +117,7 @@ void LD2450Component::setup() {
|
||||
}
|
||||
|
||||
void LD2450Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "HLK-LD2450 Human motion tracking radar module:");
|
||||
ESP_LOGCONFIG(TAG, "LD2450:");
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
LOG_BINARY_SENSOR(" ", "TargetBinarySensor", this->target_binary_sensor_);
|
||||
LOG_BINARY_SENSOR(" ", "MovingTargetBinarySensor", this->moving_target_binary_sensor_);
|
||||
@@ -189,9 +186,9 @@ void LD2450Component::dump_config() {
|
||||
LOG_NUMBER(" ", "PresenceTimeoutNumber", this->presence_timeout_number_);
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Throttle : %ums\n"
|
||||
" MAC Address : %s\n"
|
||||
" Firmware version : %s",
|
||||
" Throttle: %ums\n"
|
||||
" MAC Address: %s\n"
|
||||
" Firmware version: %s",
|
||||
this->throttle_, const_cast<char *>(this->mac_.c_str()), const_cast<char *>(this->version_.c_str()));
|
||||
}
|
||||
|
||||
@@ -266,8 +263,7 @@ bool LD2450Component::get_timeout_status_(uint32_t check_millis) {
|
||||
if (this->timeout_ == 0) {
|
||||
this->timeout_ = ld2450::convert_seconds_to_ms(DEFAULT_PRESENCE_TIMEOUT);
|
||||
}
|
||||
auto current_millis = millis();
|
||||
return current_millis - check_millis >= this->timeout_;
|
||||
return App.get_loop_component_start_time() - check_millis >= this->timeout_;
|
||||
}
|
||||
|
||||
// Extract, store and publish zone details LD2450 buffer
|
||||
@@ -354,25 +350,24 @@ void LD2450Component::send_command_(uint8_t command, const uint8_t *command_valu
|
||||
// Header Target 1 Target 2 Target 3 End
|
||||
void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
|
||||
if (len < 29) { // header (4 bytes) + 8 x 3 target data + footer (2 bytes)
|
||||
ESP_LOGE(TAG, "Periodic data: invalid message length");
|
||||
ESP_LOGE(TAG, "Invalid message length");
|
||||
return;
|
||||
}
|
||||
if (buffer[0] != 0xAA || buffer[1] != 0xFF || buffer[2] != 0x03 || buffer[3] != 0x00) { // header
|
||||
ESP_LOGE(TAG, "Periodic data: invalid message header");
|
||||
ESP_LOGE(TAG, "Invalid message header");
|
||||
return;
|
||||
}
|
||||
if (buffer[len - 2] != 0x55 || buffer[len - 1] != 0xCC) { // footer
|
||||
ESP_LOGE(TAG, "Periodic data: invalid message footer");
|
||||
ESP_LOGE(TAG, "Invalid message footer");
|
||||
return;
|
||||
}
|
||||
|
||||
auto current_millis = millis();
|
||||
if (current_millis - this->last_periodic_millis_ < this->throttle_) {
|
||||
if (App.get_loop_component_start_time() - this->last_periodic_millis_ < this->throttle_) {
|
||||
ESP_LOGV(TAG, "Throttling: %d", this->throttle_);
|
||||
return;
|
||||
}
|
||||
|
||||
this->last_periodic_millis_ = current_millis;
|
||||
this->last_periodic_millis_ = App.get_loop_component_start_time();
|
||||
|
||||
int16_t target_count = 0;
|
||||
int16_t still_target_count = 0;
|
||||
@@ -555,13 +550,13 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
|
||||
#ifdef USE_SENSOR
|
||||
// For presence timeout check
|
||||
if (target_count > 0) {
|
||||
this->presence_millis_ = millis();
|
||||
this->presence_millis_ = App.get_loop_component_start_time();
|
||||
}
|
||||
if (moving_target_count > 0) {
|
||||
this->moving_presence_millis_ = millis();
|
||||
this->moving_presence_millis_ = App.get_loop_component_start_time();
|
||||
}
|
||||
if (still_target_count > 0) {
|
||||
this->still_presence_millis_ = millis();
|
||||
this->still_presence_millis_ = App.get_loop_component_start_time();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -569,31 +564,31 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
|
||||
bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
ESP_LOGV(TAG, "Handling ack data for command %02X", buffer[COMMAND]);
|
||||
if (len < 10) {
|
||||
ESP_LOGE(TAG, "Ack data: invalid length");
|
||||
ESP_LOGE(TAG, "Invalid ack length");
|
||||
return true;
|
||||
}
|
||||
if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // frame header
|
||||
ESP_LOGE(TAG, "Ack data: invalid header (command %02X)", buffer[COMMAND]);
|
||||
ESP_LOGE(TAG, "Invalid ack header (command %02X)", buffer[COMMAND]);
|
||||
return true;
|
||||
}
|
||||
if (buffer[COMMAND_STATUS] != 0x01) {
|
||||
ESP_LOGE(TAG, "Ack data: invalid status");
|
||||
ESP_LOGE(TAG, "Invalid ack status");
|
||||
return true;
|
||||
}
|
||||
if (buffer[8] || buffer[9]) {
|
||||
ESP_LOGE(TAG, "Ack data: last buffer was %u, %u", buffer[8], buffer[9]);
|
||||
ESP_LOGE(TAG, "Last buffer was %u, %u", buffer[8], buffer[9]);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (buffer[COMMAND]) {
|
||||
case lowbyte(CMD_ENABLE_CONF):
|
||||
ESP_LOGV(TAG, "Got enable conf command");
|
||||
ESP_LOGV(TAG, "Enable conf command");
|
||||
break;
|
||||
case lowbyte(CMD_DISABLE_CONF):
|
||||
ESP_LOGV(TAG, "Got disable conf command");
|
||||
ESP_LOGV(TAG, "Disable conf command");
|
||||
break;
|
||||
case lowbyte(CMD_SET_BAUD_RATE):
|
||||
ESP_LOGV(TAG, "Got baud rate change command");
|
||||
ESP_LOGV(TAG, "Baud rate change command");
|
||||
#ifdef USE_SELECT
|
||||
if (this->baud_rate_select_ != nullptr) {
|
||||
ESP_LOGV(TAG, "Change baud rate to %s", this->baud_rate_select_->state.c_str());
|
||||
@@ -613,7 +608,7 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
if (len < 20) {
|
||||
return false;
|
||||
}
|
||||
this->mac_ = ld2450::format_mac(buffer);
|
||||
this->mac_ = format_mac_address_pretty(&buffer[10]);
|
||||
ESP_LOGV(TAG, "MAC address: %s", this->mac_.c_str());
|
||||
#ifdef USE_TEXT_SENSOR
|
||||
if (this->mac_text_sensor_ != nullptr) {
|
||||
@@ -622,15 +617,15 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
if (this->bluetooth_switch_ != nullptr) {
|
||||
this->bluetooth_switch_->publish_state(this->mac_ != NO_MAC);
|
||||
this->bluetooth_switch_->publish_state(this->mac_ != UNKNOWN_MAC);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case lowbyte(CMD_BLUETOOTH):
|
||||
ESP_LOGV(TAG, "Got Bluetooth command");
|
||||
ESP_LOGV(TAG, "Bluetooth command");
|
||||
break;
|
||||
case lowbyte(CMD_SINGLE_TARGET_MODE):
|
||||
ESP_LOGV(TAG, "Got single target conf command");
|
||||
ESP_LOGV(TAG, "Single target conf command");
|
||||
#ifdef USE_SWITCH
|
||||
if (this->multi_target_switch_ != nullptr) {
|
||||
this->multi_target_switch_->publish_state(false);
|
||||
@@ -638,7 +633,7 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
#endif
|
||||
break;
|
||||
case lowbyte(CMD_MULTI_TARGET_MODE):
|
||||
ESP_LOGV(TAG, "Got multi target conf command");
|
||||
ESP_LOGV(TAG, "Multi target conf command");
|
||||
#ifdef USE_SWITCH
|
||||
if (this->multi_target_switch_ != nullptr) {
|
||||
this->multi_target_switch_->publish_state(true);
|
||||
@@ -646,7 +641,7 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
#endif
|
||||
break;
|
||||
case lowbyte(CMD_QUERY_TARGET_MODE):
|
||||
ESP_LOGV(TAG, "Got query target tracking mode command");
|
||||
ESP_LOGV(TAG, "Query target tracking mode command");
|
||||
#ifdef USE_SWITCH
|
||||
if (this->multi_target_switch_ != nullptr) {
|
||||
this->multi_target_switch_->publish_state(buffer[10] == 0x02);
|
||||
@@ -654,7 +649,7 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
#endif
|
||||
break;
|
||||
case lowbyte(CMD_QUERY_ZONE):
|
||||
ESP_LOGV(TAG, "Got query zone conf command");
|
||||
ESP_LOGV(TAG, "Query zone conf command");
|
||||
this->zone_type_ = std::stoi(std::to_string(buffer[10]), nullptr, 16);
|
||||
this->publish_zone_type();
|
||||
#ifdef USE_SELECT
|
||||
@@ -674,7 +669,7 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
|
||||
this->process_zone_(buffer);
|
||||
break;
|
||||
case lowbyte(CMD_SET_ZONE):
|
||||
ESP_LOGV(TAG, "Got set zone conf command");
|
||||
ESP_LOGV(TAG, "Set zone conf command");
|
||||
this->query_zone_info();
|
||||
break;
|
||||
default:
|
||||
|
@@ -64,6 +64,14 @@ class ModbusDevice {
|
||||
this->parent_->send(this->address_, function, start_address, number_of_entities, payload_len, payload);
|
||||
}
|
||||
void send_raw(const std::vector<uint8_t> &payload) { this->parent_->send_raw(payload); }
|
||||
void send_error(uint8_t function_code, uint8_t exception_code) {
|
||||
std::vector<uint8_t> error_response;
|
||||
error_response.reserve(3);
|
||||
error_response.push_back(this->address_);
|
||||
error_response.push_back(function_code | 0x80);
|
||||
error_response.push_back(exception_code);
|
||||
this->send_raw(error_response);
|
||||
}
|
||||
// If more than one device is connected block sending a new command before a response is received
|
||||
bool waiting_for_response() { return parent_->waiting_for_response != 0; }
|
||||
|
||||
|
@@ -112,6 +112,22 @@ TYPE_REGISTER_MAP = {
|
||||
"FP32_R": 2,
|
||||
}
|
||||
|
||||
CPP_TYPE_REGISTER_MAP = {
|
||||
"RAW": cg.uint16,
|
||||
"U_WORD": cg.uint16,
|
||||
"S_WORD": cg.int16,
|
||||
"U_DWORD": cg.uint32,
|
||||
"U_DWORD_R": cg.uint32,
|
||||
"S_DWORD": cg.int32,
|
||||
"S_DWORD_R": cg.int32,
|
||||
"U_QWORD": cg.uint64,
|
||||
"U_QWORD_R": cg.uint64,
|
||||
"S_QWORD": cg.int64,
|
||||
"S_QWORD_R": cg.int64,
|
||||
"FP32": cg.float_,
|
||||
"FP32_R": cg.float_,
|
||||
}
|
||||
|
||||
ModbusCommandSentTrigger = modbus_controller_ns.class_(
|
||||
"ModbusCommandSentTrigger", automation.Trigger.template(cg.int_, cg.int_)
|
||||
)
|
||||
@@ -285,21 +301,24 @@ async def to_code(config):
|
||||
cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
|
||||
if CONF_SERVER_REGISTERS in config:
|
||||
for server_register in config[CONF_SERVER_REGISTERS]:
|
||||
server_register_var = cg.new_Pvariable(
|
||||
server_register[CONF_ID],
|
||||
server_register[CONF_ADDRESS],
|
||||
server_register[CONF_VALUE_TYPE],
|
||||
TYPE_REGISTER_MAP[server_register[CONF_VALUE_TYPE]],
|
||||
)
|
||||
cpp_type = CPP_TYPE_REGISTER_MAP[server_register[CONF_VALUE_TYPE]]
|
||||
cg.add(
|
||||
var.add_server_register(
|
||||
cg.new_Pvariable(
|
||||
server_register[CONF_ID],
|
||||
server_register[CONF_ADDRESS],
|
||||
server_register[CONF_VALUE_TYPE],
|
||||
TYPE_REGISTER_MAP[server_register[CONF_VALUE_TYPE]],
|
||||
await cg.process_lambda(
|
||||
server_register[CONF_READ_LAMBDA],
|
||||
[],
|
||||
return_type=cg.float_,
|
||||
),
|
||||
)
|
||||
server_register_var.set_read_lambda(
|
||||
cg.TemplateArguments(cpp_type),
|
||||
await cg.process_lambda(
|
||||
server_register[CONF_READ_LAMBDA],
|
||||
[(cg.uint16, "address")],
|
||||
return_type=cpp_type,
|
||||
),
|
||||
)
|
||||
)
|
||||
cg.add(var.add_server_register(server_register_var))
|
||||
await register_modbus_device(var, config)
|
||||
for conf in config.get(CONF_ON_COMMAND_SENT, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
|
@@ -117,12 +117,17 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
||||
bool found = false;
|
||||
for (auto *server_register : this->server_registers_) {
|
||||
if (server_register->address == current_address) {
|
||||
float value = server_register->read_lambda();
|
||||
if (!server_register->read_lambda) {
|
||||
break;
|
||||
}
|
||||
int64_t value = server_register->read_lambda();
|
||||
ESP_LOGD(TAG, "Matched register. Address: 0x%02X. Value type: %zu. Register count: %u. Value: %s.",
|
||||
server_register->address, static_cast<size_t>(server_register->value_type),
|
||||
server_register->register_count, server_register->format_value(value).c_str());
|
||||
|
||||
ESP_LOGD(TAG, "Matched register. Address: 0x%02X. Value type: %zu. Register count: %u. Value: %0.1f.",
|
||||
server_register->address, static_cast<uint8_t>(server_register->value_type),
|
||||
server_register->register_count, value);
|
||||
std::vector<uint16_t> payload = float_to_payload(value, server_register->value_type);
|
||||
std::vector<uint16_t> payload;
|
||||
payload.reserve(server_register->register_count * 2);
|
||||
number_to_payload(payload, value, server_register->value_type);
|
||||
sixteen_bit_response.insert(sixteen_bit_response.end(), payload.cbegin(), payload.cend());
|
||||
current_address += server_register->register_count;
|
||||
found = true;
|
||||
@@ -132,11 +137,7 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
||||
|
||||
if (!found) {
|
||||
ESP_LOGW(TAG, "Could not match any register to address %02X. Sending exception response.", current_address);
|
||||
std::vector<uint8_t> error_response;
|
||||
error_response.push_back(this->address_);
|
||||
error_response.push_back(0x81);
|
||||
error_response.push_back(0x02);
|
||||
this->send_raw(error_response);
|
||||
send_error(function_code, 0x02);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -63,6 +63,10 @@ enum class SensorValueType : uint8_t {
|
||||
FP32_R = 0xD
|
||||
};
|
||||
|
||||
inline bool value_type_is_float(SensorValueType v) {
|
||||
return v == SensorValueType::FP32 || v == SensorValueType::FP32_R;
|
||||
}
|
||||
|
||||
inline ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type) {
|
||||
switch (reg_type) {
|
||||
case ModbusRegisterType::COIL:
|
||||
@@ -253,18 +257,53 @@ class SensorItem {
|
||||
};
|
||||
|
||||
class ServerRegister {
|
||||
using ReadLambda = std::function<int64_t()>;
|
||||
|
||||
public:
|
||||
ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count,
|
||||
std::function<float()> read_lambda) {
|
||||
ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count) {
|
||||
this->address = address;
|
||||
this->value_type = value_type;
|
||||
this->register_count = register_count;
|
||||
this->read_lambda = std::move(read_lambda);
|
||||
}
|
||||
|
||||
template<typename T> void set_read_lambda(const std::function<T(uint16_t address)> &&user_read_lambda) {
|
||||
this->read_lambda = [this, user_read_lambda]() -> int64_t {
|
||||
T user_value = user_read_lambda(this->address);
|
||||
if constexpr (std::is_same_v<T, float>) {
|
||||
return bit_cast<uint32_t>(user_value);
|
||||
} else {
|
||||
return static_cast<int64_t>(user_value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Formats a raw value into a string representation based on the value type for debugging
|
||||
std::string format_value(int64_t value) const {
|
||||
switch (this->value_type) {
|
||||
case SensorValueType::U_WORD:
|
||||
case SensorValueType::U_DWORD:
|
||||
case SensorValueType::U_DWORD_R:
|
||||
case SensorValueType::U_QWORD:
|
||||
case SensorValueType::U_QWORD_R:
|
||||
return std::to_string(static_cast<uint64_t>(value));
|
||||
case SensorValueType::S_WORD:
|
||||
case SensorValueType::S_DWORD:
|
||||
case SensorValueType::S_DWORD_R:
|
||||
case SensorValueType::S_QWORD:
|
||||
case SensorValueType::S_QWORD_R:
|
||||
return std::to_string(value);
|
||||
case SensorValueType::FP32_R:
|
||||
case SensorValueType::FP32:
|
||||
return str_sprintf("%.1f", bit_cast<float>(static_cast<uint32_t>(value)));
|
||||
default:
|
||||
return std::to_string(value);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t address{0};
|
||||
SensorValueType value_type{SensorValueType::RAW};
|
||||
uint8_t register_count{0};
|
||||
std::function<float()> read_lambda;
|
||||
ReadLambda read_lambda;
|
||||
};
|
||||
|
||||
// ModbusController::create_register_ranges_ tries to optimize register range
|
||||
@@ -444,7 +483,7 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
||||
void on_modbus_data(const std::vector<uint8_t> &data) override;
|
||||
/// called when a modbus error response was received
|
||||
void on_modbus_error(uint8_t function_code, uint8_t exception_code) override;
|
||||
/// called when a modbus request (function code 3 or 4) was parsed without errors
|
||||
/// called when a modbus request (function code 0x03 or 0x04) was parsed without errors
|
||||
void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers) final;
|
||||
/// default delegate called by process_modbus_data when a response has retrieved from the incoming queue
|
||||
void on_register_data(ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data);
|
||||
@@ -529,7 +568,7 @@ inline float payload_to_float(const std::vector<uint8_t> &data, const SensorItem
|
||||
int64_t number = payload_to_number(data, item.sensor_value_type, item.offset, item.bitmask);
|
||||
|
||||
float float_value;
|
||||
if (item.sensor_value_type == SensorValueType::FP32 || item.sensor_value_type == SensorValueType::FP32_R) {
|
||||
if (value_type_is_float(item.sensor_value_type)) {
|
||||
float_value = bit_cast<float>(static_cast<uint32_t>(number));
|
||||
} else {
|
||||
float_value = static_cast<float>(number);
|
||||
@@ -541,7 +580,7 @@ inline float payload_to_float(const std::vector<uint8_t> &data, const SensorItem
|
||||
inline std::vector<uint16_t> float_to_payload(float value, SensorValueType value_type) {
|
||||
int64_t val;
|
||||
|
||||
if (value_type == SensorValueType::FP32 || value_type == SensorValueType::FP32_R) {
|
||||
if (value_type_is_float(value_type)) {
|
||||
val = bit_cast<uint32_t>(value);
|
||||
} else {
|
||||
val = llroundf(value);
|
||||
|
@@ -17,7 +17,8 @@ enum class MQTTClientDisconnectReason : int8_t {
|
||||
MQTT_MALFORMED_CREDENTIALS = 4,
|
||||
MQTT_NOT_AUTHORIZED = 5,
|
||||
ESP8266_NOT_ENOUGH_SPACE = 6,
|
||||
TLS_BAD_FINGERPRINT = 7
|
||||
TLS_BAD_FINGERPRINT = 7,
|
||||
DNS_RESOLVE_ERROR = 8
|
||||
};
|
||||
|
||||
/// internal struct for MQTT messages.
|
||||
|
@@ -229,6 +229,8 @@ void MQTTClientComponent::check_dnslookup_() {
|
||||
if (this->dns_resolve_error_) {
|
||||
ESP_LOGW(TAG, "Couldn't resolve IP address for '%s'", this->credentials_.address.c_str());
|
||||
this->state_ = MQTT_CLIENT_DISCONNECTED;
|
||||
this->disconnect_reason_ = MQTTClientDisconnectReason::DNS_RESOLVE_ERROR;
|
||||
this->on_disconnect_.call(MQTTClientDisconnectReason::DNS_RESOLVE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -698,7 +700,9 @@ void MQTTClientComponent::set_on_connect(mqtt_on_connect_callback_t &&callback)
|
||||
}
|
||||
|
||||
void MQTTClientComponent::set_on_disconnect(mqtt_on_disconnect_callback_t &&callback) {
|
||||
auto callback_copy = callback;
|
||||
this->mqtt_backend_.set_on_disconnect(std::forward<mqtt_on_disconnect_callback_t>(callback));
|
||||
this->on_disconnect_.add(std::move(callback_copy));
|
||||
}
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "esphome/components/network/ip_address.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#if defined(USE_ESP32)
|
||||
#include "mqtt_backend_esp32.h"
|
||||
@@ -334,6 +335,7 @@ class MQTTClientComponent : public Component {
|
||||
uint32_t connect_begin_;
|
||||
uint32_t last_connected_{0};
|
||||
optional<MQTTClientDisconnectReason> disconnect_reason_{};
|
||||
CallbackManager<MQTTBackend::on_disconnect_callback_t> on_disconnect_;
|
||||
|
||||
bool publish_nan_as_none_{false};
|
||||
bool wait_for_connection_{false};
|
||||
|
@@ -23,16 +23,22 @@ std::string state_class_to_string(StateClass state_class) {
|
||||
Sensor::Sensor() : state(NAN), raw_state(NAN) {}
|
||||
|
||||
int8_t Sensor::get_accuracy_decimals() {
|
||||
if (this->accuracy_decimals_.has_value())
|
||||
return *this->accuracy_decimals_;
|
||||
if (this->sensor_flags_.has_accuracy_override)
|
||||
return this->accuracy_decimals_;
|
||||
return 0;
|
||||
}
|
||||
void Sensor::set_accuracy_decimals(int8_t accuracy_decimals) { this->accuracy_decimals_ = accuracy_decimals; }
|
||||
void Sensor::set_accuracy_decimals(int8_t accuracy_decimals) {
|
||||
this->accuracy_decimals_ = accuracy_decimals;
|
||||
this->sensor_flags_.has_accuracy_override = true;
|
||||
}
|
||||
|
||||
void Sensor::set_state_class(StateClass state_class) { this->state_class_ = state_class; }
|
||||
void Sensor::set_state_class(StateClass state_class) {
|
||||
this->state_class_ = state_class;
|
||||
this->sensor_flags_.has_state_class_override = true;
|
||||
}
|
||||
StateClass Sensor::get_state_class() {
|
||||
if (this->state_class_.has_value())
|
||||
return *this->state_class_;
|
||||
if (this->sensor_flags_.has_state_class_override)
|
||||
return this->state_class_;
|
||||
return StateClass::STATE_CLASS_NONE;
|
||||
}
|
||||
|
||||
|
@@ -80,9 +80,9 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
|
||||
* state changes to the database when they are published, even if the state is the
|
||||
* same as before.
|
||||
*/
|
||||
bool get_force_update() const { return force_update_; }
|
||||
bool get_force_update() const { return sensor_flags_.force_update; }
|
||||
/// Set force update mode.
|
||||
void set_force_update(bool force_update) { force_update_ = force_update; }
|
||||
void set_force_update(bool force_update) { sensor_flags_.force_update = force_update; }
|
||||
|
||||
/// Add a filter to the filter chain. Will be appended to the back.
|
||||
void add_filter(Filter *filter);
|
||||
@@ -155,9 +155,17 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa
|
||||
|
||||
Filter *filter_list_{nullptr}; ///< Store all active filters.
|
||||
|
||||
optional<int8_t> accuracy_decimals_; ///< Accuracy in decimals override
|
||||
optional<StateClass> state_class_{STATE_CLASS_NONE}; ///< State class override
|
||||
bool force_update_{false}; ///< Force update mode
|
||||
// Group small members together to avoid padding
|
||||
int8_t accuracy_decimals_{-1}; ///< Accuracy in decimals (-1 = not set)
|
||||
StateClass state_class_{STATE_CLASS_NONE}; ///< State class (STATE_CLASS_NONE = not set)
|
||||
|
||||
// Bit-packed flags for sensor-specific settings
|
||||
struct SensorFlags {
|
||||
uint8_t has_accuracy_override : 1;
|
||||
uint8_t has_state_class_override : 1;
|
||||
uint8_t force_update : 1;
|
||||
uint8_t reserved : 5; // Reserved for future use
|
||||
} sensor_flags_{};
|
||||
};
|
||||
|
||||
} // namespace sensor
|
||||
|
@@ -741,11 +741,6 @@ void WiFiComponent::set_power_save_mode(WiFiPowerSaveMode power_save) { this->po
|
||||
|
||||
void WiFiComponent::set_passive_scan(bool passive) { this->passive_scan_ = passive; }
|
||||
|
||||
std::string WiFiComponent::format_mac_addr(const uint8_t *mac) {
|
||||
char buf[20];
|
||||
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return buf;
|
||||
}
|
||||
bool WiFiComponent::is_captive_portal_active_() {
|
||||
#ifdef USE_CAPTIVE_PORTAL
|
||||
return captive_portal::global_captive_portal != nullptr && captive_portal::global_captive_portal->is_active();
|
||||
|
@@ -321,8 +321,6 @@ class WiFiComponent : public Component {
|
||||
int32_t get_wifi_channel();
|
||||
|
||||
protected:
|
||||
static std::string format_mac_addr(const uint8_t mac[6]);
|
||||
|
||||
#ifdef USE_WIFI_AP
|
||||
void setup_ap_config_();
|
||||
#endif // USE_WIFI_AP
|
||||
|
@@ -550,7 +550,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||
format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
#if USE_NETWORK_IPV6
|
||||
this->set_timeout(100, [] { WiFi.enableIPv6(); });
|
||||
#endif /* USE_NETWORK_IPV6 */
|
||||
@@ -566,7 +566,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf,
|
||||
format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
|
||||
format_mac_address_pretty(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
|
||||
}
|
||||
|
||||
uint8_t reason = it.reason;
|
||||
@@ -636,13 +636,13 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_STACONNECTED: {
|
||||
auto it = info.wifi_sta_connected;
|
||||
auto &mac = it.bssid;
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_addr(mac).c_str());
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_address_pretty(mac).c_str());
|
||||
break;
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_STADISCONNECTED: {
|
||||
auto it = info.wifi_sta_disconnected;
|
||||
auto &mac = it.bssid;
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_addr(mac).c_str());
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_address_pretty(mac).c_str());
|
||||
break;
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_STAIPASSIGNED: {
|
||||
@@ -651,7 +651,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_PROBEREQRECVED: {
|
||||
auto it = info.wifi_ap_probereqrecved;
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi);
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_address_pretty(it.mac).c_str(), it.rssi);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@@ -496,7 +496,8 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
char buf[33];
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=%s channel=%u", buf, format_mac_addr(it.bssid).c_str(), it.channel);
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=%s channel=%u", buf, format_mac_address_pretty(it.bssid).c_str(),
|
||||
it.channel);
|
||||
s_sta_connected = true;
|
||||
break;
|
||||
}
|
||||
@@ -510,7 +511,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
s_sta_connect_not_found = true;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf,
|
||||
format_mac_addr(it.bssid).c_str(), LOG_STR_ARG(get_disconnect_reason_str(it.reason)));
|
||||
format_mac_address_pretty(it.bssid).c_str(), LOG_STR_ARG(get_disconnect_reason_str(it.reason)));
|
||||
s_sta_connect_error = true;
|
||||
}
|
||||
s_sta_connected = false;
|
||||
@@ -545,17 +546,17 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
}
|
||||
case EVENT_SOFTAPMODE_STACONNECTED: {
|
||||
auto it = event->event_info.sta_connected;
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s aid=%u", format_mac_addr(it.mac).c_str(), it.aid);
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s aid=%u", format_mac_address_pretty(it.mac).c_str(), it.aid);
|
||||
break;
|
||||
}
|
||||
case EVENT_SOFTAPMODE_STADISCONNECTED: {
|
||||
auto it = event->event_info.sta_disconnected;
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s aid=%u", format_mac_addr(it.mac).c_str(), it.aid);
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s aid=%u", format_mac_address_pretty(it.mac).c_str(), it.aid);
|
||||
break;
|
||||
}
|
||||
case EVENT_SOFTAPMODE_PROBEREQRECVED: {
|
||||
auto it = event->event_info.ap_probereqrecved;
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi);
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_address_pretty(it.mac).c_str(), it.rssi);
|
||||
break;
|
||||
}
|
||||
#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 4, 0)
|
||||
@@ -567,7 +568,7 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
}
|
||||
case EVENT_SOFTAPMODE_DISTRIBUTE_STA_IP: {
|
||||
auto it = event->event_info.distribute_sta_ip;
|
||||
ESP_LOGV(TAG, "AP Distribute Station IP MAC=%s IP=%s aid=%u", format_mac_addr(it.mac).c_str(),
|
||||
ESP_LOGV(TAG, "AP Distribute Station IP MAC=%s IP=%s aid=%u", format_mac_address_pretty(it.mac).c_str(),
|
||||
format_ip_addr(it.ip).c_str(), it.aid);
|
||||
break;
|
||||
}
|
||||
|
@@ -691,7 +691,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||
format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
s_sta_connected = true;
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
@@ -708,7 +708,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf,
|
||||
format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
|
||||
format_mac_address_pretty(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
|
||||
s_sta_connect_error = true;
|
||||
}
|
||||
s_sta_connected = false;
|
||||
@@ -780,15 +780,15 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_PROBEREQRECVED) {
|
||||
const auto &it = data->data.ap_probe_req_rx;
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi);
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_address_pretty(it.mac).c_str(), it.rssi);
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_STACONNECTED) {
|
||||
const auto &it = data->data.ap_staconnected;
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_addr(it.mac).c_str());
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_address_pretty(it.mac).c_str());
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
||||
const auto &it = data->data.ap_stadisconnected;
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_addr(it.mac).c_str());
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_address_pretty(it.mac).c_str());
|
||||
|
||||
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_AP_STAIPASSIGNED) {
|
||||
const auto &it = data->data.ip_ap_staipassigned;
|
||||
|
@@ -281,7 +281,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||
format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -294,7 +294,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf,
|
||||
format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
|
||||
format_mac_address_pretty(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
|
||||
}
|
||||
|
||||
uint8_t reason = it.reason;
|
||||
@@ -349,13 +349,13 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_STACONNECTED: {
|
||||
auto it = info.wifi_sta_connected;
|
||||
auto &mac = it.bssid;
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_addr(mac).c_str());
|
||||
ESP_LOGV(TAG, "AP client connected MAC=%s", format_mac_address_pretty(mac).c_str());
|
||||
break;
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_STADISCONNECTED: {
|
||||
auto it = info.wifi_sta_disconnected;
|
||||
auto &mac = it.bssid;
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_addr(mac).c_str());
|
||||
ESP_LOGV(TAG, "AP client disconnected MAC=%s", format_mac_address_pretty(mac).c_str());
|
||||
break;
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_STAIPASSIGNED: {
|
||||
@@ -364,7 +364,7 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_AP_PROBEREQRECVED: {
|
||||
auto it = info.wifi_ap_probereqrecved;
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_addr(it.mac).c_str(), it.rssi);
|
||||
ESP_LOGVV(TAG, "AP receive Probe Request MAC=%s RSSI=%d", format_mac_address_pretty(it.mac).c_str(), it.rssi);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@@ -320,7 +320,7 @@ bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, c
|
||||
memcpy(mac_address + 4, mac_reverse + 1, 1);
|
||||
memcpy(mac_address + 5, mac_reverse, 1);
|
||||
ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): authenticated decryption failed.");
|
||||
ESP_LOGVV(TAG, " MAC address : %s", format_hex_pretty(mac_address, 6).c_str());
|
||||
ESP_LOGVV(TAG, " MAC address : %s", format_mac_address_pretty(mac_address).c_str());
|
||||
ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty(raw.data(), raw.size()).c_str());
|
||||
ESP_LOGVV(TAG, " Key : %s", format_hex_pretty(vector.key, vector.keysize).c_str());
|
||||
ESP_LOGVV(TAG, " Iv : %s", format_hex_pretty(vector.iv, vector.ivsize).c_str());
|
||||
|
@@ -1099,7 +1099,7 @@ UNIT_KILOMETER_PER_HOUR = "km/h"
|
||||
UNIT_KILOVOLT_AMPS = "kVA"
|
||||
UNIT_KILOVOLT_AMPS_HOURS = "kVAh"
|
||||
UNIT_KILOVOLT_AMPS_REACTIVE = "kVAR"
|
||||
UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kVARh"
|
||||
UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kvarh"
|
||||
UNIT_KILOWATT = "kW"
|
||||
UNIT_KILOWATT_HOURS = "kWh"
|
||||
UNIT_LITRE = "L"
|
||||
@@ -1135,7 +1135,7 @@ UNIT_VOLT = "V"
|
||||
UNIT_VOLT_AMPS = "VA"
|
||||
UNIT_VOLT_AMPS_HOURS = "VAh"
|
||||
UNIT_VOLT_AMPS_REACTIVE = "var"
|
||||
UNIT_VOLT_AMPS_REACTIVE_HOURS = "VARh"
|
||||
UNIT_VOLT_AMPS_REACTIVE_HOURS = "varh"
|
||||
UNIT_WATT = "W"
|
||||
UNIT_WATT_HOURS = "Wh"
|
||||
|
||||
|
@@ -356,6 +356,10 @@ size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count) {
|
||||
return chars;
|
||||
}
|
||||
|
||||
std::string format_mac_address_pretty(const uint8_t *mac) {
|
||||
return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
static char format_hex_char(uint8_t v) { return v >= 10 ? 'a' + (v - 10) : '0' + v; }
|
||||
std::string format_hex(const uint8_t *data, size_t length) {
|
||||
std::string ret;
|
||||
@@ -732,7 +736,7 @@ std::string get_mac_address() {
|
||||
std::string get_mac_address_pretty() {
|
||||
uint8_t mac[6];
|
||||
get_mac_address_raw(mac);
|
||||
return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return format_mac_address_pretty(mac);
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
@@ -402,6 +402,8 @@ template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> optional<
|
||||
return parse_hex<T>(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
/// Format the six-byte array \p mac into a MAC address.
|
||||
std::string format_mac_address_pretty(const uint8_t mac[6]);
|
||||
/// Format the byte array \p data of length \p len in lowercased hex.
|
||||
std::string format_hex(const uint8_t *data, size_t length);
|
||||
/// Format the vector \p data in lowercased hex.
|
||||
|
@@ -4,6 +4,31 @@ binary_sensor:
|
||||
id: some_binary_sensor
|
||||
name: "Random binary"
|
||||
lambda: return (random_uint32() & 1) == 0;
|
||||
filters:
|
||||
- invert:
|
||||
- delayed_on: 100ms
|
||||
- delayed_off: 100ms
|
||||
# Templated, delays for 1s (1000ms) only if a reed switch is active
|
||||
- delayed_on_off: !lambda "return 1000;"
|
||||
- delayed_on_off:
|
||||
time_on: 10s
|
||||
time_off: !lambda "return 1000;"
|
||||
- autorepeat:
|
||||
- delay: 1s
|
||||
time_off: 100ms
|
||||
time_on: 900ms
|
||||
- delay: 5s
|
||||
time_off: 100ms
|
||||
time_on: 400ms
|
||||
- lambda: |-
|
||||
if (id(some_binary_sensor).state) {
|
||||
return x;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
- settle: 100ms
|
||||
- timeout: 10s
|
||||
|
||||
on_state_change:
|
||||
then:
|
||||
- logger.log:
|
||||
|
@@ -8,5 +8,8 @@ sensor:
|
||||
name: Test Sensor
|
||||
id: test_sensor
|
||||
unit_of_measurement: °C
|
||||
accuracy_decimals: 2
|
||||
state_class: measurement
|
||||
force_update: true
|
||||
lambda: return 42.0;
|
||||
update_interval: 0.1s
|
||||
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
import aioesphomeapi
|
||||
from aioesphomeapi import EntityState
|
||||
import pytest
|
||||
|
||||
@@ -47,3 +48,23 @@ async def test_host_mode_with_sensor(
|
||||
# Verify the sensor state
|
||||
assert test_sensor_state.state == 42.0
|
||||
assert len(states) > 0, "No states received"
|
||||
|
||||
# Verify the optimized fields are working correctly
|
||||
# Get entity info to check accuracy_decimals, state_class, etc.
|
||||
entities, _ = await client.list_entities_services()
|
||||
sensor_info: aioesphomeapi.SensorInfo | None = None
|
||||
for entity in entities:
|
||||
if isinstance(entity, aioesphomeapi.SensorInfo):
|
||||
sensor_info = entity
|
||||
break
|
||||
|
||||
assert sensor_info is not None, "Sensor entity info not found"
|
||||
assert sensor_info.accuracy_decimals == 2, (
|
||||
f"Expected accuracy_decimals=2, got {sensor_info.accuracy_decimals}"
|
||||
)
|
||||
assert sensor_info.state_class == aioesphomeapi.StateClass.MEASUREMENT, (
|
||||
f"Expected state_class=StateClass.MEASUREMENT, got {sensor_info.state_class}"
|
||||
)
|
||||
assert sensor_info.force_update is True, (
|
||||
f"Expected force_update=True, got {sensor_info.force_update}"
|
||||
)
|
||||
|
Reference in New Issue
Block a user