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.
Part of the ChuMicro family — small, focused Python libraries for microcontrollers and laptops. See all libraries.
Installation
CircuitPython (circup)
circup is CircuitPython's package manager — it 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
Want pre-compiled
.mpybytecode? Addmpy6/before the package name for faster startup and lower RAM usage on boards with mpy format v6 (MicroPython 1.24+):mpremote mip install github:ChuMicro/ChuMicro-Bundle/mpy6/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() |
Current time in milliseconds — keeps counting even when it wraps around |
ticks_diff(end, start) |
Time elapsed between two tick values (handles wraparound correctly) |
ticks_add(ticks, delta) |
Add milliseconds to a tick value (handles wraparound correctly) |
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
You don't need to pick a tick source — the library detects your runtime and uses the best one available:
| 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
Find this library
- PyPI: chumicro-timing
- Bundle: ChuMicro-Bundle (CircuitPython & MicroPython)
- Experimental bundle: ChuMicro-Bundle-Experimental
- Source: libraries/timing
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
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-0.1.23.tar.gz.
File metadata
- Download URL: chumicro_timing-0.1.23.tar.gz
- Upload date:
- Size: 6.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a9f6d194900897fc202dceccfb5ebf1e84c9074198329d2eddf04e3fa09aaf7
|
|
| MD5 |
9f72454b1c8540cac966c25aa111bf4d
|
|
| BLAKE2b-256 |
3cdf38d89b8d5a031c1bc04d382874432719545362fad846aeafa9788507ed0f
|
Provenance
The following attestation bundles were made for chumicro_timing-0.1.23.tar.gz:
Publisher:
promote.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-0.1.23.tar.gz -
Subject digest:
0a9f6d194900897fc202dceccfb5ebf1e84c9074198329d2eddf04e3fa09aaf7 - Sigstore transparency entry: 1280302247
- Sigstore integration time:
-
Permalink:
ChuMicro/ChuMicro@0ff89253c5394cac81f9b0ac140e5ea56de887d7 -
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:
promote.yml@0ff89253c5394cac81f9b0ac140e5ea56de887d7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file chumicro_timing-0.1.23-py3-none-any.whl.
File metadata
- Download URL: chumicro_timing-0.1.23-py3-none-any.whl
- Upload date:
- Size: 8.2 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 |
76789d4de390ef22c85d0106fd71e348275a5392939803c7b9d48023564d385a
|
|
| MD5 |
71562e54706d19776a999d5f0b5b0f63
|
|
| BLAKE2b-256 |
64dde50c373266583b799d11436d3fcec1139c2ad1324af7f197a78ce1a888f4
|
Provenance
The following attestation bundles were made for chumicro_timing-0.1.23-py3-none-any.whl:
Publisher:
promote.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-0.1.23-py3-none-any.whl -
Subject digest:
76789d4de390ef22c85d0106fd71e348275a5392939803c7b9d48023564d385a - Sigstore transparency entry: 1280302303
- Sigstore integration time:
-
Permalink:
ChuMicro/ChuMicro@0ff89253c5394cac81f9b0ac140e5ea56de887d7 -
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:
promote.yml@0ff89253c5394cac81f9b0ac140e5ea56de887d7 -
Trigger Event:
workflow_dispatch
-
Statement type: