Wraparound-safe millisecond tick helpers and heartbeat scheduling for CircuitPython, MicroPython, and CPython.
Project description
chumicro-timing
Non-blocking timers that handle millisecond wraparound for you.
Capture ticks_ms() once per loop, hand it to a Heartbeat, and you've got clean periodic timing — no time.sleep(), no wraparound bugs. Works on CircuitPython, MicroPython, and CPython.
Installation
CircuitPython (circup)
circup uses bundles to find third-party packages — register the ChuMicro bundle once, then install by name:
circup bundle-add ChuMicro/ChuMicro-Bundle
circup install chumicro-timing
MicroPython (mip)
mpremote mip install github:ChuMicro/ChuMicro-Bundle/chumicro_timing
CPython (pip)
pip install chumicro-timing
Experimental (pre-release) versions and channel switching
Pre-release builds are published automatically when a library version is bumped. Do not register both bundles simultaneously — circup may pick either version for a given package.
# CircuitPython — switch to experimental
circup bundle-remove ChuMicro/ChuMicro-Bundle # skip if never added
circup bundle-add ChuMicro/ChuMicro-Bundle-Experimental
circup install chumicro-timing
# MicroPython
mpremote mip install github:ChuMicro/ChuMicro-Bundle-Experimental/chumicro_timing
# CPython
pip install chumicro-timing-experimental
Quick example
from chumicro_timing import Heartbeat, ticks_ms
heartbeat = Heartbeat(period_ms=1000)
while True:
now = ticks_ms()
if heartbeat.poll(now):
print("one second elapsed")
# ... do other work ...
What's included
Tick functions
| Symbol | Description |
|---|---|
ticks_ms() |
Monotonic millisecond counter, wraps every ~6.2 days |
ticks_diff(end, start) |
Wraparound-safe signed difference |
ticks_add(ticks, delta) |
Wraparound-safe addition |
Heartbeat
| Symbol | Description |
|---|---|
Heartbeat(period_ms, ticks=None) |
Periodic timer that fires once per elapsed period |
Heartbeat.poll(now_ms) |
Returns True once per period and advances the timer |
Heartbeat.is_due(now_ms) |
Check whether the period has elapsed (without advancing) |
Heartbeat.reset(now_ms) |
Restart the timer from the given timestamp |
Heartbeat.period_ms |
The configured period (read-only property) |
Testing
| Symbol | Description |
|---|---|
FakeTicks(start_ms=0) |
Deterministic tick source for host-side tests |
FakeTicks.advance(amount_ms) |
Move the fake clock forward |
Related libraries
For structured task scheduling with multiple services, see runner. Runner is built on timing — it captures ticks_ms() once per tick and dispatches services on a shared timestamp.
Platform support
The tick source is selected automatically at import time:
| Priority | Source | Runtime |
|---|---|---|
| 1 | supervisor.ticks_ms |
CircuitPython 7+ |
| 2 | time.ticks_ms |
MicroPython, some CircuitPython builds |
| 3 | time.monotonic_ns |
CPython, some CircuitPython boards |
| 4 | time.monotonic |
Final fallback (float seconds → int ms) |
All sources are masked to a 2²⁹ ms period, so behavior is identical regardless of which source is used.
Testing your code
The chumicro_timing.testing module provides FakeTicks for deterministic host-side tests — no wall-clock waits:
from chumicro_timing import Heartbeat
from chumicro_timing.testing import FakeTicks
fake = FakeTicks()
heartbeat = Heartbeat(period_ms=100, ticks=fake)
now = fake.ticks_ms()
assert heartbeat.poll(now) is False
fake.advance(100)
now = fake.ticks_ms()
assert heartbeat.poll(now) is True
Examples
| Example | What it shows |
|---|---|
heartbeat_blink.py |
Basic periodic timer loop |
multiple_heartbeats.py |
Multiple heartbeats at different rates |
timeout_check.py |
One-shot timeout using is_due |
debounce.py |
Simulated button debounce |
periodic_tick.py |
Manual periodic loop (what Heartbeat does under the hood) |
circuitpython_blink.py |
LED blink on CircuitPython hardware |
circuitpython_debounce.py |
GPIO button debounce on CircuitPython |
micropython_blink.py |
LED blink on MicroPython hardware |
micropython_debounce.py |
GPIO button debounce on MicroPython |
Docs
📖 Stable docs · Experimental docs
Browse on GitHub:
- User guide — getting started, usage patterns, platform notes
- API reference — full API documentation
- Testing helpers — using
FakeTicksin your tests
Find this library
- PyPI: chumicro-timing
- Bundle: ChuMicro-Bundle (CircuitPython & MicroPython)
- Source: ChuMicro/ChuMicro — cross-runtime Python libraries for ESP32, RP2040, and other microcontrollers.
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 chumicro_timing_experimental-0.1.16.tar.gz.
File metadata
- Download URL: chumicro_timing_experimental-0.1.16.tar.gz
- Upload date:
- Size: 6.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ecf8392fa28961add412dd0913000b56addc9726fdd541e720eec784649b66a
|
|
| MD5 |
e61bcf1c0190e30366674ccb44502d08
|
|
| BLAKE2b-256 |
27654522664dd8ccaaca2aecaea5f6c7e6458793067af139a8e587b4f471ace7
|
Provenance
The following attestation bundles were made for chumicro_timing_experimental-0.1.16.tar.gz:
Publisher:
release.yml on ChuMicro/ChuMicro
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
chumicro_timing_experimental-0.1.16.tar.gz -
Subject digest:
7ecf8392fa28961add412dd0913000b56addc9726fdd541e720eec784649b66a - Sigstore transparency entry: 1268332620
- Sigstore integration time:
-
Permalink:
ChuMicro/ChuMicro@864f331c3a0c15b97f806687cd60836ff6adfe0e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ChuMicro
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@864f331c3a0c15b97f806687cd60836ff6adfe0e -
Trigger Event:
push
-
Statement type:
File details
Details for the file chumicro_timing_experimental-0.1.16-py3-none-any.whl.
File metadata
- Download URL: chumicro_timing_experimental-0.1.16-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1658e71a736435e41ac2d8b1db668b4cc0fb40a9f9f48f334775ef990c929e9
|
|
| MD5 |
2e93ad20f33391b6e9474531e216349c
|
|
| BLAKE2b-256 |
c9862785938f21ee109bd4a475de2c22904493684a6327f31fea010c5877fb3e
|
Provenance
The following attestation bundles were made for chumicro_timing_experimental-0.1.16-py3-none-any.whl:
Publisher:
release.yml on ChuMicro/ChuMicro
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
chumicro_timing_experimental-0.1.16-py3-none-any.whl -
Subject digest:
c1658e71a736435e41ac2d8b1db668b4cc0fb40a9f9f48f334775ef990c929e9 - Sigstore transparency entry: 1268332687
- Sigstore integration time:
-
Permalink:
ChuMicro/ChuMicro@864f331c3a0c15b97f806687cd60836ff6adfe0e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/ChuMicro
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@864f331c3a0c15b97f806687cd60836ff6adfe0e -
Trigger Event:
push
-
Statement type: