Skip to content

Migrating from v1 to v2

This guide covers every breaking change in pyOverkiz 2.0 and shows how to update your code.

Python version

pyOverkiz 2.0 requires Python 3.12 or later. If you are on an older version, upgrade Python first.

Client constructor

The OverkizClient constructor is now keyword-only and uses dedicated credential classes instead of positional username/password arguments.

from pyoverkiz.client import OverkizClient
from pyoverkiz.const import SUPPORTED_SERVERS
from pyoverkiz.enums import Server

client = OverkizClient("user@example.com", "password", SUPPORTED_SERVERS[Server.SOMFY_EUROPE])
from pyoverkiz.auth.credentials import UsernamePasswordCredentials
from pyoverkiz.client import OverkizClient
from pyoverkiz.enums import Server

client = OverkizClient(
    server=Server.SOMFY_EUROPE,
    credentials=UsernamePasswordCredentials("user@example.com", "password"),
)

Key differences:

  • server accepts a Server enum, a server key string, or a ServerConfig instance directly — no need to look up SUPPORTED_SERVERS yourself.
  • Authentication details are wrapped in a Credentials subclass: UsernamePasswordCredentials, TokenCredentials, LocalTokenCredentials, or RexelOAuthCodeCredentials.
  • The token parameter is removed. Use TokenCredentials or LocalTokenCredentials instead.

Local API

from pyoverkiz.client import OverkizClient
from pyoverkiz.utils import generate_local_server

server = generate_local_server(host="gateway-xxxx-xxxx-xxxx.local:8443")
client = OverkizClient("", "", server, token="your-token")
from pyoverkiz.auth.credentials import LocalTokenCredentials
from pyoverkiz.client import OverkizClient
from pyoverkiz.utils import create_local_server_config

client = OverkizClient(
    server=create_local_server_config(host="gateway-xxxx-xxxx-xxxx.local:8443"),
    credentials=LocalTokenCredentials("your-token"),
)

Server configuration

v1 v2
OverkizServer ServerConfig
generate_local_server() create_local_server_config()
client.api_type client.server_config.api_type

ServerConfig adds a server field (the Server enum key) and an explicit api_type field (APIType.CLOUD or APIType.LOCAL).

Executing commands

The command execution API has been consolidated into a single method.

v1 v2
client.execute_command(device_url, command) client.execute_action_group(actions=[...])
client.execute_commands(device_url, commands) client.execute_action_group(actions=[...])
Command Action wrapping one or more Command objects
from pyoverkiz.models import Command

await client.execute_command(
    "io://1234-5678-1234/12345678",
    Command("open", []),
)
from pyoverkiz.models import Action, Command

await client.execute_action_group(
    actions=[
        Action(
            device_url="io://1234-5678-1234/12345678",
            commands=[Command(name="open")],
        )
    ],
)

