mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 18:22:48 +00:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a70f565a22 | ||
|
|
1e45d1893c | ||
|
|
c4c19a00e0 | ||
|
|
0f8d26e1dd | ||
|
|
522395de11 | ||
|
|
39d63a3166 | ||
|
|
36cfe5c785 | ||
|
|
d8dd8cf36c | ||
|
|
12c35c1545 | ||
|
|
0e8a3dfb6f | ||
|
|
00f8e89f28 | ||
|
|
8acf885241 | ||
|
|
f829447b2e | ||
|
|
74e96b7da6 | ||
|
|
753c10e5ea | ||
|
|
5326d1dfe9 | ||
|
|
ba9705e19b | ||
|
|
543a818307 | ||
|
|
b31bedd464 | ||
|
|
c8d331d44b | ||
|
|
62f79e007a | ||
|
|
b989221c71 | ||
|
|
096921cddb | ||
|
|
e3d33df379 | ||
|
|
c263852df9 | ||
|
|
7c58d26d13 | ||
|
|
88f7fc7454 | ||
|
|
140488723d | ||
|
|
b626711d50 | ||
|
|
a6cb560e90 | ||
|
|
a721574706 | ||
|
|
568934cc91 | ||
|
|
13057b7ae3 | ||
|
|
b4289aee59 | ||
|
|
93aecdd435 | ||
|
|
afac871938 | ||
|
|
4c6e6b5447 | ||
|
|
b5c06efb2f | ||
|
|
5cbdf26993 | ||
|
|
6f5108eb70 | ||
|
|
4ef86fe534 |
@@ -106,6 +106,7 @@ esphome/components/bp1658cj/* @Cossid
|
||||
esphome/components/bp5758d/* @Cossid
|
||||
esphome/components/bq25186/* @Rapsssito
|
||||
esphome/components/bq27220/* @rggammon
|
||||
esphome/components/bq76972/* @limpkin
|
||||
esphome/components/bridge/* @kbx81
|
||||
esphome/components/bthome_mithermometer/* @nagyrobi
|
||||
esphome/components/button/* @esphome/core
|
||||
|
||||
@@ -10,7 +10,7 @@ void AbsoluteHumidityComponent::setup() {
|
||||
this->temperature_ = state;
|
||||
this->enable_loop();
|
||||
});
|
||||
ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
|
||||
ESP_LOGD(TAG, " Added callback for temperature '%s'", LOG_STR_ARG(this->temperature_sensor_->get_log_name()));
|
||||
// Get initial value
|
||||
if (this->temperature_sensor_->has_state()) {
|
||||
this->temperature_ = this->temperature_sensor_->get_state();
|
||||
@@ -20,7 +20,7 @@ void AbsoluteHumidityComponent::setup() {
|
||||
this->humidity_ = state;
|
||||
this->enable_loop();
|
||||
});
|
||||
ESP_LOGD(TAG, " Added callback for relative humidity '%s'", this->humidity_sensor_->get_name().c_str());
|
||||
ESP_LOGD(TAG, " Added callback for relative humidity '%s'", LOG_STR_ARG(this->humidity_sensor_->get_log_name()));
|
||||
// Get initial value
|
||||
if (this->humidity_sensor_->has_state()) {
|
||||
this->humidity_ = this->humidity_sensor_->get_state();
|
||||
@@ -49,7 +49,8 @@ void AbsoluteHumidityComponent::dump_config() {
|
||||
"Sources\n"
|
||||
" Temperature: '%s'\n"
|
||||
" Relative Humidity: '%s'",
|
||||
this->temperature_sensor_->get_name().c_str(), this->humidity_sensor_->get_name().c_str());
|
||||
LOG_STR_ARG(this->temperature_sensor_->get_log_name()),
|
||||
LOG_STR_ARG(this->humidity_sensor_->get_log_name()));
|
||||
}
|
||||
|
||||
void AbsoluteHumidityComponent::loop() {
|
||||
|
||||
@@ -66,7 +66,7 @@ template class Aggregator<uint32_t>;
|
||||
|
||||
void ADCSensor::update() {
|
||||
float value_v = this->sample();
|
||||
ESP_LOGV(TAG, "'%s': Voltage=%.4fV", this->get_name().c_str(), value_v);
|
||||
ESP_LOGV(TAG, "'%s': Voltage=%.4fV", LOG_STR_ARG(this->get_log_name()), value_v);
|
||||
this->publish_state(value_v);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ float ADS1115Sensor::sample() {
|
||||
void ADS1115Sensor::update() {
|
||||
float v = this->sample();
|
||||
if (!std::isnan(v)) {
|
||||
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
|
||||
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", LOG_STR_ARG(this->get_log_name()), v);
|
||||
this->publish_state(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ float ADS1118Sensor::sample() {
|
||||
void ADS1118Sensor::update() {
|
||||
float v = this->sample();
|
||||
if (!std::isnan(v)) {
|
||||
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v);
|
||||
ESP_LOGD(TAG, "'%s': Got Voltage=%fV", LOG_STR_ARG(this->get_log_name()), v);
|
||||
this->publish_state(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) {
|
||||
this->last_update_ = millis();
|
||||
if (state != this->current_state_) {
|
||||
auto prev_state = this->current_state_;
|
||||
ESP_LOGV(TAG, "'%s' >> %s (was %s)", this->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "'%s' >> %s (was %s)", LOG_STR_ARG(this->get_log_name()),
|
||||
LOG_STR_ARG(alarm_control_panel_state_to_string(state)),
|
||||
LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state)));
|
||||
this->current_state_ = state;
|
||||
|
||||
@@ -30,9 +30,9 @@ void Am43Component::loop() {
|
||||
auto status =
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
ESP_LOGI(TAG, "[%s] Logging into AM43", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "[%s] Logging into AM43", LOG_STR_ARG(this->get_log_name()));
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_pin to device, error = %d", LOG_STR_ARG(this->get_log_name()), status);
|
||||
} else {
|
||||
this->logged_in_ = true;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ CoverTraits Am43Component::get_traits() {
|
||||
|
||||
void Am43Component::control(const CoverCall &call) {
|
||||
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot send cover control, not connected", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Cannot send cover control, not connected", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
if (call.get_stop()) {
|
||||
@@ -59,7 +59,7 @@ void Am43Component::control(const CoverCall &call) {
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", LOG_STR_ARG(this->get_log_name()), status);
|
||||
}
|
||||
}
|
||||
auto opt_pos = call.get_position();
|
||||
@@ -73,7 +73,8 @@ void Am43Component::control(const CoverCall &call) {
|
||||
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
|
||||
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", LOG_STR_ARG(this->get_log_name()),
|
||||
status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,9 +90,9 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
|
||||
if (chr == nullptr) {
|
||||
if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) {
|
||||
ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->get_name().c_str());
|
||||
ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", LOG_STR_ARG(this->get_log_name()));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?", this->get_name().c_str());
|
||||
ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -100,7 +101,8 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
|
||||
chr->handle);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", LOG_STR_ARG(this->get_log_name()),
|
||||
status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -126,25 +128,26 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
|
||||
if (this->decoder_->has_pin_response()) {
|
||||
if (this->decoder_->pin_ok_) {
|
||||
ESP_LOGI(TAG, "[%s] AM43 pin accepted.", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "[%s] AM43 pin accepted.", LOG_STR_ARG(this->get_log_name()));
|
||||
auto *packet = this->encoder_->get_position_request();
|
||||
auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||
this->char_handle_, packet->length, packet->data,
|
||||
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", LOG_STR_ARG(this->get_log_name()),
|
||||
status);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] AM43 pin rejected!", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
}
|
||||
|
||||
if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) {
|
||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
|
||||
if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) {
|
||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -67,8 +67,9 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
|
||||
if (chr == nullptr) {
|
||||
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", LOG_STR_ARG(this->get_log_name()));
|
||||
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
break;
|
||||
}
|
||||
this->char_handle_ = chr->handle;
|
||||
@@ -76,7 +77,8 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
|
||||
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
|
||||
chr->handle);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", LOG_STR_ARG(this->get_log_name()),
|
||||
status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -251,6 +251,9 @@ def _validate_supports_response(value: Any) -> str:
|
||||
return cv.enum(SUPPORTS_RESPONSE_OPTIONS, lower=True)(value)
|
||||
|
||||
|
||||
# ESP8266 copies every string of an action into a stack buffer sized by codegen; keep it small
|
||||
ESP8266_ACTION_STRINGS_MAX_TOTAL = 384
|
||||
|
||||
VARIABLE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_TYPE): cv.one_of(*SERVICE_ARG_NATIVE_TYPES, lower=True),
|
||||
@@ -481,6 +484,29 @@ def _action_strings(conf: ConfigType, has_metadata: bool) -> list[str | None]:
|
||||
return strings
|
||||
|
||||
|
||||
def _action_strings_size(strings: list[str | None]) -> int:
|
||||
"""Bytes needed to copy every string out of flash, each with its terminator."""
|
||||
return sum(
|
||||
len(string.encode("utf-8")) + 1 for string in strings if string is not None
|
||||
)
|
||||
|
||||
|
||||
def _validate_esp8266_action_strings(config: ConfigType) -> ConfigType:
|
||||
if not CORE.is_esp8266:
|
||||
return config
|
||||
actions = config.get(CONF_ACTIONS, [])
|
||||
has_metadata = _has_action_metadata(actions)
|
||||
for conf in actions:
|
||||
size = _action_strings_size(_action_strings(conf, has_metadata))
|
||||
if size > ESP8266_ACTION_STRINGS_MAX_TOTAL:
|
||||
raise cv.Invalid(
|
||||
f"Action '{conf[CONF_ACTION]}' has {size} bytes of name, variable name, "
|
||||
f"description and example text; ESP8266 allows at most "
|
||||
f"{ESP8266_ACTION_STRINGS_MAX_TOTAL} bytes per action"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def _validate_outgoing_host_ipv6(config: ConfigType) -> ConfigType:
|
||||
"""An IPv6 host can never be parsed, so never dialed, without IPv6."""
|
||||
if (
|
||||
@@ -505,6 +531,7 @@ def _validate_wizard(config: ConfigType) -> ConfigType:
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||
_validate_esp8266_action_strings,
|
||||
_validate_outgoing_host_ipv6,
|
||||
_validate_wizard,
|
||||
)
|
||||
@@ -560,6 +587,7 @@ async def to_code(config: ConfigType) -> None:
|
||||
if config[CONF_HOMEASSISTANT_STATES]:
|
||||
cg.add_define("USE_API_HOMEASSISTANT_STATES")
|
||||
|
||||
scratch_size = 0
|
||||
if actions:
|
||||
# Metadata is compiled in for every action once any action declares it, because the
|
||||
# string table layout is fixed by the define rather than per action
|
||||
@@ -611,6 +639,8 @@ async def to_code(config: ConfigType) -> None:
|
||||
func_args.append((native, name))
|
||||
strings = _action_strings(conf, has_metadata)
|
||||
table = _add_action_strings(index, strings)
|
||||
if CORE.is_esp8266:
|
||||
scratch_size = max(scratch_size, _action_strings_size(strings))
|
||||
# Template args: supports_response mode, then user service arg types
|
||||
templ = cg.TemplateArguments(supports_response, *service_template_args)
|
||||
# Key is hashed here because the name is not readable at runtime on ESP8266
|
||||
@@ -637,6 +667,9 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add(auto.add_action(unregister_action))
|
||||
# Register all services at once - single allocation, no reallocations
|
||||
cg.add(var.initialize_user_services(triggers))
|
||||
if CORE.is_esp8266 and has_user_actions:
|
||||
# Stack buffer that list-entities copies PROGMEM strings into, sized for the largest action
|
||||
cg.add_define("API_USER_ACTION_STRINGS_SCRATCH_SIZE", max(scratch_size, 1))
|
||||
|
||||
if (wizard_config := config.get(wizard.CONF_WIZARD)) is not None:
|
||||
await wizard.to_code(wizard_config)
|
||||
|
||||
@@ -552,7 +552,7 @@ message ListEntitiesBinarySensorResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string device_class = 5 [(max_data_length) = 47];
|
||||
@@ -586,7 +586,7 @@ message ListEntitiesCoverResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
bool assumed_state = 5;
|
||||
@@ -670,7 +670,7 @@ message ListEntitiesFanResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
bool supports_oscillation = 5;
|
||||
@@ -758,7 +758,7 @@ message ListEntitiesLightResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
repeated ColorMode supported_color_modes = 12 [(container_pointer_no_template) = "light::ColorModeMask"];
|
||||
@@ -863,7 +863,7 @@ message ListEntitiesSensorResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -904,7 +904,7 @@ message ListEntitiesSwitchResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -949,7 +949,7 @@ message ListEntitiesTextSensorResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1157,21 +1157,21 @@ enum SupportsResponseType {
|
||||
}
|
||||
message ListEntitiesServicesArgument {
|
||||
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
|
||||
string name = 1 [(progmem) = true];
|
||||
string name = 1;
|
||||
ServiceArgType type = 2;
|
||||
string description = 3 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_METADATA", (progmem) = true];
|
||||
string example = 4 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_METADATA", (progmem) = true];
|
||||
string description = 3 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_METADATA"];
|
||||
string example = 4 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_METADATA"];
|
||||
}
|
||||
message ListEntitiesServicesResponse {
|
||||
option (id) = 41;
|
||||
option (source) = SOURCE_SERVER;
|
||||
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
|
||||
|
||||
string name = 1 [(progmem) = true];
|
||||
string name = 1;
|
||||
fixed32 key = 2 [(force) = true];
|
||||
repeated ListEntitiesServicesArgument args = 3 [(fixed_vector) = true];
|
||||
SupportsResponseType supports_response = 4;
|
||||
string description = 5 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_METADATA", (progmem) = true];
|
||||
string description = 5 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_METADATA"];
|
||||
}
|
||||
message ExecuteServiceArgument {
|
||||
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
|
||||
@@ -1220,7 +1220,7 @@ message ListEntitiesCameraResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
bool disabled_by_default = 5;
|
||||
string icon = 6 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1312,7 +1312,7 @@ message ListEntitiesClimateResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
bool supports_current_temperature = 5; // Deprecated: use feature_flags
|
||||
@@ -1427,7 +1427,7 @@ message ListEntitiesWaterHeaterResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
bool disabled_by_default = 5;
|
||||
EntityCategory entity_category = 6;
|
||||
@@ -1507,7 +1507,7 @@ message ListEntitiesNumberResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1556,7 +1556,7 @@ message ListEntitiesSelectResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1600,7 +1600,7 @@ message ListEntitiesSirenResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1665,7 +1665,7 @@ message ListEntitiesLockResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1714,7 +1714,7 @@ message ListEntitiesButtonResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -1781,7 +1781,7 @@ message ListEntitiesMediaPlayerResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2373,7 +2373,7 @@ message ListEntitiesAlarmControlPanelResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
bool disabled_by_default = 6;
|
||||
@@ -2420,7 +2420,7 @@ message ListEntitiesTextResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
bool disabled_by_default = 6;
|
||||
@@ -2468,7 +2468,7 @@ message ListEntitiesDateResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2515,7 +2515,7 @@ message ListEntitiesTimeResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2562,7 +2562,7 @@ message ListEntitiesEventResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2593,7 +2593,7 @@ message ListEntitiesValveResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2648,7 +2648,7 @@ message ListEntitiesDateTimeResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2691,7 +2691,7 @@ message ListEntitiesUpdateResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
reserved 4; // Deprecated: was string unique_id
|
||||
|
||||
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
@@ -2791,7 +2791,7 @@ message ListEntitiesInfraredResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
bool disabled_by_default = 5;
|
||||
EntityCategory entity_category = 6;
|
||||
@@ -2860,7 +2860,7 @@ message ListEntitiesRadioFrequencyResponse {
|
||||
|
||||
string object_id = 1 [(max_data_length) = 120, (force) = true];
|
||||
fixed32 key = 2 [(force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true];
|
||||
string name = 3 [(max_data_length) = 120, (force) = true, (progmem) = true];
|
||||
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON", (max_data_length) = 63];
|
||||
bool disabled_by_default = 5;
|
||||
EntityCategory entity_category = 6;
|
||||
|
||||
@@ -474,7 +474,7 @@ uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResp
|
||||
msg.key = entity->get_object_id_hash();
|
||||
|
||||
if (entity->has_own_name()) {
|
||||
msg.name = entity->get_name();
|
||||
msg.name = entity->get_name_progmem();
|
||||
}
|
||||
|
||||
// Set common EntityBase properties
|
||||
|
||||
@@ -401,7 +401,7 @@ uint8_t *ListEntitiesBinarySensorResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesBinarySensorResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.device_class);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 6, msg.is_status_binary_sensor);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 7, msg.disabled_by_default);
|
||||
@@ -459,7 +459,7 @@ uint8_t *ListEntitiesCoverResponse::encode_msg(const void *self, uint8_t *__rest
|
||||
const auto &msg = *static_cast<const ListEntitiesCoverResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.assumed_state);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 6, msg.supports_position);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 7, msg.supports_tilt);
|
||||
@@ -558,7 +558,7 @@ uint8_t *ListEntitiesFanResponse::encode_msg(const void *self, uint8_t *__restri
|
||||
const auto &msg = *static_cast<const ListEntitiesFanResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.supports_oscillation);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 6, msg.supports_speed);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 7, msg.supports_direction);
|
||||
@@ -678,7 +678,7 @@ uint8_t *ListEntitiesLightResponse::encode_msg(const void *self, uint8_t *__rest
|
||||
const auto &msg = *static_cast<const ListEntitiesLightResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
for (const auto &it : *msg.supported_color_modes) {
|
||||
pos = ProtoEncode::encode_uint32_force(pos PROTO_ENCODE_DEBUG_ARG, 12, static_cast<uint32_t>(it));
|
||||
}
|
||||
@@ -884,7 +884,7 @@ uint8_t *ListEntitiesSensorResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesSensorResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -954,7 +954,7 @@ uint8_t *ListEntitiesSwitchResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesSwitchResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -1030,7 +1030,7 @@ uint8_t *ListEntitiesTextSensorResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesTextSensorResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -1324,13 +1324,13 @@ void GetTimeResponse::decode_field(void *self, uint32_t tag, const uint8_t *data
|
||||
uint8_t *ListEntitiesServicesArgument::encode_msg(const void *self,
|
||||
uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM) {
|
||||
const auto &msg = *static_cast<const ListEntitiesServicesArgument *>(self);
|
||||
pos = ProtoEncode::encode_progmem_string(pos PROTO_ENCODE_DEBUG_ARG, 1, msg.name);
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 1, msg.name);
|
||||
pos = ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 2, static_cast<uint32_t>(msg.type));
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
pos = ProtoEncode::encode_progmem_string(pos PROTO_ENCODE_DEBUG_ARG, 3, msg.description);
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 3, msg.description);
|
||||
#endif
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
pos = ProtoEncode::encode_progmem_string(pos PROTO_ENCODE_DEBUG_ARG, 4, msg.example);
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 4, msg.example);
|
||||
#endif
|
||||
return pos;
|
||||
}
|
||||
@@ -1350,14 +1350,14 @@ uint32_t ListEntitiesServicesArgument::calc_size_msg(const void *self) {
|
||||
uint8_t *ListEntitiesServicesResponse::encode_msg(const void *self,
|
||||
uint8_t *__restrict__ pos PROTO_ENCODE_DEBUG_PARAM) {
|
||||
const auto &msg = *static_cast<const ListEntitiesServicesResponse *>(self);
|
||||
pos = ProtoEncode::encode_progmem_string(pos PROTO_ENCODE_DEBUG_ARG, 1, msg.name);
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 1, msg.name);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
for (auto &it : msg.args) {
|
||||
pos = ProtoEncode::encode_sub_message(pos PROTO_ENCODE_DEBUG_ARG, 3, it);
|
||||
}
|
||||
pos = ProtoEncode::encode_uint32(pos PROTO_ENCODE_DEBUG_ARG, 4, static_cast<uint32_t>(msg.supports_response));
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
pos = ProtoEncode::encode_progmem_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.description);
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.description);
|
||||
#endif
|
||||
return pos;
|
||||
}
|
||||
@@ -1478,7 +1478,7 @@ uint8_t *ListEntitiesCameraResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesCameraResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.disabled_by_default);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 6, msg.icon);
|
||||
@@ -1544,7 +1544,7 @@ uint8_t *ListEntitiesClimateResponse::encode_msg(const void *self, uint8_t *__re
|
||||
const auto &msg = *static_cast<const ListEntitiesClimateResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.supports_current_temperature);
|
||||
pos = ProtoEncode::encode_bool(pos PROTO_ENCODE_DEBUG_ARG, 6, msg.supports_two_point_target_temperature);
|
||||
for (const auto &it : *msg.supported_modes) {
|
||||
@@ -1781,7 +1781,7 @@ uint8_t *ListEntitiesWaterHeaterResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesWaterHeaterResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 4, msg.icon);
|
||||
#endif
|
||||
@@ -1908,7 +1908,7 @@ uint8_t *ListEntitiesNumberResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesNumberResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -1999,7 +1999,7 @@ uint8_t *ListEntitiesSelectResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesSelectResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -2078,7 +2078,7 @@ uint8_t *ListEntitiesSirenResponse::encode_msg(const void *self, uint8_t *__rest
|
||||
const auto &msg = *static_cast<const ListEntitiesSirenResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -2180,7 +2180,7 @@ uint8_t *ListEntitiesLockResponse::encode_msg(const void *self, uint8_t *__restr
|
||||
const auto &msg = *static_cast<const ListEntitiesLockResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -2263,7 +2263,7 @@ uint8_t *ListEntitiesButtonResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesButtonResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -2332,7 +2332,7 @@ uint8_t *ListEntitiesMediaPlayerResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesMediaPlayerResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3178,7 +3178,7 @@ uint8_t *ListEntitiesAlarmControlPanelResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesAlarmControlPanelResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3258,7 +3258,7 @@ uint8_t *ListEntitiesTextResponse::encode_msg(const void *self, uint8_t *__restr
|
||||
const auto &msg = *static_cast<const ListEntitiesTextResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3337,7 +3337,7 @@ uint8_t *ListEntitiesDateResponse::encode_msg(const void *self, uint8_t *__restr
|
||||
const auto &msg = *static_cast<const ListEntitiesDateResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3418,7 +3418,7 @@ uint8_t *ListEntitiesTimeResponse::encode_msg(const void *self, uint8_t *__restr
|
||||
const auto &msg = *static_cast<const ListEntitiesTimeResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3499,7 +3499,7 @@ uint8_t *ListEntitiesEventResponse::encode_msg(const void *self, uint8_t *__rest
|
||||
const auto &msg = *static_cast<const ListEntitiesEventResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3561,7 +3561,7 @@ uint8_t *ListEntitiesValveResponse::encode_msg(const void *self, uint8_t *__rest
|
||||
const auto &msg = *static_cast<const ListEntitiesValveResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3649,7 +3649,7 @@ uint8_t *ListEntitiesDateTimeResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesDateTimeResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3722,7 +3722,7 @@ uint8_t *ListEntitiesUpdateResponse::encode_msg(const void *self, uint8_t *__res
|
||||
const auto &msg = *static_cast<const ListEntitiesUpdateResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 5, msg.icon);
|
||||
#endif
|
||||
@@ -3878,7 +3878,7 @@ uint8_t *ListEntitiesInfraredResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesInfraredResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 4, msg.icon);
|
||||
#endif
|
||||
@@ -3996,7 +3996,7 @@ uint8_t *ListEntitiesRadioFrequencyResponse::encode_msg(const void *self,
|
||||
const auto &msg = *static_cast<const ListEntitiesRadioFrequencyResponse *>(self);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 10, msg.object_id);
|
||||
pos = ProtoEncode::write_tag_and_fixed32(pos PROTO_ENCODE_DEBUG_ARG, 21, msg.key);
|
||||
pos = ProtoEncode::encode_short_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
pos = ProtoEncode::encode_short_progmem_string_force(pos PROTO_ENCODE_DEBUG_ARG, 26, msg.name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
pos = ProtoEncode::encode_string(pos PROTO_ENCODE_DEBUG_ARG, 4, msg.icon);
|
||||
#endif
|
||||
|
||||
@@ -399,7 +399,7 @@ class InfoResponseProtoMessage : public ProtoMessage {
|
||||
public:
|
||||
StringRef object_id{};
|
||||
uint32_t key{0};
|
||||
StringRef name{};
|
||||
ProgmemStringRef name{};
|
||||
bool disabled_by_default{false};
|
||||
#ifdef USE_ENTITY_ICON
|
||||
StringRef icon{nullptr, 0}; // null until set, encode only
|
||||
@@ -1576,13 +1576,13 @@ class GetTimeResponse final : public ProtoDecodableMessage {
|
||||
#ifdef USE_API_USER_DEFINED_ACTIONS
|
||||
class ListEntitiesServicesArgument final : public ProtoMessage {
|
||||
public:
|
||||
ProgmemStringRef name{};
|
||||
StringRef name{nullptr, 0}; // null until set, encode only
|
||||
enums::ServiceArgType type{};
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
ProgmemStringRef description{};
|
||||
StringRef description{nullptr, 0}; // null until set, encode only
|
||||
#endif
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
ProgmemStringRef example{};
|
||||
StringRef example{nullptr, 0}; // null until set, encode only
|
||||
#endif
|
||||
static uint8_t *encode_msg(const void *self, uint8_t *pos PROTO_ENCODE_DEBUG_PARAM);
|
||||
uint8_t *encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
|
||||
@@ -1603,12 +1603,12 @@ class ListEntitiesServicesResponse final : public ProtoMessage {
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const LogString *message_name() const override { return LOG_STR("list_entities_services_response"); }
|
||||
#endif
|
||||
ProgmemStringRef name{};
|
||||
StringRef name{nullptr, 0}; // null until set, encode only
|
||||
uint32_t key{0};
|
||||
FixedVector<ListEntitiesServicesArgument> args{};
|
||||
enums::SupportsResponseType supports_response{};
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
ProgmemStringRef description{};
|
||||
StringRef description{nullptr, 0}; // null until set, encode only
|
||||
#endif
|
||||
static uint8_t *encode_msg(const void *self, uint8_t *pos PROTO_ENCODE_DEBUG_PARAM);
|
||||
uint8_t *encode(ProtoWriteBuffer &buffer PROTO_ENCODE_DEBUG_PARAM) const {
|
||||
|
||||
@@ -1190,7 +1190,7 @@ const char *ListEntitiesBinarySensorResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesBinarySensorResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("device_class"), this->device_class);
|
||||
dump_field(out, ESPHOME_PSTR("is_status_binary_sensor"), this->is_status_binary_sensor);
|
||||
dump_field(out, ESPHOME_PSTR("disabled_by_default"), this->disabled_by_default);
|
||||
@@ -1219,7 +1219,7 @@ const char *ListEntitiesCoverResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesCoverResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("assumed_state"), this->assumed_state);
|
||||
dump_field(out, ESPHOME_PSTR("supports_position"), this->supports_position);
|
||||
dump_field(out, ESPHOME_PSTR("supports_tilt"), this->supports_tilt);
|
||||
@@ -1265,7 +1265,7 @@ const char *ListEntitiesFanResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesFanResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("supports_oscillation"), this->supports_oscillation);
|
||||
dump_field(out, ESPHOME_PSTR("supports_speed"), this->supports_speed);
|
||||
dump_field(out, ESPHOME_PSTR("supports_direction"), this->supports_direction);
|
||||
@@ -1320,7 +1320,7 @@ const char *ListEntitiesLightResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesLightResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
for (const auto &it : *this->supported_color_modes) {
|
||||
dump_field(out, ESPHOME_PSTR("supported_color_modes"), static_cast<enums::ColorMode>(it), 4);
|
||||
}
|
||||
@@ -1399,7 +1399,7 @@ const char *ListEntitiesSensorResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesSensorResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -1431,7 +1431,7 @@ const char *ListEntitiesSwitchResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesSwitchResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -1469,7 +1469,7 @@ const char *ListEntitiesTextSensorResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesTextSensorResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -1620,19 +1620,19 @@ const char *GetTimeResponse::dump_to(DumpBuffer &out) const {
|
||||
#ifdef USE_API_USER_DEFINED_ACTIONS
|
||||
const char *ListEntitiesServicesArgument::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesServicesArgument"));
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("type"), static_cast<enums::ServiceArgType>(this->type));
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("description"), this->description);
|
||||
dump_field(out, ESPHOME_PSTR("description"), this->description);
|
||||
#endif
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("example"), this->example);
|
||||
dump_field(out, ESPHOME_PSTR("example"), this->example);
|
||||
#endif
|
||||
return out.c_str();
|
||||
}
|
||||
const char *ListEntitiesServicesResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesServicesResponse"));
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
for (const auto &it : this->args) {
|
||||
out.append(4, ' ').append_p(ESPHOME_PSTR("args")).append(": ");
|
||||
@@ -1641,7 +1641,7 @@ const char *ListEntitiesServicesResponse::dump_to(DumpBuffer &out) const {
|
||||
}
|
||||
dump_field(out, ESPHOME_PSTR("supports_response"), static_cast<enums::SupportsResponseType>(this->supports_response));
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("description"), this->description);
|
||||
dump_field(out, ESPHOME_PSTR("description"), this->description);
|
||||
#endif
|
||||
return out.c_str();
|
||||
}
|
||||
@@ -1700,7 +1700,7 @@ const char *ListEntitiesCameraResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesCameraResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("disabled_by_default"), this->disabled_by_default);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
@@ -1733,7 +1733,7 @@ const char *ListEntitiesClimateResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesClimateResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_field(out, ESPHOME_PSTR("supports_current_temperature"), this->supports_current_temperature);
|
||||
dump_field(out, ESPHOME_PSTR("supports_two_point_target_temperature"), this->supports_two_point_target_temperature);
|
||||
for (const auto &it : *this->supported_modes) {
|
||||
@@ -1831,7 +1831,7 @@ const char *ListEntitiesWaterHeaterResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesWaterHeaterResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -1885,7 +1885,7 @@ const char *ListEntitiesNumberResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesNumberResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -1927,7 +1927,7 @@ const char *ListEntitiesSelectResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesSelectResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -1966,7 +1966,7 @@ const char *ListEntitiesSirenResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesSirenResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2013,7 +2013,7 @@ const char *ListEntitiesLockResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesLockResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2054,7 +2054,7 @@ const char *ListEntitiesButtonResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesButtonResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2089,7 +2089,7 @@ const char *ListEntitiesMediaPlayerResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesMediaPlayerResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2479,7 +2479,7 @@ const char *ListEntitiesAlarmControlPanelResponse::dump_to(DumpBuffer &out) cons
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesAlarmControlPanelResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2518,7 +2518,7 @@ const char *ListEntitiesTextResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesTextResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2558,7 +2558,7 @@ const char *ListEntitiesDateResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesDateResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2598,7 +2598,7 @@ const char *ListEntitiesTimeResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesTimeResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2638,7 +2638,7 @@ const char *ListEntitiesEventResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesEventResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2668,7 +2668,7 @@ const char *ListEntitiesValveResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesValveResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2710,7 +2710,7 @@ const char *ListEntitiesDateTimeResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesDateTimeResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2746,7 +2746,7 @@ const char *ListEntitiesUpdateResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesUpdateResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2809,7 +2809,7 @@ const char *ListEntitiesInfraredResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesInfraredResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
@@ -2867,7 +2867,7 @@ const char *ListEntitiesRadioFrequencyResponse::dump_to(DumpBuffer &out) const {
|
||||
MessageDumpHelper helper(out, ESPHOME_PSTR("ListEntitiesRadioFrequencyResponse"));
|
||||
dump_field(out, ESPHOME_PSTR("object_id"), this->object_id);
|
||||
dump_field(out, ESPHOME_PSTR("key"), this->key);
|
||||
dump_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
dump_progmem_string_field(out, ESPHOME_PSTR("name"), this->name);
|
||||
#ifdef USE_ENTITY_ICON
|
||||
dump_field(out, ESPHOME_PSTR("icon"), this->icon);
|
||||
#endif
|
||||
|
||||
@@ -99,7 +99,8 @@ ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(clie
|
||||
static constexpr uint8_t SERVICE_YIELD_INTERVAL = 3;
|
||||
|
||||
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
|
||||
auto resp = service->encode_list_service_response();
|
||||
UserActionScratch scratch;
|
||||
auto resp = service->encode_list_service_response(scratch);
|
||||
if (!this->client_->send_message(resp))
|
||||
return false;
|
||||
// at_ is this service's index
|
||||
|
||||
@@ -1,36 +1,47 @@
|
||||
#include "user_services.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/progmem.h"
|
||||
#include "esphome/core/string_ref.h"
|
||||
|
||||
namespace esphome::api {
|
||||
|
||||
ProgmemStringRef UserServiceStatic::str_(size_t idx) const {
|
||||
StringRef UserServiceStatic::str_(size_t idx, std::span<char> &scratch) const {
|
||||
const char *s = progmem_read_ptr(&this->strings_[idx]);
|
||||
if (s == nullptr)
|
||||
return {};
|
||||
return ProgmemStringRef(s, ESPHOME_strlen_P(s));
|
||||
#ifdef USE_ESP8266
|
||||
// Codegen sizes the scratch buffer for the largest service; the bound only guards other callers
|
||||
if (scratch.empty())
|
||||
return {};
|
||||
size_t len = strnlen_P(s, scratch.size() - 1);
|
||||
progmem_memcpy(scratch.data(), s, len);
|
||||
scratch[len] = '\0';
|
||||
StringRef ref(scratch.data(), len);
|
||||
scratch = scratch.subspan(len + 1);
|
||||
return ref;
|
||||
#else
|
||||
return StringRef(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
ListEntitiesServicesResponse UserServiceStatic::encode_list_service_response_(
|
||||
std::span<const enums::ServiceArgType> arg_types) const {
|
||||
std::span<const enums::ServiceArgType> arg_types, std::span<char> scratch) const {
|
||||
ListEntitiesServicesResponse msg;
|
||||
msg.name = this->str_(0);
|
||||
msg.name = this->str_(0, scratch);
|
||||
msg.key = this->key_;
|
||||
msg.supports_response = this->supports_response_;
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
msg.description = this->str_(1);
|
||||
msg.description = this->str_(1, scratch);
|
||||
#endif
|
||||
msg.args.init(arg_types.size());
|
||||
for (size_t i = 0; i < arg_types.size(); i++) {
|
||||
size_t base = USER_ACTION_HEADER_STRINGS + i * USER_ACTION_ARG_STRINGS;
|
||||
auto &arg = msg.args.emplace_back();
|
||||
arg.type = arg_types[i];
|
||||
arg.name = this->str_(base);
|
||||
arg.name = this->str_(base, scratch);
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_METADATA
|
||||
arg.description = this->str_(base + 1);
|
||||
arg.example = this->str_(base + 2);
|
||||
arg.description = this->str_(base + 1, scratch);
|
||||
arg.example = this->str_(base + 2, scratch);
|
||||
#endif
|
||||
}
|
||||
return msg;
|
||||
|
||||
@@ -20,8 +20,9 @@ class APIServer;
|
||||
|
||||
class UserServiceDescriptor {
|
||||
public:
|
||||
/// Build the list-entities message; its strings may point into flash (PROGMEM).
|
||||
virtual ListEntitiesServicesResponse encode_list_service_response() = 0;
|
||||
/// Build the list-entities message. On ESP8266 the strings live in PROGMEM and are copied into
|
||||
/// `scratch`, so the returned message is only valid while `scratch` is; other platforms ignore it.
|
||||
virtual ListEntitiesServicesResponse encode_list_service_response(std::span<char> scratch) = 0;
|
||||
|
||||
virtual bool execute_service(const ExecuteServiceRequest &req) = 0;
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
@@ -36,6 +37,13 @@ template<typename T> T get_execute_arg_value(const ExecuteServiceArgument &arg);
|
||||
|
||||
template<typename T> enums::ServiceArgType to_service_arg_type();
|
||||
|
||||
// Scratch buffer list-entities hands to encode_list_service_response(); only ESP8266 copies into it
|
||||
#ifdef USE_ESP8266
|
||||
using UserActionScratch = std::array<char, API_USER_ACTION_STRINGS_SCRATCH_SIZE>;
|
||||
#else
|
||||
using UserActionScratch = std::array<char, 0>;
|
||||
#endif
|
||||
|
||||
// Non-template base for YAML-defined services so the list-entities encoder is compiled once.
|
||||
// All strings live in one PROGMEM pointer table emitted by codegen (see _action_strings in
|
||||
// __init__.py), so each service costs a single pointer of RAM. Layout: the action name, then
|
||||
@@ -55,9 +63,12 @@ class UserServiceStatic : public UserServiceDescriptor {
|
||||
: strings_(strings), key_(key), supports_response_(supports_response) {}
|
||||
|
||||
protected:
|
||||
ListEntitiesServicesResponse encode_list_service_response_(std::span<const enums::ServiceArgType> arg_types) const;
|
||||
/// Table entry `idx` as it sits in flash; nullptr gives an empty string.
|
||||
ProgmemStringRef str_(size_t idx) const;
|
||||
ListEntitiesServicesResponse encode_list_service_response_(std::span<const enums::ServiceArgType> arg_types,
|
||||
std::span<char> scratch) const;
|
||||
/// Reference table entry `idx`; nullptr gives an empty StringRef.
|
||||
/// On ESP8266 the bytes are copied out of PROGMEM into `scratch` with a terminator, and the span
|
||||
/// is advanced past the copy.
|
||||
StringRef str_(size_t idx, std::span<char> &scratch) const;
|
||||
|
||||
const char *const *strings_; // PROGMEM pointer table, read with progmem_read_ptr()
|
||||
uint32_t key_;
|
||||
@@ -68,9 +79,9 @@ template<typename... Ts> class UserServiceBase : public UserServiceStatic {
|
||||
public:
|
||||
using UserServiceStatic::UserServiceStatic;
|
||||
|
||||
ListEntitiesServicesResponse encode_list_service_response() override {
|
||||
ListEntitiesServicesResponse encode_list_service_response(std::span<char> scratch) override {
|
||||
std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
|
||||
return this->encode_list_service_response_(arg_types);
|
||||
return this->encode_list_service_response_(arg_types, scratch);
|
||||
}
|
||||
|
||||
bool execute_service(const ExecuteServiceRequest &req) override {
|
||||
@@ -114,9 +125,9 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
|
||||
this->key_ = fnv1_hash(this->name_.c_str());
|
||||
}
|
||||
|
||||
ListEntitiesServicesResponse encode_list_service_response() override {
|
||||
ListEntitiesServicesResponse encode_list_service_response(std::span<char> /*scratch*/) override {
|
||||
ListEntitiesServicesResponse msg;
|
||||
msg.name = ProgmemStringRef(StringRef(this->name_));
|
||||
msg.name = StringRef(this->name_);
|
||||
msg.key = this->key_;
|
||||
msg.supports_response = enums::SUPPORTS_RESPONSE_NONE; // Dynamic services don't support responses yet
|
||||
std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
|
||||
@@ -124,7 +135,7 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
|
||||
for (size_t i = 0; i < sizeof...(Ts); i++) {
|
||||
auto &arg = msg.args.emplace_back();
|
||||
arg.type = arg_types[i];
|
||||
arg.name = ProgmemStringRef(StringRef(this->arg_names_[i]));
|
||||
arg.name = StringRef(this->arg_names_[i]);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ void AQISensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Extended Range: %s",
|
||||
this->extended_range_ ? LOG_STR_LITERAL("enabled") : LOG_STR_LITERAL("disabled"));
|
||||
if (this->pm_2_5_sensor_ != nullptr) {
|
||||
ESP_LOGCONFIG(TAG, " PM2.5 Sensor: '%s'", this->pm_2_5_sensor_->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, " PM2.5 Sensor: '%s'", LOG_STR_ARG(this->pm_2_5_sensor_->get_log_name()));
|
||||
}
|
||||
if (this->pm_10_0_sensor_ != nullptr) {
|
||||
ESP_LOGCONFIG(TAG, " PM10 Sensor: '%s'", this->pm_10_0_sensor_->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, " PM10 Sensor: '%s'", LOG_STR_ARG(this->pm_10_0_sensor_->get_log_name()));
|
||||
}
|
||||
LOG_SENSOR(" ", "AQI", this);
|
||||
}
|
||||
|
||||
@@ -1289,7 +1289,7 @@ void ATM90E32Component::check_phase_status() {
|
||||
if (!status.empty()) {
|
||||
status.pop_back(); // remove space
|
||||
status.pop_back(); // remove semicolon
|
||||
ESP_LOGW(TAG, "%s: %s", sensor->get_name().c_str(), status.c_str());
|
||||
ESP_LOGW(TAG, "%s: %s", LOG_STR_ARG(sensor->get_log_name()), status.c_str());
|
||||
sensor->publish_state(status);
|
||||
} else {
|
||||
sensor->publish_state("Okay");
|
||||
|
||||
@@ -8,11 +8,12 @@ ESPHOME_LOG_TAG(TAG, "atm90e32.button");
|
||||
|
||||
void ATM90E32GainCalibrationButton::press_action() {
|
||||
if (this->parent_ == nullptr) {
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Gain Calibration button [%s]", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Gain Calibration button [%s]",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "%s", LOG_STR_ARG(this->get_log_name()));
|
||||
ESP_LOGI(TAG,
|
||||
"[CALIBRATION] Use gain_ct: & gain_voltage: under each phase_x: in your config file to save these values");
|
||||
this->parent_->run_gain_calibrations();
|
||||
@@ -20,21 +21,22 @@ void ATM90E32GainCalibrationButton::press_action() {
|
||||
|
||||
void ATM90E32ClearGainCalibrationButton::press_action() {
|
||||
if (this->parent_ == nullptr) {
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Clear Gain button [%s]", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Clear Gain button [%s]", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "%s", LOG_STR_ARG(this->get_log_name()));
|
||||
this->parent_->clear_gain_calibrations();
|
||||
}
|
||||
|
||||
void ATM90E32OffsetCalibrationButton::press_action() {
|
||||
if (this->parent_ == nullptr) {
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Offset Calibration button [%s]", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Offset Calibration button [%s]",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "%s", LOG_STR_ARG(this->get_log_name()));
|
||||
ESP_LOGI(TAG, "[CALIBRATION] **NOTE: CTs and ACVs must be 0 during this process. USB power only**");
|
||||
ESP_LOGI(TAG, "[CALIBRATION] Use offset_voltage: & offset_current: under each phase_x: in your config file to save "
|
||||
"these values");
|
||||
@@ -43,21 +45,22 @@ void ATM90E32OffsetCalibrationButton::press_action() {
|
||||
|
||||
void ATM90E32ClearOffsetCalibrationButton::press_action() {
|
||||
if (this->parent_ == nullptr) {
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Clear Offset button [%s]", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Clear Offset button [%s]", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "%s", LOG_STR_ARG(this->get_log_name()));
|
||||
this->parent_->clear_offset_calibrations();
|
||||
}
|
||||
|
||||
void ATM90E32PowerOffsetCalibrationButton::press_action() {
|
||||
if (this->parent_ == nullptr) {
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Power Calibration button [%s]", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Power Calibration button [%s]",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "%s", LOG_STR_ARG(this->get_log_name()));
|
||||
ESP_LOGI(TAG, "[CALIBRATION] **NOTE: CTs must be 0 during this process. Voltage reference should be present**");
|
||||
ESP_LOGI(TAG, "[CALIBRATION] Use offset_active_power: & offset_reactive_power: under each phase_x: in your config "
|
||||
"file to save these values");
|
||||
@@ -66,11 +69,11 @@ void ATM90E32PowerOffsetCalibrationButton::press_action() {
|
||||
|
||||
void ATM90E32ClearPowerOffsetCalibrationButton::press_action() {
|
||||
if (this->parent_ == nullptr) {
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Clear Power button [%s]", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[CALIBRATION] No meters assigned to Clear Power button [%s]", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "%s", LOG_STR_ARG(this->get_log_name()));
|
||||
this->parent_->clear_power_offset_calibrations();
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ void BedJetClimate::control(const ClimateCall &call) {
|
||||
} else if (fan_mode == CLIMATE_FAN_HIGH) {
|
||||
result = this->parent_->set_fan_speed(75);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "[%s] Unsupported fan mode: %s", this->get_name().c_str(),
|
||||
ESP_LOGW(TAG, "[%s] Unsupported fan mode: %s", LOG_STR_ARG(this->get_log_name()),
|
||||
LOG_STR_ARG(climate_fan_mode_to_string(fan_mode)));
|
||||
return;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ void BedJetClimate::control(const ClimateCall &call) {
|
||||
auto fan_mode = call.get_custom_fan_mode();
|
||||
auto fan_index = bedjet_fan_speed_to_step(fan_mode.c_str());
|
||||
if (fan_index <= 19) {
|
||||
ESP_LOGV(TAG, "[%s] Converted fan mode %.*s to bedjet fan step %d", this->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "[%s] Converted fan mode %.*s to bedjet fan step %d", LOG_STR_ARG(this->get_log_name()),
|
||||
(int) fan_mode.size(), fan_mode.c_str(), fan_index);
|
||||
bool result = this->parent_->set_fan_index(fan_index);
|
||||
if (result) {
|
||||
@@ -236,7 +236,7 @@ void BedJetClimate::control(const ClimateCall &call) {
|
||||
void BedJetClimate::on_bedjet_state(bool is_ready) {}
|
||||
|
||||
void BedJetClimate::on_status(const BedjetStatusPacket *data) {
|
||||
ESP_LOGV(TAG, "[%s] Handling on_status with data=%p", this->get_name().c_str(), (void *) data);
|
||||
ESP_LOGV(TAG, "[%s] Handling on_status with data=%p", LOG_STR_ARG(this->get_log_name()), (void *) data);
|
||||
|
||||
auto converted_temp = bedjet_temp_to_c(data->target_temp_step);
|
||||
if (converted_temp > 0)
|
||||
@@ -310,11 +310,11 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) {
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "[%s] Unexpected mode: 0x%02X", this->get_name().c_str(), data->mode);
|
||||
ESP_LOGW(TAG, "[%s] Unexpected mode: 0x%02X", LOG_STR_ARG(this->get_log_name()), data->mode);
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "[%s] After on_status, new mode=%s", this->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "[%s] After on_status, new mode=%s", LOG_STR_ARG(this->get_log_name()),
|
||||
LOG_STR_ARG(climate_mode_to_string(this->mode)));
|
||||
// FIXME: compare new state to previous state.
|
||||
this->publish_state();
|
||||
@@ -351,11 +351,11 @@ bool BedJetClimate::update_status_() {
|
||||
}
|
||||
|
||||
void BedJetClimate::update() {
|
||||
ESP_LOGD(TAG, "[%s] update()", this->get_name().c_str());
|
||||
ESP_LOGD(TAG, "[%s] update()", LOG_STR_ARG(this->get_log_name()));
|
||||
// TODO: if the hub component is already polling, do we also need to include polling?
|
||||
// We're already going to get on_status() at the hub's polling interval.
|
||||
auto result = this->update_status_();
|
||||
ESP_LOGD(TAG, "[%s] update_status result=%s", this->get_name().c_str(), result ? "true" : "false");
|
||||
ESP_LOGD(TAG, "[%s] update_status result=%s", LOG_STR_ARG(this->get_log_name()), result ? "true" : "false");
|
||||
}
|
||||
|
||||
} // namespace esphome::bedjet
|
||||
|
||||
@@ -53,7 +53,7 @@ void BedJetFan::control(const fan::FanCall &call) {
|
||||
}
|
||||
|
||||
void BedJetFan::on_status(const BedjetStatusPacket *data) {
|
||||
ESP_LOGVV(TAG, "[%s] Handling on_status with data=%p", this->get_name().c_str(), (void *) data);
|
||||
ESP_LOGVV(TAG, "[%s] Handling on_status with data=%p", LOG_STR_ARG(this->get_log_name()), (void *) data);
|
||||
bool did_change = false;
|
||||
bool new_state = data->mode != MODE_STANDBY && data->mode != MODE_WAIT;
|
||||
|
||||
@@ -96,11 +96,11 @@ bool BedJetFan::update_status_() {
|
||||
}
|
||||
|
||||
void BedJetFan::update() {
|
||||
ESP_LOGD(TAG, "[%s] update()", this->get_name().c_str());
|
||||
ESP_LOGD(TAG, "[%s] update()", LOG_STR_ARG(this->get_log_name()));
|
||||
// TODO: if the hub component is already polling, do we also need to include polling?
|
||||
// We're already going to get on_status() at the hub's polling interval.
|
||||
auto result = this->update_status_();
|
||||
ESP_LOGD(TAG, "[%s] update_status result=%s", this->get_name().c_str(), result ? "true" : "false");
|
||||
ESP_LOGD(TAG, "[%s] update_status result=%s", LOG_STR_ARG(this->get_log_name()), result ? "true" : "false");
|
||||
}
|
||||
|
||||
/** Resets states to defaults. */
|
||||
|
||||
@@ -75,7 +75,7 @@ void BH1750Sensor::dump_config() {
|
||||
LOG_SENSOR("", "BH1750", this);
|
||||
LOG_I2C_DEVICE(this);
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->get_name().c_str());
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
@@ -154,7 +154,7 @@ void BH1750Sensor::loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "'%s': Illuminance=%.1flx", this->get_name().c_str(), lx);
|
||||
ESP_LOGV(TAG, "'%s': Illuminance=%.1flx", LOG_STR_ARG(this->get_log_name()), lx);
|
||||
this->status_clear_warning();
|
||||
this->publish_state(lx);
|
||||
this->state_ = IDLE;
|
||||
|
||||
@@ -13,7 +13,7 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, LOG_STR_ARG(obj->get_log_name()));
|
||||
LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ bool BinarySensor::set_new_state(const optional<bool> &new_state) {
|
||||
#if defined(USE_BINARY_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_binary_sensor_update(this);
|
||||
#endif
|
||||
ESP_LOGV(TAG, "'%s' >> %s", this->get_name().c_str(), ONOFFMAYBE(new_state));
|
||||
ESP_LOGV(TAG, "'%s' >> %s", LOG_STR_ARG(this->get_log_name()), ONOFFMAYBE(new_state));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -47,7 +47,7 @@ void BinarySensorMap::process_group_() {
|
||||
}
|
||||
} else if (this->last_mask_ != 0ULL) {
|
||||
// no buttons are pressed and the states have changed since last run, so publish NAN
|
||||
ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str());
|
||||
ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", LOG_STR_ARG(this->get_log_name()));
|
||||
this->publish_state(NAN);
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ float BL0940::update_temp_(sensor::Sensor *sensor, uint16_le_t temperature) cons
|
||||
if (sensor != nullptr) {
|
||||
if (sensor->has_state() && std::abs(converted_temp - sensor->get_state()) > max_temperature_diff_) {
|
||||
ESP_LOGD(TAG, "Invalid temperature change. Sensor: '%s', Old temperature: %f, New temperature: %f",
|
||||
sensor->get_name().c_str(), sensor->get_state(), converted_temp);
|
||||
LOG_STR_ARG(sensor->get_log_name()), sensor->get_state(), converted_temp);
|
||||
return 0.0f;
|
||||
}
|
||||
sensor->publish_state(converted_temp);
|
||||
|
||||
@@ -63,7 +63,7 @@ void BLEClientRSSISensor::gap_event_handler(esp_gap_ble_cb_event_t event, esp_bl
|
||||
|
||||
void BLEClientRSSISensor::update() {
|
||||
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", LOG_STR_ARG(this->get_log_name()));
|
||||
this->should_update_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
switch (event) {
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
if (param->open.status == ESP_GATT_OK) {
|
||||
ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "[%s] Connected successfully!", LOG_STR_ARG(this->get_log_name()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTC_CLOSE_EVT: {
|
||||
ESP_LOGW(TAG, "[%s] Disconnected!", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Disconnected!", LOG_STR_ARG(this->get_log_name()));
|
||||
this->status_set_warning();
|
||||
this->publish_state(NAN);
|
||||
break;
|
||||
@@ -102,10 +102,10 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
}
|
||||
case ESP_GATTC_NOTIFY_EVT: {
|
||||
if (param->notify.value_len == 0) {
|
||||
ESP_LOGW(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: empty value", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: empty value", LOG_STR_ARG(this->get_log_name()));
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
|
||||
ESP_LOGD(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", LOG_STR_ARG(this->get_log_name()),
|
||||
param->notify.handle, param->notify.value[0]);
|
||||
if (param->notify.handle != this->handle)
|
||||
break;
|
||||
@@ -143,11 +143,11 @@ float BLESensor::parse_data_(uint8_t *value, uint16_t value_len) {
|
||||
|
||||
void BLESensor::update() {
|
||||
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
if (this->handle == 0) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ void BLESensor::update() {
|
||||
if (status) {
|
||||
this->status_set_warning();
|
||||
this->publish_state(NAN);
|
||||
ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", LOG_STR_ARG(this->get_log_name()), status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
switch (event) {
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
if (param->open.status == ESP_GATT_OK) {
|
||||
ESP_LOGI(TAG, "[%s] Connected successfully!", this->get_name().c_str());
|
||||
ESP_LOGI(TAG, "[%s] Connected successfully!", LOG_STR_ARG(this->get_log_name()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -104,10 +104,10 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
if (param->notify.handle != this->handle)
|
||||
break;
|
||||
if (param->notify.value_len == 0) {
|
||||
ESP_LOGW(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: empty value", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: empty value", LOG_STR_ARG(this->get_log_name()));
|
||||
break;
|
||||
}
|
||||
ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", this->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "[%s] ESP_GATTC_NOTIFY_EVT: handle=0x%x, value=0x%x", LOG_STR_ARG(this->get_log_name()),
|
||||
param->notify.handle, param->notify.value[0]);
|
||||
this->publish_state(reinterpret_cast<const char *>(param->notify.value), param->notify.value_len);
|
||||
break;
|
||||
@@ -124,11 +124,11 @@ void BLETextSensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
|
||||
void BLETextSensor::update() {
|
||||
if (this->node_state != espbt::ClientState::ESTABLISHED) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
if (this->handle == 0) {
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "[%s] Cannot poll, no service or characteristic found", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ void BLETextSensor::update() {
|
||||
if (status) {
|
||||
this->status_set_warning();
|
||||
this->publish_state("");
|
||||
ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", this->get_name().c_str(), status);
|
||||
ESP_LOGW(TAG, "[%s] Error sending read request for sensor, status=%d", LOG_STR_ARG(this->get_log_name()), status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_ID,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_VOLT,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["sensor"]
|
||||
CODEOWNERS = ["@limpkin"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
DOMAIN = "bq76972"
|
||||
MULTI_CONF = True
|
||||
|
||||
bq76972_ns = cg.esphome_ns.namespace("bq76972")
|
||||
BQ76972Component = bq76972_ns.class_(
|
||||
"BQ76972Component", cg.PollingComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
CONF_REG_DISABLED = "reg_disabled"
|
||||
CONF_CRC_ENABLED = "crc_enabled"
|
||||
CONF_STACK_VOLTAGE = "stack_voltage"
|
||||
|
||||
# Ordered as the chip reports them, starting at command 0x68
|
||||
CONF_TEMPERATURES = [
|
||||
"internal_temperature",
|
||||
"cfetoff_temperature",
|
||||
"dfetoff_temperature",
|
||||
"alert_temperature",
|
||||
"ts1_temperature",
|
||||
"ts2_temperature",
|
||||
"ts3_temperature",
|
||||
"hdq_temperature",
|
||||
"dchg_temperature",
|
||||
"ddsg_temperature",
|
||||
]
|
||||
|
||||
CONF_CELL_VOLTAGES = [f"cell_{i}_voltage" for i in range(1, 17)]
|
||||
|
||||
voltage_sensor_schema = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=3,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
|
||||
temp_sensor_schema = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_CELSIUS,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BQ76972Component),
|
||||
cv.Optional(CONF_CRC_ENABLED, default=False): cv.boolean,
|
||||
cv.Optional(CONF_REG_DISABLED, default=False): cv.boolean,
|
||||
cv.Optional(CONF_STACK_VOLTAGE): voltage_sensor_schema,
|
||||
**{cv.Optional(key): voltage_sensor_schema for key in CONF_CELL_VOLTAGES},
|
||||
**{cv.Optional(key): temp_sensor_schema for key in CONF_TEMPERATURES},
|
||||
}
|
||||
)
|
||||
.extend(i2c.i2c_device_schema(0x08))
|
||||
.extend(cv.polling_component_schema("10s"))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_crc_mode(config[CONF_CRC_ENABLED]))
|
||||
cg.add(var.set_reg_disable(config[CONF_REG_DISABLED]))
|
||||
|
||||
sensors = sensor.sub_sensors(config)
|
||||
await sensors(CONF_STACK_VOLTAGE, var.set_stack_voltage_sensor)
|
||||
|
||||
for idx, key in enumerate(CONF_TEMPERATURES):
|
||||
if (conf := config.get(key)) is not None:
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_temperature_sensor(sens, idx))
|
||||
|
||||
for idx, key in enumerate(CONF_CELL_VOLTAGES):
|
||||
if (conf := config.get(key)) is not None:
|
||||
sens = await sensor.new_sensor(conf)
|
||||
cg.add(var.set_cell_sensor(sens, idx))
|
||||
|
||||
|
||||
BQ76972_PROGRAM_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(BQ76972Component),
|
||||
cv.Required(CONF_ADDRESS): cv.templatable(cv.i2c_address),
|
||||
},
|
||||
key=CONF_ADDRESS,
|
||||
)
|
||||
|
||||
automation.register_apply_action(
|
||||
"bq76972.program_i2c_address",
|
||||
BQ76972_PROGRAM_I2C_ADDRESS_SCHEMA,
|
||||
automation.ApplyField(CONF_ADDRESS, "program_i2c_address", cg.uint8),
|
||||
)
|
||||
@@ -0,0 +1,298 @@
|
||||
#include "bq76972.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::bq76972 {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "bq76972");
|
||||
|
||||
static constexpr uint8_t BQ76972_REG_SUBCOMMAND = 0x3E; // 0x3E low byte, 0x3F high byte
|
||||
static constexpr uint8_t BQ76972_REG_TRANSFER_BUFFER = 0x40;
|
||||
static constexpr uint8_t BQ76972_REG_CHECKSUM = 0x60; // 0x60 checksum, 0x61 length
|
||||
static constexpr uint8_t BQ76972_CMD_BAT_STATUS = 0x12;
|
||||
static constexpr uint8_t BQ76972_CMD_CELL_START = 0x14;
|
||||
static constexpr uint8_t BQ76972_CMD_STACK_VOLTAGE = 0x34;
|
||||
static constexpr uint8_t BQ76972_CMD_TEMP_START = 0x68;
|
||||
static constexpr uint16_t BQ76972_SUBCMD_ENTER_CFG_UPDATE = 0x0090;
|
||||
static constexpr uint16_t BQ76972_SUBCMD_EXIT_CFG_UPDATE = 0x0092;
|
||||
static constexpr uint16_t BQ76972_MEM_REG12_CONFIG = 0x9236;
|
||||
static constexpr uint16_t BQ76972_MEM_REG0_CONFIG = 0x9237;
|
||||
static constexpr uint16_t BQ76972_MEM_I2C_ADDRESS = 0x923A;
|
||||
static constexpr uint16_t BQ76972_MEM_SWAP_COMM_MODE = 0x29BC;
|
||||
// Pin config of temperature reading N (1 = CFETOFF ... 9 = DDSG) is at this base + N
|
||||
static constexpr uint16_t BQ76972_MEM_TEMP_PIN_CONFIG_BASE = 0x92F9;
|
||||
static constexpr size_t BQ76972_TS1_INDEX = 4; // a thermistor input by default
|
||||
static constexpr uint8_t BQ76972_PIN_CONFIG_THERMISTOR = 0x07;
|
||||
|
||||
// 16 words with a CRC byte after every data byte
|
||||
static constexpr size_t BQ76972_MAX_TRANSFER = 64;
|
||||
static constexpr uint8_t BQ76972_MAX_POLLS = 50;
|
||||
|
||||
static float raw_to_celsius(uint16_t raw) { return static_cast<int16_t>(raw) * 0.1f - 273.15f; }
|
||||
|
||||
bool BQ76972Component::read_block_(uint8_t start_register, uint8_t *data, size_t len) {
|
||||
if (!this->crc_mode_)
|
||||
return this->read_bytes(start_register, data, len);
|
||||
|
||||
// With CRC enabled, every data byte is followed by a CRC byte
|
||||
std::array<uint8_t, BQ76972_MAX_TRANSFER> buffer;
|
||||
if (len == 0 || len * 2 > buffer.size())
|
||||
return false;
|
||||
if (!this->read_bytes(start_register, buffer.data(), len * 2))
|
||||
return false;
|
||||
|
||||
// The first CRC also covers the write address, register and read address
|
||||
const uint8_t crc0_input[4] = {static_cast<uint8_t>(this->address_ << 1), start_register,
|
||||
static_cast<uint8_t>((this->address_ << 1) | 1), buffer[0]};
|
||||
if (crc8(crc0_input, 4, 0x00, 0x07, true) != buffer[1]) {
|
||||
ESP_LOGD(TAG, "CRC mismatch at register 0x%02X byte 0", start_register);
|
||||
return false;
|
||||
}
|
||||
data[0] = buffer[0];
|
||||
for (size_t i = 1; i < len; ++i) {
|
||||
if (crc8(&buffer[i * 2], 1, 0x00, 0x07, true) != buffer[i * 2 + 1]) {
|
||||
ESP_LOGD(TAG, "CRC mismatch at register 0x%02X byte %u", start_register, static_cast<unsigned>(i));
|
||||
return false;
|
||||
}
|
||||
data[i] = buffer[i * 2];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BQ76972Component::write_block_(uint8_t start_register, const uint8_t *data, size_t len) {
|
||||
if (!this->crc_mode_)
|
||||
return this->write_bytes(start_register, data, len);
|
||||
|
||||
std::array<uint8_t, BQ76972_MAX_TRANSFER> buffer;
|
||||
if (len == 0 || len * 2 > buffer.size())
|
||||
return false;
|
||||
|
||||
// The first CRC also covers the write address and register
|
||||
const uint8_t crc0_input[3] = {static_cast<uint8_t>(this->address_ << 1), start_register, data[0]};
|
||||
buffer[0] = data[0];
|
||||
buffer[1] = crc8(crc0_input, 3, 0x00, 0x07, true);
|
||||
for (size_t i = 1; i < len; ++i) {
|
||||
buffer[i * 2] = data[i];
|
||||
buffer[i * 2 + 1] = crc8(&data[i], 1, 0x00, 0x07, true);
|
||||
}
|
||||
return this->write_bytes(start_register, buffer.data(), len * 2);
|
||||
}
|
||||
|
||||
bool BQ76972Component::read_words_(uint8_t start_register, uint16_t *data, size_t num_words) {
|
||||
std::array<uint8_t, BQ76972_MAX_TRANSFER / 2> bytes;
|
||||
if (num_words * 2 > bytes.size() || !this->read_block_(start_register, bytes.data(), num_words * 2))
|
||||
return false;
|
||||
for (size_t i = 0; i < num_words; i++)
|
||||
data[i] = encode_uint16(bytes[2 * i + 1], bytes[2 * i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BQ76972Component::send_subcommand_(uint16_t subcommand) {
|
||||
const uint8_t bytes[2] = {static_cast<uint8_t>(subcommand & 0xFF), static_cast<uint8_t>(subcommand >> 8)};
|
||||
return this->write_block_(BQ76972_REG_SUBCOMMAND, bytes, 2);
|
||||
}
|
||||
|
||||
bool BQ76972Component::wait_for_subcommand_() {
|
||||
uint8_t bytes[2];
|
||||
for (uint8_t i = 0; i < BQ76972_MAX_POLLS; i++) {
|
||||
if (!this->read_block_(BQ76972_REG_SUBCOMMAND, bytes, 2))
|
||||
return false;
|
||||
if (bytes[0] != 0xFF && bytes[1] != 0xFF)
|
||||
return true;
|
||||
delay(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BQ76972Component::wait_for_cfgupdate_() {
|
||||
uint16_t status;
|
||||
for (uint8_t i = 0; i < BQ76972_MAX_POLLS; i++) {
|
||||
if (!this->read_words_(BQ76972_CMD_BAT_STATUS, &status, 1))
|
||||
return false;
|
||||
if (status & 0x0001)
|
||||
return true;
|
||||
delay(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BQ76972Component::read_subcommand_(uint16_t subcommand, uint8_t *data, size_t len) {
|
||||
return this->send_subcommand_(subcommand) && this->wait_for_subcommand_() &&
|
||||
this->read_block_(BQ76972_REG_TRANSFER_BUFFER, data, len);
|
||||
}
|
||||
|
||||
bool BQ76972Component::write_subcommand_(uint16_t subcommand, const uint8_t *data, size_t len) {
|
||||
if (!this->send_subcommand_(subcommand))
|
||||
return false;
|
||||
if (len == 0)
|
||||
return true;
|
||||
if (!this->write_block_(BQ76972_REG_TRANSFER_BUFFER, data, len))
|
||||
return false;
|
||||
|
||||
// Inverted 8-bit sum of 0x3E, 0x3F and the data; length counts 0x3E, 0x3F, 0x60, 0x61 and the data
|
||||
uint8_t sum = static_cast<uint8_t>(subcommand & 0xFF) + static_cast<uint8_t>(subcommand >> 8);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
sum += data[i];
|
||||
const uint8_t tail[2] = {static_cast<uint8_t>(~sum), static_cast<uint8_t>(4 + len)};
|
||||
return this->write_block_(BQ76972_REG_CHECKSUM, tail, 2);
|
||||
}
|
||||
|
||||
bool BQ76972Component::enter_cfg_update_() {
|
||||
if (!this->write_subcommand_(BQ76972_SUBCMD_ENTER_CFG_UPDATE, nullptr, 0))
|
||||
return false;
|
||||
delay(10);
|
||||
return this->wait_for_cfgupdate_();
|
||||
}
|
||||
|
||||
bool BQ76972Component::exit_cfg_update_() {
|
||||
return this->write_subcommand_(BQ76972_SUBCMD_EXIT_CFG_UPDATE, nullptr, 0);
|
||||
}
|
||||
|
||||
bool BQ76972Component::regs_disabled_(bool &out) {
|
||||
uint8_t reg12;
|
||||
uint8_t reg0;
|
||||
if (!this->read_subcommand_(BQ76972_MEM_REG12_CONFIG, ®12, 1) ||
|
||||
!this->read_subcommand_(BQ76972_MEM_REG0_CONFIG, ®0, 1))
|
||||
return false;
|
||||
out = reg12 == 0 && (reg0 & 0x01) == 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const LogString *BQ76972Component::configure_() {
|
||||
uint16_t internal_temp;
|
||||
if (!this->read_words_(BQ76972_CMD_TEMP_START, &internal_temp, 1))
|
||||
return LOG_STR(ESP_LOG_MSG_COMM_FAIL);
|
||||
|
||||
// Only write the regulator config when it differs, see
|
||||
// https://e2e.ti.com/support/power-management-group/power-management/f/power-management-forum/1583718/bq76972-undocumented-4-minute-config_update-auto-exit-timeout
|
||||
bool regs_disabled = true;
|
||||
if (this->reg_disable_ && !this->regs_disabled_(regs_disabled))
|
||||
return LOG_STR("Reading regulator config failed");
|
||||
const bool write_regs = !regs_disabled;
|
||||
|
||||
bool write_thermistors = false;
|
||||
for (size_t i = 1; i < BQ76972_NUM_TEMPERATURES; i++) {
|
||||
if (i != BQ76972_TS1_INDEX && this->temperature_sensors_[i] != nullptr)
|
||||
write_thermistors = true;
|
||||
}
|
||||
|
||||
if (write_regs || write_thermistors) {
|
||||
if (!this->enter_cfg_update_())
|
||||
return LOG_STR("Entering config update mode failed");
|
||||
const LogString *error = this->write_config_(write_regs);
|
||||
// The chip stops measuring in config update mode, so leave it even after a failed write
|
||||
if (!this->exit_cfg_update_() && error == nullptr)
|
||||
error = LOG_STR("Exiting config update mode failed");
|
||||
if (error != nullptr)
|
||||
return error;
|
||||
if (write_regs && (!this->regs_disabled_(regs_disabled) || !regs_disabled))
|
||||
return LOG_STR("Disabling regulators failed");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Internal temperature: %.1f°C", raw_to_celsius(internal_temp));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const LogString *BQ76972Component::write_config_(bool write_regs) {
|
||||
if (write_regs) {
|
||||
const uint8_t zero = 0;
|
||||
if (!this->write_subcommand_(BQ76972_MEM_REG12_CONFIG, &zero, 1) ||
|
||||
!this->write_subcommand_(BQ76972_MEM_REG0_CONFIG, &zero, 1))
|
||||
return LOG_STR("Writing regulator config failed");
|
||||
}
|
||||
for (size_t i = 1; i < BQ76972_NUM_TEMPERATURES; i++) {
|
||||
if (i == BQ76972_TS1_INDEX || this->temperature_sensors_[i] == nullptr)
|
||||
continue;
|
||||
if (!this->write_subcommand_(BQ76972_MEM_TEMP_PIN_CONFIG_BASE + i, &BQ76972_PIN_CONFIG_THERMISTOR, 1))
|
||||
return LOG_STR("Writing thermistor pin config failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BQ76972Component::setup() {
|
||||
if (const LogString *error = this->configure_(); error != nullptr)
|
||||
this->mark_failed(error);
|
||||
}
|
||||
|
||||
void BQ76972Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "BQ76972:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" CRC Mode: %s\n"
|
||||
" Regulators disabled: %s",
|
||||
this->crc_mode_ ? LOG_STR_LITERAL("Enabled") : LOG_STR_LITERAL("Disabled"), YESNO(this->reg_disable_));
|
||||
}
|
||||
|
||||
void BQ76972Component::program_i2c_address(uint8_t address) {
|
||||
if (this->is_failed())
|
||||
return;
|
||||
const uint8_t shifted = address << 1;
|
||||
if (!this->enter_cfg_update_()) {
|
||||
this->status_set_warning(LOG_STR("Programming I2C address failed"));
|
||||
return;
|
||||
}
|
||||
// The new address only takes effect with the swap, so after a failed write the chip still answers at the
|
||||
// old one and must still be taken out of config update mode
|
||||
const bool written = this->write_subcommand_(BQ76972_MEM_I2C_ADDRESS, &shifted, 1) &&
|
||||
this->write_subcommand_(BQ76972_MEM_SWAP_COMM_MODE, nullptr, 0);
|
||||
if (written) {
|
||||
delay(10);
|
||||
this->set_i2c_address(address);
|
||||
}
|
||||
if (!this->exit_cfg_update_() || !written) {
|
||||
this->status_set_warning(LOG_STR("Programming I2C address failed"));
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "I2C address set to 0x%02X", address);
|
||||
}
|
||||
|
||||
template<size_t N> static bool any_set(const std::array<sensor::Sensor *, N> &sensors) {
|
||||
for (auto *sensor : sensors) {
|
||||
if (sensor != nullptr)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BQ76972Component::update() {
|
||||
// Each group publishes as soon as its read succeeds, so one failed read does not hold back the others
|
||||
bool ok = true;
|
||||
uint16_t words[BQ76972_NUM_CELLS];
|
||||
if (this->stack_voltage_sensor_ != nullptr) {
|
||||
if (this->read_words_(BQ76972_CMD_STACK_VOLTAGE, words, 1)) {
|
||||
if (words[0] != 0)
|
||||
this->stack_voltage_sensor_->publish_state(words[0] * 0.01f); // 10 mV units
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (any_set(this->cell_sensors_)) {
|
||||
if (this->read_words_(BQ76972_CMD_CELL_START, words, BQ76972_NUM_CELLS)) {
|
||||
for (size_t i = 0; i < BQ76972_NUM_CELLS; i++) {
|
||||
if (this->cell_sensors_[i] != nullptr && words[i] != 0)
|
||||
this->cell_sensors_[i]->publish_state(words[i] * 0.001f); // mV
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (any_set(this->temperature_sensors_)) {
|
||||
if (this->read_words_(BQ76972_CMD_TEMP_START, words, BQ76972_NUM_TEMPERATURES)) {
|
||||
for (size_t i = 0; i < BQ76972_NUM_TEMPERATURES; i++) {
|
||||
if (this->temperature_sensors_[i] != nullptr)
|
||||
this->temperature_sensors_[i]->publish_state(raw_to_celsius(words[i]));
|
||||
}
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
this->status_clear_warning();
|
||||
} else {
|
||||
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::bq76972
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace esphome::bq76972 {
|
||||
|
||||
static constexpr size_t BQ76972_NUM_CELLS = 16;
|
||||
static constexpr size_t BQ76972_NUM_TEMPERATURES = 10;
|
||||
|
||||
class BQ76972Component final : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
|
||||
void set_crc_mode(bool crc_mode) { this->crc_mode_ = crc_mode; }
|
||||
void set_reg_disable(bool reg_disable) { this->reg_disable_ = reg_disable; }
|
||||
void set_stack_voltage_sensor(sensor::Sensor *s) { this->stack_voltage_sensor_ = s; }
|
||||
void set_cell_sensor(sensor::Sensor *s, size_t index) { this->cell_sensors_[index] = s; }
|
||||
void set_temperature_sensor(sensor::Sensor *s, size_t index) { this->temperature_sensors_[index] = s; }
|
||||
|
||||
void program_i2c_address(uint8_t address);
|
||||
|
||||
protected:
|
||||
bool read_block_(uint8_t start_register, uint8_t *data, size_t len);
|
||||
bool write_block_(uint8_t start_register, const uint8_t *data, size_t len);
|
||||
bool read_words_(uint8_t start_register, uint16_t *data, size_t num_words);
|
||||
bool send_subcommand_(uint16_t subcommand);
|
||||
bool read_subcommand_(uint16_t subcommand, uint8_t *data, size_t len);
|
||||
bool write_subcommand_(uint16_t subcommand, const uint8_t *data, size_t len);
|
||||
bool wait_for_subcommand_();
|
||||
bool wait_for_cfgupdate_();
|
||||
bool enter_cfg_update_();
|
||||
bool exit_cfg_update_();
|
||||
bool regs_disabled_(bool &out);
|
||||
const LogString *configure_();
|
||||
const LogString *write_config_(bool write_regs);
|
||||
|
||||
bool reg_disable_{false};
|
||||
bool crc_mode_{false};
|
||||
|
||||
sensor::Sensor *stack_voltage_sensor_{nullptr};
|
||||
std::array<sensor::Sensor *, BQ76972_NUM_CELLS> cell_sensors_{};
|
||||
std::array<sensor::Sensor *, BQ76972_NUM_TEMPERATURES> temperature_sensors_{};
|
||||
};
|
||||
|
||||
} // namespace esphome::bq76972
|
||||
@@ -11,12 +11,12 @@ void log_button(const char *tag, const char *prefix, const char *type, Button *o
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
|
||||
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, LOG_STR_ARG(obj->get_log_name()));
|
||||
LOG_ENTITY_ICON(tag, prefix, *obj);
|
||||
}
|
||||
|
||||
void Button::press() {
|
||||
ESP_LOGV(TAG, "'%s' Pressed.", this->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' Pressed.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->press_action();
|
||||
this->press_callback_.call();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ constexpr StringToUint8 CLIMATE_SWING_MODES_BY_STR[] = {
|
||||
|
||||
void ClimateCall::perform() {
|
||||
this->parent_->control_callback_.call(*this);
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
this->validate_();
|
||||
if (this->mode_.has_value()) {
|
||||
const LogString *mode_s = climate_mode_to_string(*this->mode_);
|
||||
@@ -183,7 +183,7 @@ ClimateCall &ClimateCall::set_mode(const char *mode, size_t len) {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized mode %.*s", this->parent_->get_name().c_str(), (int) len, mode);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized mode %.*s", LOG_STR_ARG(this->parent_->get_log_name()), (int) len, mode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,8 @@ ClimateCall &ClimateCall::set_fan_mode(const char *custom_fan_mode, size_t len)
|
||||
this->fan_mode_.reset();
|
||||
return *this;
|
||||
}
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %.*s", this->parent_->get_name().c_str(), (int) len, custom_fan_mode);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %.*s", LOG_STR_ARG(this->parent_->get_log_name()), (int) len,
|
||||
custom_fan_mode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -252,7 +253,8 @@ ClimateCall &ClimateCall::set_preset(const char *custom_preset, size_t len) {
|
||||
this->preset_.reset();
|
||||
return *this;
|
||||
}
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized preset %.*s", this->parent_->get_name().c_str(), (int) len, custom_preset);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized preset %.*s", LOG_STR_ARG(this->parent_->get_log_name()), (int) len,
|
||||
custom_preset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -280,7 +282,8 @@ ClimateCall &ClimateCall::set_swing_mode(const char *swing_mode, size_t len) {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized swing mode %.*s", this->parent_->get_name().c_str(), (int) len, swing_mode);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized swing mode %.*s", LOG_STR_ARG(this->parent_->get_log_name()), (int) len,
|
||||
swing_mode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -428,7 +431,7 @@ void Climate::save_state_(const ClimateTraits &traits) {
|
||||
|
||||
void Climate::publish_state() {
|
||||
this->set_has_state(true);
|
||||
ESP_LOGV(TAG, "'%s' >>", this->name_.c_str());
|
||||
ESP_LOGV(TAG, "'%s' >>", LOG_STR_ARG(this->get_log_name()));
|
||||
auto traits = this->get_traits();
|
||||
|
||||
ESP_LOGV(TAG, " Mode: %s", LOG_STR_ARG(climate_mode_to_string(this->mode)));
|
||||
@@ -549,7 +552,7 @@ void ClimateDeviceRestoreState::apply(Climate *climate) {
|
||||
if (traits.supports_mode(this->mode)) {
|
||||
climate->mode = this->mode;
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Saved mode %s is no longer supported, keeping %s", climate->get_name().c_str(),
|
||||
ESP_LOGW(TAG, "'%s' - Saved mode %s is no longer supported, keeping %s", LOG_STR_ARG(climate->get_log_name()),
|
||||
LOG_STR_ARG(climate_mode_to_string(this->mode)), LOG_STR_ARG(climate_mode_to_string(climate->mode)));
|
||||
}
|
||||
if (traits.has_feature_flags(CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace esphome::climate {
|
||||
|
||||
#define LOG_CLIMATE(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
}
|
||||
|
||||
class Climate;
|
||||
|
||||
@@ -30,14 +30,14 @@ void CombinationOneParameterComponent::add_source(Sensor *sensor, float value) {
|
||||
void CombinationNoParameterComponent::log_source_sensors() {
|
||||
ESP_LOGCONFIG(TAG, " Source Sensors:");
|
||||
for (const auto &sensor : this->sensors_) {
|
||||
ESP_LOGCONFIG(TAG, " - %s", sensor->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, " - %s", LOG_STR_ARG(sensor->get_log_name()));
|
||||
}
|
||||
}
|
||||
|
||||
void CombinationOneParameterComponent::log_source_sensors() {
|
||||
ESP_LOGCONFIG(TAG, " Source Sensors:");
|
||||
for (const auto &source : this->sensor_sources_) {
|
||||
ESP_LOGCONFIG(TAG, " - %s", source.sensor->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, " - %s", LOG_STR_ARG(source.sensor->get_log_name()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ CoverCall &CoverCall::set_command(const char *command) {
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("TOGGLE")) == 0) {
|
||||
this->set_command_toggle();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized command %s", this->parent_->get_name().c_str(), command);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized command %s", LOG_STR_ARG(this->parent_->get_log_name()), command);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ CoverCall &CoverCall::set_tilt(float tilt) {
|
||||
return *this;
|
||||
}
|
||||
void CoverCall::perform() {
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
auto traits = this->parent_->get_traits();
|
||||
this->validate_();
|
||||
if (this->stop_) {
|
||||
@@ -94,7 +94,7 @@ const optional<float> &CoverCall::get_tilt() const { return this->tilt_; }
|
||||
const optional<bool> &CoverCall::get_toggle() const { return this->toggle_; }
|
||||
void CoverCall::validate_() {
|
||||
auto traits = this->parent_->get_traits();
|
||||
const char *name = this->parent_->get_name().c_str();
|
||||
const char *name = LOG_STR_ARG(this->parent_->get_log_name());
|
||||
|
||||
if (this->position_.has_value()) {
|
||||
auto pos = *this->position_;
|
||||
@@ -139,7 +139,7 @@ void Cover::publish_state(bool save) {
|
||||
this->position = clamp(this->position, 0.0f, 1.0f);
|
||||
this->tilt = clamp(this->tilt, 0.0f, 1.0f);
|
||||
|
||||
ESP_LOGV(TAG, "'%s' >>", this->name_.c_str());
|
||||
ESP_LOGV(TAG, "'%s' >>", LOG_STR_ARG(this->get_log_name()));
|
||||
auto traits = this->get_traits();
|
||||
if (traits.get_supports_position()) {
|
||||
ESP_LOGV(TAG, " Position: %.0f%%", this->position * 100.0f);
|
||||
|
||||
@@ -15,7 +15,7 @@ static constexpr float COVER_CLOSED = 0.0f;
|
||||
|
||||
#define LOG_COVER(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
auto traits_ = (obj)->get_traits(); \
|
||||
if (traits_.get_is_assumed_state()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
|
||||
|
||||
@@ -40,7 +40,8 @@ void CTClampSensor::update() {
|
||||
if (rms_ac_squared > 0)
|
||||
rms_ac = std::sqrt(rms_ac_squared);
|
||||
ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %" PRIu32 " different samples (%" PRIu32 " SPS)",
|
||||
this->name_.c_str(), rms_ac, this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_);
|
||||
LOG_STR_ARG(this->get_log_name()), rms_ac, this->num_samples_,
|
||||
1000 * this->num_samples_ / this->sample_duration_);
|
||||
this->publish_state(rms_ac);
|
||||
});
|
||||
|
||||
|
||||
@@ -70,20 +70,20 @@ void CurrentBasedCover::loop() {
|
||||
this->direction_idle_();
|
||||
this->malfunction_trigger_.trigger();
|
||||
ESP_LOGI(TAG, "'%s' - Malfunction detected during opening. Current flow detected in close circuit",
|
||||
this->name_.c_str());
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
} else if (this->is_opening_blocked_()) { // Blocked
|
||||
ESP_LOGD(TAG, "'%s' - Obstacle detected during opening.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Obstacle detected during opening.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->direction_idle_();
|
||||
if (this->obstacle_rollback_ != 0) {
|
||||
this->set_timeout(ROLLBACK_TIMEOUT_ID, 300, [this]() {
|
||||
ESP_LOGD(TAG, "'%s' - Rollback.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Rollback.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->target_position_ = clamp(this->position - this->obstacle_rollback_, 0.0F, 1.0F);
|
||||
this->start_direction_(COVER_OPERATION_CLOSING);
|
||||
});
|
||||
}
|
||||
} else if (this->is_initial_delay_finished_() && !this->is_opening_()) { // End reached
|
||||
auto dur = (now - this->start_dir_time_) / 1e3f;
|
||||
ESP_LOGD(TAG, "'%s' - Open position reached. Took %.1fs.", this->name_.c_str(), dur);
|
||||
ESP_LOGD(TAG, "'%s' - Open position reached. Took %.1fs.", LOG_STR_ARG(this->get_log_name()), dur);
|
||||
this->direction_idle_(COVER_OPEN);
|
||||
}
|
||||
} else if (this->current_operation == COVER_OPERATION_CLOSING) {
|
||||
@@ -91,25 +91,25 @@ void CurrentBasedCover::loop() {
|
||||
this->direction_idle_();
|
||||
this->malfunction_trigger_.trigger();
|
||||
ESP_LOGI(TAG, "'%s' - Malfunction detected during closing. Current flow detected in open circuit",
|
||||
this->name_.c_str());
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
} else if (this->is_closing_blocked_()) { // Blocked
|
||||
ESP_LOGD(TAG, "'%s' - Obstacle detected during closing.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Obstacle detected during closing.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->direction_idle_();
|
||||
if (this->obstacle_rollback_ != 0) {
|
||||
this->set_timeout(ROLLBACK_TIMEOUT_ID, 300, [this]() {
|
||||
ESP_LOGD(TAG, "'%s' - Rollback.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Rollback.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->target_position_ = clamp(this->position + this->obstacle_rollback_, 0.0F, 1.0F);
|
||||
this->start_direction_(COVER_OPERATION_OPENING);
|
||||
});
|
||||
}
|
||||
} else if (this->is_initial_delay_finished_() && !this->is_closing_()) { // End reached
|
||||
auto dur = (now - this->start_dir_time_) / 1e3f;
|
||||
ESP_LOGD(TAG, "'%s' - Close position reached. Took %.1fs.", this->name_.c_str(), dur);
|
||||
ESP_LOGD(TAG, "'%s' - Close position reached. Took %.1fs.", LOG_STR_ARG(this->get_log_name()), dur);
|
||||
this->direction_idle_(COVER_CLOSED);
|
||||
}
|
||||
}
|
||||
if (now - this->start_dir_time_ > this->max_duration_) {
|
||||
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->direction_idle_();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void DallasTemperatureSensor::update() {
|
||||
}
|
||||
|
||||
float tempc = this->get_temp_c_();
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%f°C", this->get_name().c_str(), tempc);
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%f°C", LOG_STR_ARG(this->get_log_name()), tempc);
|
||||
this->publish_state(tempc);
|
||||
});
|
||||
}
|
||||
@@ -65,7 +65,7 @@ bool DallasTemperatureSensor::read_scratch_pad_() {
|
||||
i = this->bus_->read8();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - reading scratch pad failed bus reset", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s' - reading scratch pad failed bus reset", LOG_STR_ARG(this->get_log_name()));
|
||||
this->status_set_warning(LOG_STR("bus reset failed"));
|
||||
}
|
||||
return success;
|
||||
|
||||
@@ -30,7 +30,7 @@ void DateEntity::publish_state() {
|
||||
return;
|
||||
}
|
||||
this->set_has_state(true);
|
||||
ESP_LOGV(TAG, "'%s' >> %d-%d-%d", this->get_name().c_str(), this->year_, this->month_, this->day_);
|
||||
ESP_LOGV(TAG, "'%s' >> %d-%d-%d", LOG_STR_ARG(this->get_log_name()), this->year_, this->month_, this->day_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_DATE) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_date_update(this);
|
||||
@@ -81,7 +81,7 @@ void DateCall::validate_() {
|
||||
|
||||
void DateCall::perform() {
|
||||
this->validate_();
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
|
||||
if (this->year_.has_value()) {
|
||||
ESP_LOGV(TAG, " Year: %d", *this->year_);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace esphome::datetime {
|
||||
|
||||
#define LOG_DATETIME_DATE(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ void DateTimeEntity::publish_state() {
|
||||
return;
|
||||
}
|
||||
this->set_has_state(true);
|
||||
ESP_LOGV(TAG, "'%s' >> %04u-%02u-%02u %02d:%02d:%02d", this->get_name().c_str(), this->year_, this->month_,
|
||||
ESP_LOGV(TAG, "'%s' >> %04u-%02u-%02u %02d:%02d:%02d", LOG_STR_ARG(this->get_log_name()), this->year_, this->month_,
|
||||
this->day_, this->hour_, this->minute_, this->second_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_DATETIME) && defined(USE_CONTROLLER_REGISTRY)
|
||||
@@ -125,7 +125,7 @@ void DateTimeCall::validate_() {
|
||||
|
||||
void DateTimeCall::perform() {
|
||||
this->validate_();
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
|
||||
if (this->year_.has_value()) {
|
||||
ESP_LOGV(TAG, " Year: %d", *this->year_);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace esphome::datetime {
|
||||
|
||||
#define LOG_DATETIME_DATETIME(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ void TimeEntity::publish_state() {
|
||||
return;
|
||||
}
|
||||
this->set_has_state(true);
|
||||
ESP_LOGV(TAG, "'%s' >> %02d:%02d:%02d", this->get_name().c_str(), this->hour_, this->minute_, this->second_);
|
||||
ESP_LOGV(TAG, "'%s' >> %02d:%02d:%02d", LOG_STR_ARG(this->get_log_name()), this->hour_, this->minute_, this->second_);
|
||||
this->state_callback_.call();
|
||||
#if defined(USE_DATETIME_TIME) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_time_update(this);
|
||||
@@ -50,7 +50,7 @@ void TimeCall::validate_() {
|
||||
|
||||
void TimeCall::perform() {
|
||||
this->validate_();
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
if (this->hour_.has_value()) {
|
||||
ESP_LOGV(TAG, " Hour: %d", *this->hour_);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace esphome::datetime {
|
||||
|
||||
#define LOG_DATETIME_TIME(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ void DewPointComponent::dump_config() {
|
||||
"Sources\n"
|
||||
" Temperature: '%s'\n"
|
||||
" Humidity: '%s'",
|
||||
this->temperature_sensor_->get_name().c_str(), this->humidity_sensor_->get_name().c_str());
|
||||
LOG_STR_ARG(this->temperature_sensor_->get_log_name()),
|
||||
LOG_STR_ARG(this->humidity_sensor_->get_log_name()));
|
||||
}
|
||||
|
||||
float DewPointComponent::get_setup_priority() const { return setup_priority::DATA; }
|
||||
@@ -75,8 +76,8 @@ void DewPointComponent::loop() {
|
||||
// Publish the calculated dew point
|
||||
this->publish_state(dew_point);
|
||||
|
||||
ESP_LOGD(TAG, "'%s' >> %.1f°C (T: %.1f°C, RH: %.1f%%)", this->get_name().c_str(), dew_point, this->temperature_value_,
|
||||
this->humidity_value_);
|
||||
ESP_LOGD(TAG, "'%s' >> %.1f°C (T: %.1f°C, RH: %.1f%%)", LOG_STR_ARG(this->get_log_name()), dew_point,
|
||||
this->temperature_value_, this->humidity_value_);
|
||||
}
|
||||
|
||||
} // namespace esphome::dew_point
|
||||
|
||||
@@ -36,7 +36,7 @@ void DutyCycleSensor::update() {
|
||||
const float total_time = float(now - this->last_update_);
|
||||
|
||||
const float value = (on_time * 100.0f) / total_time;
|
||||
ESP_LOGD(TAG, "'%s' Got duty cycle=%.1f%%", this->get_name().c_str(), value);
|
||||
ESP_LOGD(TAG, "'%s' Got duty cycle=%.1f%%", LOG_STR_ARG(this->get_log_name()), value);
|
||||
this->publish_state(value);
|
||||
}
|
||||
this->last_update_ = now;
|
||||
|
||||
@@ -70,20 +70,20 @@ void EndstopCover::loop() {
|
||||
|
||||
if (this->current_operation == COVER_OPERATION_OPENING && this->is_open_()) {
|
||||
float dur = (now - this->start_dir_time_) / 1e3f;
|
||||
ESP_LOGD(TAG, "'%s' - Open endstop reached. Took %.1fs.", this->name_.c_str(), dur);
|
||||
ESP_LOGD(TAG, "'%s' - Open endstop reached. Took %.1fs.", LOG_STR_ARG(this->get_log_name()), dur);
|
||||
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->position = COVER_OPEN;
|
||||
this->publish_state();
|
||||
} else if (this->current_operation == COVER_OPERATION_CLOSING && this->is_closed_()) {
|
||||
float dur = (now - this->start_dir_time_) / 1e3f;
|
||||
ESP_LOGD(TAG, "'%s' - Close endstop reached. Took %.1fs.", this->name_.c_str(), dur);
|
||||
ESP_LOGD(TAG, "'%s' - Close endstop reached. Took %.1fs.", LOG_STR_ARG(this->get_log_name()), dur);
|
||||
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->position = COVER_CLOSED;
|
||||
this->publish_state();
|
||||
} else if (now - this->start_dir_time_ > this->max_duration_) {
|
||||
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->publish_state();
|
||||
}
|
||||
|
||||
@@ -132,9 +132,9 @@ void ESP32Camera::dump_config() {
|
||||
" External Clock: Pin:%d Frequency:%u\n"
|
||||
" I2C Pins: SDA:%d SCL:%d\n"
|
||||
" Reset Pin: %d",
|
||||
this->name_.c_str(), YESNO(this->is_internal()), conf.pin_d0, conf.pin_d1, conf.pin_d2, conf.pin_d3,
|
||||
conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7, conf.pin_vsync, conf.pin_href, conf.pin_pclk,
|
||||
conf.pin_xclk, conf.xclk_freq_hz, conf.pin_sccb_sda, conf.pin_sccb_scl, conf.pin_reset);
|
||||
LOG_STR_ARG(this->get_log_name()), YESNO(this->is_internal()), conf.pin_d0, conf.pin_d1, conf.pin_d2,
|
||||
conf.pin_d3, conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7, conf.pin_vsync, conf.pin_href,
|
||||
conf.pin_pclk, conf.pin_xclk, conf.xclk_freq_hz, conf.pin_sccb_sda, conf.pin_sccb_scl, conf.pin_reset);
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Resolution: %s", frame_size_to_str(this->config_.frame_size));
|
||||
ESP_LOGCONFIG(TAG, " Pixel Format: %s", pixel_format_to_str(this->config_.pixel_format));
|
||||
|
||||
@@ -346,13 +346,13 @@ void ESP32TouchComponent::loop() {
|
||||
child->publish_state(new_state);
|
||||
#ifdef USE_ESP32_VARIANT_ESP32
|
||||
ESP_LOGV(TAG, "Touch Pad '%s' state: %s (value: %" PRIu32 ", threshold: %" PRIu32 ")",
|
||||
child->get_name().c_str(), ONOFF(new_state), value, child->get_threshold());
|
||||
LOG_STR_ARG(child->get_log_name()), ONOFF(new_state), value, child->get_threshold());
|
||||
#else
|
||||
if (new_state) {
|
||||
ESP_LOGV(TAG, "Touch Pad '%s' state: ON (value: %" PRIu32 ", benchmark: %" PRIu32 ", threshold: %" PRIu32 ")",
|
||||
child->get_name().c_str(), value, benchmark, child->get_threshold());
|
||||
LOG_STR_ARG(child->get_log_name()), value, benchmark, child->get_threshold());
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Touch Pad '%s' state: OFF", child->get_name().c_str());
|
||||
ESP_LOGV(TAG, "Touch Pad '%s' state: OFF", LOG_STR_ARG(child->get_log_name()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -475,7 +475,8 @@ void ESP32TouchComponent::process_setup_mode_logging_(uint32_t now) {
|
||||
child->value_ = smooth_value;
|
||||
|
||||
#ifdef USE_ESP32_VARIANT_ESP32
|
||||
ESP_LOGD(TAG, "Touch Pad '%s' (Ch%d): %" PRIu32, child->get_name().c_str(), child->channel_id_, smooth_value);
|
||||
ESP_LOGD(TAG, "Touch Pad '%s' (Ch%d): %" PRIu32, LOG_STR_ARG(child->get_log_name()), child->channel_id_,
|
||||
smooth_value);
|
||||
#else
|
||||
uint32_t benchmark = 0;
|
||||
touch_channel_read_data(child->chan_handle_, TOUCH_CHAN_DATA_TYPE_BENCHMARK, &benchmark);
|
||||
@@ -484,7 +485,7 @@ void ESP32TouchComponent::process_setup_mode_logging_(uint32_t now) {
|
||||
ESP_LOGD(TAG,
|
||||
"Touch Pad '%s' (Ch%d): value=%" PRIu32 ", benchmark=%" PRIu32 ", difference=%" PRId32
|
||||
" (set threshold < %" PRId32 " to detect touch)",
|
||||
child->get_name().c_str(), child->channel_id_, smooth_value, benchmark, difference, difference);
|
||||
LOG_STR_ARG(child->get_log_name()), child->channel_id_, smooth_value, benchmark, difference, difference);
|
||||
#endif
|
||||
}
|
||||
this->setup_mode_last_log_print_ = now;
|
||||
@@ -496,7 +497,7 @@ void ESP32TouchComponent::publish_initial_state_if_needed_(ESP32TouchBinarySenso
|
||||
if (now > INITIAL_STATE_DELAY_MS) {
|
||||
child->publish_initial_state(false);
|
||||
child->initial_state_published_ = true;
|
||||
ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str());
|
||||
ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", LOG_STR_ARG(child->get_log_name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ void Event::trigger(const char *event_type) {
|
||||
}
|
||||
}
|
||||
if (found == nullptr) {
|
||||
ESP_LOGE(TAG, "'%s': invalid event type for trigger(): %s", this->get_name().c_str(), event_type);
|
||||
ESP_LOGE(TAG, "'%s': invalid event type for trigger(): %s", LOG_STR_ARG(this->get_log_name()), event_type);
|
||||
return;
|
||||
}
|
||||
this->last_event_type_ = found;
|
||||
ESP_LOGV(TAG, "'%s' >> '%s'", this->get_name().c_str(), this->last_event_type_);
|
||||
ESP_LOGV(TAG, "'%s' >> '%s'", LOG_STR_ARG(this->get_log_name()), this->last_event_type_);
|
||||
this->event_callback_.call(StringRef(found));
|
||||
#if defined(USE_EVENT) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_event(this);
|
||||
|
||||
@@ -16,7 +16,7 @@ using EventTypes = ConstVector<const char *, true>;
|
||||
|
||||
#define LOG_EVENT(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
LOG_ENTITY_DEVICE_CLASS(TAG, prefix, *(obj)); \
|
||||
}
|
||||
|
||||
@@ -52,14 +52,15 @@ FanCall &FanCall::set_preset_mode(const char *preset_mode, size_t len) {
|
||||
this->preset_mode_ = validated_mode; // Store pointer from traits
|
||||
} else {
|
||||
// Preset mode not found in traits - log warning and don't set
|
||||
ESP_LOGW(TAG, "%s: Preset mode '%.*s' not supported", this->parent_.get_name().c_str(), (int) len, preset_mode);
|
||||
ESP_LOGW(TAG, "%s: Preset mode '%.*s' not supported", LOG_STR_ARG(this->parent_.get_log_name()), (int) len,
|
||||
preset_mode);
|
||||
this->preset_mode_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FanCall::perform() {
|
||||
ESP_LOGV(TAG, "'%s' - Setting:", this->parent_.get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting:", LOG_STR_ARG(this->parent_.get_log_name()));
|
||||
this->validate_();
|
||||
if (this->binary_state_.has_value()) {
|
||||
ESP_LOGV(TAG, " State: %s", ONOFF(*this->binary_state_));
|
||||
@@ -103,17 +104,17 @@ void FanCall::validate_() {
|
||||
}
|
||||
|
||||
if (this->oscillating_.has_value() && !traits.supports_oscillation()) {
|
||||
ESP_LOGW(TAG, "%s: Oscillation not supported", this->parent_.get_name().c_str());
|
||||
ESP_LOGW(TAG, "%s: Oscillation not supported", LOG_STR_ARG(this->parent_.get_log_name()));
|
||||
this->oscillating_.reset();
|
||||
}
|
||||
|
||||
if (this->speed_.has_value() && !traits.supports_speed()) {
|
||||
ESP_LOGW(TAG, "%s: Speed control not supported", this->parent_.get_name().c_str());
|
||||
ESP_LOGW(TAG, "%s: Speed control not supported", LOG_STR_ARG(this->parent_.get_log_name()));
|
||||
this->speed_.reset();
|
||||
}
|
||||
|
||||
if (this->direction_.has_value() && !traits.supports_direction()) {
|
||||
ESP_LOGW(TAG, "%s: Direction control not supported", this->parent_.get_name().c_str());
|
||||
ESP_LOGW(TAG, "%s: Direction control not supported", LOG_STR_ARG(this->parent_.get_log_name()));
|
||||
this->direction_.reset();
|
||||
}
|
||||
}
|
||||
@@ -221,7 +222,7 @@ void Fan::publish_state() {
|
||||
ESP_LOGV(TAG,
|
||||
"'%s' >>\n"
|
||||
" State: %s",
|
||||
this->name_.c_str(), ONOFF(this->state));
|
||||
LOG_STR_ARG(this->get_log_name()), ONOFF(this->state));
|
||||
if (traits.supports_speed()) {
|
||||
ESP_LOGV(TAG, " Speed: %d", this->speed);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace esphome::fan {
|
||||
|
||||
#define LOG_FAN(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
(obj)->dump_traits_(TAG, prefix); \
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ void FeedbackCover::set_open_sensor(binary_sensor::BinarySensor *open_feedback)
|
||||
|
||||
// setup callbacks to react to sensor changes
|
||||
open_feedback->add_on_state_callback([this](bool state) {
|
||||
ESP_LOGD(TAG, "'%s' - Open feedback '%s'.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - Open feedback '%s'.", LOG_STR_ARG(this->get_log_name()),
|
||||
state ? LOG_STR_LITERAL("STARTED") : LOG_STR_LITERAL("ENDED"));
|
||||
this->recompute_position_();
|
||||
if (!state && this->infer_endstop_ && this->current_trigger_operation_ == COVER_OPERATION_OPENING) {
|
||||
@@ -112,7 +112,7 @@ void FeedbackCover::set_close_sensor(binary_sensor::BinarySensor *close_feedback
|
||||
this->close_feedback_ = close_feedback;
|
||||
|
||||
close_feedback->add_on_state_callback([this](bool state) {
|
||||
ESP_LOGD(TAG, "'%s' - Close feedback '%s'.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - Close feedback '%s'.", LOG_STR_ARG(this->get_log_name()),
|
||||
state ? LOG_STR_LITERAL("STARTED") : LOG_STR_LITERAL("ENDED"));
|
||||
this->recompute_position_();
|
||||
if (!state && this->infer_endstop_ && this->current_trigger_operation_ == COVER_OPERATION_CLOSING) {
|
||||
@@ -151,7 +151,7 @@ void FeedbackCover::endstop_reached_(bool open_endstop) {
|
||||
// from a position slightly past the endpoint
|
||||
if (this->current_trigger_operation_ == (open_endstop ? COVER_OPERATION_OPENING : COVER_OPERATION_CLOSING)) {
|
||||
float dur = (now - this->start_dir_time_) / 1e3f;
|
||||
ESP_LOGD(TAG, "'%s' - %s endstop reached. Took %.1fs.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - %s endstop reached. Took %.1fs.", LOG_STR_ARG(this->get_log_name()),
|
||||
open_endstop ? LOG_STR_LITERAL("Open") : LOG_STR_LITERAL("Close"), dur);
|
||||
|
||||
// if there is no external mechanism, stop the cover
|
||||
@@ -198,7 +198,7 @@ void FeedbackCover::set_close_obstacle_sensor(binary_sensor::BinarySensor *close
|
||||
close_obstacle->add_on_state_callback([this](bool state) {
|
||||
if (state && (this->current_operation == COVER_OPERATION_CLOSING ||
|
||||
this->current_trigger_operation_ == COVER_OPERATION_CLOSING)) {
|
||||
ESP_LOGD(TAG, "'%s' - Close obstacle detected.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Close obstacle detected.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
|
||||
if (this->obstacle_rollback_) {
|
||||
@@ -215,7 +215,7 @@ void FeedbackCover::set_open_obstacle_sensor(binary_sensor::BinarySensor *open_o
|
||||
open_obstacle->add_on_state_callback([this](bool state) {
|
||||
if (state && (this->current_operation == COVER_OPERATION_OPENING ||
|
||||
this->current_trigger_operation_ == COVER_OPERATION_OPENING)) {
|
||||
ESP_LOGD(TAG, "'%s' - Open obstacle detected.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Open obstacle detected.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
|
||||
if (this->obstacle_rollback_) {
|
||||
@@ -251,7 +251,7 @@ void FeedbackCover::loop() {
|
||||
this->start_overshoot_time_ = now;
|
||||
} else if (now - this->start_overshoot_time_ > this->overshoot_duration_ ||
|
||||
now - this->start_dir_time_ > this->max_duration_) {
|
||||
ESP_LOGD(TAG, "'%s' - Overshoot duration reached. Stopping cover.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Overshoot duration reached. Stopping cover.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
}
|
||||
#endif
|
||||
@@ -259,7 +259,7 @@ void FeedbackCover::loop() {
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
}
|
||||
} else if (now - this->start_dir_time_ > this->max_duration_) {
|
||||
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
}
|
||||
}
|
||||
@@ -390,7 +390,7 @@ void FeedbackCover::start_direction_(CoverOperation dir) {
|
||||
// check if there is an obstacle to start the new operation -> abort without any change
|
||||
// the case when an obstacle appears while moving is handled in the callback
|
||||
if (obstacle != nullptr && obstacle->state) {
|
||||
ESP_LOGD(TAG, "'%s' - %s obstacle detected. Action not started.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - %s obstacle detected. Action not started.", LOG_STR_ARG(this->get_log_name()),
|
||||
dir == COVER_OPERATION_OPENING ? LOG_STR_LITERAL("Open") : LOG_STR_LITERAL("Close"));
|
||||
return;
|
||||
}
|
||||
@@ -401,13 +401,13 @@ void FeedbackCover::start_direction_(CoverOperation dir) {
|
||||
if (this->direction_change_waittime_.has_value() && dir != COVER_OPERATION_IDLE &&
|
||||
this->current_operation != COVER_OPERATION_IDLE && dir != this->current_operation) {
|
||||
const uint32_t waittime = *this->direction_change_waittime_;
|
||||
ESP_LOGD(TAG, "'%s' - Reversing direction.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Reversing direction.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->set_timeout(DIRECTION_CHANGE_TIMEOUT_ID, waittime, [this, dir]() { this->start_direction_(dir); });
|
||||
} else {
|
||||
this->set_current_operation_(dir, true);
|
||||
this->prev_command_trigger_ = trig;
|
||||
ESP_LOGD(TAG, "'%s' - Firing '%s' trigger.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - Firing '%s' trigger.", LOG_STR_ARG(this->get_log_name()),
|
||||
dir == COVER_OPERATION_OPENING ? LOG_STR_LITERAL("OPEN")
|
||||
: dir == COVER_OPERATION_CLOSING ? LOG_STR_LITERAL("CLOSE")
|
||||
: LOG_STR_LITERAL("STOP"));
|
||||
|
||||
@@ -28,7 +28,7 @@ void GPIOSwitch::dump_config() {
|
||||
for (auto *lock : this->interlock_) {
|
||||
if (lock == this)
|
||||
continue;
|
||||
ESP_LOGCONFIG(TAG, " %s", lock->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, " %s", LOG_STR_ARG(lock->get_log_name()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -58,7 +58,7 @@ void HE60rCover::endstop_reached_(CoverOperation operation) {
|
||||
this->current_operation = COVER_OPERATION_IDLE;
|
||||
if (this->last_command_ == operation) {
|
||||
float dur = (float) (now - this->start_dir_time_) / 1e3f;
|
||||
ESP_LOGD(TAG, "'%s' - %s endstop reached. Took %.1fs.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - %s endstop reached. Took %.1fs.", LOG_STR_ARG(this->get_log_name()),
|
||||
operation == COVER_OPERATION_OPENING ? LOG_STR_LITERAL("Open") : LOG_STR_LITERAL("Close"), dur);
|
||||
}
|
||||
this->publish_state();
|
||||
@@ -213,7 +213,7 @@ void HE60rCover::start_direction_(CoverOperation dir) {
|
||||
this->last_command_ = dir;
|
||||
if (this->current_operation == dir)
|
||||
return;
|
||||
ESP_LOGD(TAG, "'%s' - Direction '%s' requested.", this->name_.c_str(),
|
||||
ESP_LOGD(TAG, "'%s' - Direction '%s' requested.", LOG_STR_ARG(this->get_log_name()),
|
||||
dir == COVER_OPERATION_OPENING ? LOG_STR_LITERAL("OPEN")
|
||||
: dir == COVER_OPERATION_CLOSING ? LOG_STR_LITERAL("CLOSE")
|
||||
: LOG_STR_LITERAL("STOP"));
|
||||
@@ -229,7 +229,7 @@ void HE60rCover::start_direction_(CoverOperation dir) {
|
||||
// just stop and reverse
|
||||
this->toggles_needed_ = 2;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s' - Reversing direction.", this->name_.c_str());
|
||||
ESP_LOGD(TAG, "'%s' - Reversing direction.", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
this->start_dir_time_ = millis();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ void HomeassistantButton::press_action() {
|
||||
|
||||
#ifdef USE_API_WIZARD_LINKED_INPUTS
|
||||
if (this->entity_id_[0] == '\0') {
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@ void HomeassistantNumber::min_retrieved_(StringRef min) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'min' value '%s' to number!", this->entity_id_, min.c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Min retrieved: %s", get_name().c_str(), min.c_str());
|
||||
ESP_LOGD(TAG, "'%s': Min retrieved: %s", LOG_STR_ARG(this->get_log_name()), min.c_str());
|
||||
this->traits.set_min_value(min_value.value());
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ void HomeassistantNumber::max_retrieved_(StringRef max) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'max' value '%s' to number!", this->entity_id_, max.c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Max retrieved: %s", get_name().c_str(), max.c_str());
|
||||
ESP_LOGD(TAG, "'%s': Max retrieved: %s", LOG_STR_ARG(this->get_log_name()), max.c_str());
|
||||
this->traits.set_max_value(max_value.value());
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ void HomeassistantNumber::step_retrieved_(StringRef step) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'step' value '%s' to number!", this->entity_id_, step.c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Step Retrieved %s", get_name().c_str(), step.c_str());
|
||||
ESP_LOGD(TAG, "'%s': Step Retrieved %s", LOG_STR_ARG(this->get_log_name()), step.c_str());
|
||||
this->traits.set_step(step_value.value());
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ void HomeassistantNumber::control(float value) {
|
||||
|
||||
#ifdef USE_API_WIZARD_LINKED_INPUTS
|
||||
if (this->entity_id_[0] == '\0') {
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -232,7 +232,7 @@ void HomeassistantSelect::control(size_t index) {
|
||||
|
||||
#ifdef USE_API_WIZARD_LINKED_INPUTS
|
||||
if (this->entity_id_[0] == '\0') {
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,7 @@ void HomeassistantSwitch::write_state(bool state) {
|
||||
|
||||
#ifdef USE_API_WIZARD_LINKED_INPUTS
|
||||
if (this->entity_id_[0] == '\0') {
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -81,7 +81,7 @@ void HomeassistantText::control(const std::string &value) {
|
||||
|
||||
#ifdef USE_API_WIZARD_LINKED_INPUTS
|
||||
if (this->entity_id_[0] == '\0') {
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s': No entity ID set yet", LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,7 +25,7 @@ void HX711Sensor::update() {
|
||||
uint32_t result;
|
||||
if (this->read_sensor_(&result)) {
|
||||
int32_t value = static_cast<int32_t>(result);
|
||||
ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), value);
|
||||
ESP_LOGD(TAG, "'%s': Got value %" PRId32, LOG_STR_ARG(this->get_log_name()), value);
|
||||
this->publish_state(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,24 @@ static const uint8_t INA3221_REGISTER_CHANNEL2_SHUNT_VOLTAGE = 0x03;
|
||||
static const uint8_t INA3221_REGISTER_CHANNEL2_BUS_VOLTAGE = 0x04;
|
||||
static const uint8_t INA3221_REGISTER_CHANNEL3_SHUNT_VOLTAGE = 0x05;
|
||||
static const uint8_t INA3221_REGISTER_CHANNEL3_BUS_VOLTAGE = 0x06;
|
||||
#ifdef USE_INA3221_ALERT_LIMITS
|
||||
static constexpr uint8_t INA3221_REGISTER_CHANNEL1_CRITICAL_ALERT = 0x07;
|
||||
static constexpr uint8_t INA3221_REGISTER_CHANNEL1_WARNING_ALERT = 0x0A;
|
||||
#endif
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
static constexpr uint8_t INA3221_REGISTER_SHUNT_VOLTAGE_SUM = 0x0D;
|
||||
static constexpr uint8_t INA3221_REGISTER_MASK_ENABLE = 0x0F;
|
||||
#endif
|
||||
|
||||
// Configuration register: bit 15 resets the chip, bits 14..12 enable channels 1..3 (the same bit
|
||||
// positions select channels for summation in the mask/enable register) and bits 2..0 set the mode.
|
||||
// Code generation fills in the averaging and conversion time fields.
|
||||
static constexpr uint16_t INA3221_CONFIG_RESET = 0x8000;
|
||||
static constexpr uint16_t INA3221_CONFIG_CHANNEL1_ENABLE = 0x4000;
|
||||
static constexpr uint16_t INA3221_CONFIG_CHANNEL_MASK = 0x7000;
|
||||
static constexpr uint16_t INA3221_CONFIG_MODE_MASK = 0x0007;
|
||||
|
||||
static constexpr uint32_t READ_TIMEOUT_ID = 0;
|
||||
|
||||
// Addresses:
|
||||
// A0 = GND -> 0x40
|
||||
@@ -21,37 +39,38 @@ static const uint8_t INA3221_REGISTER_CHANNEL3_BUS_VOLTAGE = 0x06;
|
||||
// A0 = SCL -> 0x43
|
||||
|
||||
void INA3221Component::setup() {
|
||||
// Config Register
|
||||
// 0bx000000000000000 << 15 RESET Bit (1 -> trigger reset)
|
||||
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, 0x8000)) {
|
||||
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, INA3221_CONFIG_RESET)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
delay(1);
|
||||
|
||||
uint16_t config = 0;
|
||||
// 0b0xxx000000000000 << 12 Channel Enables (1 -> ON)
|
||||
if (this->channels_[0].exists()) {
|
||||
config |= 0b0100000000000000;
|
||||
}
|
||||
if (this->channels_[1].exists()) {
|
||||
config |= 0b0010000000000000;
|
||||
}
|
||||
if (this->channels_[2].exists()) {
|
||||
config |= 0b0001000000000000;
|
||||
}
|
||||
// 0b0000xxx000000000 << 9 Averaging Mode (0 -> 1 sample, 111 -> 1024 samples)
|
||||
config |= 0b0000000000000000;
|
||||
// 0b0000000xxx000000 << 6 Bus Voltage Conversion time (100 -> 1.1ms, 111 -> 8.244 ms)
|
||||
config |= 0b0000000111000000;
|
||||
// 0b0000000000xxx000 << 3 Shunt Voltage Conversion time (same as above)
|
||||
config |= 0b0000000000111000;
|
||||
// 0b0000000000000xxx << 0 Operating mode (111 -> Shunt and bus, continuous)
|
||||
config |= 0b0000000000000111;
|
||||
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, config)) {
|
||||
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, this->config_)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_INA3221_ALERT_LIMITS
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
const INA3221Channel &channel = this->channels_[i];
|
||||
if ((channel.critical_limit_ != 0 &&
|
||||
!this->write_byte_16(INA3221_REGISTER_CHANNEL1_CRITICAL_ALERT + i, channel.critical_limit_)) ||
|
||||
(channel.warning_limit_ != 0 &&
|
||||
!this->write_byte_16(INA3221_REGISTER_CHANNEL1_WARNING_ALERT + i, channel.warning_limit_))) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
// Sum the shunt voltages of every enabled channel
|
||||
if (this->sum_shunt_voltage_sensor_ != nullptr &&
|
||||
!this->write_byte_16(INA3221_REGISTER_MASK_ENABLE, this->config_ & INA3221_CONFIG_CHANNEL_MASK)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void INA3221Component::dump_config() {
|
||||
@@ -61,6 +80,10 @@ void INA3221Component::dump_config() {
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
ESP_LOGCONFIG(TAG, " Config register: 0x%04X", this->config_);
|
||||
if (this->single_shot_wait_ms_ != 0) {
|
||||
ESP_LOGCONFIG(TAG, " Single-shot conversion: %u ms", this->single_shot_wait_ms_);
|
||||
}
|
||||
|
||||
LOG_SENSOR(" ", "Bus Voltage #1", this->channels_[0].bus_voltage_sensor_);
|
||||
LOG_SENSOR(" ", "Shunt Voltage #1", this->channels_[0].shunt_voltage_sensor_);
|
||||
@@ -74,6 +97,11 @@ void INA3221Component::dump_config() {
|
||||
LOG_SENSOR(" ", "Shunt Voltage #3", this->channels_[2].shunt_voltage_sensor_);
|
||||
LOG_SENSOR(" ", "Current #3", this->channels_[2].current_sensor_);
|
||||
LOG_SENSOR(" ", "Power #3", this->channels_[2].power_sensor_);
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
LOG_SENSOR(" ", "Sum Shunt Voltage", this->sum_shunt_voltage_sensor_);
|
||||
LOG_SENSOR(" ", "Sum Current", this->sum_current_sensor_);
|
||||
LOG_SENSOR(" ", "Sum Power", this->sum_power_sensor_);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint8_t ina3221_bus_voltage_register(int channel) { return 0x02 + channel * 2; }
|
||||
@@ -81,11 +109,36 @@ inline uint8_t ina3221_bus_voltage_register(int channel) { return 0x02 + channel
|
||||
inline uint8_t ina3221_shunt_voltage_register(int channel) { return 0x01 + channel * 2; }
|
||||
|
||||
void INA3221Component::update() {
|
||||
if (this->single_shot_wait_ms_ == 0) {
|
||||
this->read_data_();
|
||||
return;
|
||||
}
|
||||
// In single-shot mode, writing the configuration register starts one conversion of every channel
|
||||
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, this->config_)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
this->set_timeout(READ_TIMEOUT_ID, this->single_shot_wait_ms_, [this]() { this->read_data_(); });
|
||||
}
|
||||
|
||||
void INA3221Component::read_data_() {
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
// The software sums need every enabled channel's readings, not only the ones with their own sensors
|
||||
const bool sum_all = this->sum_current_sensor_ != nullptr || this->sum_power_sensor_ != nullptr;
|
||||
float total_current_a = 0.0f;
|
||||
float total_power_w = 0.0f;
|
||||
#else
|
||||
constexpr bool sum_all = false;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if ((this->config_ & (INA3221_CONFIG_CHANNEL1_ENABLE >> i)) == 0) {
|
||||
continue;
|
||||
}
|
||||
INA3221Channel &channel = this->channels_[i];
|
||||
float bus_voltage_v = NAN, current_a = NAN;
|
||||
uint16_t raw;
|
||||
if (channel.should_measure_bus_voltage()) {
|
||||
if (sum_all || channel.should_measure_bus_voltage()) {
|
||||
if (!this->read_byte_16(ina3221_bus_voltage_register(i), &raw)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
@@ -94,7 +147,7 @@ void INA3221Component::update() {
|
||||
if (channel.bus_voltage_sensor_ != nullptr)
|
||||
channel.bus_voltage_sensor_->publish_state(bus_voltage_v);
|
||||
}
|
||||
if (channel.should_measure_shunt_voltage()) {
|
||||
if (sum_all || channel.should_measure_shunt_voltage()) {
|
||||
if (!this->read_byte_16(ina3221_shunt_voltage_register(i), &raw)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
@@ -109,17 +162,42 @@ void INA3221Component::update() {
|
||||
if (channel.power_sensor_ != nullptr) {
|
||||
channel.power_sensor_->publish_state(bus_voltage_v * current_a);
|
||||
}
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
if (sum_all) {
|
||||
total_current_a += current_a;
|
||||
total_power_w += bus_voltage_v * current_a;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
if (this->sum_shunt_voltage_sensor_ != nullptr) {
|
||||
uint16_t raw;
|
||||
if (!this->read_byte_16(INA3221_REGISTER_SHUNT_VOLTAGE_SUM, &raw)) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
// 40 uV per step, held in bits 15..1
|
||||
this->sum_shunt_voltage_sensor_->publish_state(int16_t(raw) * 40.0f / 2.0f / 1000000.0f);
|
||||
}
|
||||
if (this->sum_current_sensor_ != nullptr) {
|
||||
this->sum_current_sensor_->publish_state(total_current_a);
|
||||
}
|
||||
if (this->sum_power_sensor_ != nullptr) {
|
||||
this->sum_power_sensor_->publish_state(total_power_w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void INA3221Component::on_powerdown() {
|
||||
// Mode 0 powers the chip down; setup() resets it on the next boot
|
||||
this->write_byte_16(INA3221_REGISTER_CONFIG, static_cast<uint16_t>(this->config_ & ~INA3221_CONFIG_MODE_MASK));
|
||||
}
|
||||
|
||||
void INA3221Component::set_shunt_resistance(int channel, float resistance_ohm) {
|
||||
this->channels_[channel].shunt_resistance_ = resistance_ohm;
|
||||
}
|
||||
|
||||
bool INA3221Component::INA3221Channel::exists() {
|
||||
return this->bus_voltage_sensor_ != nullptr || this->shunt_voltage_sensor_ != nullptr ||
|
||||
this->current_sensor_ != nullptr || this->power_sensor_ != nullptr;
|
||||
}
|
||||
bool INA3221Component::INA3221Channel::should_measure_shunt_voltage() {
|
||||
return this->shunt_voltage_sensor_ != nullptr || this->current_sensor_ != nullptr || this->power_sensor_ != nullptr;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,17 @@
|
||||
namespace esphome::ina3221 {
|
||||
|
||||
class INA3221Component final : public PollingComponent, public i2c::I2CDevice {
|
||||
#ifdef USE_INA3221_SUMMATION
|
||||
SUB_SENSOR(sum_shunt_voltage)
|
||||
SUB_SENSOR(sum_current)
|
||||
SUB_SENSOR(sum_power)
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
void on_powerdown() override;
|
||||
|
||||
void set_bus_voltage_sensor(int channel, sensor::Sensor *obj) { this->channels_[channel].bus_voltage_sensor_ = obj; }
|
||||
void set_shunt_voltage_sensor(int channel, sensor::Sensor *obj) {
|
||||
@@ -19,19 +26,35 @@ class INA3221Component final : public PollingComponent, public i2c::I2CDevice {
|
||||
void set_current_sensor(int channel, sensor::Sensor *obj) { this->channels_[channel].current_sensor_ = obj; }
|
||||
void set_power_sensor(int channel, sensor::Sensor *obj) { this->channels_[channel].power_sensor_ = obj; }
|
||||
void set_shunt_resistance(int channel, float resistance_ohm);
|
||||
/// Configuration register value built by code generation: channel enables, averaging, conversion times, mode
|
||||
void set_config_register(uint16_t config) { this->config_ = config; }
|
||||
/// Time one single-shot conversion of every enabled channel takes; zero means continuous mode
|
||||
void set_single_shot_wait_ms(uint16_t wait_ms) { this->single_shot_wait_ms_ = wait_ms; }
|
||||
#ifdef USE_INA3221_ALERT_LIMITS
|
||||
void set_warning_limit(int channel, uint16_t reg) { this->channels_[channel].warning_limit_ = reg; }
|
||||
void set_critical_limit(int channel, uint16_t reg) { this->channels_[channel].critical_limit_ = reg; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void read_data_();
|
||||
|
||||
struct INA3221Channel {
|
||||
float shunt_resistance_{0.1f};
|
||||
sensor::Sensor *bus_voltage_sensor_{nullptr};
|
||||
sensor::Sensor *shunt_voltage_sensor_{nullptr};
|
||||
sensor::Sensor *current_sensor_{nullptr};
|
||||
sensor::Sensor *power_sensor_{nullptr};
|
||||
#ifdef USE_INA3221_ALERT_LIMITS
|
||||
// Alert limit register values; zero keeps the chip default, which never trips
|
||||
uint16_t warning_limit_{0};
|
||||
uint16_t critical_limit_{0};
|
||||
#endif
|
||||
|
||||
bool exists();
|
||||
bool should_measure_shunt_voltage();
|
||||
bool should_measure_bus_voltage();
|
||||
} channels_[3];
|
||||
uint16_t config_{0};
|
||||
uint16_t single_shot_wait_ms_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome::ina3221
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
from typing import Any
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.components.const import CONF_ADC_AVERAGING, CONF_ADC_TIME
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_BUS_VOLTAGE,
|
||||
@@ -8,6 +11,7 @@ from esphome.const import (
|
||||
CONF_POWER,
|
||||
CONF_SHUNT_RESISTANCE,
|
||||
CONF_SHUNT_VOLTAGE,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
@@ -23,69 +27,195 @@ DEPENDENCIES = ["i2c"]
|
||||
CONF_CHANNEL_1 = "channel_1"
|
||||
CONF_CHANNEL_2 = "channel_2"
|
||||
CONF_CHANNEL_3 = "channel_3"
|
||||
CONF_CONTINUOUS_MODE = "continuous_mode"
|
||||
CONF_WARNING_CURRENT_LIMIT = "warning_current_limit"
|
||||
CONF_CRITICAL_CURRENT_LIMIT = "critical_current_limit"
|
||||
CONF_SUM_SHUNT_VOLTAGE = "sum_shunt_voltage"
|
||||
CONF_SUM_CURRENT = "sum_current"
|
||||
CONF_SUM_POWER = "sum_power"
|
||||
|
||||
CHANNELS = (CONF_CHANNEL_1, CONF_CHANNEL_2, CONF_CHANNEL_3)
|
||||
|
||||
# Configuration register layout: channel enables in bits 14..12, averaging in 11..9,
|
||||
# bus conversion time in 8..6, shunt conversion time in 5..3, operating mode in 2..0
|
||||
CHANNEL_ENABLE_BITS = (1 << 14, 1 << 13, 1 << 12)
|
||||
ADC_AVERAGING_SHIFT = 9
|
||||
ADC_TIME_BUS_SHIFT = 6
|
||||
ADC_TIME_SHUNT_SHIFT = 3
|
||||
MODE_SINGLE_SHOT = 0b011
|
||||
MODE_CONTINUOUS = 0b111
|
||||
|
||||
# Register field value by sample count and by conversion time in microseconds
|
||||
ADC_AVERAGING = {1: 0, 4: 1, 16: 2, 64: 3, 128: 4, 256: 5, 512: 6, 1024: 7}
|
||||
ADC_TIMES_US = {140: 0, 204: 1, 332: 2, 588: 3, 1100: 4, 2116: 5, 4156: 6, 8244: 7}
|
||||
|
||||
# Alert limits are shunt voltages in 40 uV steps, held in bits 15..3
|
||||
ALERT_LIMIT_LSB_V = 40e-6
|
||||
ALERT_LIMIT_MAX_V = 0x0FFF * ALERT_LIMIT_LSB_V
|
||||
# Headroom on top of the computed conversion time before the results are read
|
||||
SINGLE_SHOT_MARGIN_MS = 5
|
||||
|
||||
ina3221_ns = cg.esphome_ns.namespace("ina3221")
|
||||
INA3221Component = ina3221_ns.class_(
|
||||
"INA3221Component", cg.PollingComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
INA3221_CHANNEL_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_SHUNT_VOLTAGE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_AMPERE,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_CURRENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_POWER): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All(
|
||||
cv.resistance, cv.Range(min=0.0, max=32.0)
|
||||
),
|
||||
}
|
||||
VOLTAGE_SCHEMA = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
CURRENT_SCHEMA = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_AMPERE,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_CURRENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
POWER_SCHEMA = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_WATT,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_POWER,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
CURRENT_LIMIT_SCHEMA = cv.All(cv.current, cv.Range(min=0.0, min_included=False))
|
||||
|
||||
|
||||
def validate_adc_time(value: Any) -> int:
|
||||
value = cv.positive_time_period_microseconds(value).total_microseconds
|
||||
return cv.one_of(*ADC_TIMES_US, int=True)(value)
|
||||
|
||||
|
||||
def validate_alert_limits(config: ConfigType) -> ConfigType:
|
||||
shunt = config[CONF_SHUNT_RESISTANCE]
|
||||
for key in (CONF_WARNING_CURRENT_LIMIT, CONF_CRITICAL_CURRENT_LIMIT):
|
||||
if (limit := config.get(key)) is None:
|
||||
continue
|
||||
if limit * shunt > ALERT_LIMIT_MAX_V:
|
||||
raise cv.Invalid(
|
||||
f"{key} times shunt_resistance exceeds the "
|
||||
f"{ALERT_LIMIT_MAX_V * 1000:.1f} mV alert range",
|
||||
path=[key],
|
||||
)
|
||||
if alert_limit_register(limit, shunt) == 0:
|
||||
raise cv.Invalid(
|
||||
f"{key} times shunt_resistance is below the "
|
||||
f"{ALERT_LIMIT_LSB_V * 1e6:.0f} µV alert resolution",
|
||||
path=[key],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
INA3221_CHANNEL_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_BUS_VOLTAGE): VOLTAGE_SCHEMA,
|
||||
cv.Optional(CONF_SHUNT_VOLTAGE): VOLTAGE_SCHEMA,
|
||||
cv.Optional(CONF_CURRENT): CURRENT_SCHEMA,
|
||||
cv.Optional(CONF_POWER): POWER_SCHEMA,
|
||||
cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All(
|
||||
cv.resistance, cv.Range(min=0.0, max=32.0)
|
||||
),
|
||||
cv.Optional(CONF_WARNING_CURRENT_LIMIT): CURRENT_LIMIT_SCHEMA,
|
||||
cv.Optional(CONF_CRITICAL_CURRENT_LIMIT): CURRENT_LIMIT_SCHEMA,
|
||||
}
|
||||
),
|
||||
cv.has_at_least_one_key(
|
||||
CONF_BUS_VOLTAGE,
|
||||
CONF_SHUNT_VOLTAGE,
|
||||
CONF_CURRENT,
|
||||
CONF_POWER,
|
||||
CONF_WARNING_CURRENT_LIMIT,
|
||||
CONF_CRITICAL_CURRENT_LIMIT,
|
||||
),
|
||||
validate_alert_limits,
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
|
||||
def adc_times_us(config: ConfigType) -> tuple[int, int]:
|
||||
"""Return the bus and shunt conversion times in microseconds."""
|
||||
adc_time = config[CONF_ADC_TIME]
|
||||
if isinstance(adc_time, dict):
|
||||
return adc_time[CONF_BUS_VOLTAGE], adc_time[CONF_SHUNT_VOLTAGE]
|
||||
return adc_time, adc_time
|
||||
|
||||
|
||||
def single_shot_wait_ms(config: ConfigType) -> int:
|
||||
"""Time one conversion of every enabled channel takes, plus headroom."""
|
||||
bus_us, shunt_us = adc_times_us(config)
|
||||
channels = sum(1 for channel in CHANNELS if channel in config)
|
||||
total_us = (bus_us + shunt_us) * config[CONF_ADC_AVERAGING] * channels
|
||||
return -(-total_us // 1000) + SINGLE_SHOT_MARGIN_MS
|
||||
|
||||
|
||||
def validate_single_shot_interval(config: ConfigType) -> ConfigType:
|
||||
if config[CONF_CONTINUOUS_MODE]:
|
||||
return config
|
||||
wait_ms = single_shot_wait_ms(config)
|
||||
if config[CONF_UPDATE_INTERVAL].total_milliseconds <= wait_ms:
|
||||
raise cv.Invalid(
|
||||
f"A single-shot conversion of all channels takes {wait_ms} ms, which does "
|
||||
f"not fit in the update_interval; lower {CONF_ADC_AVERAGING} or "
|
||||
f"{CONF_ADC_TIME}, or raise the interval",
|
||||
path=[CONF_UPDATE_INTERVAL],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(INA3221Component),
|
||||
cv.Optional(CONF_CHANNEL_1): INA3221_CHANNEL_SCHEMA,
|
||||
cv.Optional(CONF_CHANNEL_2): INA3221_CHANNEL_SCHEMA,
|
||||
cv.Optional(CONF_CHANNEL_3): INA3221_CHANNEL_SCHEMA,
|
||||
cv.Optional(CONF_CONTINUOUS_MODE, default=True): cv.boolean,
|
||||
cv.Optional(CONF_ADC_AVERAGING, default=1): cv.one_of(
|
||||
*ADC_AVERAGING, int=True
|
||||
),
|
||||
cv.Optional(CONF_ADC_TIME, default="8244us"): cv.Any(
|
||||
validate_adc_time,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_BUS_VOLTAGE): validate_adc_time,
|
||||
cv.Required(CONF_SHUNT_VOLTAGE): validate_adc_time,
|
||||
}
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_SUM_SHUNT_VOLTAGE): VOLTAGE_SCHEMA,
|
||||
cv.Optional(CONF_SUM_CURRENT): CURRENT_SCHEMA,
|
||||
cv.Optional(CONF_SUM_POWER): POWER_SCHEMA,
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(i2c.i2c_device_schema(0x40))
|
||||
.extend(i2c.i2c_device_schema(0x40)),
|
||||
cv.has_at_least_one_key(*CHANNELS),
|
||||
validate_single_shot_interval,
|
||||
)
|
||||
|
||||
|
||||
def alert_limit_register(current_a: float, shunt_ohm: float) -> int:
|
||||
return round(current_a * shunt_ohm / ALERT_LIMIT_LSB_V) << 3
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
for i, channel in enumerate([CONF_CHANNEL_1, CONF_CHANNEL_2, CONF_CHANNEL_3]):
|
||||
if channel not in config:
|
||||
bus_us, shunt_us = adc_times_us(config)
|
||||
register = (
|
||||
ADC_AVERAGING[config[CONF_ADC_AVERAGING]] << ADC_AVERAGING_SHIFT
|
||||
| ADC_TIMES_US[bus_us] << ADC_TIME_BUS_SHIFT
|
||||
| ADC_TIMES_US[shunt_us] << ADC_TIME_SHUNT_SHIFT
|
||||
| (MODE_CONTINUOUS if config[CONF_CONTINUOUS_MODE] else MODE_SINGLE_SHOT)
|
||||
)
|
||||
for i, channel in enumerate(CHANNELS):
|
||||
if (conf := config.get(channel)) is None:
|
||||
continue
|
||||
conf = config[channel]
|
||||
if CONF_SHUNT_RESISTANCE in conf:
|
||||
cg.add(var.set_shunt_resistance(i, conf[CONF_SHUNT_RESISTANCE]))
|
||||
register |= CHANNEL_ENABLE_BITS[i]
|
||||
shunt = conf[CONF_SHUNT_RESISTANCE]
|
||||
cg.add(var.set_shunt_resistance(i, shunt))
|
||||
if CONF_BUS_VOLTAGE in conf:
|
||||
sens = await sensor.new_sensor(conf[CONF_BUS_VOLTAGE])
|
||||
cg.add(var.set_bus_voltage_sensor(i, sens))
|
||||
@@ -98,3 +228,23 @@ async def to_code(config: ConfigType) -> None:
|
||||
if CONF_POWER in conf:
|
||||
sens = await sensor.new_sensor(conf[CONF_POWER])
|
||||
cg.add(var.set_power_sensor(i, sens))
|
||||
for key, setter in (
|
||||
(CONF_WARNING_CURRENT_LIMIT, var.set_warning_limit),
|
||||
(CONF_CRITICAL_CURRENT_LIMIT, var.set_critical_limit),
|
||||
):
|
||||
if (limit := conf.get(key)) is not None:
|
||||
cg.add_define("USE_INA3221_ALERT_LIMITS")
|
||||
cg.add(setter(i, alert_limit_register(limit, shunt)))
|
||||
cg.add(var.set_config_register(register))
|
||||
if not config[CONF_CONTINUOUS_MODE]:
|
||||
cg.add(var.set_single_shot_wait_ms(single_shot_wait_ms(config)))
|
||||
|
||||
if any(
|
||||
key in config
|
||||
for key in (CONF_SUM_SHUNT_VOLTAGE, CONF_SUM_CURRENT, CONF_SUM_POWER)
|
||||
):
|
||||
cg.add_define("USE_INA3221_SUMMATION")
|
||||
sensors = sensor.sub_sensors(config)
|
||||
await sensors(CONF_SUM_SHUNT_VOLTAGE, var.set_sum_shunt_voltage_sensor)
|
||||
await sensors(CONF_SUM_CURRENT, var.set_sum_current_sensor)
|
||||
await sensors(CONF_SUM_POWER, var.set_sum_power_sensor)
|
||||
|
||||
@@ -11,7 +11,7 @@ void Infrared::dump_config() {
|
||||
"Infrared '%s'\n"
|
||||
" Supports Transmitter: %s\n"
|
||||
" Supports Receiver: %s",
|
||||
this->get_name().c_str(), YESNO(this->get_supports_transmitter()),
|
||||
LOG_STR_ARG(this->get_log_name()), YESNO(this->get_supports_transmitter()),
|
||||
YESNO(this->get_supports_receiver()));
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ bool IrRfEntity::expect_api_reply_(api::APIConnection *conn) {
|
||||
if (this->api_reply_ == ApiReply::API_REPLY_WAITING)
|
||||
this->finish_api_reply_(false);
|
||||
if (this->api_reply_ != ApiReply::API_REPLY_NONE && !this->send_api_reply_()) {
|
||||
ESP_LOGW(TAG, "'%s': transmit %s", this->get_name().c_str(), LOG_STR_LITERAL("refused, reply still owed"));
|
||||
ESP_LOGW(TAG, "'%s': transmit %s", LOG_STR_ARG(this->get_log_name()), LOG_STR_LITERAL("refused, reply still owed"));
|
||||
this->refuse_api_call_(conn);
|
||||
return false;
|
||||
}
|
||||
@@ -198,13 +198,14 @@ void IrRfEntity::loop() {
|
||||
if (this->api_reply_ != ApiReply::API_REPLY_WAITING) {
|
||||
if (this->send_api_reply_() || remaining > 0)
|
||||
return;
|
||||
ESP_LOGW(TAG, "'%s': transmit %s", this->get_name().c_str(), LOG_STR_LITERAL("reply dropped, client not reading"));
|
||||
ESP_LOGW(TAG, "'%s': transmit %s", LOG_STR_ARG(this->get_log_name()),
|
||||
LOG_STR_LITERAL("reply dropped, client not reading"));
|
||||
this->clear_api_reply_();
|
||||
return;
|
||||
}
|
||||
if (remaining > 0)
|
||||
return;
|
||||
ESP_LOGW(TAG, "'%s': transmit %s", this->get_name().c_str(), LOG_STR_LITERAL("never reported completion"));
|
||||
ESP_LOGW(TAG, "'%s': transmit %s", LOG_STR_ARG(this->get_log_name()), LOG_STR_LITERAL("never reported completion"));
|
||||
this->finish_api_reply_(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ void IrRfProxy::dump_config() {
|
||||
"IR Proxy '%s'\n"
|
||||
" Supports Transmitter: %s\n"
|
||||
" Supports Receiver: %s",
|
||||
this->get_name().c_str(), YESNO(this->get_supports_transmitter()),
|
||||
LOG_STR_ARG(this->get_log_name()), YESNO(this->get_supports_transmitter()),
|
||||
YESNO(this->get_supports_receiver()));
|
||||
|
||||
if (this->is_rf()) {
|
||||
@@ -44,7 +44,7 @@ void RfProxy::dump_config() {
|
||||
"RF Proxy '%s'\n"
|
||||
" Supports Transmitter: %s\n"
|
||||
" Supports Receiver: %s",
|
||||
this->get_name().c_str(), YESNO(this->get_supports_transmitter()),
|
||||
LOG_STR_ARG(this->get_log_name()), YESNO(this->get_supports_transmitter()),
|
||||
YESNO(this->get_supports_receiver()));
|
||||
|
||||
const auto &traits = this->traits_;
|
||||
|
||||
@@ -4,6 +4,7 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["ld24xx"]
|
||||
CODEOWNERS = ["@NovakIrs"]
|
||||
DEPENDENCIES = ["uart"]
|
||||
DOMAIN = "ld2410s"
|
||||
@@ -13,6 +14,7 @@ CONF_LD2410S_ID = "ld2410s_id"
|
||||
|
||||
ld2410s_ns = cg.esphome_ns.namespace(DOMAIN)
|
||||
LD2410SComponent = ld2410s_ns.class_("LD2410SComponent", cg.Component, uart.UARTDevice)
|
||||
Parameter = ld2410s_ns.enum("Parameter", is_class=True)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "ld2410s.h"
|
||||
#include "ld2410s_number.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "esphome/core/application.h"
|
||||
@@ -25,18 +26,46 @@ static constexpr uint16_t CMD_CONFIRMATION = 0x0100; // set in the command word
|
||||
static constexpr uint16_t CONFIG_MODE_START_CMD = 0x00FF;
|
||||
static constexpr uint16_t CONFIG_MODE_START_VALUE = 0x0001;
|
||||
static constexpr uint16_t CONFIG_MODE_END_CMD = 0x00FE;
|
||||
static constexpr uint16_t VERSION_READ_CMD = 0x0000;
|
||||
static constexpr uint16_t PARAMETERS_WRITE_CMD = 0x0070;
|
||||
static constexpr uint16_t PARAMETERS_READ_CMD = 0x0071;
|
||||
static constexpr uint16_t OUTPUT_MODE_SWITCH_CMD = 0x007A;
|
||||
// Minimal output mode (short frames carrying presence and distance only) is selected by six zero bytes
|
||||
static constexpr uint8_t OUTPUT_MODE_MINIMAL_SIZE = 6;
|
||||
static constexpr uint8_t CMD_FRAME_MAX_SIZE =
|
||||
LONG_PAYLOAD_POS + 2 + OUTPUT_MODE_MINIMAL_SIZE + sizeof(CMD_FRAME_FOOTER);
|
||||
// The parameter write carries a 16-bit key and a 32-bit value per parameter, the read only the keys
|
||||
static constexpr uint8_t PARAMETER_KEY_SIZE = 2;
|
||||
static constexpr uint8_t PARAMETER_VALUE_SIZE = 4;
|
||||
static constexpr uint8_t PARAMETERS_WRITE_SIZE = PARAMETER_COUNT * (PARAMETER_KEY_SIZE + PARAMETER_VALUE_SIZE);
|
||||
static constexpr uint8_t CMD_FRAME_MAX_SIZE = LONG_PAYLOAD_POS + 2 + PARAMETERS_WRITE_SIZE + sizeof(CMD_FRAME_FOOTER);
|
||||
// Keys of the parameters, in Parameter order
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
static constexpr uint16_t PARAMETER_KEYS[] PROGMEM = {0x0005, 0x000A, 0x0006, 0x0002, 0x000C, 0x000B};
|
||||
static_assert(sizeof(PARAMETER_KEYS) / sizeof(PARAMETER_KEYS[0]) == PARAMETER_COUNT, "one key per parameter");
|
||||
#endif
|
||||
// The version answer: 4 bytes device type, then major, minor and patch as 16-bit words
|
||||
static constexpr uint8_t VERSION_TYPE_SIZE = 4;
|
||||
static constexpr uint8_t VERSION_SIZE = VERSION_TYPE_SIZE + 3 * 2;
|
||||
|
||||
// Everything the module needs at start: enter configuration mode, pick the output mode, leave it
|
||||
static constexpr uint16_t INIT_SEQUENCE[] PROGMEM = {CONFIG_MODE_START_CMD, OUTPUT_MODE_SWITCH_CMD,
|
||||
CONFIG_MODE_END_CMD};
|
||||
// Everything the module needs at start: configuration mode on, read the version and parameters when
|
||||
// an entity shows them, pick the output mode, configuration mode off
|
||||
static constexpr uint16_t INIT_SEQUENCE[] PROGMEM = {
|
||||
CONFIG_MODE_START_CMD,
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
VERSION_READ_CMD,
|
||||
#endif
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
PARAMETERS_READ_CMD,
|
||||
#endif
|
||||
OUTPUT_MODE_SWITCH_CMD, CONFIG_MODE_END_CMD,
|
||||
};
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
static constexpr uint16_t WRITE_SEQUENCE[] PROGMEM = {CONFIG_MODE_START_CMD, PARAMETERS_WRITE_CMD, CONFIG_MODE_END_CMD};
|
||||
#endif
|
||||
static constexpr uint8_t INIT_SEQUENCE_LENGTH = sizeof(INIT_SEQUENCE) / sizeof(INIT_SEQUENCE[0]);
|
||||
static uint16_t init_command(uint8_t step) { return progmem_read_uint16(&INIT_SEQUENCE[step]); }
|
||||
static constexpr uint8_t INIT_MAX_TIMEOUTS = 2;
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
static constexpr uint8_t WRITE_SEQUENCE_LENGTH = sizeof(WRITE_SEQUENCE) / sizeof(WRITE_SEQUENCE[0]);
|
||||
#endif
|
||||
static constexpr uint8_t STEP_MAX_TIMEOUTS = 2;
|
||||
static constexpr uint32_t ACK_TIMEOUT_MS = 300;
|
||||
static constexpr uint32_t COMMAND_GAP_MS = 300; // pause after an acknowledgement before the next command
|
||||
static constexpr uint32_t REINIT_PAUSE_MS = 15000; // pause before starting over after the module stopped answering
|
||||
@@ -49,6 +78,20 @@ void LD2410SComponent::dump_config() {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
LOG_BINARY_SENSOR(" ", "Has Target", this->target_binary_sensor_);
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
LOG_SENSOR_WITH_DEDUP_SAFE(" ", "Distance", this->distance_sensor_);
|
||||
#endif
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
LOG_TEXT_SENSOR(" ", "Version", this->version_text_sensor_);
|
||||
#endif
|
||||
#if defined(USE_NUMBER) && defined(USE_LD2410S_PARAMETERS)
|
||||
for (auto *number : this->numbers_) {
|
||||
LOG_NUMBER(" ", "Setting", number);
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_SELECT) && defined(USE_LD2410S_PARAMETERS)
|
||||
LOG_SELECT(" ", "Response Speed", this->response_speed_select_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LD2410SComponent::loop() {
|
||||
@@ -67,35 +110,80 @@ void LD2410SComponent::loop() {
|
||||
avail -= len;
|
||||
}
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
this->run_init_sequence_(now);
|
||||
if (this->init_step_ >= INIT_SEQUENCE_LENGTH && now - this->last_frame_at_ > LINK_TIMEOUT_MS) {
|
||||
if (this->sequence_ == nullptr) {
|
||||
if (!this->init_done_) {
|
||||
this->start_sequence_(INIT_SEQUENCE, INIT_SEQUENCE_LENGTH, now);
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
} else if (this->parameters_dirty_) {
|
||||
this->parameters_dirty_ = false;
|
||||
this->start_sequence_(WRITE_SEQUENCE, WRITE_SEQUENCE_LENGTH, this->next_send_at_);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
this->run_sequence_(now);
|
||||
if (this->init_done_ && now - this->last_frame_at_ > LINK_TIMEOUT_MS) {
|
||||
// The count tells real silence apart from frames that never parse (wrong baud rate or firmware)
|
||||
ESP_LOGW(TAG, "No data for %" PRIu32 " s (%u frames dropped), starting over", LINK_TIMEOUT_MS / 1000,
|
||||
this->dropped_frames_);
|
||||
this->dropped_frames_ = 0;
|
||||
this->status_set_warning();
|
||||
this->init_step_ = 0;
|
||||
this->init_timeouts_ = 0;
|
||||
this->awaiting_ack_ = false;
|
||||
this->next_send_at_ = now;
|
||||
this->restart_init_(now);
|
||||
}
|
||||
}
|
||||
|
||||
void LD2410SComponent::run_init_sequence_(uint32_t now) {
|
||||
if (this->init_step_ >= INIT_SEQUENCE_LENGTH || static_cast<int32_t>(now - this->next_send_at_) < 0) {
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
bool LD2410SComponent::set_parameter(Parameter parameter, uint8_t value) {
|
||||
// All six are written together, so the other five must be the module's own values
|
||||
if (!this->init_done_) {
|
||||
ESP_LOGW(TAG, "Parameters not read yet, change ignored");
|
||||
return false;
|
||||
}
|
||||
if (!this->parameters_known_) {
|
||||
ESP_LOGW(TAG, "The module reported a parameter out of range, changes are disabled");
|
||||
return false;
|
||||
}
|
||||
this->parameters_[static_cast<uint8_t>(parameter)] = value;
|
||||
this->parameters_dirty_ = true; // written by loop() once no sequence is running
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void LD2410SComponent::restart_init_(uint32_t at) {
|
||||
this->init_done_ = false;
|
||||
this->status_set_warning(); // cleared again when the new init sequence is acknowledged
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
// The module's own values count again once it is set up anew
|
||||
if (this->parameters_dirty_) {
|
||||
ESP_LOGW(TAG, "Dropping the pending parameter change, the module's values are read back");
|
||||
}
|
||||
this->parameters_dirty_ = false;
|
||||
this->parameters_known_ = false; // a refused value may sit in parameters_ until the read replaces it
|
||||
#endif
|
||||
this->start_sequence_(INIT_SEQUENCE, INIT_SEQUENCE_LENGTH, at);
|
||||
}
|
||||
|
||||
void LD2410SComponent::start_sequence_(const uint16_t *sequence, uint8_t length, uint32_t now) {
|
||||
this->sequence_ = sequence;
|
||||
this->sequence_len_ = length;
|
||||
this->step_ = 0;
|
||||
this->step_timeouts_ = 0;
|
||||
this->awaiting_ack_ = false;
|
||||
this->next_send_at_ = now;
|
||||
}
|
||||
|
||||
uint16_t LD2410SComponent::current_command_() const { return progmem_read_uint16(&this->sequence_[this->step_]); }
|
||||
|
||||
void LD2410SComponent::run_sequence_(uint32_t now) {
|
||||
if (this->sequence_ == nullptr || static_cast<int32_t>(now - this->next_send_at_) < 0) {
|
||||
return;
|
||||
}
|
||||
const uint16_t command = init_command(this->init_step_);
|
||||
const uint16_t command = this->current_command_();
|
||||
if (this->awaiting_ack_) {
|
||||
if (++this->init_timeouts_ > INIT_MAX_TIMEOUTS) {
|
||||
if (++this->step_timeouts_ > STEP_MAX_TIMEOUTS) {
|
||||
ESP_LOGW(TAG, "No acknowledgement for command %04X, starting over in %" PRIu32 " s", command,
|
||||
REINIT_PAUSE_MS / 1000);
|
||||
// Leave configuration mode whatever state the module is in, then begin again
|
||||
this->send_command_(CONFIG_MODE_END_CMD);
|
||||
this->init_step_ = 0;
|
||||
this->init_timeouts_ = 0;
|
||||
this->awaiting_ack_ = false;
|
||||
this->next_send_at_ = now + REINIT_PAUSE_MS;
|
||||
this->restart_init_(now + REINIT_PAUSE_MS);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "No acknowledgement for command %04X, resending", command);
|
||||
@@ -120,6 +208,22 @@ void LD2410SComponent::send_command_(uint16_t command) {
|
||||
frame[pos++] = CONFIG_MODE_START_VALUE & 0xFF;
|
||||
frame[pos++] = CONFIG_MODE_START_VALUE >> 8;
|
||||
break;
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
case PARAMETERS_READ_CMD:
|
||||
case PARAMETERS_WRITE_CMD:
|
||||
for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
|
||||
const uint16_t key = progmem_read_uint16(&PARAMETER_KEYS[i]);
|
||||
frame[pos++] = key & 0xFF;
|
||||
frame[pos++] = key >> 8;
|
||||
if (command == PARAMETERS_WRITE_CMD) {
|
||||
const uint32_t value = this->parameters_[i]; // a 32-bit field on the wire
|
||||
for (uint8_t shift = 0; shift < 32; shift += 8) {
|
||||
frame[pos++] = (value >> shift) & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -252,27 +356,27 @@ bool LD2410SComponent::handle_frame_() {
|
||||
}
|
||||
|
||||
bool LD2410SComponent::handle_data_frame_(const uint8_t *payload, uint16_t len) {
|
||||
uint8_t state;
|
||||
if (this->frame_type_ == FrameType::SHORT_DATA) {
|
||||
// [state][distance low][distance high]
|
||||
state = payload[0];
|
||||
} else if (len >= 4 && payload[0] == DATA_TYPE_STANDARD) {
|
||||
// [type][state][distance low][distance high]...; the module only sends these before the init
|
||||
// sequence switches it to minimal output
|
||||
state = payload[1];
|
||||
} else {
|
||||
if (len >= 1) {
|
||||
ESP_LOGV(TAG, "Ignoring data frame type %02X", payload[0]);
|
||||
// Short frames carry [state][distance low][distance high]; standard frames put a type byte first, and the
|
||||
// module only sends them before the init sequence switches it to minimal output
|
||||
const uint8_t *data = payload;
|
||||
if (this->frame_type_ == FrameType::STD_DATA) {
|
||||
if (len < 4 || payload[0] != DATA_TYPE_STANDARD) {
|
||||
if (len >= 1) {
|
||||
ESP_LOGV(TAG, "Ignoring data frame type %02X", payload[0]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
data = payload + 1;
|
||||
}
|
||||
const uint8_t state = data[0];
|
||||
const uint16_t distance = encode_uint16(data[2], data[1]);
|
||||
// States 0 and 1 mean no target, 2 and 3 a target; anything else is line noise that happened to
|
||||
// carry the header and footer bytes
|
||||
if (state > 3) {
|
||||
ESP_LOGV(TAG, "Dropping frame with impossible state %u", state);
|
||||
return false;
|
||||
}
|
||||
this->publish_target_(state > 1);
|
||||
this->publish_target_(state > 1, distance);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -283,32 +387,147 @@ void LD2410SComponent::handle_command_ack_(const uint8_t *payload, uint16_t len)
|
||||
}
|
||||
const uint16_t command_word = encode_uint16(payload[1], payload[0]);
|
||||
const uint16_t ack = encode_uint16(payload[3], payload[2]);
|
||||
if (!this->awaiting_ack_ || command_word != (init_command(this->init_step_) | CMD_CONFIRMATION)) {
|
||||
if (!this->awaiting_ack_) {
|
||||
ESP_LOGV(TAG, "Unexpected acknowledgement %04X", command_word);
|
||||
return;
|
||||
}
|
||||
if (ack != 0) {
|
||||
// Leave the command pending so the timeout resends it
|
||||
ESP_LOGW(TAG, "Module rejected command %04X, ack %04X", init_command(this->init_step_), ack);
|
||||
const uint16_t command = this->current_command_();
|
||||
if (command_word != (command | CMD_CONFIRMATION)) {
|
||||
ESP_LOGV(TAG, "Unexpected acknowledgement %04X", command_word);
|
||||
return;
|
||||
}
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
if (ack != 0 && command == PARAMETERS_WRITE_CMD) {
|
||||
// Resending the same values would be rejected again; leave configuration mode and read the
|
||||
// module's own values back, which republishes them
|
||||
ESP_LOGW(TAG, "Module rejected the parameters, ack %04X", ack);
|
||||
this->send_command_(CONFIG_MODE_END_CMD);
|
||||
this->restart_init_(App.get_loop_component_start_time() + COMMAND_GAP_MS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (ack != 0) {
|
||||
// Leave the command pending so the timeout resends it
|
||||
ESP_LOGW(TAG, "Module rejected command %04X, ack %04X", command, ack);
|
||||
return;
|
||||
}
|
||||
// A short answer leaves the read pending the same way, so init cannot finish without the values
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
if (command == PARAMETERS_READ_CMD && !this->handle_parameters_(&payload[4], len - 4))
|
||||
return;
|
||||
#endif
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
if (command == VERSION_READ_CMD && !this->handle_version_(&payload[4], len - 4))
|
||||
return;
|
||||
#endif
|
||||
this->awaiting_ack_ = false;
|
||||
this->init_timeouts_ = 0;
|
||||
this->init_step_++;
|
||||
this->next_send_at_ = App.get_loop_component_start_time() + COMMAND_GAP_MS;
|
||||
if (this->init_step_ >= INIT_SEQUENCE_LENGTH) {
|
||||
this->step_timeouts_ = 0;
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
this->next_send_at_ = now + COMMAND_GAP_MS;
|
||||
if (++this->step_ < this->sequence_len_) {
|
||||
return;
|
||||
}
|
||||
const bool was_init = this->sequence_ == INIT_SEQUENCE;
|
||||
this->sequence_ = nullptr;
|
||||
if (was_init) {
|
||||
ESP_LOGD(TAG, "Setup done");
|
||||
this->last_frame_at_ = App.get_loop_component_start_time();
|
||||
this->init_done_ = true;
|
||||
this->last_frame_at_ = now;
|
||||
this->status_clear_warning();
|
||||
}
|
||||
}
|
||||
|
||||
void LD2410SComponent::publish_target_(bool target) {
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
// The answer lists the parameter values in key order, 32 bits each; returns false when it is cut short
|
||||
bool LD2410SComponent::handle_parameters_(const uint8_t *values, uint16_t len) {
|
||||
if (len < PARAMETER_COUNT * PARAMETER_VALUE_SIZE) {
|
||||
ESP_LOGW(TAG, "Parameter answer too short (%u bytes)", len);
|
||||
return false;
|
||||
}
|
||||
// Every parameter must fit the low byte of its little-endian value; otherwise nothing is stored or
|
||||
// published and writes stay refused, so a cut-down value is never shown or sent back
|
||||
for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
|
||||
const uint8_t *v = &values[i * PARAMETER_VALUE_SIZE];
|
||||
if ((v[1] | v[2] | v[3]) != 0) {
|
||||
ESP_LOGW(TAG, "Parameter %u out of range: %" PRIu32 ", changes stay disabled", i,
|
||||
encode_uint32(v[3], v[2], v[1], v[0]));
|
||||
this->parameters_known_ = false;
|
||||
#ifdef USE_NUMBER
|
||||
// A value a number showed before the module answered is not confirmed
|
||||
for (auto *number : this->numbers_) {
|
||||
if (number != nullptr) {
|
||||
number->publish_state(NAN);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
|
||||
this->parameters_[i] = values[i * PARAMETER_VALUE_SIZE];
|
||||
}
|
||||
this->parameters_known_ = true;
|
||||
this->publish_parameters_();
|
||||
ESP_LOGD(TAG, "Parameters: gates %u to %u, no delay %u s, frequencies %u/%u dHz, response speed %u",
|
||||
this->parameters_[1], this->parameters_[0], this->parameters_[2], this->parameters_[3], this->parameters_[4],
|
||||
this->parameters_[5]);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
// Returns false when the answer is cut short
|
||||
bool LD2410SComponent::handle_version_(const uint8_t *values, uint16_t len) {
|
||||
if (len < VERSION_SIZE) {
|
||||
ESP_LOGW(TAG, "Version answer too short (%u bytes)", len);
|
||||
return false;
|
||||
}
|
||||
const uint8_t *v = &values[VERSION_TYPE_SIZE];
|
||||
char version[18];
|
||||
snprintf(version, sizeof(version), "%u.%u.%u", encode_uint16(v[1], v[0]), encode_uint16(v[3], v[2]),
|
||||
encode_uint16(v[5], v[4]));
|
||||
ESP_LOGD(TAG, "Firmware %s", version);
|
||||
if (this->version_text_sensor_ != nullptr) {
|
||||
this->version_text_sensor_->publish_state(version);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void LD2410SComponent::publish_target_(bool target, uint16_t distance) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
if (this->target_binary_sensor_ != nullptr) {
|
||||
this->target_binary_sensor_->publish_state(target);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
// The module keeps reporting the last distance after the target left
|
||||
SAFE_PUBLISH_SENSOR(this->distance_sensor_, target ? distance : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
void LD2410SComponent::publish_parameters_() {
|
||||
#ifdef USE_NUMBER
|
||||
for (uint8_t i = 0; i < PARAMETER_COUNT; i++) {
|
||||
if (this->numbers_[i] != nullptr) {
|
||||
this->numbers_[i]->publish_raw(this->parameters_[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
if (this->response_speed_select_ != nullptr) {
|
||||
const uint8_t speed = this->parameters_[static_cast<uint8_t>(Parameter::PARAMETER_RESPONSE_SPEED)];
|
||||
for (uint8_t i = 0; i < RESPONSE_SPEED_COUNT; i++) {
|
||||
if (progmem_read_byte(&RESPONSE_SPEEDS[i]) == speed) {
|
||||
this->response_speed_select_->publish_state(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ESP_LOGV(TAG, "Unknown response speed %u", speed);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome::ld2410s
|
||||
|
||||
@@ -2,10 +2,21 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/ld24xx/ld24xx.h"
|
||||
#endif
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
#endif
|
||||
#if defined(USE_SELECT) && defined(USE_LD2410S_PARAMETERS)
|
||||
#include "esphome/components/select/select.h"
|
||||
#endif
|
||||
|
||||
namespace esphome::ld2410s {
|
||||
|
||||
@@ -13,16 +24,55 @@ namespace esphome::ld2410s {
|
||||
static constexpr size_t RX_BUFFER_SIZE = 96;
|
||||
static_assert(RX_BUFFER_SIZE <= 255, "frame lengths are kept in a byte");
|
||||
|
||||
/// The module's common parameters, in the order the parameter read answers them
|
||||
enum class Parameter : uint8_t {
|
||||
PARAMETER_MAX_DISTANCE,
|
||||
PARAMETER_MIN_DISTANCE,
|
||||
PARAMETER_NO_DELAY,
|
||||
PARAMETER_STATUS_FREQUENCY,
|
||||
PARAMETER_DISTANCE_FREQUENCY,
|
||||
PARAMETER_RESPONSE_SPEED,
|
||||
PARAMETER_COUNT,
|
||||
};
|
||||
static constexpr uint8_t PARAMETER_COUNT = static_cast<uint8_t>(Parameter::PARAMETER_COUNT);
|
||||
// Response speed values, in the order of the select's options (Normal, Fast)
|
||||
static constexpr uint8_t RESPONSE_SPEEDS[] PROGMEM = {5, 10};
|
||||
static constexpr uint8_t RESPONSE_SPEED_COUNT = sizeof(RESPONSE_SPEEDS);
|
||||
|
||||
#if defined(USE_NUMBER) && defined(USE_LD2410S_PARAMETERS)
|
||||
class LD2410SNumber;
|
||||
#endif
|
||||
|
||||
class LD2410SComponent final : public Component, public uart::UARTDevice {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
SUB_BINARY_SENSOR(target)
|
||||
#endif
|
||||
#ifdef USE_SENSOR
|
||||
SUB_SENSOR_WITH_DEDUP(distance, uint16_t)
|
||||
#endif
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
SUB_TEXT_SENSOR(version)
|
||||
#endif
|
||||
#if defined(USE_SELECT) && defined(USE_LD2410S_PARAMETERS)
|
||||
SUB_SELECT(response_speed)
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup() override { this->status_set_warning(); } // cleared once the module acknowledged the init sequence
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
|
||||
/// Store a parameter in the module's units; loop() then writes all of them to the module.
|
||||
/// Returns false, and changes nothing, until the module's own values have been read.
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
bool set_parameter(Parameter parameter, uint8_t value);
|
||||
#ifdef USE_NUMBER
|
||||
void set_number(Parameter parameter, LD2410SNumber *number) {
|
||||
this->numbers_[static_cast<uint8_t>(parameter)] = number;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
protected:
|
||||
enum class FrameType : uint8_t { NONE, SHORT_DATA, STD_DATA, COMMAND };
|
||||
|
||||
@@ -32,6 +82,12 @@ class LD2410SComponent final : public Component, public uart::UARTDevice {
|
||||
/// Returns false for a data frame whose state byte is impossible, so it counts as dropped.
|
||||
bool handle_data_frame_(const uint8_t *payload, uint16_t len);
|
||||
void handle_command_ack_(const uint8_t *payload, uint16_t len);
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
bool handle_parameters_(const uint8_t *values, uint16_t len);
|
||||
#endif
|
||||
#ifdef USE_LD2410S_VERSION
|
||||
bool handle_version_(const uint8_t *values, uint16_t len);
|
||||
#endif
|
||||
void count_dropped_frame_() {
|
||||
if (this->dropped_frames_ < UINT8_MAX) {
|
||||
this->dropped_frames_++;
|
||||
@@ -42,21 +98,41 @@ class LD2410SComponent final : public Component, public uart::UARTDevice {
|
||||
this->expected_len_ = 0;
|
||||
this->frame_type_ = FrameType::NONE;
|
||||
}
|
||||
void run_init_sequence_(uint32_t now);
|
||||
void start_sequence_(const uint16_t *sequence, uint8_t length, uint32_t now);
|
||||
void restart_init_(uint32_t at);
|
||||
void run_sequence_(uint32_t now);
|
||||
uint16_t current_command_() const;
|
||||
void send_command_(uint16_t command);
|
||||
void publish_target_(bool target);
|
||||
void publish_target_(bool target, uint16_t distance);
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
void publish_parameters_();
|
||||
#endif
|
||||
|
||||
#if defined(USE_NUMBER) && defined(USE_LD2410S_PARAMETERS)
|
||||
LD2410SNumber *numbers_[PARAMETER_COUNT]{}; // null for parameters without a number
|
||||
#endif
|
||||
|
||||
const uint16_t *sequence_{nullptr}; // PROGMEM; null while nothing is being sent
|
||||
uint32_t next_send_at_{0};
|
||||
uint32_t last_frame_at_{0};
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
uint8_t parameters_[PARAMETER_COUNT]{}; // all fit a byte: gates, seconds, tenths of a hertz, speed
|
||||
#endif
|
||||
uint8_t rx_buffer_[RX_BUFFER_SIZE];
|
||||
uint8_t rx_len_{0};
|
||||
uint8_t expected_len_{0};
|
||||
uint8_t init_step_{0};
|
||||
uint8_t init_timeouts_{0};
|
||||
uint8_t sequence_len_{0};
|
||||
uint8_t step_{0};
|
||||
uint8_t step_timeouts_{0};
|
||||
uint8_t dropped_frames_{0}; // since the last accepted data frame, saturates at 255
|
||||
FrameType frame_type_{FrameType::NONE};
|
||||
bool awaiting_ack_{false};
|
||||
bool rescanning_{false};
|
||||
bool init_done_{false};
|
||||
#ifdef USE_LD2410S_PARAMETERS
|
||||
bool parameters_known_{false}; // the module answered the parameter read at least once
|
||||
bool parameters_dirty_{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2410s
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_NUMBER) && defined(USE_LD2410S_PARAMETERS)
|
||||
|
||||
#include "ld2410s.h"
|
||||
#include "esphome/components/number/number.h"
|
||||
|
||||
namespace esphome::ld2410s {
|
||||
|
||||
/// Edits one common parameter; scale converts the module's units to the number's.
|
||||
class LD2410SNumber final : public number::Number, public Parented<LD2410SComponent> {
|
||||
public:
|
||||
LD2410SNumber(Parameter parameter, float scale) : parameter_(parameter), scale_(scale) {}
|
||||
|
||||
void publish_raw(uint8_t raw) { this->publish_state(raw * this->scale_); }
|
||||
|
||||
protected:
|
||||
void control(float value) override {
|
||||
// Show the step the module got, not a value between two steps
|
||||
const uint8_t raw = lroundf(value / this->scale_); // the schema keeps every parameter within a byte
|
||||
if (this->parent_->set_parameter(this->parameter_, raw))
|
||||
this->publish_raw(raw);
|
||||
}
|
||||
|
||||
const Parameter parameter_;
|
||||
const float scale_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2410s
|
||||
|
||||
#endif // USE_NUMBER && USE_LD2410S_PARAMETERS
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_SELECT) && defined(USE_LD2410S_PARAMETERS)
|
||||
|
||||
#include "ld2410s.h"
|
||||
#include "esphome/components/select/select.h"
|
||||
|
||||
namespace esphome::ld2410s {
|
||||
|
||||
class LD2410SSelect final : public select::Select, public Parented<LD2410SComponent> {
|
||||
protected:
|
||||
void control(size_t index) override {
|
||||
if (this->parent_->set_parameter(Parameter::PARAMETER_RESPONSE_SPEED, progmem_read_byte(&RESPONSE_SPEEDS[index])))
|
||||
this->publish_state(index);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace esphome::ld2410s
|
||||
|
||||
#endif // USE_SELECT && USE_LD2410S_PARAMETERS
|
||||
@@ -0,0 +1,108 @@
|
||||
from functools import partial
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import number
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
DEVICE_CLASS_DURATION,
|
||||
DEVICE_CLASS_FREQUENCY,
|
||||
ENTITY_CATEGORY_CONFIG,
|
||||
ICON_PULSE,
|
||||
ICON_TIMELAPSE,
|
||||
UNIT_HERTZ,
|
||||
UNIT_METER,
|
||||
UNIT_SECOND,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from . import CONF_LD2410S_ID, LD2410SComponent, Parameter, ld2410s_ns
|
||||
|
||||
DEPENDENCIES = ["ld2410s"]
|
||||
|
||||
CONF_DISTANCE_REPORTING_FREQUENCY = "distance_reporting_frequency"
|
||||
CONF_MAX_DISTANCE = "max_distance"
|
||||
CONF_MIN_DISTANCE = "min_distance"
|
||||
CONF_NO_DELAY = "no_delay"
|
||||
CONF_STATUS_REPORTING_FREQUENCY = "status_reporting_frequency"
|
||||
|
||||
LD2410SNumber = ld2410s_ns.class_("LD2410SNumber", number.Number)
|
||||
|
||||
# The module counts distances in 0.7 m gates and frequencies in tenths of a hertz
|
||||
GATE_WIDTH_M = 0.7
|
||||
FREQUENCY_SCALE = 0.1
|
||||
_DISTANCE_RANGE = {"min_value": 0, "max_value": 16 * GATE_WIDTH_M, "step": GATE_WIDTH_M}
|
||||
_FREQUENCY_RANGE = {"min_value": 0.5, "max_value": 8, "step": 0.5}
|
||||
|
||||
|
||||
def _number_schema(device_class: str, unit: str, icon: str) -> cv.Schema:
|
||||
return number.number_schema(
|
||||
LD2410SNumber,
|
||||
device_class=device_class,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
unit_of_measurement=unit,
|
||||
icon=icon,
|
||||
)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
cv.GenerateID(CONF_LD2410S_ID): cv.use_id(LD2410SComponent),
|
||||
cv.Optional(CONF_MAX_DISTANCE): _number_schema(
|
||||
DEVICE_CLASS_DISTANCE, UNIT_METER, "mdi:arrow-collapse-right"
|
||||
),
|
||||
cv.Optional(CONF_MIN_DISTANCE): _number_schema(
|
||||
DEVICE_CLASS_DISTANCE, UNIT_METER, "mdi:arrow-collapse-left"
|
||||
),
|
||||
cv.Optional(CONF_NO_DELAY): _number_schema(
|
||||
DEVICE_CLASS_DURATION, UNIT_SECOND, ICON_TIMELAPSE
|
||||
),
|
||||
cv.Optional(CONF_STATUS_REPORTING_FREQUENCY): _number_schema(
|
||||
DEVICE_CLASS_FREQUENCY, UNIT_HERTZ, ICON_PULSE
|
||||
),
|
||||
cv.Optional(CONF_DISTANCE_REPORTING_FREQUENCY): _number_schema(
|
||||
DEVICE_CLASS_FREQUENCY, UNIT_HERTZ, ICON_PULSE
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("USE_LD2410S_PARAMETERS")
|
||||
hub = await cg.get_variable(config[CONF_LD2410S_ID])
|
||||
numbers = number.sub_numbers(config, parent=hub)
|
||||
await numbers(
|
||||
CONF_MAX_DISTANCE,
|
||||
partial(hub.set_number, Parameter.PARAMETER_MAX_DISTANCE),
|
||||
Parameter.PARAMETER_MAX_DISTANCE,
|
||||
GATE_WIDTH_M,
|
||||
**_DISTANCE_RANGE,
|
||||
)
|
||||
await numbers(
|
||||
CONF_MIN_DISTANCE,
|
||||
partial(hub.set_number, Parameter.PARAMETER_MIN_DISTANCE),
|
||||
Parameter.PARAMETER_MIN_DISTANCE,
|
||||
GATE_WIDTH_M,
|
||||
**_DISTANCE_RANGE,
|
||||
)
|
||||
await numbers(
|
||||
CONF_NO_DELAY,
|
||||
partial(hub.set_number, Parameter.PARAMETER_NO_DELAY),
|
||||
Parameter.PARAMETER_NO_DELAY,
|
||||
1,
|
||||
min_value=1,
|
||||
max_value=120,
|
||||
step=1,
|
||||
)
|
||||
await numbers(
|
||||
CONF_STATUS_REPORTING_FREQUENCY,
|
||||
partial(hub.set_number, Parameter.PARAMETER_STATUS_FREQUENCY),
|
||||
Parameter.PARAMETER_STATUS_FREQUENCY,
|
||||
FREQUENCY_SCALE,
|
||||
**_FREQUENCY_RANGE,
|
||||
)
|
||||
await numbers(
|
||||
CONF_DISTANCE_REPORTING_FREQUENCY,
|
||||
partial(hub.set_number, Parameter.PARAMETER_DISTANCE_FREQUENCY),
|
||||
Parameter.PARAMETER_DISTANCE_FREQUENCY,
|
||||
FREQUENCY_SCALE,
|
||||
**_FREQUENCY_RANGE,
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import select
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import ENTITY_CATEGORY_CONFIG
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from . import CONF_LD2410S_ID, LD2410SComponent, ld2410s_ns
|
||||
|
||||
DEPENDENCIES = ["ld2410s"]
|
||||
|
||||
CONF_RESPONSE_SPEED = "response_speed"
|
||||
|
||||
LD2410SSelect = ld2410s_ns.class_("LD2410SSelect", select.Select)
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
cv.GenerateID(CONF_LD2410S_ID): cv.use_id(LD2410SComponent),
|
||||
cv.Required(CONF_RESPONSE_SPEED): select.select_schema(
|
||||
LD2410SSelect,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
icon="mdi:speedometer",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("USE_LD2410S_PARAMETERS")
|
||||
hub = await cg.get_variable(config[CONF_LD2410S_ID])
|
||||
selects = select.sub_selects(config, parent=hub)
|
||||
await selects(
|
||||
CONF_RESPONSE_SPEED, hub.set_response_speed_select, options=["Normal", "Fast"]
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_DISTANCE,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
ICON_SIGNAL_DISTANCE_VARIANT,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CENTIMETER,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from . import CONF_LD2410S_ID, LD2410SComponent
|
||||
|
||||
DEPENDENCIES = ["ld2410s"]
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
cv.GenerateID(CONF_LD2410S_ID): cv.use_id(LD2410SComponent),
|
||||
cv.Required(CONF_DISTANCE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_CENTIMETER,
|
||||
icon=ICON_SIGNAL_DISTANCE_VARIANT,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_LD2410S_ID])
|
||||
sensors = sensor.sub_sensors(config)
|
||||
await sensors(CONF_DISTANCE, hub.set_distance_sensor)
|
||||
@@ -0,0 +1,23 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import text_sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_VERSION, ENTITY_CATEGORY_DIAGNOSTIC, ICON_CHIP
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from . import CONF_LD2410S_ID, LD2410SComponent
|
||||
|
||||
DEPENDENCIES = ["ld2410s"]
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
cv.GenerateID(CONF_LD2410S_ID): cv.use_id(LD2410SComponent),
|
||||
cv.Required(CONF_VERSION): text_sensor.text_sensor_schema(
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC, icon=ICON_CHIP
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("USE_LD2410S_VERSION")
|
||||
hub = await cg.get_variable(config[CONF_LD2410S_ID])
|
||||
text_sensors = text_sensor.sub_text_sensors(config)
|
||||
await text_sensors(CONF_VERSION, hub.set_version_text_sensor)
|
||||
@@ -1058,8 +1058,8 @@ void LD6002BComponent::publish_number_clamped_(number::Number *number, float val
|
||||
// Outside the declared range the user cannot write the value back, so publish
|
||||
// what they can reach and say what the module actually sent.
|
||||
if (value < min_value || value > max_value) {
|
||||
ESP_LOGW(TAG, "'%s': module reported %.1f, clamped to %.1f..%.1f", number->get_name().c_str(), value, min_value,
|
||||
max_value);
|
||||
ESP_LOGW(TAG, "'%s': module reported %.1f, clamped to %.1f..%.1f", LOG_STR_ARG(number->get_log_name()), value,
|
||||
min_value, max_value);
|
||||
value = std::clamp(value, min_value, max_value);
|
||||
}
|
||||
number->publish_state(value);
|
||||
|
||||
@@ -10,7 +10,7 @@ void AddressableLight::call_setup() {
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
this->set_interval(5000, [this]() {
|
||||
const char *name = this->state_parent_ == nullptr ? "" : this->state_parent_->get_name().c_str();
|
||||
const char *name = this->state_parent_ == nullptr ? "" : LOG_STR_ARG(this->state_parent_->get_log_name());
|
||||
ESP_LOGVV(TAG, "Addressable Light '%s' (effect_active=%s)", name, YESNO(this->effect_active_));
|
||||
for (int i = 0; i < this->size(); i++) {
|
||||
auto color = this->get(i);
|
||||
|
||||
@@ -74,7 +74,7 @@ static void log_percent(const LogString *param, float value) {
|
||||
#endif
|
||||
|
||||
void LightCall::perform() {
|
||||
const char *name = this->parent_->get_name().c_str();
|
||||
const char *name = LOG_STR_ARG(this->parent_->get_log_name());
|
||||
LightColorValues v = this->validate_();
|
||||
const bool publish = this->get_publish_();
|
||||
|
||||
@@ -182,7 +182,7 @@ void LightCall::perform() {
|
||||
}
|
||||
|
||||
void LightCall::log_and_clear_unsupported_(FieldFlags flag, const LogString *feature, bool use_color_mode_log) {
|
||||
auto *name = this->parent_->get_name().c_str();
|
||||
auto *name = LOG_STR_ARG(this->parent_->get_log_name());
|
||||
if (use_color_mode_log) {
|
||||
log_color_mode_not_supported(name, feature);
|
||||
} else {
|
||||
@@ -192,7 +192,7 @@ void LightCall::log_and_clear_unsupported_(FieldFlags flag, const LogString *fea
|
||||
}
|
||||
|
||||
LightColorValues LightCall::validate_() {
|
||||
auto *name = this->parent_->get_name().c_str();
|
||||
auto *name = LOG_STR_ARG(this->parent_->get_log_name());
|
||||
auto traits = this->parent_->get_traits();
|
||||
|
||||
// Snapshot before the adjustments below add flags of their own
|
||||
@@ -446,7 +446,7 @@ void LightCall::transform_parameters_(const LightTraits &traits) {
|
||||
!(this->color_mode_ & ColorCapability::COLOR_TEMPERATURE) && //
|
||||
min_mireds > 0.0f && max_mireds > 0.0f) {
|
||||
ESP_LOGV(TAG, "'%s': setting cold/warm white channels using white/color temperature values",
|
||||
this->parent_->get_name().c_str());
|
||||
LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
// Only compute cold_white/warm_white from color_temperature if they're not already explicitly set.
|
||||
// This is important for state restoration, where both color_temperature and cold_white/warm_white
|
||||
// are restored from flash - we want to preserve the saved cold_white/warm_white values.
|
||||
@@ -492,7 +492,7 @@ ColorMode LightCall::compute_color_mode_(const LightTraits &traits) {
|
||||
|
||||
// Don't change if the current mode is in the intersection (suitable AND supported)
|
||||
if (ColorModeMask::mask_contains(intersection, current_mode)) {
|
||||
ESP_LOGV(TAG, "'%s': color mode not specified; retaining %s", this->parent_->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "'%s': color mode not specified; retaining %s", LOG_STR_ARG(this->parent_->get_log_name()),
|
||||
LOG_STR_ARG(color_mode_to_human(current_mode)));
|
||||
return current_mode;
|
||||
}
|
||||
@@ -500,7 +500,7 @@ ColorMode LightCall::compute_color_mode_(const LightTraits &traits) {
|
||||
// Use the preferred suitable mode.
|
||||
if (intersection != 0) {
|
||||
ColorMode mode = ColorModeMask::first_value_from_mask(intersection);
|
||||
ESP_LOGV(TAG, "'%s': color mode not specified; using %s", this->parent_->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "'%s': color mode not specified; using %s", LOG_STR_ARG(this->parent_->get_log_name()),
|
||||
LOG_STR_ARG(color_mode_to_human(mode)));
|
||||
return mode;
|
||||
}
|
||||
@@ -508,7 +508,7 @@ ColorMode LightCall::compute_color_mode_(const LightTraits &traits) {
|
||||
// There's no supported mode for this call, so warn, use the current more or a mode at random and let validation strip
|
||||
// out whatever we don't support.
|
||||
auto color_mode = current_mode != ColorMode::UNKNOWN ? current_mode : *supported_modes.begin();
|
||||
ESP_LOGW(TAG, "'%s': no suitable color mode supported; defaulting to %s", this->parent_->get_name().c_str(),
|
||||
ESP_LOGW(TAG, "'%s': no suitable color mode supported; defaulting to %s", LOG_STR_ARG(this->parent_->get_log_name()),
|
||||
LOG_STR_ARG(color_mode_to_human(color_mode)));
|
||||
return color_mode;
|
||||
}
|
||||
@@ -587,7 +587,7 @@ LightCall &LightCall::set_effect(const char *effect, size_t len) {
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ESP_LOGW(TAG, "'%s': no such effect '%.*s'", this->parent_->get_name().c_str(), (int) len, effect);
|
||||
ESP_LOGW(TAG, "'%s': no such effect '%.*s'", LOG_STR_ARG(this->parent_->get_log_name()), (int) len, effect);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ void LightState::setup() {
|
||||
call.perform();
|
||||
}
|
||||
void LightState::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Light '%s'", this->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, "Light '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
auto traits = this->get_traits();
|
||||
if (traits.supports_color_capability(ColorCapability::BRIGHTNESS)) {
|
||||
#ifdef USE_LIGHT_GAMMA_LUT
|
||||
|
||||
@@ -30,10 +30,10 @@ void Lock::lock() { this->set_state_(LOCK_STATE_LOCKED); }
|
||||
void Lock::unlock() { this->set_state_(LOCK_STATE_UNLOCKED); }
|
||||
void Lock::open() {
|
||||
if (traits.get_supports_open()) {
|
||||
ESP_LOGD(TAG, "'%s' Opening.", this->get_name().c_str());
|
||||
ESP_LOGD(TAG, "'%s' Opening.", LOG_STR_ARG(this->get_log_name()));
|
||||
this->open_latch();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' Does not support Open.", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "'%s' Does not support Open.", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
}
|
||||
void Lock::publish_state(LockState state) {
|
||||
@@ -42,7 +42,7 @@ void Lock::publish_state(LockState state) {
|
||||
|
||||
this->state = state;
|
||||
this->rtc_.save(&this->state);
|
||||
ESP_LOGV(TAG, "'%s' >> %s", this->name_.c_str(), LOG_STR_ARG(lock_state_to_string(state)));
|
||||
ESP_LOGV(TAG, "'%s' >> %s", LOG_STR_ARG(this->get_log_name()), LOG_STR_ARG(lock_state_to_string(state)));
|
||||
this->state_callback_.call(state);
|
||||
#if defined(USE_LOCK) && defined(USE_CONTROLLER_REGISTRY)
|
||||
ControllerRegistry::notify_lock_update(this);
|
||||
@@ -50,7 +50,7 @@ void Lock::publish_state(LockState state) {
|
||||
}
|
||||
|
||||
void LockCall::perform() {
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
this->validate_();
|
||||
if (this->state_.has_value()) {
|
||||
ESP_LOGV(TAG, " State: %s", LOG_STR_ARG(lock_state_to_string(*this->state_)));
|
||||
@@ -92,7 +92,7 @@ LockCall &LockCall::set_state(const char *state) {
|
||||
} else if (ESPHOME_strcasecmp_P(state, ESPHOME_PSTR("NONE")) == 0) {
|
||||
this->set_state(LOCK_STATE_NONE);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized state %s", this->parent_->get_name().c_str(), state);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized state %s", LOG_STR_ARG(this->parent_->get_log_name()), state);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class Lock;
|
||||
|
||||
#define LOG_LOCK(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
|
||||
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), LOG_STR_ARG((obj)->get_log_name())); \
|
||||
LOG_ENTITY_ICON(TAG, prefix, *(obj)); \
|
||||
if ((obj)->traits.get_assumed_state()) { \
|
||||
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
|
||||
|
||||
@@ -94,28 +94,28 @@ bool MAX31856Sensor::has_fault_() {
|
||||
this->status_set_warning();
|
||||
|
||||
if ((faults & MAX31856_FAULT_CJRANGE) == MAX31856_FAULT_CJRANGE) {
|
||||
ESP_LOGW(TAG, "Cold Junction Out-of-Range: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Cold Junction Out-of-Range: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_TCRANGE) == MAX31856_FAULT_TCRANGE) {
|
||||
ESP_LOGW(TAG, "Thermocouple Out-of-Range: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Thermocouple Out-of-Range: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_CJHIGH) == MAX31856_FAULT_CJHIGH) {
|
||||
ESP_LOGW(TAG, "Cold-Junction High Fault: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Cold-Junction High Fault: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_CJLOW) == MAX31856_FAULT_CJLOW) {
|
||||
ESP_LOGW(TAG, "Cold-Junction Low Fault: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Cold-Junction Low Fault: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_TCHIGH) == MAX31856_FAULT_TCHIGH) {
|
||||
ESP_LOGW(TAG, "Thermocouple Temperature High Fault: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Thermocouple Temperature High Fault: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_TCLOW) == MAX31856_FAULT_TCLOW) {
|
||||
ESP_LOGW(TAG, "Thermocouple Temperature Low Fault: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Thermocouple Temperature Low Fault: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_OVUV) == MAX31856_FAULT_OVUV) {
|
||||
ESP_LOGW(TAG, "Overvoltage or Undervoltage Input Fault: '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Overvoltage or Undervoltage Input Fault: '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
if ((faults & MAX31856_FAULT_OPEN) == MAX31856_FAULT_OPEN) {
|
||||
ESP_LOGW(TAG, "Thermocouple Open-Circuit Fault (possibly not connected): '%s'", this->name_.c_str());
|
||||
ESP_LOGW(TAG, "Thermocouple Open-Circuit Fault (possibly not connected): '%s'", LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -66,7 +66,7 @@ void MAX31888Sensor::update() {
|
||||
return;
|
||||
}
|
||||
const float temperature = raw * MAX31888_DEGREES_PER_LSB;
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%.3f°C", this->get_name().c_str(), temperature);
|
||||
ESP_LOGD(TAG, "'%s': Got Temperature=%.3f°C", LOG_STR_ARG(this->get_log_name()), temperature);
|
||||
this->status_clear_warning();
|
||||
this->publish_state(temperature);
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ void MAX6675Sensor::read_data_() {
|
||||
}
|
||||
|
||||
float temperature = float(val >> 3) / 4.0f;
|
||||
ESP_LOGD(TAG, "'%s': Got temperature=%.1f°C", this->name_.c_str(), temperature);
|
||||
ESP_LOGD(TAG, "'%s': Got temperature=%.1f°C", LOG_STR_ARG(this->get_log_name()), temperature);
|
||||
this->publish_state(temperature);
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
@@ -20,21 +20,21 @@ void MCP9808Sensor::setup() {
|
||||
uint16_t manu = 0;
|
||||
if (!this->read_byte_16(MCP9808_REG_MANUF_ID, &manu) || manu != MCP9808_MANUF_ID) {
|
||||
this->mark_failed();
|
||||
ESP_LOGE(TAG, "Incorrect manufacturer ID (%X) for '%s'", manu, this->name_.c_str());
|
||||
ESP_LOGE(TAG, "Incorrect manufacturer ID (%X) for '%s'", manu, LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
uint16_t dev_id = 0;
|
||||
if (!this->read_byte_16(MCP9808_REG_DEVICE_ID, &dev_id) || dev_id != MCP9808_DEV_ID) {
|
||||
this->mark_failed();
|
||||
ESP_LOGE(TAG, "Incorrect device ID (%X) for '%s'", dev_id, this->name_.c_str());
|
||||
ESP_LOGE(TAG, "Incorrect device ID (%X) for '%s'", dev_id, LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
void MCP9808Sensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "%s:", this->name_.c_str());
|
||||
ESP_LOGCONFIG(TAG, "%s:", LOG_STR_ARG(this->get_log_name()));
|
||||
LOG_I2C_DEVICE(this);
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->name_.c_str());
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, LOG_STR_ARG(this->get_log_name()));
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_SENSOR(" ", "Temperature", this);
|
||||
@@ -68,7 +68,7 @@ void MCP9808Sensor::update() {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "%s: Got temperature=%.4f°C", this->name_.c_str(), temp);
|
||||
ESP_LOGD(TAG, "%s: Got temperature=%.4f°C", LOG_STR_ARG(this->get_log_name()), temp);
|
||||
this->publish_state(temp);
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ void MediaPlayerCall::validate_() {
|
||||
}
|
||||
|
||||
void MediaPlayerCall::perform() {
|
||||
ESP_LOGV(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
||||
ESP_LOGV(TAG, "'%s' - Setting", LOG_STR_ARG(this->parent_->get_log_name()));
|
||||
this->validate_();
|
||||
if (this->command_.has_value()) {
|
||||
const char *command_s = media_player_command_to_string(this->command_.value());
|
||||
@@ -177,7 +177,7 @@ MediaPlayerCall &MediaPlayerCall::set_command(const char *command) {
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("GROUP_JOIN")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_GROUP_JOIN);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized command %s", this->parent_->get_name().c_str(), command);
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized command %s", LOG_STR_ARG(this->parent_->get_log_name()), command);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ void MLX90614Component::update() {
|
||||
|
||||
// Bit 15 set means the device flagged the reading as invalid
|
||||
const float temperature = (raw & 0x8000) ? NAN : raw * 0.02f - 273.15f;
|
||||
ESP_LOGD(TAG, "'%s': Got temperature=%.1f°C", sensor->get_name().c_str(), temperature);
|
||||
ESP_LOGD(TAG, "'%s': Got temperature=%.1f°C", LOG_STR_ARG(sensor->get_log_name()), temperature);
|
||||
sensor->publish_state(temperature);
|
||||
return ec;
|
||||
};
|
||||
|
||||
@@ -57,7 +57,8 @@ void ModbusNumber::control(float value) {
|
||||
bytes.push_back(word_bytes[1]);
|
||||
}
|
||||
if (!this->send_raw_frame_deprecated_(std::span<const uint8_t>(bytes.data(), bytes.size()))) {
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
this->publish_state(value);
|
||||
@@ -82,7 +83,7 @@ void ModbusNumber::control(float value) {
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
"Updating register: connected Sensor=%s start address=0x%X register count=%d new value=%.02f (val=%.02f)",
|
||||
this->get_name().c_str(), this->start_address, this->entity_count(), value, write_value);
|
||||
LOG_STR_ARG(this->get_log_name()), this->start_address, this->entity_count(), value, write_value);
|
||||
|
||||
bool queued;
|
||||
if (this->entity_count() == 1 && !this->use_write_multiple_) {
|
||||
@@ -91,7 +92,8 @@ void ModbusNumber::control(float value) {
|
||||
queued = this->write_multiple_registers(this->write_address(), data);
|
||||
}
|
||||
if (!queued) {
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
this->publish_state(value);
|
||||
|
||||
@@ -100,7 +100,8 @@ void ModbusSelect::control(size_t index) {
|
||||
}
|
||||
|
||||
if (!queued) {
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
if (this->optimistic_)
|
||||
|
||||
@@ -48,7 +48,7 @@ void ModbusSwitch::parse_and_publish(std::span<const uint8_t> data) {
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Publish '%s': new value = %s type = %d address = %X offset = %zx", this->get_name().c_str(),
|
||||
ESP_LOGV(TAG, "Publish '%s': new value = %s type = %d address = %X offset = %zx", LOG_STR_ARG(this->get_log_name()),
|
||||
ONOFF(value), (int) this->register_type, this->start_address, offset);
|
||||
this->publish_state(value);
|
||||
}
|
||||
@@ -77,7 +77,8 @@ void ModbusSwitch::write_state(bool state) {
|
||||
format_hex_pretty_to(hex_buf, sizeof(hex_buf), data.data(), data.size()));
|
||||
// The lambda filled a legacy raw frame (device address + function code + data).
|
||||
if (!this->send_raw_frame_deprecated_(data)) {
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
this->publish_state(state);
|
||||
@@ -93,8 +94,8 @@ void ModbusSwitch::write_state(bool state) {
|
||||
write_value = val.value();
|
||||
}
|
||||
ESP_LOGV(TAG, "write_state '%s': new value = %s (wire = %s) type = %d address = %X offset = %x",
|
||||
this->get_name().c_str(), ONOFF(state), ONOFF(write_value), (int) this->register_type, this->start_address,
|
||||
this->offset);
|
||||
LOG_STR_ARG(this->get_log_name()), ONOFF(state), ONOFF(write_value), (int) this->register_type,
|
||||
this->start_address, this->offset);
|
||||
bool queued;
|
||||
if (this->register_type == EntityType::COIL) {
|
||||
// offset for coil and discrete inputs is the coil/register number not bytes
|
||||
@@ -113,7 +114,8 @@ void ModbusSwitch::write_state(bool state) {
|
||||
}
|
||||
}
|
||||
if (!queued) {
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published", this->get_name().c_str());
|
||||
ESP_LOGW(TAG, "Modbus write for '%s' was refused by the hub; state not published",
|
||||
LOG_STR_ARG(this->get_log_name()));
|
||||
return;
|
||||
}
|
||||
this->publish_state(state);
|
||||
|
||||
@@ -59,9 +59,9 @@ void MQTTAlarmControlPanelComponent::setup() {
|
||||
if (!root.isNull()) {
|
||||
const char *state = root[ESPHOME_F("state")];
|
||||
if (state == nullptr) {
|
||||
ESP_LOGW(TAG, "'%s': JSON payload missing 'state' key", this->friendly_name_().c_str());
|
||||
ESP_LOGW(TAG, "'%s': JSON payload missing 'state' key", LOG_STR_ARG(this->log_name_()));
|
||||
} else if (!apply_command(call, state)) {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown state in JSON payload: %s", this->friendly_name_().c_str(), state);
|
||||
ESP_LOGW(TAG, "'%s': Received unknown state in JSON payload: %s", LOG_STR_ARG(this->log_name_()), state);
|
||||
} else {
|
||||
const char *code = root[ESPHOME_F("code")];
|
||||
if (code != nullptr) {
|
||||
@@ -70,14 +70,14 @@ void MQTTAlarmControlPanelComponent::setup() {
|
||||
}
|
||||
}
|
||||
} else if (!apply_command(call, payload.c_str())) {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown command payload %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown command payload %s", LOG_STR_ARG(this->log_name_()), payload.c_str());
|
||||
}
|
||||
call.perform();
|
||||
});
|
||||
}
|
||||
|
||||
void MQTTAlarmControlPanelComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MQTT alarm_control_panel '%s':", this->alarm_control_panel_->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, "MQTT alarm_control_panel '%s':", LOG_STR_ARG(this->alarm_control_panel_->get_log_name()));
|
||||
LOG_MQTT_COMPONENT(true, true);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Supported Features: %" PRIu32 "\n"
|
||||
|
||||
@@ -18,7 +18,7 @@ void MQTTBinarySensorComponent::setup() {
|
||||
}
|
||||
|
||||
void MQTTBinarySensorComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MQTT Binary Sensor '%s':", this->binary_sensor_->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, "MQTT Binary Sensor '%s':", LOG_STR_ARG(this->binary_sensor_->get_log_name()));
|
||||
LOG_MQTT_COMPONENT(true, false);
|
||||
}
|
||||
MQTTBinarySensorComponent::MQTTBinarySensorComponent(binary_sensor::BinarySensor *binary_sensor)
|
||||
|
||||
@@ -19,13 +19,13 @@ void MQTTButtonComponent::setup() {
|
||||
if (payload == "PRESS") {
|
||||
this->button_->press();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
|
||||
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", LOG_STR_ARG(this->log_name_()), payload.c_str());
|
||||
this->status_momentary_warning(5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
void MQTTButtonComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MQTT Button '%s': ", this->button_->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, "MQTT Button '%s': ", LOG_STR_ARG(this->button_->get_log_name()));
|
||||
LOG_MQTT_COMPONENT(false, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,11 +186,11 @@ bool MQTTComponent::send_discovery_() {
|
||||
StringRef discovery_topic = this->get_discovery_topic_to_(discovery_topic_buf, discovery_info);
|
||||
|
||||
if (discovery_info.clean) {
|
||||
ESP_LOGV(TAG, "'%s': Cleaning discovery", this->friendly_name_().c_str());
|
||||
ESP_LOGV(TAG, "'%s': Cleaning discovery", LOG_STR_ARG(this->log_name_()));
|
||||
return global_mqtt_client->publish(discovery_topic.c_str(), "", 0, this->qos_, true);
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "'%s': Sending discovery", this->friendly_name_().c_str());
|
||||
ESP_LOGV(TAG, "'%s': Sending discovery", LOG_STR_ARG(this->log_name_()));
|
||||
|
||||
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
return global_mqtt_client->publish_json(
|
||||
@@ -207,7 +207,12 @@ bool MQTTComponent::send_discovery_() {
|
||||
}
|
||||
|
||||
// Fields from EntityBase
|
||||
root[MQTT_NAME] = this->get_entity()->has_own_name() ? this->friendly_name_() : StringRef();
|
||||
if (this->get_entity()->has_own_name()) {
|
||||
// ArduinoJson copies flash strings into the document itself
|
||||
root[MQTT_NAME] = reinterpret_cast<ProgmemStr>(this->get_entity()->get_name_progmem().progmem_ptr());
|
||||
} else {
|
||||
root[MQTT_NAME] = StringRef();
|
||||
}
|
||||
|
||||
if (this->is_disabled_by_default_())
|
||||
root[MQTT_ENABLED_BY_DEFAULT] = false;
|
||||
@@ -253,9 +258,10 @@ bool MQTTComponent::send_discovery_() {
|
||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||
StringRef object_id = this->get_default_object_id_to_(object_id_buf);
|
||||
if (discovery_info.unique_id_generator == MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR) {
|
||||
char name_buf[ENTITY_NAME_BUF_SIZE];
|
||||
char friendly_name_hash[9];
|
||||
buf_append_printf(friendly_name_hash, sizeof(friendly_name_hash), 0, "%08" PRIx32,
|
||||
fnv1_hash(this->friendly_name_().c_str()));
|
||||
fnv1_hash(this->get_entity()->get_name_to(name_buf).c_str()));
|
||||
// Format: mac-component_type-hash (e.g. "aabbccddeeff-sensor-12345678")
|
||||
// MAC (12) + "-" (1) + domain (max 20) + "-" (1) + hash (8) + null (1) = 43
|
||||
char unique_id[MAC_ADDRESS_BUFFER_SIZE + ESPHOME_DOMAIN_MAX_LEN + 11];
|
||||
@@ -407,7 +413,11 @@ void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
|
||||
bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
|
||||
|
||||
// Pull these properties from EntityBase if not overridden
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
const StringRef &MQTTComponent::friendly_name_() const { return this->get_entity()->get_name(); }
|
||||
#pragma GCC diagnostic pop
|
||||
const LogString *MQTTComponent::log_name_() const { return this->get_entity()->get_log_name(); }
|
||||
StringRef MQTTComponent::get_default_object_id_to_(std::span<char, OBJECT_ID_MAX_LEN> buf) const {
|
||||
return this->get_entity()->get_object_id_to(buf);
|
||||
}
|
||||
|
||||
@@ -300,7 +300,9 @@ class MQTTComponent : public Component {
|
||||
*/
|
||||
virtual const EntityBase *get_entity() const = 0;
|
||||
|
||||
/// Get the friendly name of this MQTT component.
|
||||
/// Entity name for a "%s" log argument.
|
||||
const LogString *log_name_() const;
|
||||
ESPDEPRECATED("Use log_name_() for logging. Removed in 2027.5.0", "2026.11.0")
|
||||
const StringRef &friendly_name_() const;
|
||||
|
||||
/// Get the icon field of this component into a stack buffer
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user