Skip to content

tjbot-ce/tjbot-server

Repository files navigation

tjbot-server

HTTP API server for controlling TJBot through node-tjbotlib.

This service initializes TJBot once at server startup, then exposes selected TJBot public methods as HTTP endpoints.

API Artifacts

  • Human-readable API spec: this README
  • OpenAPI spec: openapi.yaml

Running the Server

Prerequisites

  • Node.js 20+
  • node-tjbotlib available at ../node-tjbotlib (this server depends on tjbot via local file dependency)
  • TJBot hardware and ~/.tjbot/tjbot.toml configured on the host

Local Development

npm install
npm run dev

The server starts on http://0.0.0.0:8765 by default.

You can override bind host/port:

HOST=127.0.0.1 PORT=9000 npm run dev

Production Run

npm install
npm run build
npm start

Run on Startup with systemd

1. Build the server

cd /home/pi/.tjbot/tjbot-server
npm install
npm run build

2. Create a systemd unit file

Create /etc/systemd/system/tjbot-server.service with:

[Unit]
Description=TJBot HTTP Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/.tjbot/tjbot-server
Environment=NODE_ENV=production
Environment=HOST=0.0.0.0
Environment=PORT=8765
ExecStart=/usr/bin/npm start
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

3. Enable and start the service

sudo systemctl daemon-reload
sudo systemctl enable tjbot-server
sudo systemctl start tjbot-server

4. Check status and logs

sudo systemctl status tjbot-server
sudo journalctl -u tjbot-server -f

5. Deploy updates

After code updates:

cd /home/pi/.tjbot/tjbot-server
npm install
npm run build
sudo systemctl restart tjbot-server

Scope

The API intentionally excludes the following TJBot methods:

  • initialize() (done at server startup)
  • setLogLevel() (configured in TJBot config)
  • getRecipeConfig() (no active recipe context)
  • look() (server-local file path is not useful to remote clients)
  • sleep() (utility not needed for remote control)

Conventions

  • Base path: /api/v1
  • Content type: application/json unless stated otherwise
  • Validation: request payloads are validated with AJV using JSON Schema-compatible constraints
  • Error model: all non-2xx responses use a consistent { ok: false, error: { ... } } shape

Response Envelope

Success

{
	"ok": true,
	"data": {}
}

Error

{
	"ok": false,
	"error": {
		"code": "VALIDATION_ERROR",
		"message": "human-readable summary",
		"details": []
	}
}

Listen Modes

listen() is exposed in two forms:

  • POST /api/v1/listen for offline, single-result transcription
  • GET /api/v1/listen/stream for streaming partial/final transcription via Server-Sent Events (SSE)

Only one streaming listen session may be active at a time.

Endpoint Summary

Status

  • GET /api/v1/status

Listen

  • POST /api/v1/listen
  • GET /api/v1/listen/stream

See

  • POST /api/v1/see
  • POST /api/v1/vision/detect-objects
  • POST /api/v1/vision/classify-image
  • POST /api/v1/vision/detect-faces
  • POST /api/v1/vision/describe-image

Shine

  • POST /api/v1/shine
  • POST /api/v1/pulse
  • GET /api/v1/shine/colors
  • GET /api/v1/shine/random

Speak

  • POST /api/v1/speak
  • POST /api/v1/play

Wave

  • POST /api/v1/wave
  • POST /api/v1/arm/back
  • POST /api/v1/arm/raise
  • POST /api/v1/arm/lower

Detailed Endpoint Contracts

GET /api/v1/status

Returns server and TJBot runtime state.

Example response:

{
	"ok": true,
	"data": {
		"initialized": true,
		"rpiModel": "Raspberry Pi 5",
		"activeListenStream": false,
		"lastKnown": {
			"color": "#ff0000",
			"speechText": "Hello from TJBot",
			"audioFile": "/opt/sounds/chime.wav",
			"armAction": "wave",
			"updatedAt": "2026-05-22T20:30:00.000Z"
		}
	}
}

POST /api/v1/shine

Request:

{
	"color": "red"
}

POST /api/v1/pulse

Request:

{
	"color": "#00ff00",
	"duration": 1.0
}

GET /api/v1/shine/colors

Returns all recognized named colors.

GET /api/v1/shine/random

Returns one random recognized color.

POST /api/v1/speak

Request:

{
	"text": "Hello, I am TJBot"
}

POST /api/v1/play

Request:

{
	"soundFile": "/opt/tjbot/sounds/chime.wav"
}

POST /api/v1/wave

No request body.

POST /api/v1/arm/back

No request body.

POST /api/v1/arm/raise

No request body.

POST /api/v1/arm/lower

No request body.

POST /api/v1/listen

Offline single-result transcription.

Request body is optional and currently empty.

Response:

{
	"ok": true,
	"data": {
		"transcript": "turn on the light"
	}
}

GET /api/v1/listen/stream

Streaming transcription using SSE.

Response header:

  • Content-Type: text/event-stream

Event stream format:

event: partial
data: {"text":"turn"}

event: partial
data: {"text":"turn on"}

event: final
data: {"text":"turn on the light"}

event: done
data: {}

Error event shape:

event: error
data: {"code":"LISTEN_FAILED","message":"..."}

POST /api/v1/see

Captures one image using TJBot camera.

Request:

{
	"responseFormat": "base64"
}

responseFormat values:

  • base64 default: returns JSON with imageBase64 and mimeType
  • binary: returns image/jpeg bytes directly

Vision Analysis Endpoints

  • POST /api/v1/vision/detect-objects
  • POST /api/v1/vision/classify-image
  • POST /api/v1/vision/detect-faces
  • POST /api/v1/vision/describe-image

All vision analysis endpoints use the same image input contract:

{
	"imagePath": "/tmp/frame.jpg"
}

or

{
	"imageBase64": "..."
}

Exactly one of imagePath or imageBase64 must be provided.

Validation Notes

  • Schemas are designed to compile cleanly in AJV.
  • Unknown properties are rejected (additionalProperties: false).
  • Vision image payload enforces one-of semantics (imagePath xor imageBase64).

OpenAPI

The canonical machine-readable API definition is in openapi.yaml.

About

Control TJBot via HTTP requests

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors