Use the CLI
Scripting
JSON output, exit codes, commands that take input on stdin, and several accounts.
On this page
Every command is meant to be as easy to use from a script, or an agent, as at a terminal: results are JSON, failures are JSON, and the exit code says what kind of failure it was.
Output
A command prints its result as JSON on stdout, indented for reading. With --json (or -j) it
prints the same JSON on one line. Either form goes straight into a tool such as jq:
ledable devices list --json | jq -r '.[].nickname'Commands that print as they go, such as ble scan,
devices logs and the page commands below, print one JSON
object per line, with or without --json.
Everything meant for a person goes to stderr: prompts, progress such as Sent a sign-in link…,
and failures. stdout carries results only.
Failures and exit codes
A command that fails writes one JSON object to stderr, on one line, and exits with a code other than 0:
{"error":{"code":"usage","message":"Specify the device with --device <id>"}}| Exit code | code | What happened |
|---|---|---|
| 0 | The command did what it was asked | |
| 1 | operation_failed, or a code from LEDABLE's servers | It could not be done |
| 2 | usage | An argument, option, file, stdin line or setting value was wrong |
| 124 | timeout | The command ran out of time |
| 130 | interrupted | Ctrl-C, or the process received SIGINT or SIGTERM |
When LEDABLE's servers refuse a request, code says why: unauthorized when the sign-in is no
longer accepted (sign in again), transport when the network failed, or a specific reason such as
deviceNotFound. message says what went wrong, in the phone app's words where it has some.
Timeouts
Every command gives up after a time of its own, which --help and the
command reference show: 30 seconds for most, longer for those that
wait on a person or a display. --timeout <seconds> sets another, up to 86400 (a day):
ledable devices logs --device "$DEVICE" --timeout 3600A command that runs out of time fails with exit code 124. The exceptions are the commands that
watch something until you stop them, such as devices logs
or devices presence: for them the timeout is how long
to watch, and reaching it ends them with exit code 0.
Secrets in scripts
A password, token or one-time code is never an argument, where shell history and the process list would keep it. At a terminal the CLI asks for it without showing what you type. In a script, pipe it into stdin, one line per secret:
wifi join --password-stdinreads the Wi‑Fi password.auth login --code-stdinreads the one-time code from the sign-in page.store installandplaylist configureread one line for each--credentialfield, in the order you named them, whenever stdin is not a terminal.
printf '%s\n' "$PASS" | ledable wifi join Home -d "$DEVICE" --password-stdinPage commands
Some commands run one of the app's pages instead of doing one thing: the same page, with the same
rules, the phone shows. Their descriptions in --help start with "Run the app's …":
| Command | Page |
|---|---|
ble link | Pairing |
wifi setup | Wi‑Fi |
playlist page | Playlist |
playback control | Player |
settings page | Display settings |
firmware page | Firmware |
devices logs-page | Logs |
devices presence | Online status |
A page command prints a line {"state": …} each time what the page shows changes. It reads stdin
one line at a time: the first word names what to do, as tapping a control would, and the rest of
the line is its argument, kept whole so that a network name may contain spaces. The lines a page
takes are listed under "Stdin, one line at a time" in its --help and in the reference. A line the
page does not know is reported on stderr, and the page carries on. A line sent before the page can
act on it may be refused or ignored, so wait for the state that offers it.
A page runs until its timeout and then ends with exit code 0; the pairing page also ends once a display is claimed. Ctrl-C ends a page at once, with exit code 130.
Example: reorder the playlist
Open the playlist page for a display, giving yourself two minutes:
ledable playlist page --device "$DEVICE" --timeout 120The first line says the playlist is loading. The next shows it, on one line; here it is indented for reading:
{
"state": {
"load": { "kind": "loaded" },
"editing": false,
"changed": false,
"writing": false,
"failure": null,
"apps": [
{
"instance_id": "…",
"name": "Clock",
"enabled": true,
"kind": "urlApp"
},
{
"instance_id": "…",
"name": "Weather",
"enabled": true,
"kind": "urlApp"
},
{
"instance_id": "…",
"name": "Holiday",
"enabled": true,
"kind": "dataApp"
}
]
}
}kind is urlApp for a store app and dataApp for a picture. To move the picture to the top,
type these lines, as you would tap Edit, drag the row and tap Done:
edit
move 2 0
doneAfter edit, the state has editing: true. After move 2 0 (from position 2 to position 0,
counted from 0), the picture is first in apps and changed is true. After done, a line with
writing: true follows, and then one with writing: false and failure: null once the new order
is stored. If the playlist changed elsewhere in the meantime, failure says so; type force to
store your order over it, or discard to drop it. Press Ctrl-C to leave, or let the timeout end
the page.
From a program
A program drives a page the same way: read stdout line by line, parse each state, and write a line
to stdin when the state shows what you were waiting for. Send edit only once load is loaded,
for example, just as a person would wait for the list to appear.
For a single change, the one-shot commands do this for you and exit when the change is stored:
playlist move opens the same page, makes the same moves
and waits for the write. Several page commands also have a one-shot form of their own:
ble link --first, firmware page --update, and wifi join for the Wi‑Fi page.
Several accounts
You can be signed in to more than one account on one computer. Each auth login with another
address adds that account and makes it the current one, and every other command acts as the
current account, on its displays.
ledable auth accounts
ledable auth use <user_id>auth accounts lists the accounts signed in here, each
with its user_id, email and whether it is current.
auth use makes another one current.
auth logout signs out of the current account only; until
you auth use another, no account is current.
What the CLI keeps on your computer
- A folder in your home directory,
.ledable/cli, which on macOS and Linux only your user can read. It holds the accounts signed in here, each account's list of displays, the log lines read so far, cached files and the date of the last update check. - Sign-in tokens and the keys that let the CLI talk to your displays over Bluetooth are kept in your system's credential store, such as the Keychain on macOS or the Credential Manager on Windows, never in that folder.
auth logout removes the current account's credentials and
its list of displays.
The update notice
At most once a day, the CLI asks npm for its newest version. When there is a newer one, it says so on stderr after the command has finished:
ledable 0.2.0 is available (this is 0.1.0): npm install -g @ledable/cliIt only does this when stderr is a terminal and the CI environment variable is not set, so
scripts and CI always see the same output. If npm cannot be reached, there is simply no notice.