1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-31 07:03:55 +00:00

Merge branch 'dev' into multi_device

This commit is contained in:
DanielV
2025-04-19 18:58:09 +02:00
committed by GitHub
91 changed files with 1917 additions and 386 deletions

View File

@@ -26,3 +26,17 @@ binary_sensor:
threshold: 100
filters:
- invert:
- platform: analog_threshold
name: Analog Threshold 3
sensor_id: template_sensor
threshold: !lambda return 100;
filters:
- invert:
- platform: analog_threshold
name: Analog Threshold 4
sensor_id: template_sensor
threshold:
upper: !lambda return 110;
lower: !lambda return 90;
filters:
- invert:

View File

@@ -0,0 +1,10 @@
packages:
common: !include common.yaml
wifi:
ssid: MySSID
password: password1
api:
encryption:
key: !remove

View File

@@ -0,0 +1,71 @@
image:
grayscale:
alpha_channel:
- file: ../../pnglogo.png
id: image_1
resize: 50x50
- file: ../../pnglogo.png
id: image_2
resize: 50x50
mapping:
- id: weather_map
from: string
to: "image::Image"
entries:
clear-night: image_1
sunny: image_2
- id: weather_map_1
from: string
to: esphome::image::Image
entries:
clear-night: image_1
sunny: image_2
- id: weather_map_2
from: string
to: image
entries:
clear-night: image_1
sunny: image_2
- id: int_map
from: int
to: string
entries:
1: "one"
2: "two"
3: "three"
77: "seventy-seven"
- id: string_map
from: string
to: int
entries:
one: 1
two: 2
three: 3
seventy-seven: 77
- id: color_map
from: string
to: color
entries:
red: red_id
blue: blue_id
green: green_id
color:
- id: red_id
red: 1.0
green: 0.0
blue: 0.0
- id: green_id
red: 0.0
green: 1.0
blue: 0.0
- id: blue_id
red: 0.0
green: 0.0
blue: 1.0
display:
lambda: |-
it.image(0, 0, id(weather_map)[0]);
it.image(0, 100, id(weather_map)[1]);

View File

@@ -0,0 +1,17 @@
spi:
- id: spi_main_lcd
clk_pin: 16
mosi_pin: 17
miso_pin: 15
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 12
dc_pin: 13
reset_pin: 21
invert_colors: false
packages:
map: !include common.yaml

View File

@@ -0,0 +1,17 @@
spi:
- id: spi_main_lcd
clk_pin: 6
mosi_pin: 7
miso_pin: 5
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 8
dc_pin: 9
reset_pin: 10
invert_colors: false
packages:
map: !include common.yaml

View File

@@ -0,0 +1,17 @@
spi:
- id: spi_main_lcd
clk_pin: 6
mosi_pin: 7
miso_pin: 5
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 8
dc_pin: 9
reset_pin: 10
invert_colors: false
packages:
map: !include common.yaml

View File

@@ -0,0 +1,17 @@
spi:
- id: spi_main_lcd
clk_pin: 16
mosi_pin: 17
miso_pin: 15
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 12
dc_pin: 13
reset_pin: 21
invert_colors: false
packages:
map: !include common.yaml

View File

@@ -0,0 +1,17 @@
spi:
- id: spi_main_lcd
clk_pin: 14
mosi_pin: 13
miso_pin: 12
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 5
dc_pin: 15
reset_pin: 16
invert_colors: false
packages:
map: !include common.yaml

View File

@@ -0,0 +1,12 @@
display:
- platform: sdl
id: sdl_display
update_interval: 1s
auto_clear_enabled: false
show_test_card: true
dimensions:
width: 450
height: 600
packages:
map: !include common.yaml

View File

@@ -0,0 +1,17 @@
spi:
- id: spi_main_lcd
clk_pin: 2
mosi_pin: 3
miso_pin: 4
display:
- platform: ili9xxx
id: main_lcd
model: ili9342
cs_pin: 20
dc_pin: 21
reset_pin: 22
invert_colors: false
packages:
map: !include common.yaml

View File

@@ -0,0 +1,13 @@
i2c:
- id: i2c_pm2005
scl: ${scl_pin}
sda: ${sda_pin}
sensor:
- platform: pm2005
pm_1_0:
name: PM1.0
pm_2_5:
name: PM2.5
pm_10_0:
name: PM10.0

View File

@@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO16
sda_pin: GPIO17
<<: !include common.yaml

View File

@@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO16
sda_pin: GPIO17
<<: !include common.yaml

View File

@@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@@ -0,0 +1,5 @@
substitutions:
scl_pin: GPIO5
sda_pin: GPIO4
<<: !include common.yaml

View File

@@ -1,6 +1,3 @@
substitutions:
verify_ssl: "false"
esphome:
name: livingroomdevice
friendly_name: Living Room Device
@@ -129,6 +126,14 @@ valve:
optimistic: true
has_position: true
remote_transmitter:
pin: ${pin}
carrier_duty_percent: 50%
climate:
- platform: climate_ir_lg
name: LG Climate
prometheus:
include_internal: true
relabel:

View File

@@ -1,3 +1,7 @@
substitutions:
verify_ssl: "false"
pin: GPIO5
<<: !include common.yaml
i2s_audio:

View File

