Skip to content

Devices

Device templates and registry for common components.

devices

Device templates and registry for pinviz.

All devices are now loaded from JSON configurations in device_configs/. Use the registry to create device instances:

from pinviz.devices import get_registry

registry = get_registry()
sensor = registry.create('bh1750')
led = registry.create('led', color_name='Blue')
display = registry.create('ssd1306')

For testing or isolated contexts, create independent registries:

from pinviz.devices import create_registry

test_registry = create_registry()
# Use test_registry independently without affecting global state

Available devices are automatically discovered from JSON configs.

DeviceRegistry

DeviceRegistry()

Central registry for device templates loaded from JSON configurations.

Source code in src/pinviz/devices/registry.py
def __init__(self):
    self._templates: dict[str, DeviceTemplate] = {}
    self._failed_configs: list[str] = []
    self._scan_device_configs()

create

create(type_id: str, **kwargs: Any) -> Device

Create a device instance from JSON configuration.

PARAMETER DESCRIPTION
type_id

Device type identifier (matches JSON config filename)

TYPE: str

**kwargs

Parameters to pass to the config loader (e.g., color_name, num_leds)

TYPE: Any DEFAULT: {}

RETURNS DESCRIPTION
Device

Device instance with metadata

RAISES DESCRIPTION
ValueError

If device config file not found

Source code in src/pinviz/devices/registry.py
def create(self, type_id: str, **kwargs: Any) -> Device:
    """
    Create a device instance from JSON configuration.

    Args:
        type_id: Device type identifier (matches JSON config filename)
        **kwargs: Parameters to pass to the config loader (e.g., color_name, num_leds)

    Returns:
        Device instance with metadata

    Raises:
        ValueError: If device config file not found
    """
    from .loader import load_device_from_config

    try:
        device = load_device_from_config(type_id, **kwargs)

        # Enrich device with metadata from registry
        template = self.get(type_id)
        if template:
            device.type_id = template.type_id
            device.description = template.description
            device.url = template.url
            device.category = template.category
            device.i2c_address = template.i2c_address

        return device
    except FileNotFoundError:
        raise ValueError(
            f"Unknown device type: {type_id}. No JSON configuration found in device_configs/."
        ) from None

get

get(type_id: str) -> DeviceTemplate | None

Get device template metadata by type ID.

PARAMETER DESCRIPTION
type_id

Device type identifier (case-insensitive)

TYPE: str

RETURNS DESCRIPTION
DeviceTemplate | None

DeviceTemplate with metadata, or None if not found

Example

registry = get_registry() template = registry.get('bh1750') print(template.name) BH1750 Light Sensor

Source code in src/pinviz/devices/registry.py
def get(self, type_id: str) -> DeviceTemplate | None:
    """
    Get device template metadata by type ID.

    Args:
        type_id: Device type identifier (case-insensitive)

    Returns:
        DeviceTemplate with metadata, or None if not found

    Example:
        >>> registry = get_registry()
        >>> template = registry.get('bh1750')
        >>> print(template.name)
        BH1750 Light Sensor
    """
    return self._templates.get(type_id.lower())

get_categories

get_categories() -> list[str]

Get all unique device categories.

RETURNS DESCRIPTION
list[str]

Sorted list of category names

Example

registry = get_registry() categories = registry.get_categories() print(categories) ['displays', 'generic', 'io', 'leds', 'sensors']

Source code in src/pinviz/devices/registry.py
def get_categories(self) -> list[str]:
    """
    Get all unique device categories.

    Returns:
        Sorted list of category names

    Example:
        >>> registry = get_registry()
        >>> categories = registry.get_categories()
        >>> print(categories)
        ['displays', 'generic', 'io', 'leds', 'sensors']
    """
    categories = {t.category for t in self._templates.values()}
    return sorted(categories)

get_failed_configs

get_failed_configs() -> list[str]

Get list of config files that failed to load.

RETURNS DESCRIPTION
list[str]

List of filenames that failed during registry initialization

Example

registry = get_registry() failed = registry.get_failed_configs() if failed: ... print(f"Warning: {len(failed)} configs failed to load")

Source code in src/pinviz/devices/registry.py
def get_failed_configs(self) -> list[str]:
    """
    Get list of config files that failed to load.

    Returns:
        List of filenames that failed during registry initialization

    Example:
        >>> registry = get_registry()
        >>> failed = registry.get_failed_configs()
        >>> if failed:
        ...     print(f"Warning: {len(failed)} configs failed to load")
    """
    return self._failed_configs.copy()

get_health_status

get_health_status() -> dict[str, int]

Get registry health status.

RETURNS DESCRIPTION
dict[str, int]

Dictionary with 'loaded', 'failed', and 'total' counts

Example

registry = get_registry() status = registry.get_health_status() print(f"Loaded: {status['loaded']}/{status['total']}")

Source code in src/pinviz/devices/registry.py
def get_health_status(self) -> dict[str, int]:
    """
    Get registry health status.

    Returns:
        Dictionary with 'loaded', 'failed', and 'total' counts

    Example:
        >>> registry = get_registry()
        >>> status = registry.get_health_status()
        >>> print(f"Loaded: {status['loaded']}/{status['total']}")
    """
    return {
        "loaded": len(self._templates),
        "failed": len(self._failed_configs),
        "total": len(self._templates) + len(self._failed_configs),
    }

