Skip to main content

Build and drive CAR-TER layouts from Python — the control docs are the library.

Project description

carterkit

PyPI Downloads Python versions

Build and drive CAR-TER layouts from Python.

The control docs are the library. Every control's schema, fields, and examples are parsed at runtime from the ControlDocs markdown bundled inside the package — the exact same docs the CAR-TER app renders — so the catalog never drifts from the definitions.

pip install carterkit

Explore the controls (zero config)

import carterkit

carterkit.controls()            # {type: schema} for every placeable control
carterkit.doc("gauge")          # full parsed doc: fields, themeFields, examples
print(carterkit.doc_markdown("gauge"))   # the rendered documentation prose
carterkit.examples("button")    # documented example snippets

Build a layout

Controls are methods on the layout, ids are positional, tabs and groups are context managers, and bindings fold into kwargs. Each control method returns a handle you can use as a binding target or patch later. Unknown control types and bad enum values raise instead of silently shipping a broken layout:

from carterkit import Layout

with Layout("Dashboard", cols=4, rows=4) as ui:
    ui.connect("ws://192.168.1.50:8765", channel="home")
    with ui.tab("Main", icon="gauge"):
        cpu = ui.gauge("cpu", label="CPU", min=0, max=100, span=(2, 2),
                       listen="cpu", when={"msg_type": "metrics"})
        ui.status_light("warn", visible=cpu > 90)      # handle → visibility condition
        ui.button("refresh", label="Refresh", send="refresh", request=True)

print(ui.findings())        # schema + grid + binding lint against the bundled catalog
ui.save("dashboard.json")   # the composed layout, ready to push/load

Binding sugar: listen=/when=/event= build a sync, and send=/request=/payload= build an action; pass sync=[...]/action={...} (via carterkit.bind) for anything fancier. A handle comparison (cpu > 90) becomes a real visibility condition; ==/!= stay normal Python, so use .eq()/.neq(). help(carterkit.build.gauge) prints any control's documentation, straight from the bundled docs.

Prefer a declarative style? A class veneer compiles to the same layout — ids come from attribute names, tabs/groups are nested classes (great for fixed dashboards; the flat builder reads better for generated ones):

from carterkit.declare import Screen, Tab, Connect, Gauge, Button, StatusLight

class Dashboard(Screen, cols=4, rows=4):
    relay = Connect("ws://192.168.1.50:8765", channel="home")
    class Main(Tab, icon="gauge"):
        cpu  = Gauge(label="CPU", min=0, max=100, span=(2, 2), listen="cpu")
        warn = StatusLight(visible=cpu > 90)
        refresh = Button(label="Refresh", send="refresh", request=True)

Dashboard.save("dashboard.json")

Dynamic groups

Generate controls in for/if loops (auto-placed in the group's own grid), or mark a group dynamic="event" and replace its children live at runtime. Build that replacement payload with Fragment, then lint it against the broadcasts your server actually emits — catching events that never arrive, missing children arrays, and off-grid/invalid injected controls before they ship:

import carterkit
from carterkit import Fragment

ui.group("Now Playing", span=(3, 4), cols=4, rows=3, dynamic="player_state")

frag = Fragment(cols=4, rows=3)
frag.label("title", text="Song", span=(1, 4))
frag.button("play", label="Play", send="play")
# your server broadcasts frag.payload("player_state") == {"msg_type": ..., "children": [...]}

print(carterkit.format_findings(
    carterkit.lint_dynamic_traffic(ui.layout, [frag.payload("player_state")])))

Prefer surgical edits? LayoutBuffer gives add_control / update_control / move_control over a held draft; lay.buffer exposes it.

infer.build_layout(payload) generates a wired layout from a sample telemetry dict; codegen.generate_service_stub(layout) emits a runnable MeshSocket server skeleton; theming.theme_for(...) and tune.tune_gauge(...) round out the authoring tools.

CLI

carterkit catalog                 # list every control type
carterkit doc gauge               # print a control's documentation
carterkit examples button         # list a control's examples (--name to print one)
carterkit validate layout.json    # lint a layout (exit 1 on errors)
carterkit gen layout.json         # generate a MeshSocket service stub
carterkit relay --port 8765       # run the bundled MeshSocket relay

Drive a device

import asyncio
from carterkit import CarterClient

async def main():
    async with CarterClient(gateway_url="ws://localhost:18080", token="<mesh token>",
                            channel="home", role="device", name="my-hub") as c:
        c.on("toggle", lambda d: {"ok": True, **d})
        await c.broadcast("reading", {"temp_c": 21.4})
        await asyncio.sleep(60)
    # leaving the `async with` disconnects automatically

asyncio.run(main())

End-to-end encryption (ChaCha20-Poly1305 + per-session salt) is transparent when you pass an e2ee_key. Send a push to every device on a Connect+ account with CarterClient.notify(...) or the stdlib-only carterkit.notify_http(...).

Built on

meshsocket — the WebSocket mesh transport.

The ControlDocs are vendored from the CAR-TER app repo; refresh them with scripts/sync-controldocs.sh.

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

carterkit-0.5.1.tar.gz (100.5 kB view details)

Uploaded Source

Built Distribution

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

carterkit-0.5.1-py3-none-any.whl (116.9 kB view details)

Uploaded Python 3

File details

Details for the file carterkit-0.5.1.tar.gz.

File metadata

  • Download URL: carterkit-0.5.1.tar.gz
  • Upload date:
  • Size: 100.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for carterkit-0.5.1.tar.gz
Algorithm Hash digest
SHA256 0ea5d289c6227b191b41cf0b84e101fe4aecd737479c11ff87b09412d279d173
MD5 de2299ce31094a0429e7abce1b7c1886
BLAKE2b-256 b2cbfd2020da9639f20aa495e5a6f0569551d89050ad63433063105e44d32afe

See more details on using hashes here.

Provenance

The following attestation bundles were made for carterkit-0.5.1.tar.gz:

Publisher: publish.yml on Mariner10/carterkit

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

File details

Details for the file carterkit-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: carterkit-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 116.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for carterkit-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 62644b6cbe7ccf288499786bc41be687cafeb30524933e684dd682bfbd7afd93
MD5 e5754b2a27d700a62621baf5cec22b64
BLAKE2b-256 3fdabaa5ea951da40e2ab2f0d857d43be1b08ca4b8d6c27e59f885690e0bbef3

See more details on using hashes here.

Provenance

The following attestation bundles were made for carterkit-0.5.1-py3-none-any.whl:

Publisher: publish.yml on Mariner10/carterkit

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