Skip to main content

An asynchronous Python library for Coway IoCare Air Purifiers

Project description

pycoway

CI PyPI Python License: MIT Version

pycoway is an asynchronous Python client for the Coway IoCare API. It is designed for AIRMEGA air purifiers and exposes both state retrieval and device control through a typed, asyncio-friendly interface.

Based on RobertD502/cowayaio with active maintenance, typed models, tests, CI, and automated releases.

Features

  • Async API built on aiohttp
  • Typed dataclass models for purifier state
  • Device control: power, fan speed, light, timers, modes, button lock, and more
  • Air-quality readings: PM2.5, PM10, CO2, VOC, AQI
  • Filter health monitoring: pre-filter, MAX2, and odor filter
  • Automatic token and session management
  • Full test coverage with GitHub Actions CI
  • Automated semantic version bumping, GitHub releases, and PyPI publishing

Requirements

  • Python 3.11 or newer
  • A Coway IoCare account with at least one registered purifier

Installation

pip install pycoway

For local development:

git clone https://github.com/Antonio112009/pycoway.git
cd pycoway
pip install -e ".[dev]"

Quick Start

import asyncio

from pycoway import CowayClient


async def main() -> None:
    async with CowayClient("email@example.com", "password") as client:
        await client.login()
        data = await client.async_get_purifiers_data()

        for device_id, purifier in data.purifiers.items():
            print(f"{purifier.device_attr.name} ({device_id})")
            print(f"  Power: {'On' if purifier.is_on else 'Off'}")
            print(f"  Fan Speed: {purifier.fan_speed}")
            print(f"  PM2.5: {purifier.particulate_matter_2_5}")
            print(f"  AQI: {purifier.air_quality_index}")


asyncio.run(main())

Device Control

Every control method accepts the device_attr from a CowayPurifier instance:

import asyncio

from pycoway import CowayClient, LightMode


async def control_first_purifier() -> None:
    async with CowayClient("email@example.com", "password") as client:
        await client.login()
        data = await client.async_get_purifiers_data()

        purifier = next(iter(data.purifiers.values()))
        attr = purifier.device_attr

        await client.async_set_power(attr, is_on=True)
        await client.async_set_auto_mode(attr)
        await client.async_set_fan_speed(attr, speed="2")
        await client.async_set_light(attr, light_on=True)
        await client.async_set_light_mode(attr, LightMode.AQI_OFF)
        await client.async_set_timer(attr, time="120")


asyncio.run(control_first_purifier())

Available Control Methods

Method Parameters Description
async_set_power() is_on: bool Turn purifier on or off
async_set_auto_mode() Switch to auto mode
async_set_night_mode() Switch to night mode
async_set_eco_mode() Switch to eco mode (AP-1512HHS only)
async_set_rapid_mode() Switch to rapid mode (250s only)
async_set_fan_speed() speed: str Set fan speed: "1", "2", or "3"
async_set_light() light_on: bool Toggle light on/off (not for 250s)
async_set_light_mode() light_mode: LightMode Set light mode for advanced models
async_set_timer() time: str Off timer in minutes: "0", "60", "120", "240", "480"
async_set_smart_mode_sensitivity() sensitivity: str "1" sensitive, "2" moderate, "3" insensitive
async_set_button_lock() value: str "1" lock, "0" unlock
async_change_prefilter_setting() value: int Wash frequency: 2, 3, or 4 weeks

Data Model

async_get_purifiers_data() returns a PurifierData dataclass containing a purifiers dictionary keyed by device ID.

Each CowayPurifier includes:

Device Identity

Field Type Description
device_attr DeviceAttributes Device ID, model, name, place ID
mcu_version str | None Firmware version
network_status bool | None Network connectivity

Control State

Field Type Description
is_on bool | None Power state
auto_mode bool | None Auto mode
auto_eco_mode bool | None Auto eco mode
eco_mode bool | None Eco mode
night_mode bool | None Night mode
rapid_mode bool | None Rapid mode
fan_speed int | None Fan speed level
light_on bool | None Light state
light_mode int | None Device-specific light mode
button_lock int | None Button lock state
smart_mode_sensitivity int | None Smart mode sensitivity level
timer str | None Configured off timer
timer_remaining int | None Remaining timer (minutes)

