mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 03:16:37 +00:00
Merge remote-tracking branch 'upstream/dev' into esp32-sram1-as-iram
# Conflicts: # esphome/components/esp32/__init__.py
This commit is contained in:
@@ -14,11 +14,63 @@ include the relevant `.cpp` and `.h` test files there.
|
||||
|
||||
### Override component code generation for testing
|
||||
|
||||
When generating code for testing, ESPHome won't invoke the component's `to_code` function, since most components do not
|
||||
need to generate configuration code for testing.
|
||||
During C++ test builds, `to_code` is suppressed for every component by default — most components do not
|
||||
need to generate configuration code for a unit test binary.
|
||||
|
||||
If you do need to generate code to for example configure compilation flags or add libraries,
|
||||
add the component name to the `CPP_TESTING_CODEGEN_COMPONENTS` allowlist in `script/cpp_unit_test.py`.
|
||||
#### Manifest overrides
|
||||
|
||||
If your component needs to customise code generation behavior for testing — for example to re-enable
|
||||
`to_code`, supply a lightweight stub, add a test-only dependency, or change any other manifest attribute —
|
||||
create an `__init__.py` in your component's test directory and define `override_manifest`:
|
||||
|
||||
**Top-level component** (`tests/components/<component>/__init__.py`):
|
||||
|
||||
```python
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# Re-enable the component's own to_code (needed when the component must
|
||||
# emit C++ setup code that the test binary depends on at link time).
|
||||
manifest.enable_codegen()
|
||||
```
|
||||
|
||||
Or supply a lightweight stub instead of the real `to_code`:
|
||||
|
||||
```python
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
async def to_code_testing(config):
|
||||
# Only emit what the C++ tests actually need
|
||||
pass
|
||||
|
||||
manifest.to_code = to_code_testing
|
||||
manifest.dependencies = manifest.dependencies + ["some_test_only_dep"]
|
||||
```
|
||||
|
||||
**Platform component** (`tests/components/<component>/<domain>/__init__.py`,
|
||||
e.g. `tests/components/my_sensor/sensor/__init__.py`):
|
||||
|
||||
```python
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
manifest.enable_codegen()
|
||||
```
|
||||
|
||||
`override_manifest` receives a `ComponentManifestOverride` that wraps the real manifest.
|
||||
Attribute assignments store an override; reads fall back to the real manifest when no
|
||||
override is present.
|
||||
|
||||
Key methods:
|
||||
|
||||
| Method | Effect |
|
||||
|---|---|
|
||||
| `manifest.enable_codegen()` | Remove the `to_code` suppression, re-enabling code generation |
|
||||
| `manifest.restore()` | Clear **all** overrides, reverting every attribute to the original |
|
||||
|
||||
The function is called after `to_code` has already been set to `None`, so calling
|
||||
`enable_codegen()` is a deliberate opt-in.
|
||||
|
||||
## Running component unit tests
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# core (esphome/core/config.py) must run its to_code during C++ test builds
|
||||
# because it bootstraps the fundamental application infrastructure that all
|
||||
# components depend on (component registration, event loop, etc.).
|
||||
manifest.enable_codegen()
|
||||
@@ -1,5 +1,10 @@
|
||||
esp32:
|
||||
variant: esp32s3
|
||||
partitions:
|
||||
- name: my_data
|
||||
type: data
|
||||
subtype: spiffs
|
||||
size: 0x1000
|
||||
framework:
|
||||
type: esp-idf
|
||||
advanced:
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# host must run its to_code during C++ test builds because it sets up the
|
||||
# host platform target, which is the execution environment for all unit tests.
|
||||
manifest.enable_codegen()
|
||||
@@ -1,16 +0,0 @@
|
||||
substitutions:
|
||||
i2s_bclk_pin: GPIO15
|
||||
i2s_lrclk_pin: GPIO4
|
||||
i2s_mclk_pin: GPIO5
|
||||
|
||||
<<: !include common.yaml
|
||||
|
||||
wifi:
|
||||
ssid: test
|
||||
password: test1234
|
||||
|
||||
media_player:
|
||||
- platform: i2s_audio
|
||||
name: Test Media Player
|
||||
dac_type: internal
|
||||
mode: stereo
|
||||
@@ -0,0 +1,7 @@
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# logger must run its to_code during C++ test builds because it configures
|
||||
# the logging subsystem used by ESP_LOG* macros throughout component code.
|
||||
manifest.enable_codegen()
|
||||
@@ -42,6 +42,11 @@ lvgl:
|
||||
disp_bg_color: color_id
|
||||
disp_bg_image: cat_image
|
||||
disp_bg_opa: cover
|
||||
bottom_layer:
|
||||
widgets:
|
||||
- obj:
|
||||
bg_color: 0x000000
|
||||
bg_opa: cover
|
||||
theme:
|
||||
obj:
|
||||
border_width: 1
|
||||
@@ -49,12 +54,14 @@ lvgl:
|
||||
gradients:
|
||||
- id: color_bar
|
||||
direction: hor
|
||||
dither: err_diff
|
||||
# dither: err_diff
|
||||
stops:
|
||||
- color: 0xFF0000
|
||||
position: 0
|
||||
opa: 100%
|
||||
- color: 0xFFFF00
|
||||
position: 42
|
||||
opa: 80%
|
||||
- color: 0x00FF00
|
||||
position: 84
|
||||
- color: 0x00FFFF
|
||||
@@ -156,6 +163,16 @@ lvgl:
|
||||
offset_x: !lambda return 20;
|
||||
offset_y: !lambda return 20;
|
||||
antialias: !lambda return true;
|
||||
- id: msgbox_with_header_buttons
|
||||
title: Header Buttons Test
|
||||
body:
|
||||
text: Testing header buttons
|
||||
header_buttons:
|
||||
- src: cat_image
|
||||
on_click:
|
||||
logger.log: Header button clicked
|
||||
buttons:
|
||||
- text: OK
|
||||
- id: simple_msgbox
|
||||
title: Simple
|
||||
|
||||
@@ -199,11 +216,11 @@ lvgl:
|
||||
text: Unloaded
|
||||
- lvgl.label.update:
|
||||
id: msgbox_label
|
||||
text: "" # Empty text
|
||||
text: "" # Empty text
|
||||
on_all_events:
|
||||
logger.log:
|
||||
format: "Event %s"
|
||||
args: ['lv_event_code_name_for(event->code).c_str()']
|
||||
args: ['lv_event_code_name_for(event).c_str()']
|
||||
skip: true
|
||||
layout:
|
||||
type: Flex
|
||||
@@ -241,7 +258,7 @@ lvgl:
|
||||
on_all_events:
|
||||
- logger.log:
|
||||
format: "Event %s"
|
||||
args: ['lv_event_code_name_for(event->code).c_str()']
|
||||
args: ['lv_event_code_name_for(event).c_str()']
|
||||
- lvgl.animimg.update:
|
||||
id: anim_img
|
||||
src: !lambda "return {dog_image, cat_image};"
|
||||
@@ -306,7 +323,6 @@ lvgl:
|
||||
anim_time: 1s
|
||||
bg_color: light_blue
|
||||
bg_grad_color: light_blue
|
||||
bg_dither_mode: ordered
|
||||
bg_grad_dir: hor
|
||||
bg_grad_stop: 128
|
||||
bg_image_opa: transp
|
||||
@@ -354,10 +370,18 @@ lvgl:
|
||||
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
|
||||
transform_skew_x: 10
|
||||
transform_skew_y: 20
|
||||
shadow_offset_x: 3
|
||||
shadow_offset_y: 3
|
||||
translate_x: 10
|
||||
translate_y: 10
|
||||
max_height: 100
|
||||
@@ -549,14 +573,16 @@ lvgl:
|
||||
arc_length: 120
|
||||
spin_time: 2s
|
||||
align: left_mid
|
||||
- spinner:
|
||||
align: right_mid
|
||||
send_draw_task_events: true
|
||||
- image:
|
||||
id: lv_image
|
||||
src: cat_image
|
||||
align: top_left
|
||||
y: "50"
|
||||
mode: real
|
||||
zoom: 2.0
|
||||
angle: 45
|
||||
scale: 2.0
|
||||
rotation: 45
|
||||
- tileview:
|
||||
id: tileview_id
|
||||
scrollbar_mode: active
|
||||
@@ -661,8 +687,11 @@ lvgl:
|
||||
src: cat_image
|
||||
x: 100
|
||||
y: 100
|
||||
angle: 90
|
||||
zoom: 2.0
|
||||
rotation: 90
|
||||
scale_x: 2.0
|
||||
scale_y: 1.5
|
||||
skew_x: 10
|
||||
skew_y: 5
|
||||
pivot_x: 25
|
||||
pivot_y: 25
|
||||
- lvgl.canvas.draw_line:
|
||||
@@ -710,6 +739,9 @@ lvgl:
|
||||
text:
|
||||
format: "A string with a number %d"
|
||||
args: ['(int)(random_uint32() % 1000)']
|
||||
size: 120
|
||||
dark_color: navy
|
||||
light_color: white
|
||||
|
||||
- slider:
|
||||
min_value: 0
|
||||
@@ -928,7 +960,6 @@ lvgl:
|
||||
grid_cell_row_pos: 0
|
||||
grid_cell_column_pos: 0
|
||||
src: !lambda return dog_image;
|
||||
mode: virtual
|
||||
on_click:
|
||||
then:
|
||||
- lvgl.tabview.select:
|
||||
@@ -1023,10 +1054,18 @@ lvgl:
|
||||
text_color: 0xFFFFFF
|
||||
scales:
|
||||
- ticks:
|
||||
width: !lambda return 1;
|
||||
width: 1
|
||||
count: 61
|
||||
length: 20%
|
||||
radial_offset: 5
|
||||
color: 0xFFFFFF
|
||||
major:
|
||||
stride: 5
|
||||
width: 2
|
||||
length: 8
|
||||
color: 0xC0C0C0
|
||||
radial_offset: 3
|
||||
label_gap: 6
|
||||
range_from: 0
|
||||
range_to: 60
|
||||
angle_range: 360
|
||||
@@ -1037,15 +1076,15 @@ lvgl:
|
||||
end_value: 60
|
||||
color_start: 0x0000bd
|
||||
color_end: 0xbd0000
|
||||
width: !lambda return 1;
|
||||
width: 1
|
||||
- line:
|
||||
opa: 50%
|
||||
id: minute_hand
|
||||
color: 0xFF0000
|
||||
r_mod: !lambda return -1;
|
||||
width: !lambda return 3;
|
||||
-
|
||||
angle_range: 330
|
||||
length: 99%
|
||||
radial_offset: 2
|
||||
width: 1
|
||||
- angle_range: 330
|
||||
rotation: 300
|
||||
range_from: 1
|
||||
range_to: 12
|
||||
@@ -1069,7 +1108,7 @@ lvgl:
|
||||
value: 180
|
||||
width: 4
|
||||
color: 0xA0A0A0
|
||||
r_mod: -20
|
||||
length: 80%
|
||||
opa: 0%
|
||||
- id: page3
|
||||
layout: Horizontal
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
wifi:
|
||||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
i2s_audio:
|
||||
i2s_lrclk_pin: 13
|
||||
i2s_bclk_pin: 14
|
||||
i2s_mclk_pin: 15
|
||||
|
||||
media_player:
|
||||
speaker:
|
||||
- platform: i2s_audio
|
||||
name: None
|
||||
dac_type: external
|
||||
id: test_speaker
|
||||
i2s_dout_pin: 18
|
||||
mute_pin: 19
|
||||
dac_type: external
|
||||
|
||||
media_player:
|
||||
- platform: speaker
|
||||
name: None
|
||||
speaker: test_speaker
|
||||
on_state:
|
||||
- media_player.play:
|
||||
- media_player.play_media: http://localhost/media.mp3
|
||||
|
||||
@@ -6,7 +6,7 @@ i2s_audio:
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic_id_external
|
||||
i2s_din_pin: ${i2s_din_pin}
|
||||
i2s_din_pin: ${i2s_din_pin1}
|
||||
adc_type: external
|
||||
pdm: false
|
||||
mclk_multiple: 384
|
||||
@@ -15,7 +15,15 @@ microphone:
|
||||
- if:
|
||||
condition:
|
||||
- microphone.is_muted:
|
||||
id: mic_id_external
|
||||
then:
|
||||
- microphone.unmute:
|
||||
id: mic_id_external
|
||||
else:
|
||||
- microphone.mute:
|
||||
id: mic_id_external
|
||||
- platform: i2s_audio
|
||||
id: mic_id_pdm
|
||||
i2s_din_pin: ${i2s_din_pin2}
|
||||
adc_type: external
|
||||
pdm: true
|
||||
|
||||
@@ -2,21 +2,7 @@ substitutions:
|
||||
i2s_bclk_pin: GPIO15
|
||||
i2s_lrclk_pin: GPIO4
|
||||
i2s_mclk_pin: GPIO5
|
||||
i2s_din_pin: GPIO33
|
||||
i2s_din_pin1: GPIO33
|
||||
i2s_din_pin2: GPIO34
|
||||
|
||||
i2s_audio:
|
||||
i2s_bclk_pin: ${i2s_bclk_pin}
|
||||
i2s_lrclk_pin: ${i2s_lrclk_pin}
|
||||
i2s_mclk_pin: ${i2s_mclk_pin}
|
||||
use_legacy: true
|
||||
|
||||
microphone:
|
||||
- platform: i2s_audio
|
||||
id: mic_id_external
|
||||
i2s_din_pin: ${i2s_din_pin}
|
||||
adc_type: external
|
||||
pdm: false
|
||||
- platform: i2s_audio
|
||||
id: mic_id_adc
|
||||
adc_pin: 32
|
||||
adc_type: internal
|
||||
<<: !include common.yaml
|
||||
|
||||
@@ -8,6 +8,11 @@ on_beo4:
|
||||
- logger.log:
|
||||
format: "on_beo4: %u %u"
|
||||
args: ["x.source", "x.command"]
|
||||
on_brennenstuhl:
|
||||
then:
|
||||
- logger.log:
|
||||
format: "on_brennenstuhl: %u"
|
||||
args: ["x.code"]
|
||||
on_aeha:
|
||||
then:
|
||||
- logger.log:
|
||||
|
||||
@@ -14,6 +14,12 @@ button:
|
||||
remote_transmitter.transmit_beo4:
|
||||
source: 0x01
|
||||
command: 0x0C
|
||||
- platform: template
|
||||
name: brennenstuhl
|
||||
id: button_a_on
|
||||
on_press:
|
||||
remote_transmitter.transmit_brennenstuhl:
|
||||
code: 0xBD2E2C
|
||||
- platform: template
|
||||
name: Dyson fan up
|
||||
id: dyson_fan_up
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import esphome.codegen as cg
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
async def to_code(config):
|
||||
cg.add_build_flag("-DUSE_TIME_TIMEZONE")
|
||||
|
||||
manifest.to_code = to_code
|
||||
Reference in New Issue
Block a user