mirror of
https://github.com/esphome/esphome.git
synced 2026-10-06 10:56:43 +00:00
Merge remote-tracking branch 'upstream/dev' into remove_posix_tz_parser
# Conflicts: # esphome/components/api/api_pb2_dump.cpp
This commit is contained in:
@@ -19,6 +19,7 @@ esp32:
|
||||
disable_mbedtls_pkcs7: true
|
||||
disable_regi2c_in_iram: true
|
||||
disable_fatfs: true
|
||||
sram1_as_iram: true
|
||||
|
||||
wifi:
|
||||
ssid: MySSID
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
ethernet:
|
||||
type: ENC28J60
|
||||
clk_pin: 18
|
||||
mosi_pin: 19
|
||||
miso_pin: 16
|
||||
cs_pin: 17
|
||||
interrupt_pin: 21
|
||||
reset_pin: 20
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.56
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
domain: .local
|
||||
mac_address: "02:AA:BB:CC:DD:01"
|
||||
on_connect:
|
||||
- logger.log: "Ethernet connected!"
|
||||
on_disconnect:
|
||||
- logger.log: "Ethernet disconnected!"
|
||||
@@ -0,0 +1,19 @@
|
||||
ethernet:
|
||||
type: ENC28J60
|
||||
clk_pin: 19
|
||||
mosi_pin: 21
|
||||
miso_pin: 23
|
||||
cs_pin: 18
|
||||
interrupt_pin: 36
|
||||
reset_pin: 22
|
||||
clock_speed: 10Mhz
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.56
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
domain: .local
|
||||
mac_address: "02:AA:BB:CC:DD:01"
|
||||
on_connect:
|
||||
- logger.log: "Ethernet connected!"
|
||||
on_disconnect:
|
||||
- logger.log: "Ethernet disconnected!"
|
||||
@@ -0,0 +1,18 @@
|
||||
ethernet:
|
||||
type: W5100
|
||||
clk_pin: 18
|
||||
mosi_pin: 19
|
||||
miso_pin: 16
|
||||
cs_pin: 17
|
||||
interrupt_pin: 21
|
||||
reset_pin: 20
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.56
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
domain: .local
|
||||
mac_address: "02:AA:BB:CC:DD:01"
|
||||
on_connect:
|
||||
- logger.log: "Ethernet connected!"
|
||||
on_disconnect:
|
||||
- logger.log: "Ethernet disconnected!"
|
||||
@@ -0,0 +1 @@
|
||||
<<: !include common-enc28j60.yaml
|
||||
@@ -0,0 +1 @@
|
||||
<<: !include common-enc28j60-rp2040.yaml
|
||||
@@ -0,0 +1 @@
|
||||
<<: !include common-w5100-rp2040.yaml
|
||||
@@ -8,6 +8,7 @@ infrared:
|
||||
- platform: ir_rf_proxy
|
||||
id: ir_rx
|
||||
name: "IR Receiver"
|
||||
receiver_frequency: 38kHz
|
||||
remote_receiver_id: ir_receiver
|
||||
|
||||
# RF 900MHz receiver
|
||||
|
||||
@@ -16,7 +16,7 @@ class MockUARTComponent : public uart::UARTComponent {
|
||||
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(uart::FlushResult, flush, (), (override));
|
||||
MOCK_METHOD(uart::UARTFlushResult, flush, (), (override));
|
||||
MOCK_METHOD(void, check_logger_conflict, (), (override));
|
||||
};
|
||||
|
||||
|
||||
@@ -37,11 +37,12 @@ lvgl:
|
||||
on_resume:
|
||||
logger.log: LVGL has resumed
|
||||
on_boot:
|
||||
logger.log: LVGL has started
|
||||
- logger.log: LVGL has started
|
||||
- lvgl.indicator.update:
|
||||
id: meter_arc_indicator
|
||||
start_value: 0
|
||||
end_value: 180
|
||||
bg_color: light_blue
|
||||
disp_bg_color: color_id
|
||||
disp_bg_image: cat_image
|
||||
disp_bg_opa: cover
|
||||
bottom_layer:
|
||||
widgets:
|
||||
- obj:
|
||||
@@ -54,7 +55,6 @@ lvgl:
|
||||
gradients:
|
||||
- id: color_bar
|
||||
direction: hor
|
||||
# dither: err_diff
|
||||
stops:
|
||||
- color: 0xFF0000
|
||||
position: 0
|
||||
@@ -139,12 +139,11 @@ lvgl:
|
||||
body:
|
||||
text: This is a sample messagebox
|
||||
bg_color: 0x808080
|
||||
button_style:
|
||||
bg_color: 0xff00
|
||||
border_width: 4
|
||||
buttons:
|
||||
- id: msgbox_button
|
||||
text: Button
|
||||
bg_color: 0x00ff00
|
||||
border_width: 4
|
||||
- id: msgbox_apply
|
||||
text: "Close"
|
||||
on_click:
|
||||
@@ -156,8 +155,8 @@ lvgl:
|
||||
bg_opa: !lambda return 0.5;
|
||||
- lvgl.image.update:
|
||||
id: lv_image
|
||||
zoom: !lambda return 512;
|
||||
angle: !lambda return 100;
|
||||
scale: !lambda return 512;
|
||||
rotation: !lambda return 100;
|
||||
pivot_x: !lambda return 20;
|
||||
pivot_y: !lambda return 20;
|
||||
offset_x: !lambda return 20;
|
||||
@@ -283,8 +282,8 @@ lvgl:
|
||||
then:
|
||||
- lvgl.animimg.stop: anim_img
|
||||
- lvgl.update:
|
||||
disp_bg_color: 0xffff00
|
||||
disp_bg_image: none
|
||||
bottom_layer:
|
||||
bg_color: 0xffff00
|
||||
- lvgl.widget.show: message_box
|
||||
- label:
|
||||
text: "Hello shiny day"
|
||||
@@ -357,8 +356,6 @@ lvgl:
|
||||
pad_right: 10px
|
||||
pad_top: 10px
|
||||
shadow_color: light_blue
|
||||
shadow_ofs_x: 5
|
||||
shadow_ofs_y: 5
|
||||
shadow_opa: cover
|
||||
shadow_spread: 5
|
||||
shadow_width: 10
|
||||
@@ -369,12 +366,10 @@ lvgl:
|
||||
text_letter_space: 4
|
||||
text_line_space: 4
|
||||
text_opa: cover
|
||||
transform_angle: 180
|
||||
transform_rotation: 90
|
||||
transform_height: 100
|
||||
transform_pivot_x: 50%
|
||||
transform_pivot_y: 50%
|
||||
transform_zoom: 0.5
|
||||
transform_scale: 2.0
|
||||
transform_scale_x: 1.5
|
||||
transform_scale_y: 0.8
|
||||
@@ -466,11 +461,11 @@ lvgl:
|
||||
id: button_button
|
||||
width: 20%
|
||||
height: 10%
|
||||
transform_angle: !lambda return(180*100);
|
||||
transform_rotation: !lambda return(180*100);
|
||||
arc_width: !lambda return 4;
|
||||
border_width: !lambda return 6;
|
||||
shadow_ofs_x: !lambda return 6;
|
||||
shadow_ofs_y: !lambda return 6;
|
||||
shadow_offset_x: !lambda return 6;
|
||||
shadow_offset_y: !lambda return 6;
|
||||
shadow_spread: !lambda return 6;
|
||||
shadow_width: !lambda return 6;
|
||||
pressed:
|
||||
@@ -642,8 +637,8 @@ lvgl:
|
||||
border_opa: 80%
|
||||
shadow_color: black
|
||||
shadow_width: 10
|
||||
shadow_ofs_x: 5
|
||||
shadow_ofs_y: 5
|
||||
shadow_offset_x: 5
|
||||
shadow_offset_y: 5
|
||||
shadow_spread: 4
|
||||
shadow_opa: cover
|
||||
outline_color: red
|
||||
@@ -1110,6 +1105,12 @@ lvgl:
|
||||
color: 0xA0A0A0
|
||||
length: 80%
|
||||
opa: 0%
|
||||
- arc:
|
||||
id: meter_arc_indicator
|
||||
color: 0xFF0000
|
||||
width: 6
|
||||
start_value: 0
|
||||
end_value: 360
|
||||
- id: page3
|
||||
layout: Horizontal
|
||||
pad_all: 6px
|
||||
|
||||
@@ -273,26 +273,39 @@ text_sensor:
|
||||
display:
|
||||
- platform: nextion
|
||||
id: main_lcd
|
||||
auto_wake_on_touch: true
|
||||
brightness: 80%
|
||||
command_spacing: 5ms
|
||||
dump_device_info: true
|
||||
exit_reparse_on_start: true
|
||||
lambda: |-
|
||||
ESP_LOGD("display","Display is being tested!");
|
||||
max_commands_per_loop: 20
|
||||
max_queue_age: 5000ms # Remove queue items after 5s
|
||||
max_queue_size: 50
|
||||
update_interval: 5s
|
||||
on_sleep:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display went to sleep");'
|
||||
on_wake:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display woke up");'
|
||||
on_setup:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display setup completed");'
|
||||
on_page:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display shows new page %u", x);'
|
||||
on_buffer_overflow:
|
||||
then:
|
||||
logger.log: "Nextion reported a buffer overflow!"
|
||||
|
||||
command_spacing: 5ms
|
||||
dump_device_info: true
|
||||
max_queue_age: 5000ms # Remove queue items after 5s
|
||||
on_page:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display shows new page %u", x);'
|
||||
on_setup:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display setup completed");'
|
||||
on_sleep:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display went to sleep");'
|
||||
on_touch:
|
||||
then:
|
||||
lambda: |-
|
||||
ESP_LOGD("display",
|
||||
"Display was touched at page %u, component %u, touch event: %s",
|
||||
page_id, component_id, touch_event ? "press" : "release");
|
||||
on_wake:
|
||||
then:
|
||||
lambda: 'ESP_LOGD("display","Display woke up");'
|
||||
update_interval: 5s
|
||||
start_up_page: 1
|
||||
startup_override_ms: 10000ms # Wait 10s for display ready
|
||||
touch_sleep_timeout: 3
|
||||
wake_up_page: 2
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
number:
|
||||
- platform: template
|
||||
name: "Test Number"
|
||||
id: test_number
|
||||
optimistic: true
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
step: 1
|
||||
|
||||
sensor:
|
||||
- platform: number
|
||||
name: "Test Number Value"
|
||||
source_id: test_number
|
||||
@@ -0,0 +1,2 @@
|
||||
packages:
|
||||
common: !include common.yaml
|
||||
@@ -0,0 +1,2 @@
|
||||
packages:
|
||||
common: !include common.yaml
|
||||
@@ -5,6 +5,7 @@ namespace esphome::packet_transport::testing {
|
||||
TEST(PacketTransportBinarySensorTest, AddBinarySensor) {
|
||||
TestablePacketTransport transport;
|
||||
binary_sensor::BinarySensor bs;
|
||||
transport.set_binary_sensor_count(1);
|
||||
transport.add_binary_sensor("motion", &bs);
|
||||
ASSERT_EQ(transport.binary_sensors_.size(), 1u);
|
||||
EXPECT_STREQ(transport.binary_sensors_[0].id, "motion");
|
||||
@@ -24,6 +25,7 @@ TEST(PacketTransportBinarySensorTest, UnencryptedBinarySensorRoundTrip) {
|
||||
encoder.init_for_test("sender");
|
||||
binary_sensor::BinarySensor local_bs;
|
||||
local_bs.state = true;
|
||||
encoder.set_binary_sensor_count(1);
|
||||
encoder.add_binary_sensor("motion", &local_bs);
|
||||
|
||||
encoder.send_data_(true);
|
||||
@@ -46,11 +48,13 @@ TEST(PacketTransportBinarySensorTest, MultipleSensorsRoundTrip) {
|
||||
sensor::Sensor s1, s2;
|
||||
s1.state = 10.0f;
|
||||
s2.state = 20.0f;
|
||||
encoder.set_sensor_count(2);
|
||||
encoder.add_sensor("s1", &s1);
|
||||
encoder.add_sensor("s2", &s2);
|
||||
|
||||
binary_sensor::BinarySensor bs1;
|
||||
bs1.state = true;
|
||||
encoder.set_binary_sensor_count(1);
|
||||
encoder.add_binary_sensor("bs1", &bs1);
|
||||
|
||||
encoder.send_data_(true);
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace esphome::packet_transport::testing {
|
||||
TEST(PacketTransportSensorTest, AddSensor) {
|
||||
TestablePacketTransport transport;
|
||||
sensor::Sensor s;
|
||||
transport.set_sensor_count(1);
|
||||
transport.add_sensor("temp", &s);
|
||||
ASSERT_EQ(transport.sensors_.size(), 1u);
|
||||
EXPECT_STREQ(transport.sensors_[0].id, "temp");
|
||||
@@ -26,6 +27,7 @@ TEST(PacketTransportSensorTest, UnencryptedSensorRoundTrip) {
|
||||
encoder.init_for_test("sender");
|
||||
sensor::Sensor local_sensor;
|
||||
local_sensor.state = 42.5f;
|
||||
encoder.set_sensor_count(1);
|
||||
encoder.add_sensor("temp", &local_sensor);
|
||||
|
||||
encoder.send_data_(true);
|
||||
@@ -53,6 +55,7 @@ TEST(PacketTransportSensorTest, EncryptedSensorRoundTrip) {
|
||||
encoder.set_encryption_key(key);
|
||||
sensor::Sensor local_sensor;
|
||||
local_sensor.state = 99.9f;
|
||||
encoder.set_sensor_count(1);
|
||||
encoder.add_sensor("temp", &local_sensor);
|
||||
|
||||
encoder.send_data_(true);
|
||||
@@ -77,6 +80,7 @@ TEST(PacketTransportSensorTest, SendDataOnlyUpdated) {
|
||||
sensor::Sensor s1, s2;
|
||||
s1.state = 1.0f;
|
||||
s2.state = 2.0f;
|
||||
encoder.set_sensor_count(2);
|
||||
encoder.add_sensor("s1", &s1);
|
||||
encoder.add_sensor("s2", &s2);
|
||||
|
||||
@@ -111,6 +115,7 @@ TEST(PacketTransportSensorTest, PingKeyIncludedInTransmittedPacket) {
|
||||
responder.set_encryption_key(key);
|
||||
sensor::Sensor local_sensor;
|
||||
local_sensor.state = 77.7f;
|
||||
responder.set_sensor_count(1);
|
||||
responder.add_sensor("temp", &local_sensor);
|
||||
|
||||
// Requester sends a MAGIC_PING that the responder processes
|
||||
@@ -148,6 +153,7 @@ TEST(PacketTransportSensorTest, MissingPingKeyBlocksSensorData) {
|
||||
responder.set_encryption_key(key);
|
||||
sensor::Sensor local_sensor;
|
||||
local_sensor.state = 77.7f;
|
||||
responder.set_sensor_count(1);
|
||||
responder.add_sensor("temp", &local_sensor);
|
||||
responder.send_data_(true);
|
||||
ASSERT_EQ(responder.sent_packets.size(), 1u);
|
||||
|
||||
@@ -6,4 +6,8 @@ sensor:
|
||||
humidity:
|
||||
name: SHT4X Humidity
|
||||
address: 0x44
|
||||
precision: High
|
||||
heater_max_duty: 0.02
|
||||
heater_power: High
|
||||
heater_time: Long
|
||||
update_interval: 15s
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
sensor:
|
||||
- platform: spa06_i2c
|
||||
i2c_id: i2c_bus
|
||||
address: 0x77
|
||||
temperature:
|
||||
id: spa06_i2c_temperature
|
||||
name: Outside Temperature
|
||||
sample_rate: 1
|
||||
oversampling: NONE
|
||||
pressure:
|
||||
name: Outside Pressure
|
||||
id: spa06_i2c_pressure
|
||||
sample_rate: 25p4
|
||||
oversampling: 16X
|
||||
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
|
||||
@@ -0,0 +1,15 @@
|
||||
sensor:
|
||||
- platform: spa06_spi
|
||||
spi_id: spi_bus
|
||||
cs_pin: ${cs_pin}
|
||||
temperature:
|
||||
id: spa06_spi_temperature
|
||||
name: Outside Temperature
|
||||
sample_rate: 1
|
||||
oversampling: NONE
|
||||
pressure:
|
||||
name: Outside Pressure
|
||||
id: spa06_spi_pressure
|
||||
sample_rate: 25p4
|
||||
oversampling: 16X
|
||||
update_interval: 15s
|
||||
@@ -0,0 +1,7 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO5
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp32-idf.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -0,0 +1,7 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO15
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp8266-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -0,0 +1,7 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO17
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/rp2040-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -23,3 +23,8 @@ text:
|
||||
min_length: 8
|
||||
max_length: 32
|
||||
mode: password
|
||||
|
||||
text_sensor:
|
||||
- platform: text
|
||||
name: "Test Text State"
|
||||
source_id: test_text
|
||||
|
||||
@@ -593,8 +593,6 @@ static time_t esptime_recalc_local(int year, int month, int day, int hour, int m
|
||||
t.hour = hour;
|
||||
t.minute = min;
|
||||
t.second = sec;
|
||||
t.day_of_week = 1; // Placeholder for fields_in_range()
|
||||
t.day_of_year = 1;
|
||||
t.recalc_timestamp_local();
|
||||
return t.timestamp;
|
||||
}
|
||||
@@ -750,6 +748,60 @@ TEST(RecalcTimestampLocal, NonDefaultTransitionTime) {
|
||||
EXPECT_EQ(esp_result, libc_result);
|
||||
}
|
||||
|
||||
TEST(RecalcTimestampLocal, MinimalFieldsWithoutDayOfWeekOrYear) {
|
||||
// Regression test for issue #15115: DateTimeEntity::state_as_esptime() constructs
|
||||
// an ESPTime with only year/month/day/hour/minute/second set (no day_of_week or
|
||||
// day_of_year). recalc_timestamp_local() must work without those fields.
|
||||
const char *tz_str = "CET-1CEST,M3.5.0,M10.5.0";
|
||||
setenv("TZ", tz_str, 1);
|
||||
tzset();
|
||||
time::ParsedTimezone tz{};
|
||||
ASSERT_TRUE(parse_posix_tz(tz_str, tz));
|
||||
set_global_tz(tz);
|
||||
|
||||
// Construct ESPTime with only date/time fields (like state_as_esptime does)
|
||||
ESPTime t{};
|
||||
t.year = 2026;
|
||||
t.month = 3;
|
||||
t.day_of_month = 20;
|
||||
t.hour = 23;
|
||||
t.minute = 14;
|
||||
t.second = 55;
|
||||
// day_of_week and day_of_year are deliberately left as 0
|
||||
t.recalc_timestamp_local();
|
||||
|
||||
// Must NOT return -1 (the bug: fields_in_range() rejected valid times)
|
||||
EXPECT_NE(t.timestamp, -1);
|
||||
|
||||
// Verify against libc
|
||||
time_t libc_result = libc_mktime(2026, 3, 20, 23, 14, 55);
|
||||
EXPECT_EQ(t.timestamp, libc_result);
|
||||
}
|
||||
|
||||
TEST(RecalcTimestampLocal, MinimalFieldsNoDST) {
|
||||
// Same test but with a timezone that has no DST
|
||||
const char *tz_str = "IST-5:30";
|
||||
setenv("TZ", tz_str, 1);
|
||||
tzset();
|
||||
time::ParsedTimezone tz{};
|
||||
ASSERT_TRUE(parse_posix_tz(tz_str, tz));
|
||||
set_global_tz(tz);
|
||||
|
||||
ESPTime t{};
|
||||
t.year = 2026;
|
||||
t.month = 3;
|
||||
t.day_of_month = 23;
|
||||
t.hour = 10;
|
||||
t.minute = 0;
|
||||
t.second = 0;
|
||||
t.recalc_timestamp_local();
|
||||
|
||||
EXPECT_NE(t.timestamp, -1);
|
||||
|
||||
time_t libc_result = libc_mktime(2026, 3, 23, 10, 0, 0);
|
||||
EXPECT_EQ(t.timestamp, libc_result);
|
||||
}
|
||||
|
||||
TEST(RecalcTimestampLocal, YearBoundaryDST) {
|
||||
// Test southern hemisphere DST across year boundary
|
||||
// Australia/Sydney: DST active from October to April (spans Jan 1)
|
||||
|
||||
@@ -30,7 +30,7 @@ class MockUARTComponent : public UARTComponent {
|
||||
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(FlushResult, flush, (), (override));
|
||||
MOCK_METHOD(UARTFlushResult, flush, (), (override));
|
||||
MOCK_METHOD(void, check_logger_conflict, (), (override));
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
uart:
|
||||
- id: uart_id
|
||||
tx_pin: PA23
|
||||
rx_pin: PA18
|
||||
baud_rate: 9600
|
||||
data_bits: 8
|
||||
parity: NONE
|
||||
stop_bits: 1
|
||||
|
||||
switch:
|
||||
- platform: uart
|
||||
name: "UART Switch"
|
||||
uart_id: uart_id
|
||||
data: [0x01, 0x02, 0x03]
|
||||
Reference in New Issue
Block a user