v2 also supports sending actions to multiple devices in a single call and choosing an ExecutionMode (HIGH_PRIORITY, GEOLOCATED, INTERNAL). Execution modes are only supported by the Cloud API; the local API rejects them (see Somfy-TaHoma-Developer-Mode#227).

Diagnostics

get_diagnostic_data() now returns a structured dict with named sections instead of a flat setup dump.

v1 v2
data["gateways"] data["setup"]["gateways"]
(not available) data["action_groups"]
diagnostics = await client.get_diagnostic_data()
gateways = diagnostics["gateways"]
diagnostics = await client.get_diagnostic_data()
gateways = diagnostics["setup"]["gateways"]
action_groups = diagnostics["action_groups"]

Scenarios → Action groups

v1 v2
Scenario ActionGroup
client.get_scenarios() client.get_action_groups()
client.execute_scenario(oid) client.execute_persisted_action_group(oid)
client.execute_scheduled_scenario(oid, ts) client.schedule_persisted_action_group(oid, ts)

get_action_groups() now returns list[PersistedActionGroup] instead of list[ActionGroup]. PersistedActionGroup extends ActionGroup with oid, creation_time, last_update_time, and a read-only id property (alias for oid). The base ActionGroup no longer has these fields.

Execution methods

v1 v2
CommandMode ExecutionMode
client.cancel_command(exec_id) client.cancel_execution(exec_id)
client.get_current_execution(exec_id) returns Execution Returns Execution | None
Execution.state is str Execution.state is ExecutionState
Execution.action_group is list[Action] Execution.action_group is ActionGroup | None

Device model

Removed fields

  • Device.id — was a duplicate of device_url.
  • Device.data_properties — was never populated by the API.

Moved fields

Device URL components are now grouped under device.identifier:

v1 v2
device.protocol device.identifier.protocol
device.gateway_id device.identifier.gateway_id
device.device_address device.identifier.device_address
device.subsystem_id device.identifier.subsystem_id
device.is_sub_device device.identifier.is_sub_device

The identifier also provides device.identifier.base_device_url.

State and attribute access

v2 provides a consistent API on device.states and device.attributes (both are States containers):

Method Returns Purpose
.get(name) State \| None Single-key lookup
.get_value(name) StateType Single-key value (None if missing)
.first(names) State \| None First non-None match from fallback list
.first_value(names) StateType First non-None value from fallback list
.has_value(name) bool Check single state exists with a non-None value
.has_any_value(names) bool Check any state exists with a non-None value
name in states bool Pure existence check (ignores the value)
# Get a single state value
temp = device.states.get_value("core:TemperatureState")

# Fallback chain — try multiple state names, return first hit
temp = device.states.first_value(["core:TemperatureState", "core:TemperatureInCelsiusState"])

# Value check — state exists and has a non-None value
if device.states.has_value("core:ClosureState"):
    ...

# Pure existence check (ignores the value)
if "core:ClosureState" in device.states:
    ...

# Same API works for attributes
firmware = device.attributes.get_value("core:FirmwareRevision")

Command helpers

Method Purpose
device.supports_command(cmd) Check single command support
device.supports_any_command(cmds) Check any command supported
device.first_command(cmds) First supported command from list
device.get_command_definition(cmd) Get CommandDefinition metadata

Definition helpers

device.definition is Definition | None — always check before accessing. State definitions are available via the StateDefinitions container at device.definition.states:

if device.definition:
    state_def = device.definition.states.get("core:ClosureState")
    first_def = device.definition.states.first(["core:ClosureState", "core:TargetClosureState"])
    if "core:ClosureState" in device.definition.states:
        ...
Container Method Purpose
device.definition.states .get(name) Single state definition lookup
.first(names) First matching from list
.has_any(names) Check if any exist
name in ... Membership test

Collection lookups (States, CommandDefinitions)

States.__getitem__ and CommandDefinitions.__getitem__ now raise KeyError when the requested key is not found. In v1 they returned None.

state = device.states["core:ClosureState"]  # returned None if missing
if state:
    ...
# Option 1: use .get() for the old behavior
state = device.states.get("core:ClosureState")

# Option 2: use [] and handle KeyError
try:
    state = device.states["core:ClosureState"]
except KeyError:
    ...

Gateway model

  • Gateway.connectivity is now Connectivity | None (was always set in v1).
  • Gateway.id and Place.id are now read-only properties.

Authentication methods

The per-server login helpers on OverkizClient have been removed. Authentication is now handled internally by the credential/strategy system — call the single login() method, which dispatches to the correct strategy based on the Credentials you passed to the constructor.

v1 v2
client.cozytouch_login() await client.login() (with the appropriate credentials)
client.nexity_login() await client.login()
client.somfy_tahoma_get_access_token() await client.login()
client.refresh_token() Handled internally; call await client.login() again to re-authenticate

Client internals

These changes affect you if you subclass OverkizClient or use internal APIs:

v1 v2
client.check_response(response) from pyoverkiz.response_handler import check_response; await check_response(response) (module-level async function)
client.event_listener_id = ... Read-only property; managed internally
SUPPORTED_SERVERS[key] = ... SUPPORTED_SERVERS is now immutable (MappingProxyType)
get_device_definition() returns dict Returns Definition | None

Parameter renames

v1 v2
deviceurl device_url

Update any keyword arguments using the old spelling.

Model defaults

  • Location address/string fields now default to None instead of empty strings.
  • OverkizClient raises OverkizError instead of ValueError when server configuration cannot be resolved.
  • obfuscate_sensitive_data() returns a new dict instead of mutating the input.

Boolean parsing fix

The Cloud API boolean parser previously mapped the string "false" to True (because bool("false") is truthy in Python). This is now fixed — "false" correctly maps to False. If your code relied on this incorrect behavior, update it accordingly.

Exceptions

All exception classes have been renamed from *Exception to *Error following PEP 8:

v1 v2
BaseOverkizException BaseOverkizError
OverkizException OverkizError
BadCredentialsException BadCredentialsError
NotAuthenticatedException NotAuthenticatedError
TooManyRequestsException TooManyRequestsError
MaintenanceException MaintenanceError
NotSuchTokenException NoSuchTokenError (typo fixed)
... (all other exceptions follow the same pattern)

New exception types in v2: NoSuchDeviceError, NoSuchActionGroupError, UnsupportedOperationError.

A quick way to update all imports:

# Find and replace across your codebase
find . -name "*.py" -exec sed -i '' 's/Exception\b/Error/g' {} +

Warning

The sed command above is intentionally broad. Review the result to avoid renaming unrelated exception classes in your own code.

Enum renames

All enums with an UNKNOWN fallback now inherit from UnknownEnumMixin. Unrecognized values returned by the API produce an UNKNOWN member with a logged warning instead of raising a ValueError.

Several enum members have been renamed for consistent UPPER_SNAKE_CASE or to fix typos. The tables below list every rename.

UIClass

Renamed members
v1 v2 Note
VENTILATION_SYTEM VENTILATION_SYSTEM Typo fix
Changed values
Member v1 value v2 value
UNKNOWN unknown Unknown

UIWidget

Renamed members
v1 v2 Note
DIMMER_RGBCOLOURED_LIGHT DIMMER_RGB_COLOURED_LIGHT
EWATTCH_TICCOUNTER EWATTCH_TIC_COUNTER
GENERIC_16_CHANNELS_COUNTER GENERIC16_CHANNELS_COUNTER
GENERIC_1_CHANNEL_COUNTER GENERIC1_CHANNEL_COUNTER
IOGENERIC IO_GENERIC
IOSIREN IO_SIREN
IOSTACK IO_STACK
IRBLASTER IR_BLASTER
JSWCAMERA JSW_CAMERA
OVPGENERIC OVP_GENERIC
ROCKER_SWITCHX_1_CONTROLLER ROCKER_SWITCHX1_CONTROLLER
ROCKER_SWITCHX_2_CONTROLLER ROCKER_SWITCHX2_CONTROLLER
ROCKER_SWITCHX_4_CONTROLLER ROCKER_SWITCHX4_CONTROLLER
TSKALARM_CONTROLLER TSK_ALARM_CONTROLLER
VOCSENSOR VOC_SENSOR
ZWAVE_DANFOSS_RSLINK ZWAVE_DANFOSS_RS_LINK
ZWAVE_SEDEVICE_CONFIGURATION ZWAVE_SE_DEVICE_CONFIGURATION
Changed values
Member v1 value v2 value
UNKNOWN unknown Unknown

OverkizState

Renamed members
v1 v2 Note
CORE_HOLIDAYS_MODE_STATE CORE_HOLIDAYS_MODE _STATE suffix dropped
CORE_PROGRAMING_AVAILABLE_STATE CORE_PROGRAMMING_AVAILABLE Typo fix + _STATE suffix dropped
SOMFY_THERMOSTAT_AT_HOME_TARGET_TEMPERATURE SOMFYTHERMOSTAT_AT_HOME_TARGET_TEMPERATURE Prefix SOMFY_THERMOSTAT_SOMFYTHERMOSTAT_
SOMFY_THERMOSTAT_AWAY_MODE_TARGET_TEMPERATURE SOMFYTHERMOSTAT_AWAY_MODE_TARGET_TEMPERATURE
SOMFY_THERMOSTAT_DEROGATION_HEATING_MODE SOMFYTHERMOSTAT_DEROGATION_HEATING_MODE
SOMFY_THERMOSTAT_FREEZE_MODE_TARGET_TEMPERATURE SOMFYTHERMOSTAT_FREEZE_MODE_TARGET_TEMPERATURE
SOMFY_THERMOSTAT_HEATING_MODE SOMFYTHERMOSTAT_HEATING_MODE
SOMFY_THERMOSTAT_SLEEPING_MODE_TARGET_TEMPERATURE SOMFYTHERMOSTAT_SLEEPING_MODE_TARGET_TEMPERATURE

The underlying state values (e.g. somfythermostat:HeatingModeState) are unchanged — only the Python member names changed.

EventName

Renamed members
v1 v2 Note
DELAYED_TRIGGER_SET_EVENT DELAYED_TRIGGER_SET _EVENT suffix dropped

OverkizCommandParam

Changed values

These members kept their names but their string values were corrected to match the API. Code comparing against the enum member is unaffected; code comparing against the old hard-coded string must update.

Member v1 value v2 value
FURTHER_NOTICE further_notice furtherNotice
STANDARD standard Standard

Protocol

New members
Member Value
SONOS sonos

GatewaySubType

New members
Member Value
TAHOMA_BOX_C_IO 17

New enums in v2

  • UIProfile — describes device capabilities (commands + states) at a higher level than raw command names. Auto-generated from the server's /reference/ui/profiles endpoint. Accessible via device.definition.ui_profiles (a list[UIProfile]). See UI profiles and classifiers.
  • UIClassifier — categorizes device types (e.g. SENSOR, EMITTER, GENERATOR). Accessible via device.definition.ui_classifiers (a list[UIClassifier]).
  • ExecutionState — typed states for Execution.state.
  • UpdateCriticityLevel — criticity level of gateway updates.

Dependencies

  • pyhumps has been removed and replaced with an internal _case module. No action needed unless you imported from pyhumps directly.
  • cattrs is a new required dependency (handles model structuring).
  • boto3 and warrant-lite are now optional. Install with pip install "pyoverkiz[nexity]" if you use the Nexity server.

Other changes

v1 v2
Setup.id always set Setup.id is None for Local API
get_diagnostic_data() get_diagnostic_data(mask_sensitive_data=True) — opt out of PII masking

New features in v2

These are not breaking, but worth knowing about when migrating:

  • Client settings — behavioral configuration is now grouped in OverkizClientSettings, passed via the settings parameter. This replaces standalone constructor parameters like action_queue.
  • Action queue — batch device executions automatically. See the action queue guide.
  • RTS command duration — override the default execution duration for RTS commands (15–30s) to prevent blocking consecutive commands. See RTS command duration.
  • Device helpersDevice.get_command_definition() for looking up command metadata.
  • Reference endpoints — query server metadata: get_reference_ui_classes(), get_reference_ui_widgets(), get_reference_ui_profile(), get_reference_controllable_types(), etc.
  • Firmware managementget_devices_not_up_to_date(), get_device_firmware_status(), update_device_firmware().
  • Optional Nexity dependenciesboto3 and warrant-lite are no longer installed by default. Install them with pip install "pyoverkiz[nexity]" if you use the Nexity server. A clear ImportError is raised at login time if the extra is missing.

auth_headers is now async

AuthStrategy.auth_headers() and every concrete strategy's implementation are now coroutines. This only affects code that calls auth_headers() directly or implements a custom AuthStrategy — normal OverkizClient use is unaffected.

headers = strategy.auth_headers(path)
headers = await strategy.auth_headers(path)

Custom strategies must change the method signature to async def auth_headers. This change lets token-supplied strategies (such as Rexel's RexelTokenAuthStrategy) await an externally-supplied access-token callback per request instead of caching token state.