@@ -1 +1,5 @@
substitutions:
verify_ssl: "false"
pin: GPIO2
<<: !include common.yaml

View File

@@ -1 +1,5 @@
substitutions:
verify_ssl: "false"
pin: GPIO2
<<: !include common.yaml

View File

@@ -1 +1,5 @@
substitutions:
verify_ssl: "false"
pin: GPIO2
<<: !include common.yaml

View File

@@ -1 +1,5 @@
substitutions:
verify_ssl: "false"
pin: GPIO5
<<: !include common.yaml

View File

@@ -17,3 +17,13 @@ sensor:
text_sensor:
- platform: uptime
name: Uptime Text
- platform: uptime
name: Uptime Text With Separator
format:
separator: "-"
expand: true
days: "Days"
hours: "H"
minutes: "M"
seconds: "S"
update_interval: 10s

View File

@@ -267,3 +267,13 @@ def test_sanitize(text, expected):
actual = helpers.sanitize(text)
assert actual == expected
@pytest.mark.parametrize(
"text, expected",
((["127.0.0.1", "fe80::1", "2001::2"], ["2001::2", "127.0.0.1", "fe80::1"]),),
)
def test_sort_ip_addresses(text: list[str], expected: list[str]) -> None:
actual = helpers.sort_ip_addresses(text)
assert actual == expected

View File

@@ -0,0 +1,125 @@
import json
import os
from unittest.mock import Mock, patch
from esphome import vscode
def _run_repl_test(input_data):
"""Reusable test function for different input scenarios."""
input_data.append(_exit())
with (
patch("builtins.input", side_effect=input_data),
patch("sys.stdout") as mock_stdout,
):
args = Mock([])
args.ace = False
args.substitution = None
vscode.read_config(args)
# Capture printed output
full_output = "".join(call[0][0] for call in mock_stdout.write.call_args_list)
return full_output.strip().split("\n")
def _validate(file_path: str):
return json.dumps({"type": "validate", "file": file_path})
def _file_response(data: str):
return json.dumps({"type": "file_response", "content": data})
def _read_file(file_path: str):
return json.dumps({"type": "read_file", "path": file_path})
def _exit():
return json.dumps({"type": "exit"})
RESULT_NO_ERROR = '{"type": "result", "yaml_errors": [], "validation_errors": []}'
def test_multi_file():
source_path = os.path.join("dir_path", "x.yaml")
output_lines = _run_repl_test(
[
_validate(source_path),
# read_file x.yaml
_file_response("""esphome:
name: test1
esp8266:
board: !secret my_secret_board
"""),
# read_file secrets.yaml
_file_response("""my_secret_board: esp1f"""),
]
)
expected_lines = [
_read_file(source_path),
_read_file(os.path.join("dir_path", "secrets.yaml")),
RESULT_NO_ERROR,
]
assert output_lines == expected_lines
def test_shows_correct_range_error():
source_path = os.path.join("dir_path", "x.yaml")
output_lines = _run_repl_test(
[
_validate(source_path),
# read_file x.yaml
_file_response("""esphome:
name: test1
esp8266:
broad: !secret my_secret_board # typo here
"""),
# read_file secrets.yaml
_file_response("""my_secret_board: esp1f"""),
]
)
assert len(output_lines) == 3
error = json.loads(output_lines[2])
validation_error = error["validation_errors"][0]
assert validation_error["message"].startswith("[broad] is an invalid option for")
range = validation_error["range"]
assert range["document"] == source_path
assert range["start_line"] == 3
assert range["start_col"] == 2
assert range["end_line"] == 3
assert range["end_col"] == 7
def test_shows_correct_loaded_file_error():
source_path = os.path.join("dir_path", "x.yaml")
output_lines = _run_repl_test(
[
_validate(source_path),
# read_file x.yaml
_file_response("""esphome:
name: test1
packages:
board: !include .pkg.esp8266.yaml
"""),
# read_file .pkg.esp8266.yaml
_file_response("""esp8266:
broad: esp1f # typo here
"""),
]
)
assert len(output_lines) == 3
error = json.loads(output_lines[2])
validation_error = error["validation_errors"][0]
assert validation_error["message"].startswith("[broad] is an invalid option for")
range = validation_error["range"]
assert range["document"] == os.path.join("dir_path", ".pkg.esp8266.yaml")
assert range["start_line"] == 1
assert range["start_col"] == 2
assert range["end_line"] == 1
assert range["end_col"] == 7

View File

@@ -42,3 +42,23 @@ def test_loading_a_missing_file(fixture_path):
yaml_util.load_yaml(yaml_file)
except EsphomeError as err:
assert "missing.yaml" in str(err)
def test_parsing_with_custom_loader(fixture_path):
"""Test custom loader used for vscode connection
Default loader is tested in test_include_with_vars
"""
yaml_file = fixture_path / "yaml_util" / "includetest.yaml"
loader_calls = []
def custom_loader(fname):
loader_calls.append(fname)
with open(yaml_file, encoding="utf-8") as f_handle:
yaml_util.parse_yaml(yaml_file, f_handle, custom_loader)
assert len(loader_calls) == 3
assert loader_calls[0].endswith("includes/included.yaml")
assert loader_calls[1].endswith("includes/list.yaml")
assert loader_calls[2].endswith("includes/scalar.yaml")