Files
esphome/tests/integration/fixtures/uart_mock_ld2450.yaml

223 lines
7.2 KiB
YAML

esphome:
name: uart-mock-ld2450-test
host:
api:
batch_delay: 0ms # Disable batching to receive all state updates
logger:
level: VERBOSE
external_components:
- source:
type: local
path: EXTERNAL_COMPONENT_PATH
# Dummy uart entry to satisfy ld2450's DEPENDENCIES = ["uart"]
# The actual UART bus used is the uart_mock component below
uart:
baud_rate: 115200
port: /dev/null
uart_mock:
id: mock_uart
baud_rate: 256000
auto_start: false
responses:
# Catch-all response: match any command footer (04 03 02 01).
# Returns a generic ACK to unblock setup commands.
#
# Response layout:
# [0-3] FD FC FB FA = header
# [4-5] 04 00 = length 4
# [6] FF = cmd (handled as CMD_ENABLE_CONF)
# [7] 01 = status (ACK)
# [8-9] 00 00 = error = 0
# [10-13] 04 03 02 01 = footer
- expect_tx: [0x04, 0x03, 0x02, 0x01]
inject_rx:
[
0xFD, 0xFC, 0xFB, 0xFA,
0x04, 0x00,
0xFF, 0x01,
0x00, 0x00,
0x04, 0x03, 0x02, 0x01,
]
injections:
# Phase 1 (t=100ms): Valid LD2450 periodic data frame - happy path
# The buffer is clean at this point, so this frame should parse correctly.
#
# Target 1: X=-500mm, Y=1000mm, Speed=-50mm/s (approaching), Res=320mm
# X: magnitude=500 (0x01F4), negative → high=0x01, low=0xF4
# Y: magnitude=1000 (0x03E8), positive → high=0x83, low=0xE8
# Speed: raw=5, negative (approaching) → high=0x00, low=0x05, decoded=-50mm/s
# Resolution: 320 → low=0x40, high=0x01
# Distance: sqrt(500²+1000²) = sqrt(1250000) ≈ 1118mm
#
# Target 2: X=200mm, Y=500mm, Speed=0 (stationary), Res=100mm
# X: magnitude=200 (0x00C8), positive → high=0x80, low=0xC8
# Y: magnitude=500 (0x01F4), positive → high=0x81, low=0xF4
# Speed: 0 → 0x00, 0x00
# Resolution: 100 → low=0x64, high=0x00
# Distance: sqrt(200²+500²) = sqrt(290000) ≈ 538mm
#
# Target 3: No target (all zeros)
# Distance: 0 → sensors publish unknown/NaN
#
# Counts: target_count=2, moving_target_count=1, still_target_count=1
#
# Frame layout (30 bytes):
# [0-3] AA FF 03 00 = periodic data header
# [4-11] Target 1 (8 bytes): X_L X_H Y_L Y_H SPD_L SPD_H RES_L RES_H
# [12-19] Target 2 (8 bytes)
# [20-27] Target 3 (8 bytes)
# [28-29] 55 CC = periodic data footer
- delay: 100ms
inject_rx:
[
0xAA, 0xFF, 0x03, 0x00,
0xF4, 0x01, 0xE8, 0x83, 0x05, 0x00, 0x40, 0x01,
0xC8, 0x80, 0xF4, 0x81, 0x00, 0x00, 0x64, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0xCC,
]
# Phase 2 (t=300ms): Garbage bytes
# LD2450's readline_ does NOT reject bytes at position 0 (unlike LD2412),
# so these bytes accumulate in the buffer. buffer_pos_ goes from 0 to 7.
- delay: 200ms
inject_rx: [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x11, 0x22]
# Phase 3 (t=400ms): Truncated frame (header + partial data, no footer)
# More bytes accumulating in the buffer without a footer match.
# After this, buffer_pos_ = 7 + 8 = 15.
- delay: 100ms
inject_rx: [0xAA, 0xFF, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04]
# Phase 4 (t=600ms): Overflow - inject 75 bytes of 0xFF (MAX_LINE_LENGTH=45)
# Buffer has 15 bytes from phases 2+3.
# readline_() stores bytes while buffer_pos_ < 44. When buffer_pos_ == 44,
# the next byte triggers overflow: logs warning, resets buffer_pos_ to 0,
# and discards that byte.
#
# First overflow: 29 bytes fill positions 15-43 (buffer_pos_=44), byte 30
# triggers overflow (discarded). Total consumed: 30 bytes.
# Second overflow: 44 bytes fill positions 0-43 (buffer_pos_=44), byte 45
# triggers overflow (discarded). Total consumed: 30+45 = 75 bytes.
# After both overflows, buffer_pos_ = 0 (clean state for recovery frame).
- delay: 200ms
inject_rx:
[
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
]
# Phase 5 (t=700ms): Valid frame after overflow - recovery test
# Buffer was reset by overflow. This valid frame should parse correctly.
#
# Target 1: X=300mm, Y=400mm, Speed=30mm/s (moving away), Res=100mm
# X: magnitude=300 (0x012C), positive → high=0x81, low=0x2C
# Y: magnitude=400 (0x0190), positive → high=0x81, low=0x90
# Speed: raw=3, positive (moving away) → high=0x80, low=0x03, decoded=30mm/s
# Resolution: 100 → low=0x64, high=0x00
# Distance: sqrt(300²+400²) = 500mm
#
# Target 2 & 3: No target (all zeros)
# Counts: target_count=1, moving_target_count=1, still_target_count=0
- delay: 100ms
inject_rx:
[
0xAA, 0xFF, 0x03, 0x00,
0x2C, 0x81, 0x90, 0x81, 0x03, 0x80, 0x64, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0xCC,
]
ld2450:
id: ld2450_dev
uart_id: mock_uart
sensor:
- platform: ld2450
ld2450_id: ld2450_dev
target_count:
name: "Target Count"
filters: &sensor_filters
- timeout:
timeout: 50ms
value: last
- throttle_with_priority: 50ms
still_target_count:
name: "Still Target Count"
filters: *sensor_filters
moving_target_count:
name: "Moving Target Count"
filters: *sensor_filters
target_1:
x:
name: "Target 1 X"
filters: *sensor_filters
y:
name: "Target 1 Y"
filters: *sensor_filters
speed:
name: "Target 1 Speed"
filters: *sensor_filters
distance:
name: "Target 1 Distance"
filters: *sensor_filters
resolution:
name: "Target 1 Resolution"
filters: *sensor_filters
angle:
name: "Target 1 Angle"
filters: *sensor_filters
target_2:
x:
name: "Target 2 X"
filters: *sensor_filters
y:
name: "Target 2 Y"
filters: *sensor_filters
speed:
name: "Target 2 Speed"
filters: *sensor_filters
distance:
name: "Target 2 Distance"
filters: *sensor_filters
binary_sensor:
- platform: ld2450
ld2450_id: ld2450_dev
has_target:
name: "Has Target"
filters: &binary_sensor_filters
- settle: 50ms
has_moving_target:
name: "Has Moving Target"
filters: *binary_sensor_filters
has_still_target:
name: "Has Still Target"
filters: *binary_sensor_filters
text_sensor:
- platform: ld2450
ld2450_id: ld2450_dev
target_1:
direction:
name: "Target 1 Direction"
button:
- platform: template
name: "Start Scenario"
id: start_scenario_btn
on_press:
- lambda: 'id(mock_uart).start_scenario();'