libpurecool’s documentation

https://api.travis-ci.org/etheralm/libpurecool.svg?branch=master https://coveralls.io/repos/github/etheralm/libpurecool/badge.svg?branch=master https://img.shields.io/pypi/v/libpurecool.svg

This Python 3.4+ library allow you to control Dyson fan/purifier devices and Dyson 360 Eye robot vacuum device.

Status

Backward compatibility is a goal but breaking changes can still happen.

Discovery is not fully reliable yet. It’s working most of the time but sometimes discovery will not work. Manual configuration is available to bypass this limitation.

Supported devices

  • Dyson pure cool tower (TP04)
  • Dyson pure cool desk (DP04)
  • Dyson pure cool link devices (Tower and Desk)
  • Dyson Cool+Hot devices (HP02 and HP04)
  • Dyson 360 Eye robot vacuum

Features

Commands

The following commands are supported:

  • Purifier/fan devices
    • Connect to the device using discovery or manually with IP Address
    • Turn on/off
    • Set speed
    • Turn on/off oscillation
    • Adjust oscillation angle (TP04/DP04)
    • Set Auto mode
    • Set night mode
    • Set sleep timer
    • Set Air Quality target (Normal, High, Better)
    • Enable/disable standby monitoring (the device continue to update sensors when in standby)
    • Reset filter life
  • Cool+Hot purifier/fan devices
    • Set heat mode
    • Set heat target
    • Set fan focus mode (HP02)
  • 360 Eye device
    • Set power mode (Quiet/Max)
    • Start cleaning
    • Pause cleaning
    • Resume cleaning
    • Abort cleaning

Sensors

The following sensors are available for fan/purifier devices:

  • Humidity
  • Temperature in Kelvin
  • Dust (unknown metric)
  • Air Quality (unknown metric)

Usage

Installation

pip install libpurecool

Dyson account

In order to access the devices, you need to have access to a valid Dyson account.

from libpurecool.dyson import DysonAccount

# Log to Dyson account
# Language is a two characters code (eg: FR)
dyson_account = DysonAccount("<dyson_account_email>","<dyson_account_password>","<language>")
logged = dyson_account.login()

Fan/Purifier devices

Connect to devices

After login to the Dyson account, known devices are available.

Connections to the devices can been done automatically using mDNS or manually with specifying IP address

Automatic connection (mDNS)
from libpurecool.dyson import DysonAccount

# Log to Dyson account
# Language is a two characters code (eg: FR)
dyson_account = DysonAccount("<dyson_account_email>","<dyson_account_password>","<language>")
logged = dyson_account.login()

if not logged:
    print('Unable to login to Dyson account')
    exit(1)

# List devices available on the Dyson account
devices = dyson_account.devices()

# Connect using discovery to the first device
connected = devices[0].auto_connect()

# connected == device available, state values are available, sensor values are available
Manual connection
from libpurecool.dyson import DysonAccount

# Log to Dyson account
# Language is a two characters code (eg: FR)
dyson_account = DysonAccount("<dyson_account_email>","<dyson_account_password>","<language>")
logged = dyson_account.login()

if not logged:
    print('Unable to login to Dyson account')
    exit(1)

# List devices available on the Dyson account
devices = dyson_account.devices()

# Connect using discovery to the first device
connected = devices[0].connect("192.168.1.2")

# connected == device available, state values are available, sensor values are available

Disconnect from the device

Disconnection is required for fan/purifier devices in order to release resources (an internal thread is started to request update notifications)

from libpurecool.dyson import DysonAccount

# ... connection do dyson account and to device ... #

# Disconnect
devices[0].disconnect()

Send commands

After connected to the device, commands cand be send in order to update the device configuration

from libpurecool.dyson import DysonAccount
from libpurecool.const import FanSpeed, FanMode, NightMode, Oscillation, \
    FanState, StandbyMonitoring, QualityTarget, ResetFilter, HeatMode, \
    FocusMode, HeatTarget

# ... connection do dyson account and to device ... #

# Turn on the fan to speed 2
devices[0].set_configuration(fan_mode=FanMode.FAN, fan_speed=FanSpeed.FAN_SPEED_2)

# Turn on oscillation
devices[0].set_configuration(oscillation=Oscillation.OSCILLATION_ON)

# Turn on night mode
devices[0].set_configuration(night_mode=NightMode.NIGHT_MODE_ON)

# Set 10 minutes sleep timer
devices[0].set_configuration(sleep_timer=10)

# Disable sleep timer
devices[0].set_configuration(sleep_timer=0)

# Set quality target (for auto mode)
devices[0].set_configuration(quality_target=QualityTarget.QUALITY_NORMAL)

# Disable standby monitoring
devices[0].set_configuration(standby_monitoring=StandbyMonitoring.STANDBY_MONITORING_OFF)

# Reset filter life
devices[0].set_configuration(reset_filter=ResetFilter.RESET_FILTER)

## Cool+Hot devices only
# Set Heat mode
devices[0].set_configuration(heat_mode=HeatMode.HEAT_ON)
# Set heat target
devices[0].set_configuration(heat_target=HeatTarget.celsius(25))
devices[0].set_configuration(heat_target=HeatTarget.fahrenheit(70))
# Set fan focus mode
devices[0].set_configuration(focus_mode=FocusMode.FOCUS_ON)

# Everything can be mixed in one call
devices[0].set_configuration(sleep_timer=10,
    fan_mode=FanMode.FAN,
    fan_speed=FanSpeed.FAN_SPEED_5,
    night_mode=NightMode.NIGHT_MODE_OFF,
    standby_monitoring=StandbyMonitoring.STANDBY_MONITORING_ON,
    quality_target=QualityTarget.QUALITY_HIGH)

States and sensors

States and sensors values are available using state and environmental_state properties

States values

# ... imports ... #

# ... connection do dyson account and to device ... #

print(devices[0].state.speed)
print(devices[0].state.oscillation)
# ... #

Environmental values

# ... imports ... #

# ... connection do dyson account and to device ... #

print(devices[0].environmental_state.humidity)
print(devices[0].environmental_state.sleep_timer)
# ... #

All properties are available in the sources.

Notifications

You can register to any values changed by using a callback function

# ... imports ... #
from libpurecool.dyson_pure_state import DysonPureHotCoolState, \
  DysonPureCoolState, DysonEnvironmentalSensorState

# ... connection do dyson account and to device ... #
def on_message(msg):
    # Message received
    if isinstance(msg, DysonPureCoolState):
        # Will be true for DysonPureHotCoolState too.
        print("DysonPureCoolState message received")
    if isinstance(msg, DysonPureHotCoolState):
        print("DysonPureHotCoolState message received")
    if isinstance(msg, DysonEnvironmentalSensorState)
        print("DysonEnvironmentalSensorState received")
    print(msg)

devices[0].connect("192.168.1.2")
devices[0].add_message_listener(on_message)

360 Eye robot vacuum

Connect to devices

After login to the Dyson account, known devices are available.

Auto discovery is not yet supported.

Manual connection
from libpurecool.dyson import DysonAccount

# Log to Dyson account
# Language is a two characters code (eg: FR)
dyson_account = DysonAccount("<dyson_account_email>","<dyson_account_password>","<language>")
logged = dyson_account.login()

if not logged:
    print('Unable to login to Dyson account')
    exit(1)

# List devices available on the Dyson account
devices = dyson_account.devices()

# Connect using discovery to the first device
connected = devices[0].connect("192.168.1.2")

# connected == device available, state values are available, sensor values are available

Send commands

After connected to the device, commands cand be send in order to update the device configuration.

import time
from libpurecool.dyson import DysonAccount
from libpurecool.const import PowerMode

# ... connection do dyson account and to device ... #

# Set power mode
devices[0].set_power_mode(PowerMode.QUIET)
devices[0].set_power_mode(PowerMode.MAX)

# Start cleaning
devices[0].start

time.sleep(30)

# Pause cleaning
devices[0].pause()

time.sleep(30)

# Resume cleaning
devices[0].resume()

time.sleep(30)

# Abort cleaning (device return to the base)
devices[0].abort()

States

State values are available using state property.

# ... imports ... #

# ... connection do dyson account and to device ... #

print(devices[0].state.state)
print(devices[0].state.full_clean_type)
print(devices[0].state.position)
print(devices[0].state.power_mode)
print(devices[0].state.battery_level)
print(devices[0].state.clean_id)
# ... #

All properties are available in the sources.

Notifications

You can register to any values changed by using a callback function

# ... imports ... #
from libpurecool.dyson_360_eye import Dyson360EyeState, \
  Dyson360EyeTelemetryData, Dyson360EyeMapData, Dyson360EyeMapGrid, \
  Dyson360EyeMapGlobal

# ... connection do dyson account and to device ... #
def on_message(msg):
    # Message received
    if isinstance(msg, Dyson360EyeState):
        print("Dyson360EyeState message received")
    if isinstance(msg, Dyson360EyeTelemetryData)
        print("Dyson360EyeTelemetryData received")
    if isinstance(msg, Dyson360EyeMapData)
        print("Dyson360EyeMapData received")
    if isinstance(msg, Dyson360EyeMapGrid)
        print("Dyson360EyeMapGrid received")
    if isinstance(msg, Dyson360EyeMapGlobal)
        print("Dyson360EyeMapGlobal received")
    print(msg)

devices[0].connect()
devices[0].add_message_listener(on_message)

How it’s working

Dyson devices use many different protocols in order to work:

  • HTTPS to Dyson API in order to get devices informations (credentials, historical data, etc …)
  • MDNS to discover devices on the local network
  • MQTT (with auth) to get device status and send commands

To my knowledge, no public technical information about API/MQTT are available so all the work is done by testing and a lot of properties are unknown to me at this time.

This library come with a modified version of Zeroconf because Dyson MDNS implementation is not valid.

This documentation help me to understand some of return values.

Work to do

  • Better protocol understanding
  • Better technical documentation on how it is working
  • Get historical data from the API (air quality, etc …)

Contributors

Thanks to all the wonderful folks who have contributed to Libpurecool: