Skip to main content

Pure-Python BLE library for the Qingping CGD1 alarm clock

Project description

qingping-cgd1

Local BLE control for the Qingping CGD1 "Dove" alarm clock. Pure Python, no cloud. Not affiliated with Qingping.

Install

pip install qingping-cgd1

Requires Python 3.14.2+. Depends only on bleak and bleak-retry-connector.

Passive sensor reading

Temperature, humidity, and battery ride in the BLE advertisement, so you can read them without connecting to the device:

from qingping_cgd1 import parse_advertisement

reading = parse_advertisement(service_data)  # the 0xfdcd service-data bytes
if reading is not None:
    print(reading.temperature, reading.humidity, reading.battery)

Active control

Everything else - settings, alarms, time sync - needs a connection, authenticated with a bleak BLEDevice:

from qingping_cgd1 import Alarm, QingpingCGD1Client, Weekday

async with QingpingCGD1Client(ble_device) as client:
    settings = await client.read_settings()
    await client.write_settings(settings)

    alarms = await client.read_alarms()
    await client.write_alarm(0, Alarm(
        enabled=True,
        hour=7,
        minute=30,
        days=frozenset({Weekday.MONDAY, Weekday.TUESDAY}),
        snooze=True,
    ))
    await client.delete_alarm(1)

    await client.sync_time()
    info = await client.read_firmware()

QingpingCGD1Client also has explicit connect()/disconnect() methods if you'd rather not use it as a context manager. It authenticates with a 16-byte token (overridable via the token argument, default DEFAULT_AUTH_TOKEN), retries a timed-out command once after a reconnect, and disconnects automatically after disconnect_delay seconds of inactivity (default 120s).

Working out the next alarm

next_alarm takes the list from read_alarms() and a reference time, and returns the soonest upcoming fire time (or None if nothing is enabled):

from datetime import datetime

from qingping_cgd1 import next_alarm

upcoming = next_alarm(alarms, datetime.now())

Protocol notes

This library is reverse-engineered, not an official SDK. The protocol was mapped mainly by MrBoombastic/clOwOck, an Android app for the CGD1; this is a Python port of that work. A few things worth knowing before you rely on it:

  • There are no checksums on the wire. Frames are fixed-layout and unvalidated by the device beyond their length.
  • The 16-byte auth token is a per-device pairing secret, not a universal key. A clock that's already paired (for example, one that's been used with the official Qingping+ app) will reject the default token: the device answers auth step 2 with 04 ff 02 00 01 (fail). You need to unbind/reset the clock first - long-press its button until the Bluetooth icon flashes, or remove it in the Qingping+ app - after which it binds to the first token it's presented with. This library presents its default token, and from then on that token authenticates every time. The token is injectable via the token argument if you'd rather manage pairing secrets yourself.
  • The 0xfdcd advertisement layout (model | mac | temperature | humidity | battery) is confirmed from a real CGD1 capture (firmware 1.0.1_0130): decoding it gave 20.0 C / 51.7% / 80%, matching the device's own display. There are still two unknown/reserved byte pairs in the frame whose meaning isn't established.

Scope

Covers passive sensor reading from advertisements, settings read/write, all 16 alarm slots, and time sync. Ringtone upload is not implemented.

How this was built

Built largely with AI assistance (Claude) and tested against a real CGD1 (firmware 1.0.1_0130). Tested and working, but a spare-time project - no warranty, no support promises.

Licence

MIT.

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

qingping_cgd1-0.1.0.tar.gz (50.1 kB view details)

Uploaded Source

Built Distribution

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

qingping_cgd1-0.1.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file qingping_cgd1-0.1.0.tar.gz.

File metadata

  • Download URL: qingping_cgd1-0.1.0.tar.gz
  • Upload date:
  • Size: 50.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for qingping_cgd1-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2b784c7a6077703c618b119f9d82b33c9fdb8b495d801b24d6970a267b57fe8b
MD5 21a00dceb06ad37083a86ba8241b3cd8
BLAKE2b-256 1bdc79886d3205bd78340c99c9ae4a462058882c22ac1f05c4f59b593a0778de

See more details on using hashes here.

Provenance

The following attestation bundles were made for qingping_cgd1-0.1.0.tar.gz:

Publisher: release.yml on rjocoleman/qingping-cgd1

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

File details

Details for the file qingping_cgd1-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: qingping_cgd1-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for qingping_cgd1-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c885f526f6da8749f6cdf9b81465e2aa39f8c00b201979629ecc096ae5ac5c5b
MD5 5c327a6a783a1ea6bd5840f578847fde
BLAKE2b-256 8c3e4f7618a208024d216bb2276d0c2392f7f57e826f0fdc2b31450e15b7efaa

See more details on using hashes here.

Provenance

The following attestation bundles were made for qingping_cgd1-0.1.0-py3-none-any.whl:

Publisher: release.yml on rjocoleman/qingping-cgd1

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