Enhanced Philips air purifier library with Home Assistant integration, device discovery, and setup wizard
Project description
philips-airctrl
Async Python library and CLI for controlling Philips air purifiers over encrypted CoAP. Includes network discovery, device data extraction, and an interactive setup wizard for collecting device information to help expand Home Assistant integration support.
Features
- Device Discovery -- Scan your local network to find Philips air purifiers automatically
- Device Data Extraction -- Read 70+ data points including sensors, controls, and capabilities
- Interactive Setup Wizard -- Guided collection of device info for sharing with integration developers
- Multiple Export Formats -- JSON and YAML output
- Async/Await -- Built on
aiocoapwith full async support - Encrypted CoAP -- AES-CBC encrypted communication with the device
- Real-time Monitoring -- Observe device status changes as they happen
Supported Devices
Tested with:
- Philips AC4220/12
- Other Philips air purifiers using the CoAP protocol
Installation
From Source
git clone https://github.com/domalab/philips-airctrl.git
cd philips-airctrl
uv sync
With pip
git clone https://github.com/domalab/philips-airctrl.git
cd philips-airctrl
pip install .
Development
uv sync --extra dev
uv run pre-commit install
Quick Start
Discover Devices
# Scan all local networks
philips-airctrl discover
# Scan a specific subnet
philips-airctrl discover -n 192.168.1.0/24
# Increase timeout for slow networks
philips-airctrl discover -t 10.0
Example output:
Discovering Philips air purifiers on the network...
Scanning networks: 192.168.1.0/24
Found 1 device(s):
+----------------+-----------+---------+----------+-------------+
| IP Address | Model | Name | Firmware | WiFi Signal |
+================+===========+=========+==========+=============+
| 192.168.1.100 | AC4220/12 | Bedroom | 0.2.1 | -52 dBm |
+----------------+-----------+---------+----------+-------------+
Control a Device
# Get current status
philips-airctrl status -H 192.168.1.100
# Get status as JSON
philips-airctrl status -H 192.168.1.100 --json
# Set device parameters
philips-airctrl set -H 192.168.1.100 power=true mode=auto
# Monitor status changes in real-time
philips-airctrl status-observe -H 192.168.1.100
Extract Device Information
# JSON output (default)
philips-airctrl device-info -H 192.168.1.100
# YAML output
philips-airctrl device-info -H 192.168.1.100 -f yaml
# Save to file
philips-airctrl device-info -H 192.168.1.100 -o device_report.json
Interactive Setup Wizard
The wizard walks you through discovery, analysis, and export:
philips-airctrl setup
This will:
- Discover devices on your network
- Analyse capabilities and extract technical specifications
- Generate JSON, YAML, and summary reports in
~/philips_airpurifier_config/
Library Usage
import asyncio
from philips_airctrl import CoAPClient
async def main():
client = await CoAPClient.create(host="192.168.1.100")
try:
# Read current status
status, max_age = await client.get_status()
print(status)
# Set controls
await client.set_control_values(data={"power": True, "mode": "auto"})
# Observe real-time updates
async for update in client.observe_status():
print(update)
break
finally:
await client.shutdown()
asyncio.run(main())
Discovery API
import asyncio
from philips_airctrl.discovery import DeviceDiscovery
async def main() -> None:
discovery = DeviceDiscovery(timeout=5.0)
devices = await discovery.discover_devices()
for device in devices:
print(f"{device.name} ({device.model}) at {device.ip}")
asyncio.run(main())
Device Info API
import asyncio
from philips_airctrl.device_info import DeviceInfoExtractor
async def main() -> None:
extractor = DeviceInfoExtractor("192.168.1.100")
report = await extractor.get_device_info()
print(extractor.export_json(report, pretty=True))
print(extractor.export_yaml(report))
asyncio.run(main())
CLI Reference
philips-airctrl [-D] <command> [options]
Global options:
-D, --debug Enable debug logging
Commands:
discover Find devices on the network
-n, --network CIDR Subnet to scan (e.g. 192.168.1.0/24)
-t, --timeout SECONDS Discovery timeout (default: 5.0)
status -H HOST Get device status
-H, --host HOST Device IP address (required)
-P, --port PORT CoAP port (default: 5683)
-J, --json Output as JSON
status-observe -H HOST Stream real-time status updates
-H, --host HOST Device IP address (required)
-P, --port PORT CoAP port (default: 5683)
-J, --json Output as JSON
set -H HOST K=V [K=V ..] Set device parameters
-H, --host HOST Device IP address (required)
-P, --port PORT CoAP port (default: 5683)
-I, --int Encode values as integers
device-info -H HOST Extract comprehensive device data
-H, --host HOST Device IP address (required)
-P, --port PORT CoAP port (default: 5683)
-f, --format FMT json or yaml (default: json)
-o, --output FILE Write to file instead of stdout
setup Interactive setup wizard
Helping Expand Device Support
The device-info and setup commands produce technical reports that developers use to add support for new air purifier models in Home Assistant integrations.
This tool does not generate ready-to-use Home Assistant configurations. It extracts raw device data for integration developers.
To contribute:
- Run
philips-airctrl setupand follow the prompts - Open an issue in the relevant integration repo (e.g. ha-philips-airpurifier)
- Attach the generated JSON file and include your device model number
Project Structure
philips-airctrl/
src/philips_airctrl/ # Package source (src layout)
_version.py # Single source of truth for version
cli.py # CLI entry point
models.py # Pydantic v2 data models
discovery.py # Network device discovery
device_info.py # Device data extraction
setup_wizard.py # Interactive setup wizard
coap/ # CoAP protocol layer
client.py # Async CoAP client
encryption.py # AES-CBC encryption
tests/ # Test suite (100% coverage)
pyproject.toml # Project metadata and tool config
Development
# Install dev dependencies
uv sync --extra dev
# Run tests
uv run pytest
# Lint and format
uv run ruff check src/ tests/
uv run ruff format src/ tests/
# Security scan
uv run bandit -c pyproject.toml -r src/
# Run all pre-commit hooks
uv run pre-commit run --all-files
Protocol Details
Communication uses CoAP (Constrained Application Protocol) over UDP port 5683 with:
- AES-CBC encryption with PKCS7 padding
- SHA-256 digest verification
- Custom key exchange/sync protocol
Troubleshooting
No devices found -- Ensure the purifier is on the same network, powered on, and connected to WiFi. Try -n 192.168.1.0/24 to specify a subnet, or increase the timeout with -t 10.0.
Connection refused -- Verify the IP, check that your firewall allows UDP on port 5683, and confirm the device is on the same network segment.
Timeout errors -- Check connectivity, increase timeouts, and verify the device is not in sleep mode.
Debug mode -- Add -D to any command for verbose protocol logging:
philips-airctrl -D status -H 192.168.1.100
License
MIT -- see LICENSE.
Acknowledgments
- Original implementation by betaboon
- CoAP protocol via aiocoap
- Encryption via pycryptodomex
Changelog
See CHANGELOG.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file philips_airctrl-1.0.0.tar.gz.
File metadata
- Download URL: philips_airctrl-1.0.0.tar.gz
- Upload date:
- Size: 85.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
323820267689b78107e831394634a332590c36a8a9c590c145a0862169825ee8
|
|
| MD5 |
f6268f5f5cc27d008a9e4fff0b330294
|
|
| BLAKE2b-256 |
1d572273249ae364f20b41343edd5cc4e8178e47227fb893790d55de7de8efc6
|
Provenance
The following attestation bundles were made for philips_airctrl-1.0.0.tar.gz:
Publisher:
publish.yml on ruaan-deysel/philips-airctrl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
philips_airctrl-1.0.0.tar.gz -
Subject digest:
323820267689b78107e831394634a332590c36a8a9c590c145a0862169825ee8 - Sigstore transparency entry: 947078493
- Sigstore integration time:
-
Permalink:
ruaan-deysel/philips-airctrl@be0a733c0c6cc9317c771275b65f0a550cada235 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/ruaan-deysel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@be0a733c0c6cc9317c771275b65f0a550cada235 -
Trigger Event:
release
-
Statement type:
File details
Details for the file philips_airctrl-1.0.0-py3-none-any.whl.
File metadata
- Download URL: philips_airctrl-1.0.0-py3-none-any.whl
- Upload date:
- Size: 23.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92b4092374fd9df0033686b259739bb772322ca20c7218322507d805805000c0
|
|
| MD5 |
13d13113a55cb2ee8a942895b8d45059
|
|
| BLAKE2b-256 |
35b1512b3fabc716f6bc379bf2d4fb6a47b5232aa9c6da37b48b49e78301b597
|
Provenance
The following attestation bundles were made for philips_airctrl-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on ruaan-deysel/philips-airctrl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
philips_airctrl-1.0.0-py3-none-any.whl -
Subject digest:
92b4092374fd9df0033686b259739bb772322ca20c7218322507d805805000c0 - Sigstore transparency entry: 947078498
- Sigstore integration time:
-
Permalink:
ruaan-deysel/philips-airctrl@be0a733c0c6cc9317c771275b65f0a550cada235 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/ruaan-deysel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@be0a733c0c6cc9317c771275b65f0a550cada235 -
Trigger Event:
release
-
Statement type: