Compare commits

...

8 Commits

Author SHA1 Message Date
Clyde Stubbs
00eb56d8db [esp32_touch] Fix threshold (#9291)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-02 09:08:10 -05:00
tomaszduda23
60eac6ea07 [time] fix clang-tidy (#9292) 2025-07-02 14:02:56 +00:00
Jesse Hills
9b3ece4caf [time] Add `USE_TIME_TIMEZONE` define (#9290) 2025-07-02 08:51:25 -05:00
Colm
289aedcfe2 Don't compile state_to_string() unless debugging. (#7473) 2025-07-03 00:23:37 +12:00
rwrozelle
4cdc804c17 OpenThread - add Device Type (#9272)
Co-authored-by: mc <mc@debian>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-03 00:16:28 +12:00
mrtntome
56a963dfe6 [heatpumpir] Add Support for PHS32 HeatPump (#7378)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-03 00:05:54 +12:00
Aleksey Zinchenko
f6f0e52d5e [core] Deleting CMakeCache.txt for fast recompilation with ESP-IDF (#8750) 2025-07-02 17:37:31 +10:00
J. Nick Koston
eba2c82fec Use encode_bytes() for protobuf bytes fields (#9289) 2025-07-02 04:36:09 +00:00
18 changed files with 129 additions and 69 deletions

View File

@@ -3494,7 +3494,7 @@ bool SubscribeLogsResponse::decode_length(uint32_t field_id, ProtoLengthDelimite
}
void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_enum<enums::LogLevel>(1, this->level);
buffer.encode_string(3, this->message);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->message.data()), this->message.size());
buffer.encode_bool(4, this->send_failed);
}
void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const {
@@ -3530,7 +3530,9 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD
return false;
}
}
void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->key); }
void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bytes(1, reinterpret_cast<const uint8_t *>(this->key.data()), this->key.size());
}
void NoiseEncryptionSetKeyRequest::calculate_size(uint32_t &total_size) const {
ProtoSize::add_string_field(total_size, 1, this->key, false);
}
@@ -4267,7 +4269,7 @@ bool CameraImageResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
}
void CameraImageResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_string(2, this->data);
buffer.encode_bytes(2, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
buffer.encode_bool(3, this->done);
}
void CameraImageResponse::calculate_size(uint32_t &total_size) const {
@@ -6785,7 +6787,7 @@ void BluetoothServiceData::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->legacy_data) {
buffer.encode_uint32(2, it, true);
}
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothServiceData::calculate_size(uint32_t &total_size) const {
ProtoSize::add_string_field(total_size, 1, this->uuid, false);
@@ -6859,7 +6861,7 @@ bool BluetoothLEAdvertisementResponse::decode_length(uint32_t field_id, ProtoLen
}
void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_string(2, this->name);
buffer.encode_bytes(2, reinterpret_cast<const uint8_t *>(this->name.data()), this->name.size());
buffer.encode_sint32(3, this->rssi);
for (auto &it : this->service_uuids) {
buffer.encode_string(4, it, true);
@@ -6960,7 +6962,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_sint32(2, this->rssi);
buffer.encode_uint32(3, this->address_type);
buffer.encode_string(4, this->data);
buffer.encode_bytes(4, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7493,7 +7495,7 @@ bool BluetoothGATTReadResponse::decode_length(uint32_t field_id, ProtoLengthDeli
void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7552,7 +7554,7 @@ void BluetoothGATTWriteRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_bool(3, this->response);
buffer.encode_string(4, this->data);
buffer.encode_bytes(4, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7649,7 +7651,7 @@ bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, Proto
void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTWriteDescriptorRequest::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7751,7 +7753,7 @@ bool BluetoothGATTNotifyDataResponse::decode_length(uint32_t field_id, ProtoLeng
void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -8481,7 +8483,7 @@ bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited
}
}
void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->data);
buffer.encode_bytes(1, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
buffer.encode_bool(2, this->end);
}
void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const {

View File

@@ -93,7 +93,6 @@ class ESP32TouchComponent : public Component {
uint32_t last_release_check_{0};
uint32_t release_timeout_ms_{1500};
uint32_t release_check_interval_ms_{50};
bool initial_state_published_[TOUCH_PAD_MAX] = {false};
// Common configuration parameters
uint16_t sleep_cycle_{4095};
@@ -123,13 +122,6 @@ class ESP32TouchComponent : public Component {
};
protected:
// Design note: last_touch_time_ does not require synchronization primitives because:
// 1. ESP32 guarantees atomic 32-bit aligned reads/writes
// 2. ISR only writes timestamps, main loop only reads
// 3. Timing tolerance allows for occasional stale reads (50ms check interval)
// 4. Queue operations provide implicit memory barriers
// Using atomic/critical sections would add overhead without meaningful benefit
uint32_t last_touch_time_[TOUCH_PAD_MAX] = {0};
uint32_t iir_filter_{0};
bool iir_filter_enabled_() const { return this->iir_filter_ > 0; }
@@ -147,9 +139,6 @@ class ESP32TouchComponent : public Component {
uint32_t intr_mask;
};
// Track last touch time for timeout-based release detection
uint32_t last_touch_time_[TOUCH_PAD_MAX] = {0};
protected:
// Filter configuration
touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX};
@@ -255,11 +244,22 @@ class ESP32TouchBinarySensor : public binary_sensor::BinarySensor {
touch_pad_t touch_pad_{TOUCH_PAD_MAX};
uint32_t threshold_{0};
uint32_t benchmark_{};
#ifdef USE_ESP32_VARIANT_ESP32
uint32_t value_{0};
#endif
bool last_state_{false};
const uint32_t wakeup_threshold_{0};
// Track last touch time for timeout-based release detection
// Design note: last_touch_time_ does not require synchronization primitives because:
// 1. ESP32 guarantees atomic 32-bit aligned reads/writes
// 2. ISR only writes timestamps, main loop only reads
// 3. Timing tolerance allows for occasional stale reads (50ms check interval)
// 4. Queue operations provide implicit memory barriers
// Using atomic/critical sections would add overhead without meaningful benefit
uint32_t last_touch_time_{};
bool initial_state_published_{};
};
} // namespace esp32_touch

View File

@@ -22,16 +22,20 @@ void ESP32TouchComponent::dump_config_base_() {
" Sleep cycle: %.2fms\n"
" Low Voltage Reference: %s\n"
" High Voltage Reference: %s\n"
" Voltage Attenuation: %s",
" Voltage Attenuation: %s\n"
" Release Timeout: %" PRIu32 "ms\n",
this->meas_cycle_ / (8000000.0f / 1000.0f), this->sleep_cycle_ / (150000.0f / 1000.0f), lv_s, hv_s,
atten_s);
atten_s, this->release_timeout_ms_);
}
void ESP32TouchComponent::dump_config_sensors_() {
for (auto *child : this->children_) {
LOG_BINARY_SENSOR(" ", "Touch Pad", child);
ESP_LOGCONFIG(TAG, " Pad: T%" PRIu32, (uint32_t) child->get_touch_pad());
ESP_LOGCONFIG(TAG, " Threshold: %" PRIu32, child->get_threshold());
ESP_LOGCONFIG(TAG,
" Pad: T%u\n"
" Threshold: %" PRIu32 "\n"
" Benchmark: %" PRIu32,
(unsigned) child->touch_pad_, child->threshold_, child->benchmark_);
}
}
@@ -112,12 +116,11 @@ bool ESP32TouchComponent::should_check_for_releases_(uint32_t now) {
}
void ESP32TouchComponent::publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now) {
touch_pad_t pad = child->get_touch_pad();
if (!this->initial_state_published_[pad]) {
if (!child->initial_state_published_) {
// Check if enough time has passed since startup
if (now > this->release_timeout_ms_) {
child->publish_initial_state(false);
this->initial_state_published_[pad] = true;
child->initial_state_published_ = true;
ESP_LOGV(TAG, "Touch Pad '%s' state: OFF (initial)", child->get_name().c_str());
}
}

View File

@@ -104,7 +104,7 @@ void ESP32TouchComponent::loop() {
// Track when we last saw this pad as touched
if (new_state) {
this->last_touch_time_[event.pad] = now;
child->last_touch_time_ = now;
}
// Only publish if state changed - this filters out repeated events
@@ -127,15 +127,13 @@ void ESP32TouchComponent::loop() {
size_t pads_off = 0;
for (auto *child : this->children_) {
touch_pad_t pad = child->get_touch_pad();
// Handle initial state publication after startup
this->publish_initial_state_if_needed_(child, now);
if (child->last_state_) {
// Pad is currently in touched state - check for release timeout
// Using subtraction handles 32-bit rollover correctly
uint32_t time_diff = now - this->last_touch_time_[pad];
uint32_t time_diff = now - child->last_touch_time_;
// Check if we haven't seen this pad recently
if (time_diff > this->release_timeout_ms_) {

View File

@@ -14,19 +14,16 @@ static const char *const TAG = "esp32_touch";
void ESP32TouchComponent::update_touch_state_(ESP32TouchBinarySensor *child, bool is_touched) {
// Always update timer when touched
if (is_touched) {
this->last_touch_time_[child->get_touch_pad()] = App.get_loop_component_start_time();
child->last_touch_time_ = App.get_loop_component_start_time();
}
if (child->last_state_ != is_touched) {
// Read value for logging
uint32_t value = this->read_touch_value(child->get_touch_pad());
child->last_state_ = is_touched;
child->publish_state(is_touched);
if (is_touched) {
// ESP32-S2/S3 v2: touched when value > threshold
ESP_LOGV(TAG, "Touch Pad '%s' state: ON (value: %" PRIu32 " > threshold: %" PRIu32 ")", child->get_name().c_str(),
value, child->get_threshold());
this->read_touch_value(child->touch_pad_), child->threshold_ + child->benchmark_);
} else {
ESP_LOGV(TAG, "Touch Pad '%s' state: OFF", child->get_name().c_str());
}
@@ -36,10 +33,13 @@ void ESP32TouchComponent::update_touch_state_(ESP32TouchBinarySensor *child, boo
// Helper to read touch value and update state for a given child (used for timeout events)
bool ESP32TouchComponent::check_and_update_touch_state_(ESP32TouchBinarySensor *child) {
// Read current touch value
uint32_t value = this->read_touch_value(child->get_touch_pad());
uint32_t value = this->read_touch_value(child->touch_pad_);
// ESP32-S2/S3 v2: Touch is detected when value > threshold
bool is_touched = value > child->get_threshold();
// ESP32-S2/S3 v2: Touch is detected when value > threshold + benchmark
ESP_LOGV(TAG,
"Checking touch state for '%s' (T%d): value = %" PRIu32 ", threshold = %" PRIu32 ", benchmark = %" PRIu32,
child->get_name().c_str(), child->touch_pad_, value, child->threshold_, child->benchmark_);
bool is_touched = value > child->benchmark_ + child->threshold_;
this->update_touch_state_(child, is_touched);
return is_touched;
@@ -61,9 +61,9 @@ void ESP32TouchComponent::setup() {
// Configure each touch pad first
for (auto *child : this->children_) {
esp_err_t config_err = touch_pad_config(child->get_touch_pad());
esp_err_t config_err = touch_pad_config(child->touch_pad_);
if (config_err != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure touch pad %d: %s", child->get_touch_pad(), esp_err_to_name(config_err));
ESP_LOGE(TAG, "Failed to configure touch pad %d: %s", child->touch_pad_, esp_err_to_name(config_err));
}
}
@@ -100,8 +100,8 @@ void ESP32TouchComponent::setup() {
// Configure measurement parameters
touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_);
// ESP32-S2/S3 always use the older API
touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_);
touch_pad_set_charge_discharge_times(this->meas_cycle_);
touch_pad_set_measurement_interval(this->sleep_cycle_);
// Configure timeout if needed
touch_pad_timeout_set(true, TOUCH_PAD_THRESHOLD_MAX);
@@ -118,8 +118,8 @@ void ESP32TouchComponent::setup() {
// Set thresholds for each pad BEFORE starting FSM
for (auto *child : this->children_) {
if (child->get_threshold() != 0) {
touch_pad_set_thresh(child->get_touch_pad(), child->get_threshold());
if (child->threshold_ != 0) {
touch_pad_set_thresh(child->touch_pad_, child->threshold_);
}
}
@@ -277,6 +277,7 @@ void ESP32TouchComponent::loop() {
// Process any queued touch events from interrupts
TouchPadEventV2 event;
while (xQueueReceive(this->touch_queue_, &event, 0) == pdTRUE) {
ESP_LOGD(TAG, "Event received, mask = 0x%" PRIx32 ", pad = %d", event.intr_mask, event.pad);
// Handle timeout events
if (event.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {
// Resume measurement after timeout
@@ -289,18 +290,16 @@ void ESP32TouchComponent::loop() {
// Find the child for the pad that triggered the interrupt
for (auto *child : this->children_) {
if (child->get_touch_pad() != event.pad) {
continue;
if (child->touch_pad_ == event.pad) {
if (event.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {
// For timeout events, we need to read the value to determine state
this->check_and_update_touch_state_(child);
} else if (event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) {
// We only get ACTIVE interrupts now, releases are detected by timeout
this->update_touch_state_(child, true); // Always touched for ACTIVE interrupts
}
break;
}
if (event.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {
// For timeout events, we need to read the value to determine state
this->check_and_update_touch_state_(child);
} else if (event.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) {
// We only get ACTIVE interrupts now, releases are detected by timeout
this->update_touch_state_(child, true); // Always touched for ACTIVE interrupts
}
break;
}
}
@@ -311,15 +310,15 @@ void ESP32TouchComponent::loop() {
size_t pads_off = 0;
for (auto *child : this->children_) {
touch_pad_t pad = child->get_touch_pad();
if (child->benchmark_ == 0)
touch_pad_read_benchmark(child->touch_pad_, &child->benchmark_);
// Handle initial state publication after startup
this->publish_initial_state_if_needed_(child, now);
if (child->last_state_) {
// Pad is currently in touched state - check for release timeout
// Using subtraction handles 32-bit rollover correctly
uint32_t time_diff = now - this->last_touch_time_[pad];
uint32_t time_diff = now - child->last_touch_time_;
// Check if we haven't seen this pad recently
if (time_diff > this->release_timeout_ms_) {

View File

@@ -70,6 +70,7 @@ PROTOCOLS = {
"airway": Protocol.PROTOCOL_AIRWAY,
"bgh_aud": Protocol.PROTOCOL_BGH_AUD,
"panasonic_altdke": Protocol.PROTOCOL_PANASONIC_ALTDKE,
"philco_phs32": Protocol.PROTOCOL_PHILCO_PHS32,
"vaillantvai8": Protocol.PROTOCOL_VAILLANTVAI8,
"r51m": Protocol.PROTOCOL_R51M,
}

View File

@@ -65,6 +65,7 @@ const std::map<Protocol, std::function<HeatpumpIR *()>> PROTOCOL_CONSTRUCTOR_MAP
{PROTOCOL_AIRWAY, []() { return new AIRWAYHeatpumpIR(); }}, // NOLINT
{PROTOCOL_BGH_AUD, []() { return new BGHHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PANASONIC_ALTDKE, []() { return new PanasonicAltDKEHeatpumpIR(); }}, // NOLINT
{PROTOCOL_PHILCO_PHS32, []() { return new PhilcoPHS32HeatpumpIR(); }}, // NOLINT
{PROTOCOL_VAILLANTVAI8, []() { return new VaillantHeatpumpIR(); }}, // NOLINT
{PROTOCOL_R51M, []() { return new R51MHeatpumpIR(); }}, // NOLINT
};

View File

@@ -65,6 +65,7 @@ enum Protocol {
PROTOCOL_AIRWAY,
PROTOCOL_BGH_AUD,
PROTOCOL_PANASONIC_ALTDKE,
PROTOCOL_PHILCO_PHS32,
PROTOCOL_VAILLANTVAI8,
PROTOCOL_R51M,
};

View File

@@ -11,6 +11,7 @@ from esphome.const import CONF_CHANNEL, CONF_ENABLE_IPV6, CONF_ID
import esphome.final_validate as fv
from .const import (
CONF_DEVICE_TYPE,
CONF_EXT_PAN_ID,
CONF_FORCE_DATASET,
CONF_MDNS_ID,
@@ -32,6 +33,11 @@ AUTO_LOAD = ["network"]
CONFLICTS_WITH = ["wifi"]
DEPENDENCIES = ["esp32"]
CONF_DEVICE_TYPES = [
"FTD",
"MTD",
]
def set_sdkconfig_options(config):
# and expose options for using SPI/UART RCPs
@@ -82,7 +88,7 @@ def set_sdkconfig_options(config):
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_SRP_CLIENT_MAX_SERVICES", 5)
# TODO: Add suport for sleepy end devices
add_idf_sdkconfig_option("CONFIG_OPENTHREAD_FTD", True) # Full Thread Device
add_idf_sdkconfig_option(f"CONFIG_OPENTHREAD_{config.get(CONF_DEVICE_TYPE)}", True)
openthread_ns = cg.esphome_ns.namespace("openthread")
@@ -107,6 +113,9 @@ CONFIG_SCHEMA = cv.All(
cv.GenerateID(): cv.declare_id(OpenThreadComponent),
cv.GenerateID(CONF_SRP_ID): cv.declare_id(OpenThreadSrpComponent),
cv.GenerateID(CONF_MDNS_ID): cv.use_id(MDNSComponent),
cv.Optional(CONF_DEVICE_TYPE, default="FTD"): cv.one_of(
*CONF_DEVICE_TYPES, upper=True
),
cv.Optional(CONF_FORCE_DATASET): cv.boolean,
cv.Optional(CONF_TLV): cv.string_strict,
}

View File

@@ -1,3 +1,4 @@
CONF_DEVICE_TYPE = "device_type"
CONF_EXT_PAN_ID = "ext_pan_id"
CONF_FORCE_DATASET = "force_dataset"
CONF_MDNS_ID = "mdns_id"

View File

@@ -371,6 +371,7 @@ void Rtttl::finish_() {
ESP_LOGD(TAG, "Playback finished");
}
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
static const LogString *state_to_string(State state) {
switch (state) {
case STATE_STOPPED:
@@ -387,6 +388,7 @@ static const LogString *state_to_string(State state) {
return LOG_STR("UNKNOWN");
}
};
#endif
void Rtttl::set_state_(State state) {
State old_state = this->state_;

View File

@@ -268,7 +268,19 @@ def validate_tz(value: str) -> str:
TIME_SCHEMA = cv.Schema(
{
cv.Optional(CONF_TIMEZONE, default=detect_tz): validate_tz,
cv.SplitDefault(
CONF_TIMEZONE,
esp8266=detect_tz,
esp32=detect_tz,
rp2040=detect_tz,
bk72xx=detect_tz,
rtl87xx=detect_tz,
ln882x=detect_tz,
host=detect_tz,
): cv.All(
cv.only_with_framework(["arduino", "esp-idf", "host"]),
validate_tz,
),
cv.Optional(CONF_ON_TIME): automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CronTrigger),
@@ -293,7 +305,9 @@ TIME_SCHEMA = cv.Schema(
async def setup_time_core_(time_var, config):
cg.add(time_var.set_timezone(config[CONF_TIMEZONE]))
if timezone := config.get(CONF_TIMEZONE):
cg.add(time_var.set_timezone(timezone))
cg.add_define("USE_TIME_TIMEZONE")
for conf in config.get(CONF_ON_TIME, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], time_var)

View File

@@ -35,8 +35,10 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
ret = settimeofday(&timev, nullptr);
}
#ifdef USE_TIME_TIMEZONE
// Move timezone back to local timezone.
this->apply_timezone_();
#endif
if (ret != 0) {
ESP_LOGW(TAG, "setimeofday() failed with code %d", ret);
@@ -49,10 +51,12 @@ void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
this->time_sync_callback_.call();
}
#ifdef USE_TIME_TIMEZONE
void RealTimeClock::apply_timezone_() {
setenv("TZ", this->timezone_.c_str(), 1);
tzset();
}
#endif
} // namespace time
} // namespace esphome

View File

@@ -20,6 +20,7 @@ class RealTimeClock : public PollingComponent {
public:
explicit RealTimeClock();
#ifdef USE_TIME_TIMEZONE
/// Set the time zone.
void set_timezone(const std::string &tz) {
this->timezone_ = tz;
@@ -28,6 +29,7 @@ class RealTimeClock : public PollingComponent {
/// Get the time zone currently in use.
std::string get_timezone() { return this->timezone_; }
#endif
/// Get the time in the currently defined timezone.
ESPTime now() { return ESPTime::from_epoch_local(this->timestamp_now()); }
@@ -38,7 +40,7 @@ class RealTimeClock : public PollingComponent {
/// Get the current time as the UTC epoch since January 1st 1970.
time_t timestamp_now() { return ::time(nullptr); }
void add_on_time_sync_callback(std::function<void()> callback) {
void add_on_time_sync_callback(std::function<void()> &&callback) {
this->time_sync_callback_.add(std::move(callback));
};
@@ -46,8 +48,10 @@ class RealTimeClock : public PollingComponent {
/// Report a unix epoch as current time.
void synchronize_epoch_(uint32_t epoch);
#ifdef USE_TIME_TIMEZONE
std::string timezone_{};
void apply_timezone_();
#endif
CallbackManager<void()> time_sync_callback_;
};

View File

@@ -116,6 +116,7 @@
#define USE_OTA_PASSWORD
#define USE_OTA_STATE_CALLBACK
#define USE_OTA_VERSION 2
#define USE_TIME_TIMEZONE
#define USE_WIFI
#define USE_WIFI_AP
#define USE_WIREGUARD

View File

@@ -107,6 +107,11 @@ def storage_should_clean(old: StorageJSON, new: StorageJSON) -> bool:
return True
if old.build_path != new.build_path:
return True
return False
def storage_should_update_cmake_cache(old: StorageJSON, new: StorageJSON) -> bool:
if (
old.loaded_integrations != new.loaded_integrations
or old.loaded_platforms != new.loaded_platforms
@@ -126,10 +131,11 @@ def update_storage_json():
return
if storage_should_clean(old, new):
_LOGGER.info(
"Core config, version or integrations changed, cleaning build files..."
)
_LOGGER.info("Core config, version changed, cleaning build files...")
clean_build()
elif storage_should_update_cmake_cache(old, new):
_LOGGER.info("Integrations changed, cleaning cmake cache...")
clean_cmake_cache()
new.save(path)
@@ -353,6 +359,15 @@ def write_cpp(code_s):
write_file_if_changed(path, full_file)
def clean_cmake_cache():
pioenvs = CORE.relative_pioenvs_path()
if os.path.isdir(pioenvs):
pioenvs_cmake_path = CORE.relative_pioenvs_path(CORE.name, "CMakeCache.txt")
if os.path.isfile(pioenvs_cmake_path):
_LOGGER.info("Deleting %s", pioenvs_cmake_path)
os.remove(pioenvs_cmake_path)
def clean_build():
import shutil

View File

@@ -526,9 +526,13 @@ class BytesType(TypeInfo):
reference_type = "std::string &"
const_reference_type = "const std::string &"
decode_length = "value.as_string()"
encode_func = "encode_string"
encode_func = "encode_bytes"
wire_type = WireType.LENGTH_DELIMITED # Uses wire type 2
@property
def encode_content(self) -> str:
return f"buffer.encode_bytes({self.number}, reinterpret_cast<const uint8_t*>(this->{self.field_name}.data()), this->{self.field_name}.size());"
def dump(self, name: str) -> str:
o = f"out.append(format_hex_pretty({name}));"
return o

View File

@@ -2,6 +2,7 @@ network:
enable_ipv6: true
openthread:
device_type: FTD
channel: 13
network_name: OpenThread-8f28
network_key: 0xdfd34f0f05cad978ec4e32b0413038ff