mirror of
https://github.com/home-assistant/core.git
synced 2026-05-18 06:20:17 +01:00
196 lines
5.4 KiB
Python
196 lines
5.4 KiB
Python
"""Tests for the OpenDisplay integration."""
|
|
|
|
from time import time
|
|
|
|
from bleak.backends.scanner import AdvertisementData
|
|
from opendisplay import (
|
|
BinaryInputs,
|
|
BoardManufacturer,
|
|
ColorScheme,
|
|
DisplayConfig,
|
|
GlobalConfig,
|
|
ManufacturerData,
|
|
PowerOption,
|
|
SystemConfig,
|
|
)
|
|
|
|
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
|
|
|
|
from tests.components.bluetooth import generate_ble_device
|
|
|
|
OPENDISPLAY_MANUFACTURER_ID = 9286 # 0x2446
|
|
|
|
# V1 advertisement payload (14 bytes): battery_mv=3700, temperature_c=25.0, loop_counter=1
|
|
V1_ADVERTISEMENT_DATA = b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x72\x11"
|
|
|
|
TEST_ADDRESS = "AA:BB:CC:DD:EE:FF"
|
|
TEST_TITLE = "OpenDisplay 1234"
|
|
ENCRYPTION_KEY = "aabbccddee112233aabbccddee112233" # 32 hex chars = 16 bytes
|
|
|
|
# Firmware version response: major=1, minor=2, sha="abc123"
|
|
FIRMWARE_VERSION = {"major": 1, "minor": 2, "sha": "abc123"}
|
|
|
|
DEVICE_CONFIG = GlobalConfig(
|
|
system=SystemConfig(
|
|
ic_type=0,
|
|
communication_modes=0,
|
|
device_flags=0,
|
|
pwr_pin=0xFF,
|
|
reserved=b"\x00" * 17,
|
|
),
|
|
manufacturer=ManufacturerData(
|
|
manufacturer_id=BoardManufacturer.SEEED,
|
|
board_type=1,
|
|
board_revision=0,
|
|
reserved=b"\x00" * 18,
|
|
),
|
|
power=PowerOption(
|
|
power_mode=0,
|
|
battery_capacity_mah=b"\x00" * 3,
|
|
sleep_timeout_ms=0,
|
|
tx_power=0,
|
|
sleep_flags=0,
|
|
battery_sense_pin=0xFF,
|
|
battery_sense_enable_pin=0xFF,
|
|
battery_sense_flags=0,
|
|
capacity_estimator=0,
|
|
voltage_scaling_factor=0,
|
|
deep_sleep_current_ua=0,
|
|
deep_sleep_time_seconds=0,
|
|
reserved=b"\x00" * 12,
|
|
),
|
|
displays=[
|
|
DisplayConfig(
|
|
instance_number=0,
|
|
display_technology=0,
|
|
panel_ic_type=0,
|
|
pixel_width=296,
|
|
pixel_height=128,
|
|
active_width_mm=67,
|
|
active_height_mm=29,
|
|
tag_type=0,
|
|
rotation=0,
|
|
reset_pin=0xFF,
|
|
busy_pin=0xFF,
|
|
dc_pin=0xFF,
|
|
cs_pin=0xFF,
|
|
data_pin=0,
|
|
partial_update_support=0,
|
|
color_scheme=ColorScheme.BWR.value,
|
|
transmission_modes=0x01,
|
|
clk_pin=0,
|
|
reserved_pins=b"\x00" * 7,
|
|
full_update_mC=0,
|
|
reserved=b"\x00" * 33,
|
|
)
|
|
],
|
|
)
|
|
|
|
|
|
def make_service_info(
|
|
name: str | None = "OpenDisplay 1234",
|
|
address: str = "AA:BB:CC:DD:EE:FF",
|
|
manufacturer_data: dict[int, bytes] | None = None,
|
|
) -> BluetoothServiceInfoBleak:
|
|
"""Create a BluetoothServiceInfoBleak for testing."""
|
|
if manufacturer_data is None:
|
|
manufacturer_data = {OPENDISPLAY_MANUFACTURER_ID: V1_ADVERTISEMENT_DATA}
|
|
return BluetoothServiceInfoBleak(
|
|
name=name or "",
|
|
address=address,
|
|
rssi=-60,
|
|
manufacturer_data=manufacturer_data,
|
|
service_data={},
|
|
service_uuids=[],
|
|
source="local",
|
|
connectable=True,
|
|
time=time(),
|
|
device=generate_ble_device(address, name=name),
|
|
advertisement=AdvertisementData(
|
|
local_name=name,
|
|
manufacturer_data=manufacturer_data,
|
|
service_data={},
|
|
service_uuids=[],
|
|
rssi=-60,
|
|
tx_power=-127,
|
|
platform_data=(),
|
|
),
|
|
tx_power=-127,
|
|
)
|
|
|
|
|
|
BINARY_INPUT = BinaryInputs(
|
|
instance_number=0,
|
|
input_type=0,
|
|
display_as=0,
|
|
reserved_pins=b"\x00" * 8,
|
|
input_flags=0x01, # bit 0 set → button_id 0 active
|
|
invert=0,
|
|
pullups=0,
|
|
pulldowns=0,
|
|
button_data_byte_index=0,
|
|
)
|
|
|
|
BUTTON_DEVICE_CONFIG = GlobalConfig(
|
|
system=DEVICE_CONFIG.system,
|
|
manufacturer=DEVICE_CONFIG.manufacturer,
|
|
power=DEVICE_CONFIG.power,
|
|
displays=DEVICE_CONFIG.displays,
|
|
binary_inputs=[BINARY_INPUT],
|
|
)
|
|
|
|
|
|
def make_v1_service_info(
|
|
dynamic_data: bytes = b"\x00" * 11,
|
|
name: str | None = "OpenDisplay 1234",
|
|
address: str = TEST_ADDRESS,
|
|
) -> BluetoothServiceInfoBleak:
|
|
"""Create a v1 advertisement service info with a custom 11-byte dynamic block."""
|
|
# temperature=25.0°C, battery≈3700 mV, loop_counter=1
|
|
return make_service_info(
|
|
name=name,
|
|
address=address,
|
|
manufacturer_data={OPENDISPLAY_MANUFACTURER_ID: dynamic_data + b"\x82\x72\x11"},
|
|
)
|
|
|
|
|
|
def make_binary_inputs(
|
|
instance_number: int = 0,
|
|
byte_index: int = 0,
|
|
input_flags: int = 0x01,
|
|
) -> BinaryInputs:
|
|
"""Create a minimal BinaryInputs config entry.
|
|
|
|
input_flags is a bitmask of active inputs: bit N set means button_id N is active.
|
|
"""
|
|
return BinaryInputs(
|
|
instance_number=instance_number,
|
|
input_type=0,
|
|
display_as=0,
|
|
reserved_pins=b"\x00" * 8,
|
|
input_flags=input_flags,
|
|
invert=0,
|
|
pullups=0,
|
|
pulldowns=0,
|
|
button_data_byte_index=byte_index,
|
|
)
|
|
|
|
|
|
def make_button_device_config(binary_inputs: list[BinaryInputs]) -> GlobalConfig:
|
|
"""Return a GlobalConfig with the given binary_inputs list."""
|
|
return GlobalConfig(
|
|
system=DEVICE_CONFIG.system,
|
|
manufacturer=DEVICE_CONFIG.manufacturer,
|
|
power=DEVICE_CONFIG.power,
|
|
displays=DEVICE_CONFIG.displays,
|
|
binary_inputs=binary_inputs,
|
|
)
|
|
|
|
|
|
VALID_SERVICE_INFO = make_service_info()
|
|
|
|
NOT_OPENDISPLAY_SERVICE_INFO = make_service_info(
|
|
name="Other Device",
|
|
manufacturer_data={0x1234: b"\x00\x01"},
|
|
)
|