This document prov # Dyson REST API Client Documentation
This document provides comprehensive documentation for both the synchronous and asynchronous Dyson REST API clients.
- Quick Start
- Client Overview
- Synchronous Client (DysonClient)
- Asynchronous Client (AsyncDysonClient)
- Method Comparison Table
- Authentication Flow
- Error Handling
- Data Models
from libdyson_rest import DysonClient
# Two-step authentication (recommended)
client = DysonClient("user@example.com", "your_password")
if not client.authenticate(): # Returns False - OTP needed
otp = input("Enter OTP from email: ")
client.complete_authentication(otp)
devices = client.get_devices()
for device in devices:
print(f"Device: {device.name} ({device.serial})")
# Context manager usage
with DysonClient("user@example.com", "your_password") as client:
if not client.authenticate():
otp = input("Enter OTP from email: ")
client.complete_authentication(otp)
devices = client.get_devices()import asyncio
from libdyson_rest import AsyncDysonClient
async def main():
# Two-step authentication (recommended)
client = AsyncDysonClient("user@example.com", "your_password")
if not await client.authenticate(): # Returns False - OTP needed
otp = input("Enter OTP from email: ")
await client.complete_authentication(otp)
devices = await client.get_devices()
for device in devices:
print(f"Device: {device.name} ({device.serial})")
await client.close()
# Context manager usage
async with AsyncDysonClient("user@example.com", "your_password") as client:
if not await client.authenticate():
otp = input("Enter OTP from email: ")
await client.complete_authentication(otp)
devices = await client.get_devices()
asyncio.run(main())The library provides two client implementations:
DysonClient: Synchronous client usingrequestslibraryAsyncDysonClient: Asynchronous client usinghttpxlibrary
Both clients provide identical APIs except for the async/await syntax and context manager protocols.
class DysonClient:
def __init__(
self,
email: str | None = None,
password: str | None = None,
auth_token: str | None = None,
request_timeout: int = 30,
user_agent: str = "android client"
) -> NoneParameters:
email(str | None): User's email address for authenticationpassword(str | None): User's password for authenticationauth_token(str | None): Pre-existing authentication tokenrequest_timeout(int): Request timeout in seconds (default: 30)user_agent(str): User agent string for requests (default: "android client")
def authenticate(self) -> boolInitiates the authentication process. Returns True if authentication completes without OTP, False if OTP is required.
Returns: bool - True if authenticated, False if OTP required
Raises:
DysonAuthError: Authentication failedDysonConnectionError: Network/connection issues
def complete_authentication(self, otp_code: str) -> NoneCompletes authentication using the OTP code received via email.
Parameters:
otp_code(str): One-time password from email
Raises:
DysonAuthError: Invalid OTP or authentication failedDysonConnectionError: Network/connection issues
def login_challenge(self, email: str, password: str) -> LoginChallengeLow-level method to initiate login challenge (used internally by authenticate()).
Parameters:
email(str): User's email addresspassword(str): User's password
Returns: LoginChallenge object containing challenge details
complete_login(challenge_id: str, otp_code: str, email: str | None = None, password: str | None = None)
def complete_login(
self,
challenge_id: str,
otp_code: str,
email: str | None = None,
password: str | None = None,
) -> LoginInformationLow-level method to complete login with OTP (used internally by complete_authentication()).
Parameters:
challenge_id(str): Challenge ID from login_challenge responseotp_code(str): One-time password from emailemail(str | None): User's email (optional if set in constructor)password(str | None): User's password (optional if set in constructor)
Returns: LoginInformation object containing auth token and account details
def get_devices(self) -> list[DysonDevice]Retrieves all Dyson devices associated with the account.
Returns: List of DysonDevice objects
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_device_by_serial(self, serial: str) -> DysonDevice | NoneRetrieves a specific device by its serial number.
Parameters:
serial(str): Device serial number
Returns: DysonDevice object if found, None otherwise
def get_device_credentials(self, device: DysonDevice) -> dict[str, str]Retrieves MQTT credentials for a specific device.
Parameters:
device(DysonDevice): Device object
Returns: Dictionary containing MQTT credentials (username, password, hostname)
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_clean_maps(
self, serial_number: str, *, api_version: int, include_dust_map: bool = True
) -> list[CleanRecord]Retrieves recent cleaning run history for a Vis Nav robot vacuum.
Parameters:
serial_number(str): Device serial numberapi_version(int): API version to use —1for Dyson 360 Vis Nav (H8T / product type276B),2for Dyson 360 Spot+Clean and newer (VS6 / RB05 / product type804A)include_dust_map(bool): When True (default), fetches the aggregated dust-density map blob for each run
Returns: List of CleanRecord objects, newest first
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_persistent_map_metadata(self, serial_number: str, *, api_version: int) -> list[PersistentMapMeta]Retrieves the list of saved maps (zone names, IDs, and areas) for a Vis Nav.
Parameters:
serial_number(str): Device serial numberapi_version(int): API version to use —1for Vis Nav (H8T),2for Spot+Clean and newer
Returns: List of PersistentMapMeta objects — one per stored map
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_persistent_map(self, serial_number: str, map_id: str, *, api_version: int) -> PersistentMapRetrieves the full map record for a single persistent map, including the floor-plan PNG.
Parameters:
serial_number(str): Device serial numbermap_id(str): Persistent map ID (fromget_persistent_map_metadata)api_version(int): API version to use —1for Vis Nav (H8T),2for Spot+Clean and newer
Returns: PersistentMap with presentation image, display orientation, world offset, and zone definitions
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_recommended_cleans(self, serial_number: str) -> list[RecommendedCleanMap]Retrieves Dyson's per-zone clean recommendations ranked by accumulated dust load.
Parameters:
serial_number(str): Device serial number
Returns: List of RecommendedCleanMap objects (one per persistent map), each containing per-zone ZonePrediction entries with ZoneDustBreakdown data
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def set_zone_behaviour(
self,
serial_number: str,
map_id: str,
zone_id: str,
strategy: CleaningStrategy | str,
) -> NoneSets the per-zone cleaning strategy. Equivalent to changing a zone's behaviour in the MyDyson app. The device applies the override on its next clean.
Note: The API path is
/v1/app/{serial}/{mapId}/zones/{zoneId}/zone-behaviours— there is nopersistent-maps/segment in this path.
Parameters:
serial_number(str): Device serial numbermap_id(str): Persistent map IDzone_id(str): Zone ID to updatestrategy(CleaningStrategy| str): Cleaning strategy —AUTO,QUICK,QUIET, orBOOST
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_daily_environment_data(
self, serial_number: str, language: str = "en"
) -> DailyAirQualityDataRetrieves today's indoor air-quality history at 15-minute resolution.
Parameters:
serial_number(str): Device serial numberlanguage(str): Language code for localised field values (default:"en")
Returns: DailyAirQualityData with sample series, start_time, and resolution_minutes
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
def get_scheduled_events(
self, serial_number: str, product_type: str | None = None
) -> ScheduledEventsDataRetrieves the MyDyson-app automation schedule for a device.
Parameters:
serial_number(str): Device serial numberproduct_type(str | None): Device product-type code (e.g."438K"). Required by the server to return the correct schedule schema; omit only if the product type is unknown.
Returns: ScheduledEventsData with schedule_enabled flag and list of ScheduledEvent objects
Raises:
DysonAuthError: Not authenticated or token expiredDysonAPIError: API request failedDysonConnectionError: Network/connection issues
with DysonClient("user@example.com", "password") as client:
if not client.authenticate():
otp = input("Enter OTP: ")
client.complete_authentication(otp)
devices = client.get_devices()
# Client is automatically cleaned updef get_clean_map_data(self, serial_number: str, clean_id: str) -> dict[str, Any]Retrieves detailed data for a single cleaning session (path, duration, area coverage, etc.).
Parameters:
serial_number(str): Device serial numberclean_id(str): Cleaning session ID (fromget_clean_maps)
Returns: Raw dict with detailed session data
def update_persistent_map(self, serial_number: str, map_id: str, name: str | None = None) -> NoneUpdates an existing persistent map (e.g. rename it).
def delete_persistent_map(self, serial_number: str, map_id: str) -> NonePermanently deletes a persistent map from the device.
def update_map_metadata(self, serial_number: str, map_id: str, name: str | None = None) -> NoneUpdates the persistent map metadata stored by the API (e.g. the display name).
def get_clean_estimation(
self,
serial_number: str,
map_id: str,
zone_ids: list[str] | None = None,
) -> dict[str, Any]Requests a server-side estimation of cleaning time and area for a set of zones.
Parameters:
serial_number(str): Device serial numbermap_id(str): Persistent map IDzone_ids(list[str] | None): Zone IDs to estimate; None estimates all zones
Returns: Raw dict with estimated duration and coverage
def get_restrictions(self, serial_number: str, map_id: str) -> dict[str, Any]Retrieves the no-go and restricted-area definitions for a persistent map.
def update_restrictions(self, serial_number: str, map_id: str, body: dict[str, Any]) -> NoneReplaces the restriction definitions (no-go zones, keep-out areas) for a persistent map.
def divide_zone(self, serial_number: str, map_id: str, body: dict[str, Any]) -> NoneSplits a single zone into two sub-zones along a specified boundary.
def merge_zones(self, serial_number: str, map_id: str, body: dict[str, Any]) -> NoneMerges two or more zones into a single zone on a persistent map.
def get_live_map_cleaning(self, serial_number: str) -> dict[str, Any]Returns the robot's real-time position and cleaned footprint during an active cleaning session. Poll this endpoint while a clean is in progress to display a live map.
def get_live_map_mapping(self, serial_number: str) -> dict[str, Any]Returns the robot's real-time position and discovered floor plan during an active mapping session.
def set_scheduled_events(
self,
serial_number: str,
enabled: bool,
events: list[dict[str, Any]],
product_type: str | None = None,
) -> NoneReplaces the scheduled automation event list for a device. Each event dict should contain enabled, days (list of int, 0=Mon), startTime (HH:MM), and settings.
Parameters:
serial_number(str): Device serial numberenabled(bool): Whether the overall schedule is activeevents(list[dict]): Replacement list of scheduled eventsproduct_type(str | None): Product-type code, e.g."438K"
def get_schedule_binary(self, serial_number: str) -> bytesDownloads the device schedule as a raw binary blob for BLE programming.
Returns: bytes — raw schedule binary
def get_environment_history(self, serial_number: str) -> dict[str, Any]Retrieves the multi-day indoor air-quality history for a device. Unlike get_daily_environment_data which returns today's data at 15-minute resolution, this endpoint provides a longer historical dataset across multiple days.
Returns: Raw dict with historical air-quality data
def get_energy_insights(
self,
serial_number: str,
year: int | None = None,
month: int | None = None,
) -> dict[str, Any]Retrieves monthly energy consumption insights for an EC air purifier.
Parameters:
serial_number(str): Device serial numberyear(int | None): Year (defaults to current year on the server)month(int | None): Month 1–12 (defaults to current month on the server)
Returns: Raw dict with monthly energy/EC usage data
def get_timezone(self, serial_number: str) -> str | NoneRetrieves the IANA timezone configured for a device (e.g. "Europe/London").
def set_timezone(self, serial_number: str, timezone: str) -> NoneSets the IANA timezone for a device.
def get_ota_info(self, serial_number: str) -> dict[str, Any]Returns over-the-air firmware update information for a device, including available firmware versions and update status.
def is_banned_machine(self, serial_number: str) -> boolChecks whether a device serial number appears on Dyson's banned-machine list. Banned devices cannot connect to cloud services.
Returns: True if the device is banned, False otherwise
def get_feature_support(self) -> dict[str, Any]Returns Dyson's global server-controlled feature-flag object. The MyDyson app uses this to enable or disable app features at runtime without an app update.
def get_voice_languages(self, serial_number: str) -> list[str]Returns the list of supported voice-command language codes for a device.
Returns: list[str] of IETF language tags, e.g. ["en-GB", "fr-FR"]
def get_product_faults(self, serial_number: str) -> dict[str, Any]Returns known product fault codes and their recommended remedies for a device. Useful for building in-app troubleshooting flows.
def get_product_guide(self, serial_number: str) -> dict[str, Any]Returns the product user guide content for a device as served by the Dyson API.
def get_product_voice_commands(self, serial_number: str) -> dict[str, Any]Returns the voice command reference content for a device.
def register_push_token(
self,
application_id: str,
token: str,
platform: str,
serial_numbers: list[str] | None = None,
) -> dict[str, Any]Registers an APNs or FCM push notification token with the Dyson API.
Parameters:
application_id(str): Application/token identifiertoken(str): Platform push notification tokenplatform(str):"ios"or"android"serial_numbers(list[str] | None): Device serial numbers to associate
Returns: Raw dict with registration confirmation
def get_notification_permissions(self, application_id: str, serial_number: str) -> dict[str, Any]Retrieves the per-device push notification permission settings for an application.
def update_notification_permissions(
self,
application_id: str,
serial_number: str,
permissions: dict[str, Any],
) -> NoneUpdates the push notification permission settings for a device and application.
def get_registered_products(self) -> dict[str, Any]Returns smart-home products registered with Dyson's NCP (Notification/Control Platform).
def register_ncp(self, body: dict[str, Any]) -> NoneRegisters a device with Dyson's NCP smart-home platform.
def register_nsp(self, body: dict[str, Any]) -> NoneRegisters a device with Dyson's NSP (another smart-home integration platform).
class AsyncDysonClient:
def __init__(
self,
email: str | None = None,
password: str | None = None,
auth_token: str | None = None,
request_timeout: int = 30,
user_agent: str = "android client"
) -> NoneParameters: Same as DysonClient
async def authenticate(self) -> boolAsync version of authenticate method.
Returns: bool - True if authenticated, False if OTP required
async def complete_authentication(self, otp_code: str) -> NoneAsync version of complete_authentication method.
Parameters:
otp_code(str): One-time password from email
async def login_challenge(self, email: str, password: str) -> LoginChallengeAsync version of login_challenge method.
complete_login(challenge_id: str, otp_code: str, email: str | None = None, password: str | None = None)
async def complete_login(
self,
challenge_id: str,
otp_code: str,
email: str | None = None,
password: str | None = None,
) -> LoginInformationAsync version of complete_login method.
async def get_devices(self) -> list[DysonDevice]Async version of get_devices method.
async def get_device_by_serial(self, serial: str) -> DysonDevice | NoneAsync version of get_device_by_serial method.
async def get_device_credentials(self, device: DysonDevice) -> dict[str, str]Async version of get_device_credentials method.
async def get_clean_maps(
self, serial_number: str, *, api_version: int, include_dust_map: bool = True
) -> list[CleanRecord]Async version of get_clean_maps. See sync client for full parameter/return documentation.
async def get_persistent_map_metadata(self, serial_number: str, *, api_version: int) -> list[PersistentMapMeta]Async version of get_persistent_map_metadata.
async def get_persistent_map(self, serial_number: str, map_id: str, *, api_version: int) -> PersistentMapAsync version of get_persistent_map.
async def get_recommended_cleans(self, serial_number: str) -> list[RecommendedCleanMap]Async version of get_recommended_cleans.
async def set_zone_behaviour(
self,
serial_number: str,
map_id: str,
zone_id: str,
strategy: CleaningStrategy | str,
) -> NoneAsync version of set_zone_behaviour.
async def get_daily_environment_data(
self, serial_number: str, language: str = "en"
) -> DailyAirQualityDataAsync version of get_daily_environment_data.
async def get_scheduled_events(
self, serial_number: str, product_type: str | None = None
) -> ScheduledEventsDataAsync version of get_scheduled_events.
async def close(self) -> NoneProperly closes the HTTP client session. Always call this when done with the client, or use async context manager.
async with AsyncDysonClient("user@example.com", "password") as client:
if not await client.authenticate():
otp = input("Enter OTP: ")
await client.complete_authentication(otp)
devices = await client.get_devices()
# Client is automatically closed| Feature | Synchronous | Asynchronous | Notes |
|---|---|---|---|
| Constructor | DysonClient() |
AsyncDysonClient() |
Same parameters |
| Authentication | authenticate() |
await authenticate() |
Returns bool |
| Complete Auth | complete_authentication() |
await complete_authentication() |
Takes OTP code |
| Get Devices | get_devices() |
await get_devices() |
Returns device list |
| Get Device | get_device_by_serial() |
await get_device_by_serial() |
Find by serial |
| Get Credentials | get_device_credentials() |
await get_device_credentials() |
MQTT credentials |
| Clean Maps | get_clean_maps() |
await get_clean_maps() |
Requires api_version=1 (Vis Nav) or api_version=2 (Spot+Clean) |
| Clean Map Data | get_clean_map_data() |
await get_clean_map_data() |
Detailed session data (v2 only) |
| Map Metadata | get_persistent_map_metadata() |
await get_persistent_map_metadata() |
Requires api_version=1 or api_version=2 |
| Full Map | get_persistent_map() |
await get_persistent_map() |
Requires api_version=1 or api_version=2 |
| Update Map | update_persistent_map() |
await update_persistent_map() |
Rename persistent map |
| Delete Map | delete_persistent_map() |
await delete_persistent_map() |
Remove persistent map |
| Update Metadata | update_map_metadata() |
await update_map_metadata() |
Update map metadata |
| Clean Estimate | get_clean_estimation() |
await get_clean_estimation() |
Zone cleaning estimate |
| Restrictions | get_restrictions() |
await get_restrictions() |
No-go zones |
| Update Restrictions | update_restrictions() |
await update_restrictions() |
Set no-go zones |
| Divide Zone | divide_zone() |
await divide_zone() |
Split a zone |
| Merge Zones | merge_zones() |
await merge_zones() |
Combine zones |
| Live Map (Clean) | get_live_map_cleaning() |
await get_live_map_cleaning() |
Real-time clean map |
| Live Map (Map) | get_live_map_mapping() |
await get_live_map_mapping() |
Real-time mapping |
| Recommended | get_recommended_cleans() |
await get_recommended_cleans() |
Dust predictions |
| Zone Strategy | set_zone_behaviour() |
await set_zone_behaviour() |
Vis Nav zone config |
| Set Schedule | set_scheduled_events() |
await set_scheduled_events() |
Replace schedule |
| Schedule Binary | get_schedule_binary() |
await get_schedule_binary() |
BLE schedule blob |
| AQI History | get_daily_environment_data() |
await get_daily_environment_data() |
EC purifier (today) |
| AQI Multi-Day | get_environment_history() |
await get_environment_history() |
EC purifier history |
| Energy Insights | get_energy_insights() |
await get_energy_insights() |
Monthly usage |
| Get Schedule | get_scheduled_events() |
await get_scheduled_events() |
Automation schedule |
| Outdoor Env | get_outdoor_environment_data() |
await get_outdoor_environment_data() |
Outdoor air quality |
| Timezone Get | get_timezone() |
await get_timezone() |
IANA timezone |
| Timezone Set | set_timezone() |
await set_timezone() |
IANA timezone |
| OTA Info | get_ota_info() |
await get_ota_info() |
Firmware update info |
| Banned Check | is_banned_machine() |
await is_banned_machine() |
Cloud ban check |
| Feature Flags | get_feature_support() |
await get_feature_support() |
App feature flags |
| Voice Languages | get_voice_languages() |
await get_voice_languages() |
Voice command langs |
| Product Faults | get_product_faults() |
await get_product_faults() |
Fault codes |
| Product Guide | get_product_guide() |
await get_product_guide() |
User guide content |
| Voice Commands | get_product_voice_commands() |
await get_product_voice_commands() |
Voice cmd reference |
| Register Token | register_push_token() |
await register_push_token() |
APNs/FCM token |
| Notif Perms | get_notification_permissions() |
await get_notification_permissions() |
Per-device perms |
| Update Notif | update_notification_permissions() |
await update_notification_permissions() |
Update perms |
| NCP Products | get_registered_products() |
await get_registered_products() |
Smart home devices |
| Register NCP | register_ncp() |
await register_ncp() |
NCP registration |
| Register NSP | register_nsp() |
await register_nsp() |
NSP registration |
| Context Manager | with client: |
async with client: |
Auto cleanup |
| Resource Cleanup | Automatic | await client.close() |
Manual or context manager |
The library uses a two-step authentication process:
-
Initial Authentication: Call
authenticate()with email/password- If MFA is disabled: Returns
True, authentication complete - If MFA is enabled: Returns
False, OTP sent to email
- If MFA is disabled: Returns
-
OTP Completion: If
authenticate()returnsFalse, callcomplete_authentication(otp)- Provide the OTP code received via email
- Authentication completes successfully
# Step 1: Initial authentication
client = DysonClient("user@example.com", "password")
if client.authenticate():
print("Authentication complete!")
else:
# Step 2: OTP required
otp = input("Enter OTP from email: ")
client.complete_authentication(otp)
print("Authentication complete with OTP!")
# Now authenticated - can make API calls
devices = client.get_devices()# Deprecated: Single-step with OTP (if known)
client = DysonClient("user@example.com", "password")
login_info = client.complete_login(challenge_id, "123456")The library defines custom exceptions for different error scenarios:
DysonError (base)
├── DysonAuthError (authentication failures)
├── DysonAPIError (API response errors)
└── DysonConnectionError (network/connection issues)
Base exception class for all Dyson-related errors.
Raised when authentication fails:
- Invalid credentials
- Invalid OTP code
- Token expired
- Account locked
Raised when API requests fail:
- Invalid API response format
- Server errors (5xx)
- Rate limiting
- Invalid device serial
Raised when network issues occur:
- Connection timeout
- DNS resolution failure
- SSL/TLS errors
- Network unreachable
from libdyson_rest import (
DysonClient,
DysonAuthError,
DysonAPIError,
DysonConnectionError,
)
try:
client = DysonClient("user@example.com", "password")
if not client.authenticate():
otp = input("Enter OTP: ")
client.complete_authentication(otp)
devices = client.get_devices()
except DysonAuthError as e:
print(f"Authentication failed: {e}")
except DysonAPIError as e:
print(f"API error: {e}")
except DysonConnectionError as e:
print(f"Connection error: {e}")Represents a Dyson device with the following attributes:
@dataclass
class DysonDevice:
serial: str # Device serial number
name: str # User-assigned device name
product_type: str # Product identifier (e.g., "520")
version: str # Firmware version
auto_update: bool # Auto-update enabled
new_version_available: bool # Firmware update available
category: str # Device category (e.g., "purifier")
# Optional attributes (may be None)
local_credentials: dict[str, str] | None # Local MQTT credentials
connection_type: str | None # Connection type
mqtt_server: str | None # MQTT server hostnameRepresents a login challenge response:
@dataclass
class LoginChallenge:
challenge_id: str # Challenge identifier for OTP completion
user_id: str # User account identifierRepresents completed login information:
@dataclass
class LoginInformation:
token: str # Authentication token
account: dict # Account details
challenge_id: str # Challenge identifier used# Working with devices
devices = client.get_devices()
for device in devices:
print(f"Device: {device.name}")
print(f"Serial: {device.serial}")
print(f"Type: {device.product_type}")
print(f"Category: {device.category}")
if device.new_version_available:
print("⚠️ Firmware update available")
# Get MQTT credentials for device
credentials = client.get_device_credentials(device)
print(f"MQTT Host: {credentials['hostname']}")
# Find specific device
device = client.get_device_by_serial("ABC-DEF-123")
if device:
print(f"Found: {device.name}")
else:
print("Device not found")A single cleaning run, including timeline, dust map, and cleaning programme.
@dataclass
class CleanRecord:
start_time: datetime | None
end_time: datetime | None
timeline: list[CleanTimelineEvent]
dust_map: DustMapData | None # Aggregated dust-density grid
clean_map_position: CleanMapPosition | None # World origin of dust map
cleaning_programme: CleaningProgramme | None # Zone-clean config used
footprint: CleanedFootprint | None # Cleaned area + floor-plan crop
raw: dict # Full raw API response
@property
def is_zone_clean(self) -> bool: ...Per-zone cleaning intensity used with set_zone_behaviour():
| Value | Description |
|---|---|
AUTO |
Dyson-selected intensity |
QUICK |
Fast single pass |
QUIET |
Low-noise mode |
BOOST |
Intensive multi-pass |
Metadata about a stored floor map, including its zones.
@dataclass
class PersistentMapMeta:
id: str
name: str | None
zones: list[ZoneMeta]
def zone_by_id(self, zone_id: str) -> ZoneMeta | None: ...
def zone_by_name(self, name: str) -> ZoneMeta | None: ...@dataclass
class ZoneMeta:
id: str
name: str | None
icon: str | None
area: float | None # Zone area in m²Full map record including presentation image and zone definitions.
@dataclass
class PersistentMap:
id: str
offset_x: float | None # World-mm X origin
offset_y: float | None # World-mm Y origin
display_orientation: int # Degrees rotation for display
presentation_map_data: str | None # Base64-encoded floor-plan PNG
zones_definition: dict | None
zones: list[ZoneMeta]@dataclass
class RecommendedCleanMap:
persistent_map_id: str
zone_predictions: list[ZonePrediction]
def sorted_by_dust(self) -> list[ZonePrediction]: ...@dataclass
class ZonePrediction:
zone_id: str
dust: ZoneDustBreakdownPer-particle-class dust load (milligrams).
@dataclass
class ZoneDustBreakdown:
extra_fine: float
fine: float
medium: float
large: float
other: float
total: float # Sum of all classes
raw: list # Original API arrayAggregated dust-density grid returned with each clean record.
@dataclass
class DustMapData:
width: int
height: int
resolution: float # mm per pixel
dust_data: list[list[float]] # 2-D grid, values 0–1 (divided by scaleFactor)@dataclass
class DailyAirQualityData:
start_time: datetime | None
resolution_minutes: int # Typically 15
samples: list[float | None] # AQI values; None = no reading
@property
def latest_sample(self) -> float | None: ...
@property
def min_sample(self) -> float | None: ...
@property
def max_sample(self) -> float | None: ...@dataclass
class ScheduledEventsData:
schedule_enabled: bool
events: list[ScheduledEvent]
@property
def active_events(self) -> list[ScheduledEvent]: ...@dataclass
class ScheduledEvent:
enabled: bool
days: list[int] # 0 = Monday … 6 = Sunday
start_time: str | None # "HH:MM" local time
raw: dictIf upgrading from version 0.6.x, note the following changes:
- Old (v0.6.x): Single
authenticate(otp)method - New (v0.7.0): Two-step
authenticate()→complete_authentication(otp)
# Old v0.6.x approach
client = DysonClient("user@example.com", "password")
client.authenticate("123456") # OTP required upfront
# New v0.7.0 approach
client = DysonClient("user@example.com", "password")
if not client.authenticate(): # Try without OTP first
otp = input("Enter OTP: ")
client.complete_authentication(otp)- New in v0.7.0: Full async support with
AsyncDysonClient - SSL blocking issues resolved with lazy HTTP client initialization
- Proper async context manager support
- Updated to use latest Dyson API endpoints (/v3/manifest)
- Better error handling and validation
- Enhanced device metadata support
This documentation covers the complete API surface for both synchronous and asynchronous clients. For additional examples and troubleshooting guides, see the examples/ directory in the repository.
asyncio.run(main())