libdeye
A Python library to connect to Deye 德业 Cloud and control Deye dehumidifier devices.
Supported devices:
DYD-B12A3
DYD-D50A3
DYD-D50B3
DYD-E12A3
DYD-G25A3
DYD-N20A3
DYD-L48A3
DYD-T22A3
DYD-U20A3
DYD-U20Air
DYD-V58A3
DYD-W20A3
DYD-W20A3-京鱼座
DYD-X20A3
DYD-Z12A3
DYD-Z20B3
DYD-Z20B3-天猫精灵
DYD-S12A3
DYD-F20C3
JD121EC
JD201FC
TM208FC
DY-612S
DY-620S
DY-8220C
DY-890C
DY-890T
DY-6138A
DY-8138C
DY-8158C
DY-8158T
DY-Y16A3
DY-SC60Y
DYD-P40
A10
DYD-P30
DYD-ES25A3
DYD-B13A3
DYD-RT12
DY-C65DZ/A
For devices not in the above list, consider adding your own definitions here.
Command Line Tool
This library also includes a command-line tool for testing and interacting with Deye devices.
Installation
The CLI tool is automatically installed when you install the library:
pip install libdeye
# or
uv add libdeye
Usage
# List devices (prints platform and CLASSIC / FOG / COMBO transport)
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD devices
# List all available product types
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD products
# Get device state (works for Classic, Fog, and Combo)
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD get --device-id YOUR_DEVICE_ID
# Set device state
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD set --device-id YOUR_DEVICE_ID --power on --target-humidity 50
# Set device mode and fan speed (enum names, not display labels)
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD set --device-id YOUR_DEVICE_ID --mode AUTO_MODE --fan-speed HIGH
# Set additional device features
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD set --device-id YOUR_DEVICE_ID --anion on --oscillating on --water-pump off --child-lock off
# Monitor device state changes in real-time
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD monitor --device-id YOUR_DEVICE_ID
# Get MQTT information for Classic platform
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD classic-mqtt
# Get MQTT information for Fog platform
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD fog-mqtt
# Enable debug logging
deye-cli --debug --username YOUR_USERNAME --password YOUR_PASSWORD devices
# Print authentication token (useful for saving to .env file)
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD print-token
# Force refresh the authentication token
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD refresh-token
Using Environment Variables and .env Files
Credentials can be provided via command-line arguments, process environment variables, or a .env file. Precedence (highest to lowest):
Command-line arguments (--username, --password, --token, --device-id)
Process environment variables (DEYE_USERNAME, DEYE_PASSWORD, …)
Values from a .env file
This matches the default behavior of python-dotenv and 12-factor app conventions: .env is a local default, and already-set environment variables are not overwritten.
You can export variables in your shell:
export DEYE_USERNAME=your_username
export DEYE_PASSWORD=your_password
deye-cli devices
Or store them in a .env file to avoid typing them in each command:
# Create a .env file in your working directory
echo "DEYE_USERNAME=your_username" > .env
echo "DEYE_PASSWORD=your_password" >> .env
# Now you can run commands without specifying credentials
deye-cli devices
# You can also specify a different .env file location
deye-cli --env-file /path/to/your/.env devices
The supported variable names (used by both the environment and .env files) are:
DEYE_USERNAME=your_phone_number_or_username
DEYE_PASSWORD=your_password
# Optional: store auth token to avoid login each time
DEYE_AUTH_TOKEN=your_auth_token
# Optional: default device for get / set / monitor
DEYE_DEVICE_ID=your_device_id
With DEYE_DEVICE_ID configured, you can omit --device-id:
# Get device state without specifying device-id
deye-cli get
# Set device state without specifying device-id
deye-cli set --power on --target-humidity 50
# Monitor device state changes
deye-cli monitor
Getting and Using Authentication Tokens
To avoid sending your username and password with each request, you can use an authentication token:
# Get your authentication token
deye-cli --username YOUR_USERNAME --password YOUR_PASSWORD print-token
# Copy the token and add it to your .env file
echo "DEYE_AUTH_TOKEN=your_token_here" >> .env
# Now you can use the token instead of username/password
deye-cli devices
# If your token expires, you can refresh it
deye-cli --token YOUR_TOKEN refresh-token
Available Commands
devices: List devices on the account, including IoT platform and command transport (CLASSIC, FOG, or COMBO)
products: List all available product types
get: Query current state via DeyeClient (Classic MQTT poll, Fog HTTP GET, or Combo MQTT poll)
set: Send a command via DeyeClient.apply (power, mode, fan speed, humidity, anion, water pump, oscillating, child lock, plus optional Fog sleep / UV / temperature / prompt sound / screen display / timed-off hour)
monitor: Subscribe to MQTT state and availability updates
print-token: Print the authentication token for use in .env file
refresh-token: Force refresh the authentication token
classic-mqtt: Get MQTT broker credentials for Classic / Combo devices
fog-mqtt: Get MQTT broker credentials for Fog devices (inbound state only; Fog commands use HTTP)
set --mode and set --fan-speed take DeyeDeviceMode / DeyeFanSpeed enum names, for example MANUAL_MODE, CLOTHES_DRYER_MODE, AUTO_MODE, LOW, HIGH. Humidity range depends on the product (often 25-80 or 26-90).
For more options, run:
deye-cli --help
Public API
Callers use DeyeClient and DeyeDevice. The library selects Classic MQTT, Fog HTTP, or Combo MQTT from each device-list entry. Do not construct platform MQTT clients yourself.
Call refresh() or ensure_connected() before subscribe(). Send commands with device.apply(command, baseline=...). Fog devices with cached ProtocolVersion == 0 send the official companion snapshot for each changed property (not a union of every cached key); otherwise only changed fields are posted.
DeyeDeviceCommand.to_json matches official FogDeviceManager.sendCommand: every PropertyParam Integer is skipped when null, including child lock and anion. Unset library fields stay None and are omitted. Classic to_bytes treats unset switches as off.
The product JSON (uvLight, tone, displayScreen, hasDelayer) only shows or hides those controls, the same way it gates anion and oscillating. Use get_product_feature_config (uv, prompt_sound, screen_display, timed_off) to decide whether a product advertises them.
Fog GET and device-list payloads may omit any Fog key. Optional controls stay None and are not posted. Diagnostic flags Demisting, WaterTank, and Fan default to off. ProtocolVersion == 0 companions copy cached non-null Integers for that command’s official key set (display, tone, and timer stay single-key). Sleep is DeyeDeviceMode.SLEEP_MODE. to_json_diff treats omitted keys as absent on the baseline, so the first set value is published without the caller inventing a placeholder.
import asyncio
import aiohttp
from libdeye import DeyeClient
async def main() -> None:
async with aiohttp.ClientSession() as session:
client = DeyeClient.from_credentials(
session, "<phone_number>", "<password>"
)
await client.authenticate()
devices = await client.list_devices()
if not devices:
print("No devices found")
return
device = devices[0]
print(f"Device: {device.name} (ID: {device.device_id})")
print(f"Transport: {device.transport.name}")
state = await device.refresh()
print(
f"Current humidity: {state.environment_humidity}% "
f"(Target: {state.target_humidity}%)"
)
def on_state_update(state) -> None:
print(
f"Device state updated. Current humidity: "
f"{state.environment_humidity}%"
)
unsubscribe = device.subscribe(on_state=on_state_update)
command = state.to_command()
command.target_humidity = 40
await device.apply(command, baseline=state)
await asyncio.sleep(30)
unsubscribe()
client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
Metadata
Release files for libdeye 3.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| libdeye-3.0.3.tar.gz | 842.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| libdeye-3.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 873.3 kB
Release files / libdeye-3.0.3.tar.gz
| Download URL | libdeye-3.0.3.tar.gz |
|---|---|
| Size | 842.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
627fa36e0decefbb9cfb86c03c1d9845e38f6518c1d29913ebeaf858a45de223
|
|
BLAKE2b-256 checksum How to use checksums |
cb8c126f7f695055cbab0e54e8dbc673dcc25b8991ad72e5ae935c77fa1edab3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / libdeye-3.0.3-py3-none-any.whl
| Download URL | libdeye-3.0.3-py3-none-any.whl |
|---|---|
| Size | 30.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7783a1249c6f0a4f9b9643c98896d227b0b0ccf6c73fb17a377931ac2487fad7
|
|
BLAKE2b-256 checksum How to use checksums |
9ced8d85e5650c5a365c625d3d68e44e88e6e7b24c732d21b5c53da35fafbcb3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|