atech-sdk
v0.2.0
Published
TypeScript SDK + firmware-build toolchain for Atech motherboards. Discover modules, generate, compile, and flash firmware from Node — or talk to a board over WebSocket, USB serial, or Web Serial.
Downloads
36
Maintainers
Readme
atech
TypeScript SDK and firmware-build toolchain for Atech motherboards.
Two things in one package:
- Build firmware from Node. Discover modules, write a tiny
project.yaml, and compile + flash — the same deterministic pipeline as the Python SDK, driven from JS/TS or theatechCLI.npm install atech-sdk+ a coding agent is enough to go from "make my lamp turn green when the button is pressed" to working firmware on the board. - Talk to a flashed board. A small, typed wrapper around the line-delimited
JSON event/action protocol the firmware speaks — pick a transport (gateway
WebSocket, Node USB serial, browser Web Serial, or the mock) and use the same
Board/AtechDeviceAPI regardless of pipe. Plus an optionalatech-sdk/reactUI layer for board control panels.
Build firmware (60-second tour)
npm install atech-sdk
npx atech new thermo --board 8port && cd thermo
# tell your agent (or edit project.yaml yourself):
# "add a button on port 3 and a neopixel on port 4; flash green on press"
npx atech list-modules # what's buildable
npx atech show neopixel # a module's public C++ API
npx atech validate . # check the placement
npx atech build . # -> firmware.bin (requires PlatformIO)
npx atech upload . # flash itPlatformIO (
pio) is the one external dependency — authoring, validation, and codegen are pure Node, but compiling/flashing shell out to it. Install withpipx install platformioifpio --versionfails.
What a coding agent gets
Drop CLAUDE.md into a project and an agent is fully equipped:
- A discoverable catalog —
npx atech list-modules,getModule(id).usage(a C++ snippet showing each module's public API). The agent reads what exists instead of guessing. - A declarative spec (
project.yaml) it writes/edits directly. - Deterministic codegen —
atech buildturns the YAML into a PlatformIO project and afirmware.bin. No LLM in that path; the agent owns the behavior, the SDK owns the plumbing. - A typed API mirroring the CLI:
Project,listModules,getModule.
import { Project } from "atech-sdk";
const p = new Project({ board: "8port", name: "blink" })
.add("button", { port: 3, instance: "btn" })
.add("neopixel", { port: 4, instance: "led" })
.setLoop("if (btn.wasPressed()) { led.setAll(0,255,0); led.show(); }");
await p.build(); // -> { success, firmwarePath, ... }Install
npm install atech-sdk
# optional, only if you'll use the matching transport:
npm install ws # Node <22 WebSocket
npm install serialport # Node USB serial
npm install react # only for the atech-sdk/react UI layerQuick start
import { Board, deviceFromTransport } from "atech-sdk";
import { WebSocketTransport } from "atech-sdk/websocket";
const transport = new WebSocketTransport({
url: "wss://gateway.atech.dev/ws/live/<project_id>",
});
await transport.ready();
// Low-level: board.send(key, value)
const board = new Board(transport);
board.send("set_color", { r: 255, g: 0, b: 0 });
// Typed: module-aware, autocompleted
const device = deviceFromTransport(transport);
device.neopixelGrid.setColor({ r: 255, g: 0, b: 0 });
device.dcMotor.motorSpeed(200);
device.speaker.playTone({ frequency: 440, duration: 200 });
// Stream events
for await (const e of board.events({ types: ["sensor"] })) {
console.log(e.key, e.value);
}Transports
WebSocket / gateway
Connects to the Atech gateway's /ws/live/<project_id> endpoint. Works in
browsers and in Node 22+ (built-in WebSocket). For older Node, install ws
and pass its constructor:
import WebSocket from "ws";
import { WebSocketTransport } from "atech-sdk/websocket";
const transport = new WebSocketTransport({
url: "wss://gateway.atech.dev/ws/live/<project_id>",
webSocketImpl: WebSocket,
reconnectMs: 1000,
});USB serial (Node)
import { SerialPort } from "serialport";
import { SerialTransport, discoverPorts } from "atech-sdk/serial";
const ports = await discoverPorts(SerialPort);
const transport = new SerialTransport({
port: ports[0].path,
SerialPortImpl: SerialPort,
});Web Serial (browser)
import { WebSerialTransport, ATECH_WEB_SERIAL_FILTERS } from "atech-sdk/web-serial";
const port = await navigator.serial.requestPort({
filters: ATECH_WEB_SERIAL_FILTERS,
});
await port.open({ baudRate: 115200 });
const transport = new WebSerialTransport({ port });Mock (tests)
import { Board } from "atech-sdk";
import { MockTransport } from "atech-sdk/mock";
const transport = new MockTransport();
const board = new Board(transport);
transport.pushEvent({ type: "sensor", key: "temp", value: 23.5 });
console.log(board.latest("temp")?.value); // 23.5
board.send("led", "on");
console.log(transport.sent[0]); // { key: "led", value: "on" }React UI
A drop-in UI layer for building board control panels in the browser. react is
an optional peer dependency.
import { useState } from "react";
import { ConnectButton, NeopixelGrid, Gauge, EventLog, Toggle } from "atech-sdk/react";
function Panel() {
const [board, setBoard] = useState(null);
return (
<>
<ConnectButton onConnect={setBoard} />
{board && (
<>
<NeopixelGrid board={board} /> {/* click → set_pixel_xy */}
<Toggle board={board} actionKey="led" /> {/* on/off actuator */}
<Gauge board={board} eventKey="temperature" unit="°C" />
<EventLog board={board} />
</>
)}
</>
);
}Hooks: useBoard(transport), useEvent(board, filter), useLatest(board, key).
Or scaffold a whole starter app (Vite + React, pre-wired to Web Serial, with its
own CLAUDE.md):
npm create atech-app my-panel
cd my-panel && npm install && npm run devWire protocol
Line-delimited JSON, same envelope as the Python SDK and the firmware-side
AtechSerial / AtheraWiFi classes.
Device → host (events):
{"type":"event","payload":{"event_type":"sensor","key":"temperature","value":23.5,"source":"aht20"}}Host → device (actions):
{"action":"set_led_color","value":"{\"r\":255,\"g\":0,\"b\":0}"}USB-serial firmware reads value as a C-string, so the SDK stringifies values
on the wire (dicts/lists → compact JSON; numbers → string repr). The WebSocket
transport sends the value as a native JSON object — the gateway forwards it
through and pollAction accepts both forms.
Event types: sensor, button, state, log.
Status
v0.2, alpha. Mirrors the Python SDK (atech on PyPI): the firmware-build
pipeline (catalog → project.yaml → codegen → pio build/flash) produces
byte-identical output to the Python generator, and the runtime API preserves the
v0.1 surface. Building/flashing requires PlatformIO (pio).
License
MIT.
