raspyrfm_client package

The raspyrfm_client package is the orchestration layer that glues gateways, control units, and device metadata together. It discovers available implementations on import, provides ergonomic helpers for runtime access, and ships with base classes you can extend to model new radio-frequency hardware. This chapter now pairs narrative explanations, architecture diagrams, and API maps so you can move from concept to implementation without leaving the page.

Overview

At the centre of the package sits RaspyRFMClient. It coordinates three core responsibilities:

Discovery

Automatically import all gateway and control-unit modules under raspyrfm_client.device_implementations. Any modules you drop into the tree become available the next time reload_implementation_classes() runs.

Cataloguing

Provide quick lookups for known Manufacturer values and the models each manufacturer exposes. These enumerations keep the public API self-documenting.

Execution

Instantiate gateways and control units that conform to the shared base classes in raspyrfm_client.device_implementations.gateway.base and raspyrfm_client.device_implementations.controlunit.base. Once instantiated, helper methods such as get_gateway() hand you a ready-to-use transport implementation.

System architecture

Architecture diagram showing discovery, client core, and gateway/control unit execution

RaspyRFMClient coordinates discovery (left), orchestration (centre), and the transport surface (right). Discovery scans the device_implementations namespace, the core aggregates metadata and exposes helper methods, while the transport layer instantiates gateways and control units that communicate with real hardware.

Legend:

  • Discovery bay – Base classes enumerate manufacturers, default models, and lazy-import hooks.

  • Client core – A single RaspyRFMClient instance caches the catalogue, enforces typing, and brokers connections.

  • Execution pods – Gateway and control-unit instances deliver the actual radio operations, exposing open, close, and send_code semantics.

Quick start

Follow the numbered comments to see how a typical integration unfolds:

from raspyrfm_client.client import RaspyRFMClient
from raspyrfm_client.device_implementations.manufacturer_constants import Manufacturer
from raspyrfm_client.device_implementations.gateway.manufacturer.gateway_constants import GatewayModel

# 1. Spin up the client; discovery runs on instantiation.
client = RaspyRFMClient()

# 2. Inspect the catalogue discovered on import.
print(sorted(client.get_supported_gateway_manufacturers()))

# 3. Select a specific gateway implementation by manufacturer/model.
gateway = client.get_gateway(
    manufacturer=Manufacturer.RASPYRFM,
    model=GatewayModel.RASPYRFM_DEFAULT,
    host="192.168.0.42",
    port=49880,
)

# 4. Interact with the gateway using the shared base-class contract.
gateway.open()
gateway.send_code(code="on", socket_id="A1")
gateway.close()

Core concepts

  • Gateways translate between RaspyRFM and physical transmitters. They inherit from GatewayBase and encapsulate connection handling plus RF send logic.

  • Control units describe controllable sockets, blinds, and switches. They derive from ControlUnitBase and expose high-level actions defined in raspyrfm_client.device_implementations.controlunit.actions.

  • Manufacturers and models are enumerated in the raspyrfm_client.device_implementations.manufacturer_constants and raspyrfm_client.device_implementations.gateway.manufacturer.gateway_constants modules respectively, giving you strongly-typed handles for each supported device family.

  • Device manifests (raspyrfm_client.device) capture metadata that the UI and automation engine consume for labelling, validation, and previews.

Lifecycle checklist

Use this sequence when integrating with a new installation:

  1. Initialise – Instantiate RaspyRFMClient as early as possible so discovery populates the catalogue.

  2. Catalogue – Inspect manufacturers and models using get_supported_* methods before hard-coding enums in configuration files.

  3. Connect – Use get_gateway() to create transport instances. Gateways share a consistent interface across manufacturers, so you can swap models without refactoring call sites.

  4. Compose control units – Build composite scenes by fetching get_controlunit() instances and triggering actions from automation code.

  5. Reload – Call reload_implementation_classes() after deploying new modules or updating vendor-specific logic; the client will re-import the tree and rebuild the catalogue.

Extending the catalogue

  1. Create a subclass of GatewayBase or ControlUnitBase in the appropriate device_implementations subpackage.

  2. Register new enum values in raspyrfm_client.device_implementations.manufacturer_constants and (for gateways) raspyrfm_client.device_implementations.gateway.manufacturer.gateway_constants.

  3. Wire any bespoke actions into raspyrfm_client.device_implementations.controlunit.actions so UI and automation tooling inherit correct labelling.

  4. Call reload_implementation_classes() or instantiate a fresh RaspyRFMClient to pull in the new module.

  5. Use get_gateway() and get_controlunit() to obtain your customised implementations.

Implementation map

Key modules and their responsibilities

Module

Description

raspyrfm_client.client

High-level client that bootstraps implementations, performs discovery, maintains the manufacturer/model catalogue, and exposes helper methods to retrieve gateways and control units.

raspyrfm_client.device

Data models used to serialise discovered devices, entity manifests, and control-unit payload definitions.

raspyrfm_client.device_implementations

Namespace package containing gateway/control-unit classes organised by manufacturer and model. Place your subclasses here to extend the catalogue.

raspyrfm_client.device_implementations.gateway.base

Abstract base types and mixins shared by all gateway implementations.

raspyrfm_client.device_implementations.controlunit.base

Abstract base types and helper utilities for modelling switchable devices.

raspyrfm_client.device_implementations.controlunit.actions

Re-usable action descriptors (on/off, dim, toggle, etc.) that concrete control units import.

raspyrfm_client.discovery

Internal helper that walks the package tree, imports modules lazily, and guards against circular dependencies during reloads.

Integration patterns

  • Home Assistant bridge – Use the RaspyRFMClient as a long-lived singleton in a background task. Fetch control units for each automation and queue send_code operations onto an executor to maintain responsiveness.

  • Test harness – Couple raspyrfm_client.client with the example.py script. By swapping the manufacturer and model enums you can validate new RF payloads without reconfiguring your production deployment.

  • Custom dashboards – Serialise device metadata from raspyrfm_client.device into JSON and feed it into front-end graphs or UI cards. The data classes include human-friendly labels that match the UI showcase.

Troubleshooting

  • Missing implementations – Ensure the Python package path includes the directory containing your new modules before calling RaspyRFMClient. reload_implementation_classes only rescans importable modules.

  • Enum mismatches – Align manufacturer and model enums across gateway and control-unit modules. The client raises a KeyError if the pair is unknown, helping you detect typo-induced bugs early.

  • Connection instability – Gateways expose a context manager API. Use with client.get_gateway(...) as gateway: to ensure open/close calls pair correctly even when exceptions occur.

API reference

Example usage of the RaspyRFMClient can be found in the example.py file

class raspyrfm_client.client.RaspyRFMClient[source]

Bases: object

This class is the main interface for generating and sending signals.

get_controlunit(manufacturer: Manufacturer, model: ControlUnitModel) ControlUnit[source]

Use this method to get a device implementation intance :param manufacturer: device manufacturer :param model: device model :return: device implementation

get_gateway(manufacturer: Manufacturer, model: GatewayModel, host: str = None, port: int = None) Gateway[source]

Use this method to get a gateway implementation instance :param manufacturer: gateway manufacturer :param model: gateway model :param host: gateway host address (optional) :param port: gateway port (optional) :return: gateway implementation

get_supported_controlunit_manufacturers() [<class 'str'>][source]
Returns:

a list of supported control unit manufacturers

get_supported_controlunit_models(manufacturer: Manufacturer) [<enum 'ControlUnitModel'>][source]
Parameters:

manufacturer – supported control unit manufacturer

Returns:

a list of supported control unit models for this manufacturer

get_supported_gateway_manufacturers()[source]
Returns:

a list of supported gateway manufacturers

get_supported_gateway_models(manufacturer: Manufacturer) [<enum 'GatewayModel'>][source]
Parameters:

manufacturer – supported gateway manufacturer

Returns:

a list of supported gateway models for this gateway manufacturer

list_supported_controlunits() None[source]

Prints an indented list of all supported manufacturers and models

list_supported_gateways() None[source]

Prints an indented list of all supported manufacturers and models

reload_implementation_classes()[source]

Dynamically reloads device implementations

search() [<class 'raspyrfm_client.device_implementations.gateway.base.Gateway'>][source]

Sends a local network broadcast with a specified message. If a gateway is present it will respond to this broadcast.

If a valid response is found the properties of this client object will be updated accordingly.

Returns:

list of gateways

send(gateway: Gateway, device: ControlUnit, action: Action) None[source]

Use this method to generate codes for actions on supported device. It will generates a string that can be interpreted by the the RaspyRFM module. The string contains information about the rc signal that should be sent.

Parameters:
  • gateway – the gateway to generate the code for

  • device – the device to generate the code for

  • action – action to execute

class raspyrfm_client.device_implementations.gateway.base.Gateway(manufacturer: Manufacturer, model: GatewayModel, host: str, port: int)[source]

Bases: object

Base gateway implementation

static create_from_broadcast(host: str, message: str)[source]
Parameters:
  • host – the host that sent the message

  • message – the search response message

Returns:

a new instance of this gateway based on a broadcast response message

generate_code(device: ControlUnit, action: Action) str[source]
get_firmware_version() str[source]
Returns:

the gateway firmware version

get_host() str[source]
Returns:

the ip/host address of the gateway (if one was found or specified manually)

get_manufacturer() Manufacturer[source]
Returns:

the gateway manufacturer

get_model() GatewayModel[source]
Returns:

the gateway model

get_port() int[source]
Returns:

port of the gateway

get_search_response_regex_literal() str[source]
Returns:

a regular expression that matches the response to a “search” broadcast

Base class for all controlunit implementations

class raspyrfm_client.device_implementations.controlunit.base.ControlUnit(manufacturer: Manufacturer, model: ControlUnitModel)[source]

Bases: object

get_channel_config() dict[source]
Returns:

the channel setup as a dict

get_channel_config_args()[source]

gets required config arguments and their regular expression to check the erguments has to be implemented by inheriting classes

Returns:

dictionary of arguments

example: {“ID”: “^[A-F]$”, “CH”: “^[1-4]$”}

get_manufacturer() Manufacturer[source]
Returns:

the device manufacturer

get_model() ControlUnitModel[source]
Returns:

the device model

get_pulse_data(action: Action)[source]

generates pulse data :return: (pulse pairs, repetitions, timebase)

get_supported_actions() [<enum 'Action'>][source]
Returns:

the supported actions of this device

set_channel_config(**channel_arguments) None[source]

Sets the channel as multiple arguments. See implementation specific details about how the channel should be passed in.

Parameters:

channel_arguments

class raspyrfm_client.device_implementations.controlunit.actions.Action(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]

Bases: Enum

BRIGHT = 'Bright'
DIMM = 'Dimm'
OFF = 'Off'
ON = 'On'
PAIR = 'Pair'
UNPAIR = 'Unpair'