Signals
Other programs tell Candeo what happened — a build that failed, the doorbell, a call starting — and you decide what it lights. The sender never names a device, an effect or a colour: it states a fact, and what that fact changes is decided in Candeo.
A signal is a name and a value
build is failed, volume is 0.4,
muted is true. Names are yours to choose — letters, digits and
_ - . : — and values are flat: text, a number, true or false.
A value lasts 60 seconds unless the sender says otherwise, so a script that stops does not leave a keyboard lit for the rest of the day. A state sent once — a build that stays broken — is sent with no lifetime, and lasts until it changes or is erased. Values are kept in memory only: never written to disk, never written to the log.
Turning it on
In Settings › Signals, turn on Receive signals from other
software. Candeo then listens on this computer, at
http://127.0.0.1:7317/signals, and shows the token every request carries —
Copy it into your script; New token refuses every sender
still holding the old one.
For another machine — Home Assistant, most often — tick the network interface it reaches this computer through: Wi-Fi, Ethernet. Windows asks once whether to let Candeo through its firewall; allow it on private networks only. The port is 7317, and can be changed there.
Sending one
PowerShell, at the end of a build script:
$headers = @{ Authorization = "Bearer $env:CANDEO_TOKEN" }
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:7317/signals?ttl=0" `
-Headers $headers -ContentType "application/json" -Body '{"build":"failed"}'
curl, which Windows 10 and later ship, and every Linux:
curl -H "Authorization: Bearer $CANDEO_TOKEN" -H "Content-Type: application/json" \
-d '{"build":"ok","tests":"running"}' http://127.0.0.1:7317/signals
The answer says what was taken and when it expires — ?ttl= sets the lifetime
in seconds, 0 for none, and an empty string erases a name. A request is taken
whole or not at all, and a refused one says why. Settings lists the signals held, with
their time left, and Send a test signal tries a rule before any sender
exists.
Which to use
A signal can change which effect runs — a rule, in the Automations tab — or set a value of the effect already running — a setting following it, in the gallery. The first takes the device over for a while and gives it back; the second never changes the effect, only one of its settings.
| You want | Use | Where |
|---|---|---|
| the keyboard red while the build is broken, then your effect back | a rule, while it holds | Automations |
| a flash when the doorbell rings | a rule, for a few seconds | Automations |
| your gradient's colour, or an effect's speed, set by a script | a setting following the signal | the gallery |
| several signals on the keyboard at once | Status row, or an effect reading them | the gallery |
A word someone chose — failed, ring — is for a rule, which
decides what it means. A value the sender computed — a colour, a level — is for a setting.
Three ways to use it
A rule waits for it
When build is failed · on Alienware m18 R1 · show Fixed gradient · while it holds
While it holds suits a state: the rule lasts from the moment the value arrives until it changes, expires or is erased. For 5 seconds suits an event: a flash at each receipt, so a doorbell rung again flashes again. Rules keep their priority and their Try — see automations.
A setting follows it
In the gallery, any setting of any effect — a colour, a speed, a choice — has a Value | Signal switch. On Signal, it takes the value sent under the name you type, at every frame, and keeps its own while nothing arrives. The effect needs no code for it: every effect that ships with Candeo, and every one you write, follows a signal this way. A rule's settings bind the same way.
A device's Brightness follows one the same way, under its slider: send
a number from 0 to 100, {"lux": 40}, and the keyboard dims to that percent of
the slider, whatever effect runs.
| Setting | Takes |
|---|---|
| Colour | #rrggbb or #rgb, the # optional |
| Number | a number or its text, kept within the setting's range |
| On / off | true, false, 1, 0 |
| Choice | one of its choices |
| Text | any value, as its text, up to the setting's length |
Anything else leaves the setting as it was. So a script computing a colour sends
{"status": "#ff0000"} and the colour follows; a word like failed
is for a rule, or for Scrolling text, which shows on the keys whatever
its Text setting receives. The effects the device's firmware runs are the exception: their colour is
written into the device once, not drawn frame by frame, and they have no switch.
An effect reads them all
Status row, shipped with Candeo, gives each signal a key of the top row,
in the order of their names, green, amber or red by what it says — ok,
running, failed — and a number as a level. A prefix keeps only
the names starting with it, ci. for ci.build and
ci.tests. An effect you write
does the same by declaring inputs: ['signals']; the
signals documentation
has one to copy, drawing each number received as a bar.
Naming: facts, not devices
The sender only knows the names you chose. The link between a name and a device is made in Candeo, when you bind a setting on that device or write a rule for it.
-
Name the fact —
build,meeting,doorbell— and decide in Candeo which device shows what. Change keyboards, and the script does not move. - The same name on two devices changes both with one request: every keyboard shows the build.
-
A name each —
desk.colour,laptop.colour— for a script that drives each keyboard's colour on its own.
Settings › Signals shows, under each name, what it drives — a setting on a device, a rule — and lists the names something waits for that have not arrived.
Recipe: your computer's load on the keys
A few lines send the processor's load and the memory in use, as percentages, every couple of seconds. PowerShell, left running in a window or started with your session:
# The processor's load and the memory in use, 0 to 100, as pc.cpu and pc.ram.
$headers = @{ Authorization = "Bearer $env:CANDEO_TOKEN" }
while ($true) {
$cpu = (Get-CimInstance Win32_Processor | Measure-Object LoadPercentage -Average).Average
$os = Get-CimInstance Win32_OperatingSystem
$ram = 100 * (1 - $os.FreePhysicalMemory / $os.TotalVisibleMemorySize)
$body = @{ 'pc.cpu' = [int]$cpu; 'pc.ram' = [int]$ram } | ConvertTo-Json -Compress
# Ten seconds of life: when the script stops, the keys go back to what they were.
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:7317/signals?ttl=10" `
-Headers $headers -ContentType "application/json" -Body $body | Out-Null
Start-Sleep -Seconds 2
}The same on Linux:
while true; do
cpu=$(vmstat 1 2 | awk 'END {print 100 - $15}')
ram=$(free | awk '/^Mem:/ {printf "%d", 100 * $3 / $2}')
curl -s -H "Authorization: Bearer $CANDEO_TOKEN" -H "Content-Type: application/json" \
-d "{\"pc.cpu\":$cpu,\"pc.ram\":$ram}" "http://127.0.0.1:7317/signals?ttl=10" > /dev/null
sleep 1
done
Then choose what shows it:
-
Status row with the prefix
pc.: a key per value, green when idle, red when full. -
Any setting following
pc.cpu: a wave that speeds up when the computer works, kept within the setting's range. - The brightness following it, under the device's slider: the keyboard brighter as the load climbs.
Temperatures and the graphics card are not in Windows' standard counters. A monitoring tool that serves its readings locally — LibreHardwareMonitor's web server, for one — can be read by the same loop and its numbers sent the same way.
Home Assistant
Once the interface is ticked, a rest_command in
configuration.yaml, with the address of the computer running Candeo:
rest_command:
candeo_signal:
url: "http://192.0.2.23:7317/signals"
method: post
headers:
Authorization: !secret candeo_bearer
content_type: "application/json"
payload: '{"{{ name }}": "{{ value }}"}'
with candeo_bearer: "Bearer <token>" in secrets.yaml, and
an automation calling it:
action:
- action: rest_command.candeo_signal
data:
name: doorbell
value: ring
What the token protects
Signals are off until you turn them on. Every request carries the token, this computer's own included, and a request coming from a web page is refused: a page can reach any port of this computer, and the token is what it does not have. Whoever holds it can set values, and nothing else — not choose a device or an effect, not read your settings. Keep it out of shared scripts all the same, and make a new one if it leaks. The rest is in the privacy policy.
Further
The request in full — every answer and every bound — is in docs/api/signals.md, and the reasons behind these choices in docs/design/inputs-and-automations.md.