Air Quality

Field Type Description
particulate_matter_2_5 int | None PM2.5 (μg/m³)
particulate_matter_10 int | None PM10 (μg/m³)
carbon_dioxide int | None CO₂ (ppm)
volatile_organic_compounds int | None VOC level
air_quality_index int | None AQI value
aq_grade int | None Air quality grade
lux_sensor int | None Ambient light sensor

Filter Health

Field Type Description
pre_filter_pct int | None Pre-filter remaining (%)
pre_filter_change_frequency int | None Wash frequency (weeks)
max2_pct int | None MAX2 filter remaining (%)
odor_filter_pct int | None Odor filter remaining (%)

For the complete schema, see src/pycoway/devices/models.py.

Exceptions

All exceptions inherit from CowayError:

from pycoway import AuthError, CowayError, PasswordExpired
Exception Description
CowayError Base exception for all library errors
AuthError Authentication failed
PasswordExpired Coway requires a password change
ServerMaintenance Coway API is under maintenance
RateLimited Coway temporarily blocked the account
NoPlaces No places configured in the IoCare account
NoPurifiers No air purifiers found

Migrating from cowayaio

If you're switching from the original cowayaio package:

pip uninstall cowayaio
pip install pycoway

Update your imports:

# Before
from cowayaio import CowayClient

# After
from pycoway import CowayClient

Development

git clone https://github.com/Antonio112009/pycoway.git
cd pycoway
pip install -e ".[dev]"
pytest
ruff check .
ruff format --check .

Feature work should branch from development, and pull requests merge into development first. See CONTRIBUTING.md for the full workflow.

Release Flow

  • PRs from development to main trigger the release workflow when merged
  • The workflow bumps src/pycoway/__version__.py
  • PRs to main must have exactly one version label: patch, minor, or major
  • A git tag and GitHub release are created automatically
  • The package is published to PyPI automatically

Project Structure

src/pycoway/
├── __init__.py            # Public API exports
├── __version__.py         # Version string
├── client.py              # Public CowayClient entry point
├── constants.py           # API constants
├── enums.py               # Enumerations
├── exceptions.py          # Public exception hierarchy
├── py.typed               # PEP 561 marker
├── account/
│   ├── auth.py            # Authentication (login, token refresh)
│   └── maintenance.py     # Server maintenance checks
├── devices/
│   ├── control.py         # Purifier control commands
│   ├── data.py            # Data fetching (purifiers, filters, air quality)
│   ├── models.py          # Dataclasses (CowayPurifier, PurifierData)
│   └── parser.py          # HTML/JSON response parsing
└── transport/
    └── http.py            # HTTP base client with session management

License

MIT, originally authored by RobertD502

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pycoway-1.3.0.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pycoway-1.3.0-py3-none-any.whl (23.1 kB view details)

Uploaded Python 3

File details

Details for the file pycoway-1.3.0.tar.gz.

File metadata

  • Download URL: pycoway-1.3.0.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pycoway-1.3.0.tar.gz
Algorithm Hash digest
SHA256 665ff2ba1c6ba5bd1488593a464482f3f2c1821d886a1f515b0b0081b09086ca
MD5 9da27114260bb2b19486e5691f3b0fcf
BLAKE2b-256 225e479d37e1d1b277ed5ddb2f5e99463d8e44e7b9ae9cc97e75266c1d8dfb03

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycoway-1.3.0.tar.gz:

Publisher: release.yml on Antonio112009/pycoway

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pycoway-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: pycoway-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 23.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pycoway-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8035935562ced9bdf4ef96ddd9cc744c0e07b5c3f4c5a96c35f54dc49b37b827
MD5 eed7707d20904e9aca406d6b2a4029d2
BLAKE2b-256 f4317a0ad9847590e1d12174d0406858e617ca7cb668103d1380567d8eb7aa1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pycoway-1.3.0-py3-none-any.whl:

Publisher: release.yml on Antonio112009/pycoway

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page