Skip to content

Development Utilities

Scripts in the utils/ directory help generate enum source files, documentation pages, and test fixtures from the Overkiz API.

Architecture

utils/
├── fetch_server_data.py      # Fetches all reference data from a server
├── generate_enums.py         # Generates enum .py files (offline)
├── generate_device_catalog.py # Generates device-types.md docs (offline)
└── mask_fixtures.py          # Masks sensitive data in test fixtures

Data flow:

  Overkiz API
       │
       ▼
  fetch_server_data.py  ──►  docs/data/<server>.json
                                          │
                        ┌─────────────────┼─────────────────┐
                        ▼                 ▼                  ▼
              generate_enums.py   generate_device_catalog.py
                        │                 │
                        ▼                 ▼
              pyoverkiz/enums/*.py   docs/device-types.md
                                    docs/ui-profiles.md

The per-server JSON files in docs/data/ are the single source of truth. They are checked into git and accumulate over time as you gain access to more servers.

fetch_server_data.py

Fetches all reference data from a single Overkiz server and saves it as a JSON file.

OVERKIZ_USERNAME=... OVERKIZ_PASSWORD=... uv run utils/fetch_server_data.py --server somfy_europe
OVERKIZ_USERNAME=... OVERKIZ_PASSWORD=... uv run utils/fetch_server_data.py --server atlantic_cozytouch

What it fetches:

  • Protocol types (/reference/protocolTypes)
  • UI classes, widgets, classifiers (/reference/ui/...)
  • UI profile names and details (/reference/ui/profileNames, /reference/ui/profile/<name>)
  • Device types per protocol (/reference/devices/search)
  • Controllable definitions (/reference/controllable/<name>)

Output: docs/data/<server>.json

The script includes rate-limit handling with exponential backoff (starts at 10s, doubles per retry, up to 5 attempts).

generate_enums.py

Generates all enum source files from the stored server data. No API calls — works entirely offline.

uv run utils/generate_enums.py

Generates:

File Source
pyoverkiz/enums/protocol.py referenceMetadata.protocolTypes
pyoverkiz/enums/ui.py referenceMetadata.uiClasses/uiWidgets/uiClassifiers + tests/fixtures/setup/*.json
pyoverkiz/enums/ui_profile.py referenceMetadata.uiProfiles + tests/fixtures/setup/*.json
pyoverkiz/enums/state.py protocols.*.states, controllableDefinitions.*.states/attributes + tests/fixtures/setup/*.json
pyoverkiz/enums/command.py protocols.*.commands/states, controllableDefinitions.*.states + tests/fixtures/setup/*.json
docs/ui-profiles.md referenceMetadata.uiProfiles + tests/fixtures/setup/*.json

state.py holds OverkizState + OverkizAttribute; command.py holds OverkizCommand + OverkizCommandParam (parameter values are harvested from discrete state values and command parameter enums). The ExecutionMode enum in command.py is hand-written and preserved across regeneration.

Data from all available server files is merged (union of all values). The setup fixtures in tests/fixtures/setup/ are merged in as an additional source: they capture real devices whose UI classes, widgets, classifiers and profiles (and states, commands, attributes) are not always exposed by the reference endpoints of the servers we have access to. Profiles found only in fixtures are added without details. protocol.py is the exception — Protocol members need the full id/prefix/name/label metadata, which fixtures don't carry, so they come only from referenceMetadata.protocolTypes plus the hardcoded ADDITIONAL_PROTOCOLS.

Hardcoded entries for protocols and widgets not found on any server are appended (see ADDITIONAL_PROTOCOLS and ADDITIONAL_WIDGETS in the script). Discrete values that cannot form a valid Python identifier (e.g. the purely numeric "1", "2") are skipped and reported in the run output.

generate_device_catalog.py

Generates the device types documentation page from stored server data. No API calls.

uv run utils/generate_device_catalog.py

Generates: docs/device-types.md

Merges device types from all server JSON files, deduplicates entries with identical interfaces, and enriches them with controllable definitions (discrete state values, data properties).

mask_fixtures.py

Strips sensitive data (device URLs, gateway IDs, etc.) from test fixture files.

uv run utils/mask_fixtures.py

Processes all JSON files in tests/fixtures/setup/ using the library's built-in obfuscation logic.

Per-server JSON schema

Each file in docs/data/ follows this structure:

{
  "server": "somfy_europe",
  "referenceMetadata": {
    "controllableTypes": [{"id": 1, "name": "ACTUATOR", "label": "Actuator"}, ...],
    "protocolTypes": [{"id": 1, "prefix": "io", "name": "IO", "label": "IO HomeControl©"}, ...],
    "uiClasses": ["Alarm", "Light", ...],
    "uiWidgets": ["AlarmPanelController", ...],
    "uiClassifiers": ["alarm", ...],
    "uiProfiles": {
      "Alarm": {"name": "Alarm", "formFactor": false, "commands": [...], "states": [...]},
      ...
    }
  },
  "protocols": {
    "IO": [
      {
        "typeId": 1, "uiClass": "RollerShutter", "uiWidget": "...",
        "controllableName": "io:RollerShutterGenericComponent",
        "controllableType": "ACTUATOR",
        "commands": [{"commandName": "open", "nparams": 0, ...}],
        "states": [{"name": "ClosureState", "type": "ContinuousState", ...}],
        ...
      }
    ]
  },
  "controllableDefinitions": {
    "io:RollerShutterGenericComponent": {
      "commands": [...], "states": [...], "dataProperties": [...], ...
    }
  }
}

Adding a new server

  1. Get credentials for the server
  2. Run fetch_server_data.py --server <server_name>
  3. Commit the new docs/data/<server>.json
  4. Run generate_enums.py and generate_device_catalog.py to regenerate code and docs