SolarOS

SolarOS 4.6.8 manual · job

SolarOS Jobs

This document covers the built-in background job registry. Jobs are autonomous workers such as log followers, DAQ capture, HTTP serving, Telnet shell access, SLIP, chatd, or NTP sync. Foreground applications are documented in apps.md, and shell commands are documented in commands.md. Port shells are sessions, started with session create shell <port> plus optional --term, --charset, and --size terminal settings. Display-target shells use session create shell <target>.

Job availability depends on the selected firmware flavor and board capabilities. The running system is authoritative:

jobs
job status [name]

jobs is intentionally compact so it fits on the built-in 65-column display terminal. It shows job name, state, declared worker-stack requirement, kind, event source, tick count, and resource count. Running rows are bold. Use job status <name> for the summary, owner string, worker-stack placement, last error, effective tick interval/deadline, runtime duration statistics, deadline misses, and claimed resources. Compact timing lines use interval/deadline in milliseconds, n for dispatches, us=last/max, and miss for deadline misses.

Job Control

CommandDescription
jobsList registered jobs in compact form.
job status [name]Show all jobs, or one named job with details.
job start <name> [args...]Start a job with optional arguments.
job stop <name>Stop a running job.

Only one instance of each job name can run at a time. Starting a running job first stops the previous instance, then starts it again with the new arguments.

Jobs have stable owner strings in the form job:<name>. Jobs that claim ports, files, streams, or network listeners publish those resources through the job status model. This keeps port/resource conflict messages readable and avoids job-specific inspection code in the shell.

Job states distinguish a deferred launch from a completed launch attempt:

The STACK column is the declared worker-stack admission requirement in bytes, not a worst-case total-memory estimate. - means that the job declares no dedicated worker stack; it may still allocate dynamic buffers or use a shared service. Compare this column with the internal figures from mem policy. For an internal-stack background job, admission currently requires internal free memory of at least STACK + 1 KiB overhead + 32 KiB reserve, and an internal largest block of at least STACK + 1 KiB overhead. Treat a manual check as a snapshot: other work can allocate memory before job start, which is why SolarOS retains and retries a launch that loses that race.

Jobs that use byte-stream ports claim those ports while running. If a port is already owned, SolarOS reports the owner, for example job log owns cdc0. Radio listeners expose their radio as a custom job resource.

GPIO-key mappings claim each selected pin through the same resource model. The io application therefore shows assignments such as key:UP, their job:gpio-keys owner, and the board's canonical pin policy without special GPIO-key display logic.

Tick intervals and execution-time deadlines are declared by each event-driven job. A zero descriptor value selects the runtime default. Deadline misses do not forcibly terminate a cooperative handler; SolarOS counts them, records the last and maximum duration, and emits rate-limited warnings. The DAQ and log handlers only enqueue work, so their stream, filesystem, and port I/O runs in isolated worker tasks instead of the display scheduler.

Compact list example:

NAME         STATE    STACK KIND        EVT  TICKS RES
batmon       running      - background  tick    17   1
log          stopped   6144 background  tick     0   0

Detailed status example:

job status log
NAME         STATE    STACK KIND        EVT  TICKS RES
log          running   6144 background  tick     8   1
  summary: stream SolarOS logs to a port or file
  owner: job:log
  worker stack: 6144 bytes (internal)
  tick: 250/2ms n=8 us=18/31 miss=0
  resources:
  - port   cdc0 rw

Useful ports:

cdc0
uart0

List available streams with:

stream

Startup

Jobs can be started from the normal startup script:

/.shell/startup

Example:

wifi on
job start ntp-sync once
job start batmon 60

batmon

Battery monitor. It periodically samples battery voltage, maintains a smoothed trend, estimates power state, and can request light sleep when the configured minimum voltage is reached.

Usage:

job start batmon [interval-sec]
job stop batmon
job status batmon

Defaults:

SettingValue
Interval60 seconds

Battery limits are configured with the battery shell command:

battery capacity <mAh>
battery min_voltage <volts>
battery max_voltage <volts>

Notes:

Example:

job start batmon 60

bridge

Bidirectional byte bridge between two byte-stream ports, or between one byte-stream port and an active SolarOS Link instance.

Usage:

job start bridge <port-a> <port-b>
job start bridge <port> <link> [broadcast|destination-id]
job stop bridge
job status bridge

Example:

job start bridge cdc0 uart0

To expose a UART byte stream over a packet-radio Link:

job start radio-link link0 radio0 lora-eu868
job start bridge uart0 link0 broadcast

