KUMA Timer — API Reference
HTTP/JSON API & OSC protocol for integration with Bitfocus Companion, show control systems, and custom automation
Overview
KUMA Timer exposes two integration protocols:
| Protocol | Use case | Default port |
|---|---|---|
| HTTP / JSON | Bitfocus Companion module, custom scripts, web dashboards | 5555 |
| OSC / UDP | Lighting consoles, legacy show control, QLab | 8000 (in) · 12321 (out) |
Both protocols are enabled and configured in Settings → Connections. The HTTP server runs on the same port as the Web Mirror (default 5555). No authentication is required — restrict access at network level if needed.
HTTP API
Base URL: http://<kuma-ip>:5555
All responses are application/json. CORS headers are set to * so browser-based dashboards can poll directly.
Status endpoint
Returns the current state of KUMA Timer. Companions polls this every 500 ms by default.
Response 200
{
"status": "live", // "live" | "paused" | "standby" | "hidden"
"timer": "04:32", // display string, "-MM:SS" in overtime
"timer_seconds": 272, // integer, negative in overtime
"overtime": false, // true once timer passes zero
"progress": 74.3, // 100→0, matches progress bar
"cue_name": "Jan Kowalski",// empty string if no cue loaded
"cue_index": 2, // -1 if no cue selected
"sms_active": false // true while a message is on screen
}
Command endpoint
Body: application/json with "action" plus optional parameters.
All commands are dispatched to the Qt main thread — safe to call from any thread or process.
Response 200 {"ok": true}
Response 400 {"error": "unknown action: foo"}
Actions reference
Playback
| action | Parameters | Description |
|---|---|---|
| "start" | — | Start the timer |
| "pause" | — | Toggle pause / resume |
| "reset" | — | Stop and reset to zero |
| "hide" | — | Toggle display window visibility |
Time
| action | Parameters | Description |
|---|---|---|
| "add_minute" | — | Add 60 seconds to the running timer |
| "sub_minute" | — | Subtract 60 seconds from the running timer |
| "load_time" | seconds int |
Load an exact duration in seconds (e.g. 300 = 5:00) |
| "preset" | index int 0–5 |
Activate preset button by index (0 = first button in the row) |
Cues
| action | Parameters | Description |
|---|---|---|
| "load_cue" | index int |
Load a runsheet cue by index (0 = first row). Loads time and name. |
| "next_cue" | — | Advance to the next cue in the runsheet (wraps to top) |
SMS — Send Message to Screen
| Parameter | Type | Default | Description |
|---|---|---|---|
text | string | required | Message to display (max 300 chars) |
duration | int | 10 | How long to show the message, in seconds (1–600) |
color | string | "#ffffff" | Text colour as hex (e.g. "#ff4444") |
border_color | string | "#ffaa00" | Container border colour as hex |
size | string | "medium" | "small" · "medium" · "large" |
position | string | "bottom" | "bottom" · "top" |
flash | bool | false | Flash the container on/off for attention |
scroll | bool | false | Force scrolling even if text fits on screen |
scroll_invert | bool | false | Scroll right-to-left (Arabic / Hebrew) |
scroll flag. The flag only forces scrolling for short messages too.color is #000000 the container background switches to white automatically so the text is legible.To remove a message early:
| action | Parameters | Description |
|---|---|---|
| "cancel_sms" | — | Remove the current on-screen message immediately |
OSC Protocol
KUMA listens for OSC/UDP on port 8000 (configurable in Settings → Connections). Useful for QLab, ETC Eos, MA consoles, and other show control systems.
Incoming — external device → KUMA
| Address | Argument | Action |
|---|---|---|
OSC /kuma/start | — | Start timer |
OSC /kuma/pause | — | Pause / resume toggle |
OSC /kuma/reset | — | Stop and reset to zero |
OSC /kuma/hide | — | Toggle display window visibility |
OSC /kuma/time/add | — | +1 minute |
OSC /kuma/time/sub | — | −1 minute |
OSC /kuma/warp | int seconds | Load duration in seconds (e.g. 300 = 5:00). Alias: /kuma/load |
OSC /kuma/preset | int 0–5 | Load preset by index (0 = first button) |
OSC /kuma/cue | int index | Load cue from runsheet by index |
OSC /kuma/cue/next | — | Advance to next cue (wraps) |
OSC /kuma/settime | string | Load time as HH:MM:SS or MM:SS (e.g. "01:30:00") |
OSC /kuma/sms | string text · int duration | Send message using config defaults for colour/size/position |
Outgoing — KUMA → external
Default target: 127.0.0.1 : 12321 (configurable)
| Address | Value | Sent when |
|---|---|---|
/kuma/status | string — "LIVE" · "PAUSED" · "STANDBY" · "HIDDEN" | On any state change |
/kuma/overtime | int 1 | Once, when the timer first crosses zero. Path is configurable in Settings. |
/kuma/sms command uses the colour/size/position defaults set in Settings → SMS. For full per-message styling use the HTTP API.Bitfocus Companion Module
The KUMA Timer Companion module is built on the HTTP API. It polls /api/status every 500 ms and sends all commands via POST /api/command.
| Capability | Detail |
|---|---|
| Actions | Start, Pause, Reset, Hide, ±1 min, Load Time, Preset, Load Cue, Next Cue, Send SMS (full styling), Cancel SMS |
| Feedbacks | LIVE · PAUSED · STANDBY · HIDDEN · OVERTIME · SMS active |
| Variables | $(kumatimer:timer) · $(kumatimer:timer_seconds) · $(kumatimer:status) · $(kumatimer:cue_name) · $(kumatimer:cue_index) · $(kumatimer:overtime) · $(kumatimer:progress) · $(kumatimer:sms_active) |
| Config | KUMA IP · port (default 5555) · poll interval (default 500 ms) |
Download from the Download page. Install as a developer module — see Documentation → Companion Module for step-by-step instructions.
Code examples
cURL — start the timer
curl -s -X POST http://192.168.1.10:5555/api/command \
-H "Content-Type: application/json" \
-d '{"action":"start"}'
cURL — send a red flashing SMS for 20 seconds
curl -s -X POST http://192.168.1.10:5555/api/command \
-H "Content-Type: application/json" \
-d '{
"action": "send_sms",
"text": "PLEASE WRAP UP",
"duration": 20,
"color": "#ff4444",
"border_color": "#ff0000",
"size": "large",
"position": "top",
"flash": true
}'
cURL — load cue #3 and read status
# Load cue index 2 (third row)
curl -s -X POST http://192.168.1.10:5555/api/command \
-H "Content-Type: application/json" \
-d '{"action":"load_cue","index":2}'
# Poll current state
curl -s http://192.168.1.10:5555/api/status | python3 -m json.tool
Python — poll loop
import urllib.request, json, time
KUMA = "http://192.168.1.10:5555"
def command(action, **params):
body = json.dumps({"action": action, **params}).encode()
req = urllib.request.Request(f"{KUMA}/api/command", body,
{"Content-Type": "application/json"})
urllib.request.urlopen(req)
def status():
with urllib.request.urlopen(f"{KUMA}/api/status") as r:
return json.loads(r.read())
command("load_time", seconds=300)
command("start")
while True:
s = status()
print(f"{s['timer']} [{s['status'].upper()}] cue: {s['cue_name'] or '—'}")
if s["overtime"]:
command("send_sms", text="OVERTIME!", duration=30,
color="#ff4444", flash=True)
break
time.sleep(1)
Node.js — one-liner command
// npm i node-fetch (or use native fetch in Node 18+)
await fetch("http://192.168.1.10:5555/api/command", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action: "next_cue" }),
})
QLab (OSC) — start on cue fire
// Network cue → UDP → 192.168.1.10:8000
/kuma/start