Chat
Welcome to Flux
Treat Flux like your intern. Tell it what you'd like to build and it'll get to work. You can also ask it questions, brainstorm ideas, and teach it your preferences. Learn More
WebSerialTransport initially; later WebBluetoothTransport with the same request/response/event API.application/vnd.blkmgk.kyb1.config+json; current schemaVersion is 1. Unknown required fields reject; unknown optional fields are preserved when possible for forward compatibility.JSON
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://kyb1.local/schema/config-v1.json", "type": "object", "required": ["schemaVersion", "device", "layers", "rgb", "power", "storage", "rak3112"], "properties": { "schemaVersion": {"const": 1}, "revision": {"type": "integer", "minimum": 0}, "device": { "type": "object", "required": ["keyCount", "matrix"], "properties": { "keyCount": {"const": 69}, "matrix": { "type": "object", "required": ["rows", "columns", "positions"], "properties": { "rows": {"const": 6}, "columns": {"const": 13}, "positions": { "type": "array", "minItems": 78, "maxItems": 78, "items": {"anyOf": [{"type": "integer", "minimum": 0, "maximum": 68}, {"type": "null"}]} } } } } }, "layers": { "type": "array", "minItems": 1, "maxItems": 16, "items": { "type": "object", "required": ["id", "name", "keys"], "properties": { "id": {"type": "integer", "minimum": 0, "maximum": 15}, "name": {"type": "string", "minLength": 1, "maxLength": 32}, "keys": { "type": "array", "minItems": 69, "maxItems": 69, "items": { "type": "object", "required": ["type"], "properties": { "type": {"enum": ["hid", "consumer", "layerMomentary", "layerToggle", "macro", "disabled"]}, "usage": {"type": "integer", "minimum": 0, "maximum": 65535}, "modifiers": {"type": "integer", "minimum": 0, "maximum": 255}, "targetLayer": {"type": "integer", "minimum": 0, "maximum": 15}, "macroId": {"type": "string", "pattern": "^[A-Za-z0-9_-]{1,32}$"} } } } } } }, "macros": { "type": "array", "maxItems": 128, "items": { "type": "object", "required": ["id", "steps"], "properties": { "id": {"type": "string", "pattern": "^[A-Za-z0-9_-]{1,32}$"}, "steps": {"type": "array", "maxItems": 256, "items": {"type": "object", "required": ["op"], "properties": { "op": {"enum": ["press", "release", "tap", "delayMs", "text"]}, "usage": {"type": "integer", "minimum": 0, "maximum": 65535}, "value": {"type": "integer", "minimum": 0, "maximum": 5000}, "text": {"type": "string", "maxLength": 256} } } } } } }, "rgb": { "type": "object", "required": ["enabled", "brightness", "currentLimitmA", "effect", "colors"], "properties": { "enabled": {"type": "boolean"}, "brightness": {"type": "integer", "minimum": 0, "maximum": 255}, "currentLimitmA": {"type": "integer", "minimum": 50, "maximum": 1200}, "effect": {"enum": ["off", "solid", "perKey", "breathing", "rainbow", "reactive"]}, "speed": {"type": "integer", "minimum": 0, "maximum": 255}, "colors": {"type": "array", "minItems": 69, "maxItems": 69, "items": {"type": "string", "pattern": "^#[0-9A-Fa-f]{6}$"}} } }, "power": { "type": "object", "required": ["safeStartup", "defaultSourceRgbLimitmA", "source1_5ALimitmA", "source3ALimitmA"], "properties": { "safeStartup": {"const": true}, "defaultSourceRgbLimitmA": {"type": "integer", "minimum": 0, "maximum": 250}, "source1_5ALimitmA": {"type": "integer", "minimum": 0, "maximum": 700}, "source3ALimitmA": {"type": "integer", "minimum": 0, "maximum": 1200} } }, "storage": { "type": "object", "properties": { "configPath": {"const": "/kyb1/config.json"}, "backupCount": {"type": "integer", "minimum": 1, "maximum": 8}, "allowWebFileWrite": {"type": "boolean"} } }, "rak3112": { "type": "object", "required": ["uartBaud", "wifi", "lora"], "properties": { "uartBaud": {"enum": [9600, 57600, 115200, 230400, 460800, 921600]}, "wifi": {"type": "object", "properties": { "enabled": {"type": "boolean"}, "ssid": {"type": "string", "maxLength": 32}, "credentialRef": {"type": ["string", "null"], "maxLength": 32} }}, "lora": {"type": "object", "properties": { "enabled": {"type": "boolean"}, "region": {"enum": ["EU868", "US915", "AU915", "AS923", "IN865", "KR920", "RU864"]}, "frequencyHz": {"type": "integer", "minimum": 150000000, "maximum": 960000000}, "txPowerDbm": {"type": "integer", "minimum": 0, "maximum": 22}, "bandwidthHz": {"enum": [7800, 10400, 15600, 20800, 31250, 41700, 62500, 125000, 250000, 500000]}, "spreadingFactor": {"type": "integer", "minimum": 5, "maximum": 12}, "codingRate": {"type": "integer", "minimum": 5, "maximum": 8} }} } } } }
credentialRef points to firmware-secured storage and reads return only configured: true/false.Table
| Field | Bytes | Meaning |
|---|---|---|
| SOF | 2 | 0x4B 0x44 (KD) |
| version | 1 | protocol version, initially 1 |
| flags | 1 | bit0 response, bit1 event, bit2 error, bit3 more chunks |
| requestId | 2 | browser-selected nonzero ID; 0 for unsolicited event |
| command | 1 | command ID |
| payloadLength | 2 | 0..4096 |
| payload | N | CBOR preferred; UTF-8 JSON allowed during bring-up |
| CRC32C | 4 | version through payload |
0x01 HELLO — protocol/device/firmware/schema versions, capabilities, serial number hash.0x02 GET_STATUS — uptime, reset reason, power mode, effective RGB clamp, SD state, RAK-ready state, active revision.0x10 GET_CONFIG / 0x11 VALIDATE_CONFIG / 0x12 STAGE_CONFIG / 0x13 COMMIT_CONFIG / 0x14 ROLLBACK_CONFIG.0x20 MATRIX_LIVE — start/stop debounced 69-key event stream; never inject HID from browser traffic.0x21 SET_PREVIEW_RGB / 0x22 STOP_PREVIEW_RGB — volatile, timeout-limited preview.0x30 SD_LIST / 0x31 SD_READ / 0x32 SD_WRITE_BEGIN / 0x33 SD_WRITE_CHUNK / 0x34 SD_WRITE_COMMIT / 0x35 SD_DELETE.0x40 RAK_GET / 0x41 RAK_SET / 0x42 RAK_TEST / 0x43 RAK_RESET; firmware serializes UART operations and returns sanitized results.0x50 FW_INFO / 0x51 FW_UPDATE_BEGIN / 0x52 FW_UPDATE_CHUNK / 0x53 FW_UPDATE_VERIFY / 0x54 FW_UPDATE_APPLY.POWER_MODE_CHANGED, KEY_EVENT, SD_CHANGED, RAK_EVENT, PROGRESS, FAULT.requestId and command. Error payload: {code, message, fieldPath?, retryable}. Stable codes include BAD_FRAME, UNSUPPORTED_VERSION, VALIDATION_FAILED, POWER_POLICY, BUSY, NO_SD, AUTH_REQUIRED, and INTERNAL.null holes.RGB_PWR_EN remains low until U6 is initialized and USB-C OUT1/OUT2 are sampled. Power-mode downgrade immediately blanks/clamps LEDs before other work.POWER_POLICY./kyb1; reject .., absolute host paths, control characters, and files over configured quotas./kyb1 namespace: configuration, timestamped backups, user effects, logs, and staged update images. Upload is begin/chunk/commit with size, CRC32C per frame, and final SHA-256. Interrupted uploads remain .partial and are removed at boot. Config writes use the transactional commit flow. SD removal aborts outstanding operations without changing the active NVS-backed configuration.HardwareSerial, verify, reset, and report version. Never treat a XIAO image as a RAK image./kyb1.HELLO, GET_STATUS, power events, and read-only WebSerial device page.Purpose and scope
System architecture
Versioned configuration schema
WebSerial binary framing
Command set
Validation and safety policy
Security model
microSD management
Firmware update strategy
UI pages
Implementation milestones