That direct Link form is best-effort. For an ordered, retransmitted stream, create a peer-bound virtual port and use the normal port-to-port bridge form:

link stream create link0 vser0 0x12345678
job start bridge cdc0 vser0

The remote device creates its matching vser0 and can attach a normal shell with session create shell vser0 --term dumb. On a headless DevKit, this leaves the primary uart0 shell free for administration while Linux uses USB cdc0 for the remote terminal.

Use a decimal or 0x 32-bit Link destination instead of broadcast for acknowledged unicast:

job start bridge uart0 link0 0x12345678

Notes:

gateway-sync

Background synchronizer for the gateway messaging provider. Start and stop it explicitly, using the same lifecycle as email-sync:

job start gateway-sync
job stop gateway-sync
job status gateway-sync

gateway-sync takes no polling interval. Unlike the periodic email-sync job, it maintains a live connection and applies its own exponential reconnect backoff. It can therefore be started before Wi-Fi has an address; it remains running and connects when the network becomes available. In /.shell/startup, use exactly:

job start gateway-sync

It owns transport connection lifetime, exponential retry, opaque resume cursors, joined-channel replay, and delivery of the gateway provider's shared outbound requests. The messaging service owns retained publication and Inbox projection. Replayed transport messages are deduplicated by the shared stable producer identity before another notification is published.

The gateway hello uses the SolarOS identity hostname value as its device identity; Chat does not maintain a separate device-name setting.

Stopping or closing app.chat has no effect on this job. Its worker performs transport startup, polling, and retry work outside the cooperative session/job scheduler.

The shared store retains at most 64 messages. SD-backed systems use the full-message /.messages/messages.bin ring. Systems using internal flash restore Chat history from the compact records already stored in /.inbox/messages.bin; no second ring is created, so Chat history cannot consume the remaining flash volume.

chatd

Local SolarOS chat gateway server. It is useful for testing the chat app or for small trusted local networks.

Usage:

job start chatd [port] [token] [--history path]
job start chatd [port] [token] [path]
job stop chatd
job status chatd

Defaults:

SettingValue
Port7777
Default channelgeneral
Maximum clients6
Maximum channels32
In-memory history64 events

Arguments are intentionally flexible. The first numeric argument is the port. The next non-option argument is the optional token. --history or --log selects an optional append-only history dump file.

Examples:

job start chatd
job start chatd 7777 secret
job start chatd 7777 secret --history /.shell/chatd.log

The local chat app can connect with:

chat local
chat 127.0.0.1:7777

On another SolarOS device or host on the same network, use the server IP:

chat 192.168.1.113:7777

Notes:

daq

Data acquisition job. It captures scalar streams to timestamped CSV, or one byte stream directly to a raw file.

The daq shell command is usually easier to remember:

daq
daq streams
daq start <stream...> <file> [options]
daq start <file> <stream...> [options]
daq stop
daq status

Direct job usage:

job start daq <stream...> <file> [--rate seconds|--rate-ms ms] [--append|--replace]
job start daq <file> <stream...> [--rate seconds|--rate-ms ms] [--append|--replace]
job start daq <byte-stream> <file> --raw [--rate-ms ms] [--append|--replace]
job stop daq
job status daq

Defaults:

ModeDefault interval
Scalar CSV1000 ms
Raw byte stream25 ms

Examples:

daq start temperature /logs/temp.csv --rate 60
daq start /logs/env.csv temperature humidity battery --rate 60
daq start uart0 /logs/uart0.bin --raw --rate-ms 25
job start daq /logs/env.csv temperature humidity battery --rate 60

Notes:

displayd

Authenticated HTTP display and remote control. It has two modes:

With no target argument, displayd mirrors display0 when it exists and otherwise creates web0. The latter makes the same command useful on headless PSRAM-equipped boards.

Usage:

job start displayd [target]
job stop displayd
job status displayd

Example:

wifi on
job start displayd
job start displayd web0

Starting the job prints a random six-digit access code. Open http://<device>/display, enter that code, and click the displayed image before typing. The browser frontend polls the native 1-bit U8g2 frame up to twenty times per second and performs pixel rotation in the browser instead of the HTTP server task. It sends bounded key input through the scheduler. Ctrl+] remains the application-exit key.

API:

GET  /api/displays
GET  /api/displays/<target>/frame.pbm
GET  /api/displays/<target>/frame.raw
POST /api/displays/<target>/input

All API requests require Authorization: Bearer <code>. The access code is never accepted in the URL. The built-in frontend itself is public so that it can prompt for the code, but keeps the supplied code only in page memory.

Notes:

httpd

Static HTTP file server for a folder on mounted storage.

Usage:

job start httpd <folder>
job stop httpd
job status httpd

Example:

job start httpd /www

Notes:

log

Runtime SolarOS log follower. It mirrors log entries to a byte-stream port or appends them to a file.

Usage:

job start log <port> [error|warn|info|debug]
job start log file <path> [error|warn|info|debug]
job stop log
job status log

Examples:

job start log cdc0
job start log uart0 debug
job start log file /.shell/log info

Notes:

telnetd

Remote Telnet shell server. The listener is a background job; each accepted connection is attached to its own normal SolarOS port-shell session.

Usage:

job start telnetd [port] [--password password]
job stop telnetd
job status telnetd

Examples:

job start telnetd
job start telnetd 2323 --password local-secret

Notes:

ntp-sync

Network time synchronization job. It updates the SolarOS wall clock from NTP and also updates the hardware RTC when the board provides one.

Usage:

job start ntp-sync [once] [interval-sec] [server]
job stop ntp-sync
job status ntp-sync

Defaults:

SettingValue
Interval60 seconds
Serverpool.ntp.org

Examples:

job start ntp-sync once
job start ntp-sync 300 time.cloudflare.com
job start ntp-sync once 60 pool.ntp.org

Notes:

email-sync

Receive-only IMAPS mailbox polling job. It fetches mail into the provider-local email app and publishes each new message to the universal inbox.

Usage:

job start email-sync [interval-sec] [once]
job stop email-sync
job status email-sync

The default interval is 300 seconds; accepted values are 30 through 86400 seconds. once stops the job after one attempt. The account must be configured first:

wifi on
email configure imaps://imap.example.com user@example.com app-password INBOX
job start email-sync 300

To start polling after each reboot, add the following after wifi on in /.shell/startup:

job start email-sync 300

Notes:

pocsag

POCSAG pager receiver job. It configures a registered packet radio for a continuous POCSAG byte stream, frames successive 64-byte batches, filters pages to one receiver identity code (RIC), decodes alphanumeric or numeric payloads, and publishes completed messages to the universal inbox.

Usage:

job start pocsag <radio> <frequency-hz> <baud> <ric> [alpha|numeric] [normal|inverted]
job stop pocsag
job status pocsag
pocsag status
pocsag send <radio> <frequency-hz> <baud> <ric> <message> [alpha|numeric] [normal|inverted] [function]

Example:

job start pocsag radio 448425000 1200 1841525 alpha
inbox list unread

job stop pocsag
pocsag send radio 448425000 1200 1841525 "SolarOS calling" alpha inverted

Notes:

meshcore

Non-forwarding MeshCore companion provider for Contacts and Messages.

Usage:

job start meshcore <radio> <profile>
job stop meshcore
job status meshcore
meshcore status

Example:

job start meshcore radio0 meshcore-eu868
meshcore advert flood
chat

The job requires PSRAM and a packet-radio expansion capability. It claims the radio, applies the explicit regional profile, sends one zero-hop startup advert, and continuously handles adverts, direct messages, ACKs, and group messages. Its complete protocol context is allocated as external-required PSRAM; the 6144-byte worker stack remains internal and its minimum watermark is reported by meshcore status.

Stopping restores the previous radio configuration and state before releasing ownership. MeshCore and radio-link therefore report normal ownership conflicts when pointed at the same radio. See meshcore.md for identity, trust, channel, regional-profile, and security details.

radio-link

Packet-radio adapter for the transport-independent SolarOS Link service.

Usage:

job start radio-link <link> <radio> <profile> [inbox=off|on] [chat=off|on]
job stop radio-link
job status radio-link
link status <link>

Example:

job start radio-link link0 radio0 lora-eu868 chat=on
link send link0 broadcast "hello"
link status link0

The job claims the radio, applies the complete named profile, creates the Link instance, transmits its queued frames, and continuously receives complete radio packets. The Link service validates its own CRC, suppresses duplicates, replies to requested unicast acknowledgements, and retains accepted messages in a bounded queue. inbox=on additionally publishes accepted text messages to the universal inbox. chat=on instead registers Link as a messaging provider, creates a broadcast conversation, discovers source IDs as Contacts, and supports direct and broadcast text through Chat. Both options are off by default and cannot be enabled together.

Stopping restores the radio configuration and state that existed before the job started. Mutating direct radio operations are rejected while the radio is owned by the job. See link.md for commands, frame layout, IDs, queue limits, transport MTUs, and version-one exclusions.

slip

IPv4 SLIP gateway on a byte-stream port. This is intended for retro machines, headless boards, and serial networking experiments.

Usage:

job start slip [port] [baud] [local-ip] [peer-ip] [netmask]
job stop slip
job status slip

Defaults:

SettingValue
Portuart0
Baud115200
Local IP192.168.7.1
Peer IP192.168.7.2
Netmask255.255.255.252

Examples:

job start slip uart0 115200
job start slip cdc0 115200
job start slip uart0 38400 192.168.7.1 192.168.7.2 255.255.255.252

Notes:

gpio-keys

Maps runtime-safe GPIO inputs to SolarOS keyboard presses. The job configures each pin as an input with its internal pull-up enabled, treats a low level as pressed, and applies the same 25 ms debounce used by fixed board buttons. Each debounced transition publishes a generic SolarOS key press or release. Held keys use the system repeat rate configured by setterm keyrate.

Inline usage:

job start gpio-keys gpio17:UP gpio2:ENTER gpio3:ESCAPE
job stop gpio-keys
job status gpio-keys

Configuration-file usage:

job start gpio-keys --config /flash/gpio-keys.conf

The file contains one mapping per line. A colon or whitespace can separate the pin and key. Empty lines and text after # are ignored:

# navigation buttons, active low
gpio17:UP
gpio16 DOWN
gpio4:ENTER

Canonical pins use gpioN; the job also accepts the ioN shorthand. Key names are case-insensitive. Canonical directional names are UP, DOWN, LEFT, and RIGHT; aliases such as ARROW_UP are accepted. Other names include ENTER, SPACE, TAB, BACKSPACE, ESCAPE, HOME, END, DELETE, PAGE_UP, PAGE_DOWN, F1 through F12, and the modified SolarOS navigation keys. A single character maps that exact character.

The complete configuration is validated before any pin is changed. Up to 16 pins can be loaded from a file; the shell's argument limit allows up to seven inline mappings. Duplicate pins, fixed/reserved pins, unknown keys, and busy pins reject the complete start. Starting with a button already held does not generate a press. The file is read only at startup; restart the job to reload it.

While the job runs, every pin has owner job:gpio-keys and an assignment such as key:UP in the io Pins and Claims views. Stopping the job resets the pins, releases their claims, and discards queued events from this input source. The fixed ODROID-GO button service remains independent of this job but uses the same held-key and repeat service.

ps2-keyboard

Receives keyboard scan-code set 2 from an exclusive named PS/2 bus and publishes press and release transitions through the generic SolarOS input service.

expansion bus create ps2 ps2kbd clock=gpio17 data=gpio18
job start ps2-keyboard ps2kbd
job status ps2-keyboard
job stop ps2-keyboard

The bus descriptor owns the CLOCK and DATA pins as bus:ps2kbd; the running job holds an exclusive lease and appears as job:ps2-keyboard. Normal and extended keys, modifiers, navigation keys, function keys, and keypad usages are translated to canonical USB HID identities. The configured setterm keyboard layout and setterm keyrate repeat policy apply equally to BLE and PS/2.

The receiver validates each PS/2 frame's start bit, odd parity, and stop bit in the GPIO clock-edge handler. Scan-code parsing and input publication run from the normal job tick, outside interrupt context. The current driver only receives keyboard data; it does not send LED or reset commands to the keyboard.

Use a bidirectional level shifter or another circuit that guarantees no more than 3.3 V at the ESP32 GPIOs. ESP32 inputs are not 5 V tolerant.

sump

SUMP-compatible logic analyzer server on cdc0. It claims the CDC port and uses the shared logic analyzer service for acquisition. PulseView and sigrok can connect with the OpenBench Logic Sniffer/SUMP serial driver.

Usage:

job start sump [pin ...]
job start sump [pin[,pin...]]
job stop sump
job status sump

Examples:

job start sump
job start sump 1 2 3 17
job start sump 1,2,3,17

If no pins are supplied, the job uses up to eight runtime-safe GPIOs from the active board profile. Host commands select the sample rate and capture size. The current implementation supports 10 kHz to 2 MHz requests and up to 32768 one-byte samples; the status recorded with each capture reports the measured effective rate.

Notes:

Quick reference

Use jobs to inspect state and memory requirements, job NAME start to launch a worker, job NAME status for details, and job NAME stop to release it. Jobs run in the background and may claim ports or hardware resources; this page documents every installed job's arguments and ownership rules.