list_all

list_all() -> list[DeviceTemplate]

Get all registered device templates.

RETURNS DESCRIPTION
list[DeviceTemplate]

List of all DeviceTemplate objects in the registry

Example

registry = get_registry() all_devices = registry.list_all() print(f"Found {len(all_devices)} devices") Found 8 devices

Source code in src/pinviz/devices/registry.py
def list_all(self) -> list[DeviceTemplate]:
    """
    Get all registered device templates.

    Returns:
        List of all DeviceTemplate objects in the registry

    Example:
        >>> registry = get_registry()
        >>> all_devices = registry.list_all()
        >>> print(f"Found {len(all_devices)} devices")
        Found 8 devices
    """
    return list(self._templates.values())

list_by_category

list_by_category(category: str) -> list[DeviceTemplate]

Get all device templates in a specific category.

PARAMETER DESCRIPTION
category

Device category (e.g., 'sensors', 'leds', 'displays')

TYPE: str

RETURNS DESCRIPTION
list[DeviceTemplate]

List of DeviceTemplate objects in the specified category

Example

registry = get_registry() sensors = registry.list_by_category('sensors') for sensor in sensors: ... print(f"{sensor.name}: {sensor.description}")

Source code in src/pinviz/devices/registry.py
def list_by_category(self, category: str) -> list[DeviceTemplate]:
    """
    Get all device templates in a specific category.

    Args:
        category: Device category (e.g., 'sensors', 'leds', 'displays')

    Returns:
        List of DeviceTemplate objects in the specified category

    Example:
        >>> registry = get_registry()
        >>> sensors = registry.list_by_category('sensors')
        >>> for sensor in sensors:
        ...     print(f"{sensor.name}: {sensor.description}")
    """
    return [t for t in self._templates.values() if t.category == category]

DeviceTemplate dataclass

DeviceTemplate(
    type_id: str,
    name: str,
    description: str,
    category: str,
    url: str | None = None,
    i2c_address: int | None = None,
)

Metadata for a device template.

create_registry

create_registry() -> DeviceRegistry

Create a new independent device registry.

Useful for: - Unit testing with isolated state - Multiple concurrent contexts - Custom device configurations

Each call creates a fresh registry that scans the device_configs/ directory independently. Changes to this registry do not affect the default registry returned by get_registry().

RETURNS DESCRIPTION
DeviceRegistry

A new DeviceRegistry instance

Example

from pinviz.devices import create_registry test_registry = create_registry()

Use test_registry independently

No pollution of global state

Source code in src/pinviz/devices/registry.py
def create_registry() -> DeviceRegistry:
    """
    Create a new independent device registry.

    Useful for:
    - Unit testing with isolated state
    - Multiple concurrent contexts
    - Custom device configurations

    Each call creates a fresh registry that scans the device_configs/
    directory independently. Changes to this registry do not affect
    the default registry returned by get_registry().

    Returns:
        A new DeviceRegistry instance

    Example:
        >>> from pinviz.devices import create_registry
        >>> test_registry = create_registry()
        >>> # Use test_registry independently
        >>> # No pollution of global state
    """
    return DeviceRegistry()

get_registry

get_registry() -> DeviceRegistry

Get the default device registry instance.

This is a convenience function for common use cases. The registry is lazily initialized on first access and cached for subsequent calls. For testing or isolated contexts, use create_registry() instead.

RETURNS DESCRIPTION
DeviceRegistry

The default DeviceRegistry instance

Example

from pinviz.devices import get_registry registry = get_registry() device = registry.create('bh1750') print(device.name) BH1750 Light Sensor

Source code in src/pinviz/devices/registry.py
def get_registry() -> DeviceRegistry:
    """
    Get the default device registry instance.

    This is a convenience function for common use cases. The registry is
    lazily initialized on first access and cached for subsequent calls.
    For testing or isolated contexts, use create_registry() instead.

    Returns:
        The default DeviceRegistry instance

    Example:
        >>> from pinviz.devices import get_registry
        >>> registry = get_registry()
        >>> device = registry.create('bh1750')
        >>> print(device.name)
        BH1750 Light Sensor
    """
    global _default_registry
    if _default_registry is None:
        _default_registry = DeviceRegistry()
    return _default_registry

reset_default_registry

reset_default_registry() -> None

Reset the default registry (mainly for testing).

This clears the cached default registry, causing get_registry() to create a fresh instance on the next call. This is useful for resetting state between test runs.

Example

from pinviz.devices import reset_default_registry reset_default_registry()

Next call to get_registry() will create a new instance

Source code in src/pinviz/devices/registry.py
def reset_default_registry() -> None:
    """
    Reset the default registry (mainly for testing).

    This clears the cached default registry, causing get_registry()
    to create a fresh instance on the next call. This is useful for
    resetting state between test runs.

    Example:
        >>> from pinviz.devices import reset_default_registry
        >>> reset_default_registry()
        >>> # Next call to get_registry() will create a new instance
    """
    global _default_registry
    _default_registry = None