Skip to content

API Reference: DeviceType

django_devicehub.device_type

DeviceType

Base class for declaring IoT device types.

Usage::

# devices.py
from django_devicehub import DeviceType, Reading, Command, reading_types

class WeatherStation(DeviceType):
    class Meta:
        protocol = "mqtt"
        broker = "default"
        heartbeat_interval = 300

    temperature = Reading(type=reading_types.FLOAT, unit="C")
    humidity = Reading(type=reading_types.FLOAT, unit="%")

    reboot = Command()
    set_interval = Command(payload={"interval": int})

# models.py
from .devices import WeatherStation
WeatherStationDevice, WeatherStationReading, WeatherStationMessage = (
    WeatherStation.create_models()
)
create_models(module=None) classmethod

Generate concrete Django models for this DeviceType.

Call this in your app's models.py. Returns (DeviceModel, ReadingModel, MessageModel).

get_meta() classmethod

Get Meta configuration with defaults.

get_subscribe_topics() classmethod

Get MQTT topic patterns to subscribe to (with + wildcards).

get_topic(device_id, message_type='data') classmethod

Generate the MQTT topic for a specific device and message type.

on_command_response(device, command, response)

Called when a device responds to a command.

on_connect(device)

Called when a device connects.

on_data(device, readings)

Called when a device sends data readings.

on_disconnect(device)

Called when a device disconnects or heartbeat times out.

on_status_change(device, old_status, new_status)

Called when a device status changes.

DeviceTypeMeta

Bases: type

Metaclass that collects Reading, Command, and StateField descriptors from the class namespace and stores them as _readings, _commands, _state_fields.

DeviceType

from django_devicehub import DeviceType

Base class for declaring IoT device types. Uses DeviceTypeMeta metaclass to collect descriptors and auto-register in the global registry.

Class Attributes

Attribute Type Description
_readings dict[str, Reading] Collected Reading descriptors (set by metaclass)
_commands dict[str, Command] Collected Command descriptors (set by metaclass)
_state_fields dict[str, StateField] Collected StateField descriptors (set by metaclass)
_device_model type | None Generated Device model class (set by create_models())
_reading_model type | None Generated Reading model class (set by create_models())
_message_model type | None Generated Message model class (set by create_models())

Inner Class: Meta

Optional configuration class. All attributes have defaults.

class WeatherStation(DeviceType):
    class Meta:
        protocol = "mqtt"
        broker = "default"
        auth = "token"
        heartbeat_interval = 300
        topic_template = "{prefix}/{type_name}/{device_id}/{message_type}"
Attribute Type Default Description
protocol str "mqtt" Communication protocol identifier
broker str "default" Named broker from DJANGO_DEVICEHUB["BROKERS"]
auth str "token" Authentication mechanism
heartbeat_interval int 300 Expected heartbeat interval in seconds
topic_template str "{prefix}/{type_name}/{device_id}/{message_type}" MQTT topic format string

Class Methods

create_models(module=None)

Generate concrete Django models for this DeviceType.

Parameters:

  • module (str | None): The module name to assign to generated models. If None, auto-detected from the caller's stack frame (inspect.currentframe().f_back).

Returns: tuple[type, type, type] -- (DeviceModel, ReadingModel, MessageModel)

# myapp/models.py
from .devices import WeatherStation

WeatherStationDevice, WeatherStationReading, WeatherStationMessage = (
    WeatherStation.create_models()
)

The generated models have __module__ set to the calling module, so Django's migration system discovers them in the correct app.


get_meta()

Get Meta configuration merged with defaults.

Returns: dict with keys: protocol, broker, auth, heartbeat_interval, topic_template.

meta = WeatherStation.get_meta()
# {'protocol': 'mqtt', 'broker': 'default', 'auth': 'token',
#  'heartbeat_interval': 300, 'topic_template': '...'}

get_topic(device_id, message_type="data")

Generate the MQTT topic for a specific device and message type.

Parameters:

  • device_id (str): The device identifier.
  • message_type (str): Channel name. Default: "data".

Returns: str -- the full MQTT topic.

WeatherStation.get_topic("STATION-001", "data")
# "myproject/weatherstation/STATION-001/data"

WeatherStation.get_topic("STATION-001", "cmd")
# "myproject/weatherstation/STATION-001/cmd"

get_subscribe_topics()

Get MQTT topic patterns to subscribe to, using + wildcards for device_id.

Returns: list[str] -- two topic patterns (data and status).

WeatherStation.get_subscribe_topics()
# ["myproject/weatherstation/+/data", "myproject/weatherstation/+/status"]

Instance Methods (Hooks)

Override these in subclasses to add custom behavior. They are called by the MessageRouter after signals are fired.

on_data(self, device, readings)

Called when a device sends data readings.

Parameters:

  • device: Device model instance.
  • readings (dict): Field name to value mapping.

on_status_change(self, device, old_status, new_status)

Called when a device status changes.

Parameters:

  • device: Device model instance.
  • old_status (str): Previous status value.
  • new_status (str): Current status value.

on_connect(self, device)

Called when a device connects.

Parameters:

  • device: Device model instance.

on_disconnect(self, device)

Called when a device disconnects or heartbeat times out.

Parameters:

  • device: Device model instance.

on_command_response(self, device, command, response)

Called when a device responds to a command.

Parameters:

  • device: Device model instance.
  • command (str): Command name.
  • response: Response data from the device.

DeviceTypeMeta

from django_devicehub.device_type import DeviceTypeMeta

Metaclass for DeviceType. You do not use this directly -- it operates automatically when a class inherits from DeviceType.

Behavior

  1. Inherits _readings, _commands, _state_fields from base classes
  2. Scans the class namespace for Reading, Command, StateField instances
  3. Removes descriptors from the namespace and stores them in class dicts
  4. Sets each descriptor's .name attribute
  5. Calls registry.register(cls) for non-base, non-abstract classes

Abstract device types

Set _abstract = True to prevent registration:

class BaseSensor(DeviceType):
    _abstract = True
    battery = Reading(type=reading_types.FLOAT, unit="%")

DeviceTypeRegistry

from django_devicehub import registry

Global singleton registry of device types and their models.

Methods

Method Returns Description
register(cls) None Register a DeviceType class. Raises RegistryError on name conflict.
register_models(cls, device, reading, message) None Register generated models for a DeviceType.
get(name) DeviceType | None Look up by name (case-insensitive).
get_models(name) tuple | None Get (DeviceModel, ReadingModel, MessageModel) by name.
get_by_device_model(model) DeviceType | None Find the DeviceType that owns a device model class.
all() list[DeviceType] All registered DeviceType classes.
all_with_models() list[tuple] All (DeviceType, DeviceModel, ReadingModel, MessageModel) tuples.
clear() None Clear the registry (for testing).

Dunder methods

Method Description
len(registry) Number of registered types
"name" in registry Check if a name is registered (case-insensitive)