Skip to content

Device deserialization fails with InvalidFieldValue - missing fields in Device dataclass #529

@bobmatnyc

Description

@bobmatnyc

Problem Description

When calling api.get_devices() with a real SmartThings hub, the library fails with a Mashumaro InvalidFieldValue exception. The Device dataclass in models.py is missing many fields that the SmartThings API returns in device responses.

Error Details

mashumaro.exceptions.InvalidFieldValue: Field "items" of type list[Device] in DeviceResponse has invalid value

The error occurs because the Device model (lines 388-422 in src/pysmartthings/models.py) doesn't define all fields returned by the SmartThings API.

Test Results

✅ Working Operations

  • API authentication and connection
  • get_locations() - Successfully retrieves locations
  • get_rooms() - Successfully retrieves rooms (19 rooms found)

❌ Broken Operations

  • get_devices() - Fails with InvalidFieldValue from Mashumaro

Root Cause

The Device dataclass is missing the following fields returned by SmartThings API:

Core Missing Fields:

  • manufacturerName (string)
  • presentationId (string)
  • ownerId (string)
  • createTime (string/datetime)
  • profile (dict with id field)
  • restrictionTier (integer)
  • allowed (list)
  • executionContext (string)
  • relationships (dict)

Network-Specific Objects (device-type dependent):

  • zigbee (dict)
  • zwave (dict)
  • lan (dict)
  • virtual (dict)
  • edgeChild (dict)

Example API Response

Devices in the API response contain fields like:

{
  "deviceId": "1e735b78-c7d0-429a-8b91-fd84ce96ad09",
  "name": "c2c-dimmer",
  "label": "Master Down Lights",
  "manufacturerName": "SmartThings",
  "presentationId": "SmartThings-smartthings-c2c-dimmer",
  "ownerId": "...",
  "createTime": "2024-10-28T19:26:45.019Z",
  "profile": {"id": "..."},
  "restrictionTier": 0,
  "allowed": [],
  "executionContext": "...",
  ...
}

Impact

This breaks get_devices() for users with real SmartThings hubs containing diverse device types (VIPER, ZIGBEE, ZWAVE, MATTER, LAN, VIRTUAL, EDGE_CHILD, OCF, MOBILE). Users cannot list or interact with their devices.

Environment

  • Python: 3.12+
  • pysmartthings: latest from main branch
  • Mashumaro: 3.11+ (strict type checking enabled)
  • SmartThings API: v1

Suggested Fix

Add missing fields to the Device dataclass with Optional types:

@dataclass
class Device(DataClassORJSONMixin):
    """Device model."""
    
    # Existing required fields...
    device_id: str = field(metadata=field_options(alias="deviceId"))
    name: str
    label: str
    # ... existing fields ...
    
    # Add missing fields with Optional types
    manufacturer_name: str | None = field(
        metadata=field_options(alias="manufacturerName"), default=None
    )
    presentation_id: str | None = field(
        metadata=field_options(alias="presentationId"), default=None
    )
    owner_id: str | None = field(
        metadata=field_options(alias="ownerId"), default=None
    )
    create_time: str | None = field(
        metadata=field_options(alias="createTime"), default=None
    )
    profile: dict[str, Any] | None = None
    restriction_tier: int | None = field(
        metadata=field_options(alias="restrictionTier"), default=None
    )
    allowed: list[str] | None = None
    execution_context: str | None = field(
        metadata=field_options(alias="executionContext"), default=None
    )
    relationships: dict[str, Any] | None = None
    
    # Network-specific objects (device-type dependent)
    zigbee: dict[str, Any] | None = None
    zwave: dict[str, Any] | None = None
    lan: dict[str, Any] | None = None
    virtual: dict[str, Any] | None = None
    edge_child: dict[str, Any] | None = field(
        metadata=field_options(alias="edgeChild"), default=None
    )

Reproduction

from aiohttp import ClientSession
from pysmartthings import SmartThings

async with ClientSession() as session:
    api = SmartThings(session=session)
    api.authenticate("your-token")
    
    # This works
    locations = await api.get_locations()
    
    # This fails with InvalidFieldValue
    devices = await api.get_devices()

Related Work

Recent PRs show active field additions:

This indicates maintainers are aware of evolving API fields, but the missing fields above are blocking basic device operations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions