Merge branch 'dev' into ble_set_security_params

This commit is contained in:
J. Nick Koston
2026-02-26 23:54:21 -07:00
committed by GitHub
585 changed files with 19964 additions and 12099 deletions
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-ard.yaml
<<: !include common.yaml
+96
View File
@@ -35,3 +35,99 @@ button:
data: [0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef]
- cc1101.send_packet: !lambda |-
return {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
- cc1101.set_frequency: !lambda |-
return 433.91e6;
- cc1101.set_frequency:
value: "433.91MHz"
- cc1101.set_frequency:
value: 433911000
- cc1101.set_frequency: 433912000
- cc1101.set_output_power: !lambda |-
return -29.9;
- cc1101.set_output_power:
value: "-28"
- cc1101.set_output_power:
value: 10
- cc1101.set_output_power: 11
- cc1101.set_modulation_type: !lambda |-
return cc1101::Modulation::MODULATION_2_FSK;
- cc1101.set_modulation_type:
value: "4-FSK"
- cc1101.set_modulation_type: "GFSK"
- cc1101.set_symbol_rate: !lambda |-
return 6000.0;
- cc1101.set_symbol_rate:
value: "7000.0"
- cc1101.set_symbol_rate:
value: 8000.0
- cc1101.set_symbol_rate: 9000
- cc1101.set_rx_attenuation: !lambda |-
return cc1101::RxAttenuation::RX_ATTENUATION_0DB;
- cc1101.set_rx_attenuation:
value: "6dB"
- cc1101.set_rx_attenuation: "12dB"
- cc1101.set_dc_blocking_filter: !lambda |-
return false;
- cc1101.set_dc_blocking_filter:
value: true
- cc1101.set_dc_blocking_filter: false
- cc1101.set_manchester: !lambda |-
return false;
- cc1101.set_manchester:
value: true
- cc1101.set_manchester: false
- cc1101.set_filter_bandwidth: !lambda |-
return 58e3;
- cc1101.set_filter_bandwidth:
value: "59kHz"
- cc1101.set_filter_bandwidth:
value: 60000
- cc1101.set_filter_bandwidth: "61kHz"
- cc1101.set_fsk_deviation: !lambda |-
return 1.5e3;
- cc1101.set_fsk_deviation:
value: "1.6kHz"
- cc1101.set_fsk_deviation:
value: 1700
- cc1101.set_fsk_deviation: "1.8kHz"
- cc1101.set_msk_deviation: !lambda |-
return 1;
- cc1101.set_msk_deviation:
value: "2"
- cc1101.set_msk_deviation:
value: 3
- cc1101.set_msk_deviation: "4"
- cc1101.set_channel: !lambda |-
return 0;
- cc1101.set_channel:
value: "1"
- cc1101.set_channel:
value: 3
- cc1101.set_channel: 3
- cc1101.set_channel_spacing: !lambda |-
return 25e3;
- cc1101.set_channel_spacing:
value: "26kHz"
- cc1101.set_channel_spacing:
value: 27000
- cc1101.set_channel_spacing: "28kHz"
- cc1101.set_if_frequency: !lambda |-
return 25e3;
- cc1101.set_if_frequency:
value: "26kHz"
- cc1101.set_if_frequency:
value: 27000
- cc1101.set_if_frequency: "28kHz"
+2 -2
View File
@@ -27,9 +27,9 @@ sensor:
name: Linearly combined temperatures
sources:
- source: template_temperature1
coeffecient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;"
coefficient: !lambda "return 0.4 + std::abs(x - 25) * 0.023;"
- source: template_temperature2
coeffecient: 1.5
coefficient: 1.5
- platform: combination
type: max
name: Max of combined temperatures
+9
View File
@@ -1,4 +1,13 @@
esphome:
on_boot:
then:
- lambda: |-
// Test deprecated std::string overload still compiles
std::string key = "00112233445566778899aabbccddeeff";
id(dsmr_instance).set_decryption_key(key);
dsmr:
id: dsmr_instance
decryption_key: 00112233445566778899aabbccddeeff
max_telegram_length: 1000
request_pin: ${request_pin}
@@ -57,6 +57,23 @@ display:
allow_other_uses: true
number: GPIO4
- platform: epaper_spi
spi_id: spi_bus
model: waveshare-7.5in-H
cs_pin:
allow_other_uses: true
number: GPIO5
dc_pin:
allow_other_uses: true
number: GPIO17
reset_pin:
allow_other_uses: true
number: GPIO16
busy_pin:
allow_other_uses: true
number: GPIO4
inverted: true
- platform: epaper_spi
model: seeed-reterminal-e1002
- platform: epaper_spi
@@ -64,3 +81,66 @@ display:
# Override pins to avoid conflict with other display configs
busy_pin: 43
dc_pin: 42
# WeAct 2.13" 3-color e-paper (122x250, SSD1680)
- platform: epaper_spi
spi_id: spi_bus
model: weact-2.13in-3c
cs_pin:
allow_other_uses: true
number: GPIO5
dc_pin:
allow_other_uses: true
number: GPIO17
reset_pin:
allow_other_uses: true
number: GPIO16
busy_pin:
allow_other_uses: true
number: GPIO4
lambda: |-
it.filled_rectangle(0, 0, it.get_width(), it.get_height(), Color::WHITE);
it.circle(it.get_width() / 2, it.get_height() / 2, 20, Color::BLACK);
it.circle(it.get_width() / 2, it.get_height() / 2, 15, Color(255, 0, 0));
# WeAct 2.9" 3-color e-paper (128x296, SSD1683)
- platform: epaper_spi
spi_id: spi_bus
model: weact-2.9in-3c
cs_pin:
allow_other_uses: true
number: GPIO5
dc_pin:
allow_other_uses: true
number: GPIO17
reset_pin:
allow_other_uses: true
number: GPIO16
busy_pin:
allow_other_uses: true
number: GPIO4
lambda: |-
it.filled_rectangle(0, 0, it.get_width(), it.get_height(), Color::WHITE);
it.circle(it.get_width() / 2, it.get_height() / 2, 20, Color::BLACK);
it.circle(it.get_width() / 2, it.get_height() / 2, 15, Color(255, 0, 0));
# WeAct 4.2" 3-color e-paper (400x300, SSD1683)
- platform: epaper_spi
spi_id: spi_bus
model: weact-4.2in-3c
cs_pin:
allow_other_uses: true
number: GPIO5
dc_pin:
allow_other_uses: true
number: GPIO17
reset_pin:
allow_other_uses: true
number: GPIO16
busy_pin:
allow_other_uses: true
number: GPIO4
lambda: |-
it.filled_rectangle(0, 0, it.get_width(), it.get_height(), Color::WHITE);
it.circle(it.get_width() / 2, it.get_height() / 2, 30, Color::BLACK);
it.circle(it.get_width() / 2, it.get_height() / 2, 20, Color(255, 0, 0));
@@ -1,5 +1,6 @@
esp32:
variant: esp32p4
engineering_sample: true
flash_size: 32MB
cpu_frequency: 400MHz
framework:
@@ -0,0 +1,5 @@
<<: !include common.yaml
esp32_ble:
io_capability: keyboard_only
disable_bt_logs: false
@@ -33,6 +33,10 @@ esp32_ble_server:
- uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc42d
advertise: false
characteristics:
- id: test_lambda_characteristic
uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc12c
read: true
value: !lambda return { 1, 2 };
- id: test_change_characteristic
uuid: 2a24b789-7a1b-4535-af3e-ee76a35cc11c
read: true
@@ -4,7 +4,6 @@ esp32_touch:
measurement_duration: 8ms
low_voltage_reference: 0.5V
high_voltage_reference: 2.7V
voltage_attenuation: 1.5V
binary_sensor:
- platform: esp32_touch
@@ -0,0 +1,5 @@
substitutions:
pin: GPIO5
<<: !include common-variants.yaml
<<: !include common-get-value.yaml
@@ -3,10 +3,13 @@ esp_ldo:
channel: 3
voltage: 2.5V
adjustable: true
- id: ldo_4
- id: ldo_4_passthrough
channel: 4
voltage: 2.0V
setup_priority: 900
voltage: passthrough
- id: ldo_1_internal
channel: 1
voltage: 1.8V
allow_internal_channel: true
esphome:
on_boot:
+19
View File
@@ -0,0 +1,19 @@
esphome:
on_boot:
then:
- hdc302x.heater_on:
id: hdc302x_sensor
power: QUARTER
duration: 5s
- hdc302x.heater_off:
id: hdc302x_sensor
sensor:
- platform: hdc302x
id: hdc302x_sensor
i2c_id: i2c_bus
temperature:
name: Temperature
humidity:
name: Humidity
update_interval: 15s
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
<<: !include common.yaml
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
<<: !include common.yaml
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml
<<: !include common.yaml
@@ -90,6 +90,19 @@ text_sensor:
id: ha_hello_world_text2
attribute: some_attribute
event:
- platform: template
name: Test Event
id: test_event
event_types:
- test_event_type
on_event:
- homeassistant.event:
event: esphome.test_event
data:
event_name: !lambda |-
return event_type;
time:
- platform: homeassistant
on_time:
+7 -6
View File
@@ -4,15 +4,16 @@ interval:
- interval: 60s
then:
- lambda: |-
// Test build_json
std::string json_str = esphome::json::build_json([](JsonObject root) {
// Test build_json - returns SerializationBuffer, use auto to avoid heap allocation
auto json_buf = esphome::json::build_json([](JsonObject root) {
root["sensor"] = "temperature";
root["value"] = 23.5;
root["unit"] = "°C";
});
ESP_LOGD("test", "Built JSON: %s", json_str.c_str());
ESP_LOGD("test", "Built JSON: %s", json_buf.c_str());
// Test parse_json
// Test parse_json - implicit conversion to std::string for backward compatibility
std::string json_str = json_buf;
bool parse_ok = esphome::json::parse_json(json_str, [](JsonObject root) {
if (root["sensor"].is<const char*>() && root["value"].is<float>()) {
const char* sensor = root["sensor"];
@@ -26,10 +27,10 @@ interval:
});
ESP_LOGD("test", "Parse result (JSON syntax only): %s", parse_ok ? "success" : "failed");
// Test JsonBuilder class
// Test JsonBuilder class - returns SerializationBuffer
esphome::json::JsonBuilder builder;
JsonObject obj = builder.root();
obj["test"] = "direct_builder";
obj["count"] = 42;
std::string result = builder.serialize();
auto result = builder.serialize();
ESP_LOGD("test", "JsonBuilder result: %s", result.c_str());
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "esphome/components/ld2450/ld2450.h"
#include "esphome/components/uart/uart_component.h"
namespace esphome::ld2450::testing {
// Mock UART component to satisfy UARTDevice parent requirement.
class MockUARTComponent : public uart::UARTComponent {
public:
void write_array(const uint8_t *data, size_t len) override {}
MOCK_METHOD(bool, read_array, (uint8_t * data, size_t len), (override));
MOCK_METHOD(bool, peek_byte, (uint8_t * data), (override));
MOCK_METHOD(size_t, available, (), (override));
MOCK_METHOD(void, flush, (), (override));
MOCK_METHOD(void, check_logger_conflict, (), (override));
};
// Expose protected members for testing.
class TestableLD2450 : public LD2450Component {
public:
using LD2450Component::buffer_data_;
using LD2450Component::buffer_pos_;
using LD2450Component::readline_;
void feed(const std::vector<uint8_t> &data) {
for (uint8_t byte : data) {
this->readline_(byte);
}
}
};
// LD2450 periodic data frame: header (4) + 3 targets * 8 bytes + footer (2) = 30 bytes
// All-zero targets means no presence detected.
inline std::vector<uint8_t> make_periodic_frame(uint8_t fill = 0x00) {
std::vector<uint8_t> frame = {0xAA, 0xFF, 0x03, 0x00}; // DATA_FRAME_HEADER
for (int i = 0; i < 24; i++) {
frame.push_back(fill); // 3 targets * 8 bytes
}
frame.push_back(0x55); // DATA_FRAME_FOOTER
frame.push_back(0xCC);
return frame;
}
// LD2450 command ACK frame for CMD_ENABLE_CONF (0xFF), successful.
// header (4) + length (2) + command (2) + result (2) + footer (4) = 14 bytes
inline std::vector<uint8_t> make_ack_frame() {
return {
0xFD, 0xFC, 0xFB, 0xFA, // CMD_FRAME_HEADER
0x04, 0x00, // length = 4
0xFF, 0x01, // command = enable_conf, status = success
0x00, 0x00, // result = ok
0x04, 0x03, 0x02, 0x01 // CMD_FRAME_FOOTER
};
}
} // namespace esphome::ld2450::testing
+145
View File
@@ -0,0 +1,145 @@
#include "common.h"
namespace esphome::ld2450::testing {
class LD2450ReadlineTest : public ::testing::Test {
protected:
void SetUp() override {
this->ld2450_.set_uart_parent(&this->mock_uart_);
// Ensure clean state
ASSERT_EQ(this->ld2450_.buffer_pos_, 0);
}
MockUARTComponent mock_uart_;
TestableLD2450 ld2450_;
};
// --- Good data tests ---
TEST_F(LD2450ReadlineTest, ValidPeriodicFrame) {
auto frame = make_periodic_frame();
this->ld2450_.feed(frame);
// After a complete valid frame, buffer should be reset
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
TEST_F(LD2450ReadlineTest, ValidCommandAckFrame) {
auto frame = make_ack_frame();
this->ld2450_.feed(frame);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
TEST_F(LD2450ReadlineTest, BackToBackPeriodicFrames) {
auto frame = make_periodic_frame();
for (int i = 0; i < 5; i++) {
this->ld2450_.feed(frame);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0) << "Frame " << i << " not processed";
}
}
TEST_F(LD2450ReadlineTest, BackToBackMixedFrames) {
auto periodic = make_periodic_frame();
auto ack = make_ack_frame();
this->ld2450_.feed(periodic);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
this->ld2450_.feed(ack);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
this->ld2450_.feed(periodic);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
// --- Garbage then valid frame tests ---
TEST_F(LD2450ReadlineTest, GarbageThenValidFrame) {
// Garbage bytes accumulate in the buffer but don't match any footer.
// A valid frame follows; its footer resets the buffer and resyncs.
std::vector<uint8_t> garbage = {0x01, 0x02, 0x03, 0x42, 0x99};
this->ld2450_.feed(garbage);
EXPECT_GT(this->ld2450_.buffer_pos_, 0); // Garbage accumulated
auto frame = make_periodic_frame();
this->ld2450_.feed(frame);
// Footer from the valid frame resyncs the parser
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
// --- Footer-based resynchronization tests ---
TEST_F(LD2450ReadlineTest, FooterInGarbageResyncs) {
// Garbage containing a periodic frame footer (0x55 0xCC) triggers
// a buffer reset, allowing the next frame to be parsed cleanly.
std::vector<uint8_t> garbage_with_footer = {0x01, 0x02, 0x03, 0x04, 0x55, 0xCC};
this->ld2450_.feed(garbage_with_footer);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0); // Footer reset the buffer
auto frame = make_periodic_frame();
this->ld2450_.feed(frame);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
TEST_F(LD2450ReadlineTest, CmdFooterInGarbageResyncs) {
// Garbage containing a command frame footer (04 03 02 01) also resyncs.
std::vector<uint8_t> garbage_with_footer = {0x10, 0x20, 0x30, 0x40, 0x04, 0x03, 0x02, 0x01};
this->ld2450_.feed(garbage_with_footer);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
auto frame = make_periodic_frame();
this->ld2450_.feed(frame);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
// --- Overflow recovery tests ---
TEST_F(LD2450ReadlineTest, OverflowResetsBuffer) {
// Fill the buffer to capacity with filler that won't match any footer.
// MAX_LINE_LENGTH is 45, usable is 44. The 45th byte triggers overflow.
std::vector<uint8_t> overflow_data(MAX_LINE_LENGTH, 0x11);
this->ld2450_.feed(overflow_data);
// After overflow, buffer_pos_ resets to 0 (via the < 4 early return path)
EXPECT_LT(this->ld2450_.buffer_pos_, 4);
}
TEST_F(LD2450ReadlineTest, OverflowThenValidFrame) {
// Overflow, then a valid frame should be processed.
std::vector<uint8_t> overflow_data(MAX_LINE_LENGTH, 0x11);
this->ld2450_.feed(overflow_data);
auto frame = make_periodic_frame();
this->ld2450_.feed(frame);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
TEST_F(LD2450ReadlineTest, BufferLargeEnoughForDesyncedFooter) {
// The key fix: the buffer (45) is large enough that a desynced periodic frame's
// footer (at most 30 bytes into the stream) will land inside the buffer before overflow.
// Simulate starting 10 bytes into a periodic frame, then a full frame follows.
std::vector<uint8_t> mid_frame = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
// Then a complete periodic frame whose footer will land at position 40 (10 + 30),
// well within the buffer size of 45.
auto frame = make_periodic_frame();
mid_frame.insert(mid_frame.end(), frame.begin(), frame.end());
this->ld2450_.feed(mid_frame);
// The footer from the frame should have triggered a reset
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
TEST_F(LD2450ReadlineTest, SimulatedRestartThenFrames) {
// Simulate LD2450 restart: burst of garbage followed by valid periodic frames.
// The garbage + first frame should fit in the buffer so the footer resyncs.
std::vector<uint8_t> restart_noise = {
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // 8 bytes of mid-frame data
};
auto frame = make_periodic_frame();
// 8 garbage + 30 frame = 38 bytes, well within buffer of 45
restart_noise.insert(restart_noise.end(), frame.begin(), frame.end());
this->ld2450_.feed(restart_noise);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
// Subsequent frames should work normally
this->ld2450_.feed(frame);
EXPECT_EQ(this->ld2450_.buffer_pos_, 0);
}
} // namespace esphome::ld2450::testing
+26
View File
@@ -71,6 +71,32 @@ esphome:
- light.control:
id: test_monochromatic_light
state: on
# Test static effect name resolution at codegen time
- light.turn_on:
id: test_monochromatic_light
effect: Strobe
- light.turn_on:
id: test_monochromatic_light
effect: none
# Test resolving a different effect on the same light
- light.control:
id: test_monochromatic_light
effect: My Flicker
# Test effect: None (capitalized)
- light.control:
id: test_monochromatic_light
effect: None
# Test effect lambda with no args (on_boot has empty Ts...)
- light.turn_on:
id: test_monochromatic_light
effect: !lambda 'return "Strobe";'
# Test effect lambda with non-empty args (repeat passes uint32_t iteration)
- repeat:
count: 3
then:
- light.turn_on:
id: test_monochromatic_light
effect: !lambda 'return iteration > 1 ? "Strobe" : "none";'
- light.dim_relative:
id: test_monochromatic_light
relative_brightness: 5%
@@ -5,3 +5,6 @@ esphome:
logger:
level: DEBUG
wait_for_cdc: true
early_message: true
task_log_buffer_size: 0
+7 -7
View File
@@ -13,10 +13,10 @@ esphome:
on_boot:
- priority: 100
then:
- max7129digit.invert_off:
- max7129digit.invert_on:
- max7129digit.turn_on:
- max7129digit.turn_off:
- max7129digit.reverse_on:
- max7129digit.reverse_off:
- max7129digit.intensity: 10
- max7219digit.invert_off:
- max7219digit.invert_on:
- max7219digit.turn_on:
- max7219digit.turn_off:
- max7219digit.reverse_on:
- max7219digit.reverse_off:
- max7219digit.intensity: 10
+25
View File
@@ -23,8 +23,27 @@ media_player:
- media_player.stop:
- media_player.stop:
announcement: true
on_announcement:
- media_player.play:
on_turn_on:
- media_player.play:
on_turn_off:
- media_player.stop:
on_pause:
- media_player.toggle:
- media_player.turn_on:
- media_player.turn_off:
- media_player.next:
- media_player.previous:
- media_player.mute:
- media_player.unmute:
- media_player.repeat_off:
- media_player.repeat_one:
- media_player.repeat_all:
- media_player.shuffle:
- media_player.unshuffle:
- media_player.group_join:
- media_player.clear_playlist:
- wait_until:
media_player.is_idle:
- wait_until:
@@ -33,6 +52,12 @@ media_player:
media_player.is_announcing:
- wait_until:
media_player.is_paused:
- wait_until:
media_player.is_on:
- wait_until:
media_player.is_off:
- wait_until:
media_player.is_muted:
- media_player.volume_up:
- media_player.volume_down:
- media_player.volume_set: 50%
+21 -3
View File
@@ -3,9 +3,15 @@ display:
spi_16: true
pixel_mode: 18bit
model: ili9488
dc_pin: ${dc_pin}
cs_pin: ${cs_pin}
reset_pin: ${reset_pin}
dc_pin:
allow_other_uses: true
number: ${dc_pin}
cs_pin:
allow_other_uses: true
number: ${cs_pin}
reset_pin:
allow_other_uses: true
number: ${reset_pin}
data_rate: 20MHz
invert_colors: true
show_test_card: true
@@ -24,3 +30,15 @@ display:
height: 200
enable_pin: ${enable_pin}
bus_mode: single
- platform: mipi_spi
model: WAVESHARE-1.83-V2
dc_pin:
allow_other_uses: true
number: ${dc_pin}
cs_pin:
allow_other_uses: true
number: ${cs_pin}
reset_pin:
allow_other_uses: true
number: ${reset_pin}
+48
View File
@@ -219,6 +219,7 @@ cover:
name: Template Cover
state_topic: some/topic/cover
qos: 2
mqtt_json_state_payload: true
lambda: |-
if (id(some_binary_sensor).state) {
return COVER_OPEN;
@@ -231,6 +232,53 @@ cover:
stop_action:
- logger.log: stop_action
optimistic: true
- platform: template
name: Template Cover with Position and Tilt
state_topic: some/topic/cover_pt
position_state_topic: some/topic/cover_pt/position
position_command_topic: some/topic/cover_pt/position/set
tilt_state_topic: some/topic/cover_pt/tilt
tilt_command_topic: some/topic/cover_pt/tilt/set
qos: 2
has_position: true
lambda: |-
if (id(some_binary_sensor).state) {
return COVER_OPEN;
}
return COVER_CLOSED;
position_action:
- logger.log: position_action
tilt_action:
- logger.log: tilt_action
open_action:
- logger.log: open_action
close_action:
- logger.log: close_action
stop_action:
- logger.log: stop_action
optimistic: true
- platform: template
name: Template Cover with Position and Tilt JSON
state_topic: some/topic/cover_pt_json
qos: 2
mqtt_json_state_payload: true
has_position: true
lambda: |-
if (id(some_binary_sensor).state) {
return COVER_OPEN;
}
return COVER_CLOSED;
position_action:
- logger.log: position_action
tilt_action:
- logger.log: tilt_action
open_action:
- logger.log: open_action
close_action:
- logger.log: close_action
stop_action:
- logger.log: stop_action
optimistic: true
datetime:
- platform: template
@@ -0,0 +1,10 @@
sensor:
- platform: pulse_counter
name: Pulse Counter
pin: 4
use_pcnt: false
count_mode:
rising_edge: INCREMENT
falling_edge: DECREMENT
internal_filter: 13us
update_interval: 15s
@@ -0,0 +1,12 @@
remote_receiver:
id: rcvr
pin: GPIO2
dump: all
<<: !include common-actions.yaml
binary_sensor:
- platform: remote_receiver
name: Panasonic Remote Input
panasonic:
address: 0x4004
command: 0x100BCBD
@@ -0,0 +1,7 @@
remote_transmitter:
id: xmitr
pin: GPIO2
carrier_duty_percent: 50%
packages:
buttons: !include common-buttons.yaml
+11
View File
@@ -0,0 +1,11 @@
substitutions:
network_enable_ipv6: "false"
socket:
wifi:
ssid: MySSID
password: password1
network:
enable_ipv6: ${network_enable_ipv6}
@@ -0,0 +1,4 @@
substitutions:
network_enable_ipv6: "true"
<<: !include common.yaml
@@ -0,0 +1,4 @@
socket:
network:
enable_ipv6: true
@@ -0,0 +1 @@
<<: !include common.yaml
@@ -0,0 +1 @@
<<: !include common.yaml
+3
View File
@@ -0,0 +1,3 @@
socket:
network:
@@ -0,0 +1 @@
<<: !include common.yaml
@@ -0,0 +1 @@
<<: !include common.yaml
@@ -1,9 +1,21 @@
from esphome.components import socket
from esphome.const import (
KEY_CORE,
KEY_TARGET_PLATFORM,
PLATFORM_ESP32,
PLATFORM_ESP8266,
)
from esphome.core import CORE
def _setup_platform(platform=PLATFORM_ESP8266) -> None:
"""Set up CORE.data with a platform for testing."""
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: platform}
def test_require_wake_loop_threadsafe__first_call() -> None:
"""Test that first call sets up define and consumes socket."""
_setup_platform()
CORE.config = {"wifi": True}
socket.require_wake_loop_threadsafe()
@@ -32,6 +44,7 @@ def test_require_wake_loop_threadsafe__idempotent() -> None:
def test_require_wake_loop_threadsafe__multiple_calls() -> None:
"""Test that multiple calls only set up once."""
_setup_platform()
# Call three times
CORE.config = {"openthread": True}
socket.require_wake_loop_threadsafe()
@@ -66,12 +79,38 @@ def test_require_wake_loop_threadsafe__no_networking_does_not_consume_socket() -
CORE.config = {"logger": {}}
# Track initial socket consumer state
initial_consumers = CORE.data.get(socket.KEY_SOCKET_CONSUMERS, {})
initial_udp = CORE.data.get(socket.KEY_SOCKET_CONSUMERS_UDP, {})
# Call require_wake_loop_threadsafe
socket.require_wake_loop_threadsafe()
# Verify no socket was consumed
consumers = CORE.data.get(socket.KEY_SOCKET_CONSUMERS, {})
assert "socket.wake_loop_threadsafe" not in consumers
assert consumers == initial_consumers
udp_consumers = CORE.data.get(socket.KEY_SOCKET_CONSUMERS_UDP, {})
assert "socket.wake_loop_threadsafe" not in udp_consumers
assert udp_consumers == initial_udp
def test_require_wake_loop_threadsafe__esp32_no_udp_socket() -> None:
"""Test that ESP32 uses task notifications instead of UDP socket."""
_setup_platform(PLATFORM_ESP32)
CORE.config = {"wifi": True}
socket.require_wake_loop_threadsafe()
# Verify the define was added
assert CORE.data[socket.KEY_WAKE_LOOP_THREADSAFE_REQUIRED] is True
assert any(d.name == "USE_WAKE_LOOP_THREADSAFE" for d in CORE.defines)
# Verify no UDP socket was consumed (ESP32 uses FreeRTOS task notifications)
udp_consumers = CORE.data.get(socket.KEY_SOCKET_CONSUMERS_UDP, {})
assert "socket.wake_loop_threadsafe" not in udp_consumers
def test_require_wake_loop_threadsafe__non_esp32_consumes_udp_socket() -> None:
"""Test that non-ESP32 platforms consume a UDP socket for wake notifications."""
_setup_platform(PLATFORM_ESP8266)
CORE.config = {"wifi": True}
socket.require_wake_loop_threadsafe()
# Verify UDP socket was consumed
udp_consumers = CORE.data.get(socket.KEY_SOCKET_CONSUMERS_UDP, {})
assert udp_consumers.get("socket.wake_loop_threadsafe") == 1
@@ -1,10 +0,0 @@
substitutions:
i2s_bclk_pin: GPIO27
i2s_lrclk_pin: GPIO26
i2s_mclk_pin: GPIO25
i2s_dout_pin: GPIO23
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-ard.yaml
<<: !include common-audio_dac.yaml
@@ -1,5 +1,11 @@
<<: !include common.yaml
wifi:
ap:
psram:
mode: quad
media_player:
- platform: speaker
id: speaker_media_player_id
@@ -10,3 +16,4 @@ media_player:
volume_max: 0.95
volume_min: 0.0
task_stack_in_psram: true
codec_support_enabled: all
@@ -1,9 +0,0 @@
substitutions:
scl_pin: GPIO2
sda_pin: GPIO3
i2s_bclk_pin: GPIO4
i2s_lrclk_pin: GPIO5
i2s_mclk_pin: GPIO6
i2s_dout_pin: GPIO7
<<: !include common-media_player.yaml
@@ -1,10 +0,0 @@
substitutions:
i2s_bclk_pin: GPIO27
i2s_lrclk_pin: GPIO26
i2s_mclk_pin: GPIO25
i2s_dout_pin: GPIO4
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-ard.yaml
<<: !include common.yaml
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -1,3 +1,16 @@
text_sensor:
- platform: version
name: "ESPHome Version"
name: "ESPHome Version Full"
- platform: version
name: "ESPHome Version No Timestamp"
hide_timestamp: true
- platform: version
name: "ESPHome Version No Hash"
hide_hash: true
- platform: version
name: "ESPHome Version Shortest"
hide_timestamp: true
hide_hash: true
@@ -0,0 +1,5 @@
wifi:
band_mode: 5GHZ
packages:
- !include common.yaml