RFPlayer is a Home Assistant integration for the GCE RF Player gateway. It provides a bridge between RF (radio frequency) devices and Home Assistant, supporting protocols like X10, RTS, BLYSS, OREGON, and many others. The integration handles device discovery, event processing, and entity mapping through a plugin-based device profile system.
- Gateway (
gateway.py): Central orchestrator managing RF device connections, event handling, and service registration. Single instance per config entry. - Device Profiles (
device_profiles.py): Plugin system mapping RF device JSON events to Home Assistant platforms (binary_sensor, sensor, light, climate, cover, switch). - RfPlayerLib (
rfplayerlib/): Low-level async client for USB serial communication with RF Player hardware. - Entity classes (binary_sensor.py, sensor.py, etc.): Platform adapters using common base from
entity.py.
- RF event arrives via USB serial →
RfplayerProtocol.connection_made() - Event decoded to
RfDeviceEvent→Gateway.async_handle_rf_event() - Device profile matched & platform entities created → state updated via dispatcher signals
- Config changes trigger
async_options_updated()to reload affected entities
- Current: Version 1, Minor 2 (
VERSION = 1, MINOR_VERSION = 1in config_flow.py) - New entries default to Version 1, Minor 1
- Migrations: Defined in
migration.pyusingasync_migrate_entry()hook - Always update both version and minor_version in
async_update_entry()call
- Device profiles are YAML files defining protocol + address → entity mappings
- Uses JSONPath expressions to extract values from RF event JSON payloads
- Value converters: bit_mask, bit_offset, map, factor for data transformation
- Located:
device-profiles.yaml(auto-loaded) +tests/rfplayer/device_profiles/frames/(test data) - Always use
async_get_profile_registry()to load lazily on first use
- All entities inherit from
RfEntitybase class (entity.py) - Device identifiers built via
build_device_id_from_device_info()with protocol + address - Always call
async_write_ha_state()within platform handlers to notify HA - Dispatcher signals for event updates:
SIGNAL_RFPLAYER_EVENT,SIGNAL_RFPLAYER_AVAILABILITY
- Single config entry per RF Player gateway (enforced:
single_instance_allowed) - Entry data immutable after creation; use options flow for user-changeable settings
- Device addition flow: manual config → auto-discovery on events (when enabled)
- Schema defaults: see
const.py(DEFAULT_RECONNECT_INTERVAL=10s, DEFAULT_RECEIVER_PROTOCOLS=all modes)
- Mock only external dependencies (Home Assistant, device registry), not your code
- Use
Mock(spec=...)to prevent mock drift - Test behavior with
assert_called_once_with(), not just return values - Always patch at import site:
"custom_components.rfplayer.migration.dr.async_get"nothomeassistant.helpers.device_registry - Use
@pytest.mark.asynciofor async test functions - Fixture:
setup_rfplayer_test_cfg()creates valid test config entry
- Critical: Use
_LOGGER = get_logger()not__name__for HA to display logs - Logs become visible in HA UI after enabling debug logging for
rfplayerdomain
- Enforced via
ruff(configuration inpyproject.toml)
source .venv/bin/activate
cd /workspaces/HacsRfPlayer- Format (github workflow + pre-commit hook):
uv run ruff format --check - Lint (github workflow + pre-commit hook):
uv run ruff check --fix - Typing (github workflow + pre-commit hook):
uv run mypy custom_components tests - Test (github workflow):
uv run pytest tests/ - Run HA locally: Task "Run Home Assistant on port 8123" (executes
scripts/develop)
- Run formmatter and linter, validate typing
- Run tests:
uv run pytest tests/ -v(all tests must pass) - Use conventional commits for PR titles (e.g.,
feat:,fix:,refactor:) - CHANGELOG is auto-generated by semantic-release - Verify device profile YAML syntax if modified
All platforms share common setup via async_forward_entry_setups(entry, PLATFORMS):
- binary_sensor (BinarySensorDeviceClass via profiles)
- sensor (SensorDeviceClass via profiles)
- light (on/off and brightness from RF commands)
- climate (temperature control)
- cover (position control)
- switch (on/off control)
- Home Assistant: ≥2025.1.0 (from hacs.json)
- Python: ≥3.13.2 (from pyproject.toml)
- Key libs: pydantic (data validation), jsonpath-ng (device profile queries), serialx (USB communication)
- USB device detection via
serial.tools.list_ports.comports()
- Device ID format: Must be slugified (no hyphens). Migration 1.1→1.2 removes old format devices.
- Config immutability: Don't modify
entry.datadirectly; useasync_update_entry(). - Registry access: Get via
dr.async_get(hass), then call methods on registry object (not hass). - Simulator: Use
SIMULATOR_PORT = "/simulator"constant when testing without hardware. - Entry updates: Always use
version=andminor_version=parameters together; old code with onlyversion=2fails. - Versioning:
- Integration version managed with semantic release from conventional commits
manifest.jsondependencies updated automatically with github workflow (seeupdate_manifest.py)- version in
RfplayerConfigFlowis not aligned with integration version (only for migration)