Devices
Written by ddxfish on .
- Docs
- Devices
- All docs ↓
You are reading the dev branch of the docs, which may describe unreleased changes. Read the main docs.
Add machines and gadgets once, then Sapphire uses them by name. Devices is part of Sapphire itself.
| Type | Comes with | What it is |
|---|---|---|
| This computer | Sapphire | The machine she runs on: volume, outputs, screen, power |
| Satellite | Sapphire | A room box with mic, speaker, light and camera: a Raspberry Pi, an ESP32 board |
| SSH machine | the SSH plugin | Any machine you can log in to |
| WiFi gadget | the gadget plugin | A small board with a light, a screen, a button |
| IP camera (ONVIF) | the IP Cameras plugin | A network camera she sees through, and turns and zooms when it can move |
| Hardware synth, MIDI keyboard | the MIDI plugin | Instruments she plays and hears |
| Phone (KDE Connect) | the KDE Connect plugin | A phone running the KDE Connect app: shares to her chat, its texts, a notification from her, battery |
Any plugin can bring more types. A type appears when its plugin is enabled.
The page
System > Devices in the rail (or the Devices tab in Settings). One card per device: its dot, name, what it can do, and its state. When the devices are of more than one type, a row of pills at the top filters by type; All is the default.
Add a device
- System > Devices > + Add Device (a satellite has its own button, + Add Satellite, over the left column).
- What are you adding? One row per kind of thing: Camera, Computer, MIDI, Sapphire. Open one to see the ways it is reached, each with an Add button: a Computer is This computer or an SSH connection. A greyed-out row names the plugin to enable.
- Only what that type needs to work: a name (one is filled in, change it if
you like; it is what Sapphire calls it, for example
desktop), the address and keys for a satellite, host and user for an SSH connection, nothing at all for this computer. A Location if you like, for exampleLiving Room: Sapphire sees it in her device list, and at the top of anything the device hears. - Add and test. The device window opens and checks it once. Everything else - looks, chat, camera, power - has a sensible default and is on the window's tabs.
The device window
- Status shows online or offline, the reason when it is offline, and any readings. Test now checks it fresh. Sapphire checks every device on her own in the background; a device goes offline after two missed checks in a row and comes back on the first answer, so one slow reply never flips it. A pulsing dot means a check is running right now.
- One tab per thing the device can do. Each lists its actions with a Try button. The box beside it sends what you type; the grey text in it is only an example. Empty is allowed: an action that reads something, like
volume, answers with it. - Save keeps the window open. Try runs the saved version.
What Sapphire can and cannot do
She has three tools: device_list, device_status, device_action. She can use a device. She cannot add, change, or remove one, and she never sees a stored password or key.
The tools' own descriptions name your devices, where they are, whether they
are online, and what each can do, so she rarely needs device_list.
device_action("pi2") answers with how the device is and everything it can
do, with the value each action takes; the run is her second call. One screen
stays under about a thousand tokens.
Turn a device off on its Status tab and she cannot see or use it.
Power: restart, shut down, sleep
A device that can be restarted or switched off has a Power tab.
| Device | Restart | Off |
|---|---|---|
| Satellite | Yes, back in about a minute | Shutdown. Unplug and replug it to bring it back |
| WiFi gadget | Yes, back in a few seconds | Sleep. It has no true off while plugged in. Its button wakes it |
| SSH machine | Yes | Shutdown |
Sapphire may use this is a switch on the Power tab, one per device. Turn it off and she is told that power is locked on that device, and where you can change it. Your own buttons on the tab always work, and each asks first.
| Device | The switch starts out |
|---|---|
| Satellite, WiFi gadget | On |
| SSH machine | Off |
Shut a satellite down before you touch its cables. The camera connector carries power. Moving the ribbon while the Pi runs can short it.
SSH machines use two commands that you can change on the Power tab. The
usual ones wait one minute, so a mistake can be cancelled on that machine
with sudo shutdown -c. They need sudo without a password for the login
user. Clear a command and that action is gone.
This computer
The machine Sapphire runs on. It needs no address and no key. Add it with + Add Device, type This computer.
device_action("computer","sound","set","40")
device_action("computer","sound","up")
device_action("computer","sound","mute")
device_action("computer","sound","outputs")
device_action("computer","sound","use","2")
device_action("computer","screen","look")
| Setting | What it does |
|---|---|
| Volume step | How far up and down move the volume |
| Loudest Sapphire may set | She is held to this. Your own volume keys are not |
| Part | Linux | Windows |
|---|---|---|
| Volume and mute | Yes. Needs one of wpctl, pactl, amixer |
Yes |
| Outputs | Yes, with wpctl or pactl |
No |
| Screen | Yes, through the Screenshot plugin | Yes, through the Screenshot plugin |
| Power | Restart, shutdown, sleep | Restart, shutdown |
Power starts out locked for her. Turn on "Sapphire may use this" on the Power tab if you want her to restart or shut down your computer. She goes down with it, and says so.
The screen has the same switch. With the Screenshot plugin switched off, this computer has no Screen tab.
Backups into a folder here
The Backup tab on this computer takes a folder that already exists: a USB
stick, a NAS mount, a second disk. Every night Sapphire copies the local backup
there and keeps the counts you set. A folder on your own machine may hold plain
.tar.gz backups (the default); tick Seal them to get .sapphirebak files
that only the backup password opens. A network share mounted here (SMB, NFS,
sshfs) is another machine with a local name, so it is always sealed whatever
the box says: that is how a NAS gets backups. A folder inside Sapphire's own user/ is
refused. A stick that is not plugged in is reported, never replaced by a folder
on the main disk. The opener scripts land beside the backups either way.
MIDI keyboard
A plain MIDI keyboard makes no sound of its own. This device gives it one: the computer becomes the instrument. It comes with the MIDI plugin. Linux only.
- Plug the keyboard in.
- + Add Device, type MIDI keyboard.
- Play.
Every MIDI source plays through it: a keyboard on USB, a synth linked over Bluetooth, several at once. One that is plugged in later joins in under half a second.
The sound runs only while something is there to play. It starts when the first source arrives. It stops 20 seconds after the last one leaves, so a replug is not a restart. A source that is pulled out with a key or the pedal down never leaves a note ringing.
Plays through it, on the Status tab, says which sources count:
(•) Every MIDI source
( ) Only these
[x] AKM320 USB
[x] FM-1_BLE Bluetooth
[ ] Old keys not here now
[Look again]
The list is live. A source you ticked stays on the list while it is away.
device_action("keyboard","sound","instrument","organ")
device_action("keyboard","sound","loudness","60")
device_action("keyboard","notes","play","C4 E4 G4 C5:2 bpm=120")
device_action("keyboard","notes","listen","30")
Sapphire plays on the same instrument, so you can play together. She hears
what you play with listen.
The keyboard's own volume slider works. Its lowest position is quiet, not silent. A keyboard whose slider sits at zero would otherwise make no sound at all, with nothing on the screen to say why. A pedal that sends expression is treated the same way.
| Setting | What it does |
|---|---|
| Instrument | A name like piano, organ, strings, or a General MIDI number |
| Loudness | The instrument's own level. The computer's volume comes on top |
| Plays through it | Every MIDI source, or only the ones you tick |
| SoundFont file | Optional. Your own file with other instrument sounds |
It needs fluidsynth, alsa-utils and a SoundFont. On Debian and Ubuntu the
packages are fluidsynth, alsa-utils and fluid-soundfont-gm. The Status
tab says which one is missing. The hardware synth device and the MIDI tools
need none of these: they talk to the ports through the plugin's own MIDI
library, installed with one click on the plugin's card, on Windows, Linux and
macOS alike.
Connections
A device is added with one way to reach it. A kind that can be reached more than one way (a Computer) has a Connections tab in its window: + Add Connection gives it another, the arrows change their order, Remove takes one off and forgets its keys. When two connections can do the same thing (restart it, say), the earlier one does it. A device counts as online while any of its connections answers, and the Status tab says how each one is.
SSH machines
Four ways to log in:
| Login | Use it when |
|---|---|
| Auto | The user Sapphire runs as can already ssh to the machine |
| Key file | The key is a file on this machine |
| Pasted key | You want the key stored with Sapphire, scrambled |
| Password | The machine takes passwords. The weakest choice |
Keys locked with a passphrase are not supported yet.
Premade commands are a name and the command it runs. Put {value} where Sapphire's input goes. Keep {value} outside of quotes. It is quoted for you.
name: volume command: pactl set-sink-volume @DEFAULT_SINK@ {value}%
Allow any command lets her run anything, checked against the SSH plugin's blacklist. Leave it off and she can run only your premade commands.
Backups there. Give the machine a Backup folder on its Backup tab (absolute, or relative to the login's home, such as backups/sapphire) and it holds sealed backups like a satellite's card: the nightly copy after each 3am run, backup on demand, and Send to devices on Settings > Backup. scp carries the file, then the machine's own sha256sum is checked before the copy counts. A Raspberry Pi added this way needs nothing installed on it. Keep counts and the opener scripts work the same as on a card.
Where things are stored
| What | Where | In backups |
|---|---|---|
| Devices and their settings | user/plugin_state/devices.json |
yes |
| Passwords and keys | the Sapphire config folder, device_secrets.json |
no |
After a restore onto another machine, devices come back but their passwords and keys must be entered again.
Satellites
A satellite is a small box in another room with a microphone, a speaker and a light. Say its wake word, ask your question, and Sapphire answers from that same box. The Raspberry Pi bodies are satellites. This type is built in.
A satellite says what it has. A board with no light shows no Light tab, and Sapphire is not offered one. Press Test now after you change what is on a board. Any board that speaks the Satellite Protocol can be added here. The programs for the boards Sapphire knows live in their own repository: https://github.com/ddxfish/sapphire-firmware.
A board with sensors (a light sensor, a temperature or humidity module) gets
a Sensors tab with one action, read, which measures everything now;
each sensor also shows as a reading in the status strip. A name ends in its
unit, like temp_c or humidity_pct; a bare light sensor sends its raw
number until it is calibrated.
A new board from the browser
An ESP32 board that has never been set up is done entirely from this page:
+ Add Satellite, then Dev board. The first question is where the board is
plugged in. This computer means the browser writes it over USB (Web
Serial, so Chrome or Edge): press Connect and pick its port in the
browser's window. The computer Sapphire runs on means she writes it
herself, from any browser: pick the port from the list. That lane needs
esptool in her environment; the first time it is missing, the page offers
to install it on the spot (the flash set, install/requirements-flash.txt,
into her own interpreter, with pip's words shown as they come). Flashing
from Chrome or Edge needs nothing. Either way the chip
is read, so only the boards it can run are offered, and the chip's own id
(its MAC) becomes the device's fingerprint: a board set up before is named
on the spot and keeps its name, and no name can be taken by a second board.
Install writes the firmware (a progress bar, under a minute) and checks
the hash of every part against what the chip reports.
Then a name, the WiFi (the networks the board can see, or one typed, for
a hidden network or a board being set up away from home), the password,
and Sapphire's address as the house sees this computer, prefilled from
its network interfaces. Check that one when a VPN is on: the tunnel's
address is not the house, and a board sent there never calls in. Sapphire
makes the board's two keys, hands it her address and certificate, and the
board restarts and joins the WiFi. The flasher writes the board's own
address into the device as soon as the board reports it, so the device
window can reach it at once; its status strip says whether the board
reaches Sapphire ("link to Sapphire"). From then on the address is learned
from the board's own calls, so a board that moves is followed. A board set
up away from its WiFi stays "waiting for the board" until it gets home.
A board that is already a device has both jobs in the ⋮ menu on its card: Reflash (USB) writes its program again, and Change WiFi (USB) gives it a new WiFi or a new address for Sapphire without reinstalling. Both take that board only, and it keeps its name; plug in another and you are sent to + Add Satellite. The same menu has Delete device. A device that already exists keeps its keys, its name and its address until the board calls in with the new ones, so a setup that fails halfway leaves it working as it was; a known board given a new name is that device renamed when it calls in. A name in use by a board Sapphire cannot prove is this one (a device added by hand, or a board whose id could not be read) is taken over only after the page asks: the board that has that name now stops working when this one calls in.
Updates, over the air. After that first install the cable is never
needed again: a board with two program slots says firmware and gets a
Firmware tab with one action, update. It sends the newest program the
firmware source has for that board, the board writes it into its other
slot, checks it, and restarts onto it. The new program is on trial until it
joins the WiFi or runs 90 seconds; one that fails is replaced by the old one
at the next boot, by the bootloader, with nobody's help. The status strip
says "update: 0.3.1 is in the firmware source" when a newer one is known
(check reads the source now; nothing is fetched in the background), and
the device's card in the list wears an "update 0.3.1" badge. update is
yours alone: Sapphire never runs it on her own and it can't be scheduled.
again installs the same version once more.
Every satellite's status strip says how its program is replaced:
"updates: over the air, running ota_0", "over USB only: one program slot"
(a board whose builder kept the whole flash for the program, or a tiny
chip), or "over the air, turned off for this device". That last one is the
Updates over the air switch on the device's Status tab: off means no
program is ever sent to that board from here, and its Firmware tab only
checks. The switch is Sapphire's; the board's own two slots are its
builder's choice and show up as firmware in what it says it has.
The firmware comes from the firmware sources: Sapphire's own release (the
latest release of the firmware repository, DEVICE_FIRMWARE_SOURCE), and
before it any you add in Settings > Devices > Settings with + Board Repo
(DEVICE_FIRMWARE_SOURCES). A source is a release URL, or a folder on
Sapphire's computer with an index.json (the firmware repository's
build.sh makes one in its dist folder). Every source is read; a board
two of them have comes from the first, yours before hers, and a board from a
source that is not hers is marked. Sapphire fetches it, never the page, and keeps each board's parts
under user/firmware_cache so a board can be flashed again offline.
The flasher's board list says where the firmware comes from: any source that is not Sapphire's release is named with a warning, each board from one is marked, and a device's Firmware tab says so too. Firmware from another source is someone else's code, not part of Sapphire: it runs on your board, holds your WiFi password and can talk to Sapphire as that device. Sources are added and removed in Settings > Devices > Settings, by you alone.
On Linux the browser opens the port as you, so you need to be in the
dialout group once; for the Sapphire-side lane it is the user she runs as. A board with native USB (an ESP32-S3) vanishes from
the port list while it restarts; if it does not come back on its own, the
flasher asks you to unplug it and plug it back in. If no bootloader answers
at all, hold the BOOT button while plugging the board in.
Adding one by hand
Add one with + Add Satellite, then Raspberry Pi or computer:
| Field | What to enter |
|---|---|
| Address | Where the satellite listens, like http://192.168.1.100:8090. Empty = learned the first time it calls in; it follows the satellite when its address changes, but only once the old address stops answering: an address you typed that works is never overwritten |
| Key Sapphire sends | The satellite's own key |
| Has a camera | Turn off for a satellite with no camera. Sapphire is then not offered one |
| Talks in chat | On the first tab. The chat this device is in: what it hears, what is typed on it and what its buttons send land there, and its screen shows it. Empty means the last chat used. A name means always that chat; a name that is not a chat yet is made when you save |
| Key the satellite sends | The satellite's own key for talking to Sapphire. See "Give a Pi its own key" below |
What Sapphire can do with it:
device_action("kitchen","speaker","say","Dinner is ready")
device_action("kitchen","speaker","stop")
device_action("kitchen","speaker","volume","80")
device_action("kitchen","speaker","sound","ping")
device_action("kitchen","mic","listen","10")
device_action("kitchen","light","set","cyan blink 5s")
device_action("kitchen","light","rest","sapphire heartbeat bpm=33")
device_action("kitchen","wake","off")
device_action("kitchen","camera","look")
device_action("kitchen","power","restart")
Stop. stop ends what she is saying there: nothing more of that reply
is sent, and the satellite cuts the sentence playing (Pi body 0.7.3 and the
ESP32 program have the door; an older body's sentence ends by itself). The
Speaker tab of the device window has a stop row with a Try button. On a
Pi body, one tap of the speaker's play/pause button while she is talking
does the same.
Two satellites in one room. When two of them hear your wake word, or a satellite and this computer's own microphone do, Sapphire answers once. The main app's microphone wins over any satellite. A satellite asks for the wake the moment it hears it; the one that asks first records and answers, the other's light goes back to resting within a second and it sends nothing. A board that cannot ask (an older body) is still answered once: its recording is transcribed and dropped if it says what the other heard, so a second person asking something else at the other box is still answered. Nothing to set up. A Pi body does not listen for its wake word while its own speaker plays, so her saying "hey Sapphire" cannot wake it (the ESP32 cancels its own speaker and needs no such rule).
All of them at once. all is every device that can speak, as one name:
device_action("all","speaker","say","Dinner is ready")
device_action("all","speaker","stop")
Her voice is rendered once and played on each at the same moment; a device
that is offline is left out and said so. all appears once two devices can
speak, and only speaks: volume and everything else stay per device. The
devices do not play in lockstep, so two in the same room sound like a doubled
voice; across rooms it is fine. A question asked at one satellite is still
answered on that satellite alone.
The camera. look takes one picture and she sees it. The ring spins red and
the satellite pings for 2 seconds first, so nobody in the room is caught
unaware. The Try button on the Camera tab shows you the same picture.
The light. set holds a color and animation for a time, 5 minutes if you
give none. clear ends it early. rest sets the resting light the ring
returns to, and it is kept after a restart. Fine settings are written
name=value: bpm=40 speed=fast floor=0.05 ceiling=0.4.
Its looks are settings on the Light tab, in the same words, one for each
state: Resting, Listening, Thinking, Using a tool, Speaking, No link to
Sapphire. rainbow is a color too, and rainbow is an animation. New
satellites start yellow for listening, rainbow for thinking, purple for a
tool, cyan for speaking.
Thinking rainbow spin
Using a tool purple pulse
Speaking cyan solid ceiling=0.6
Lights on from / until are clock times, by the board's own clock. Outside
them the ring shows Outside those hours instead of resting: off is dark,
and sapphire pulse ceiling=0.05 is a soft night light. A new satellite starts
at 08:00 to 00:00 and off, which is what the boards do before any save. Both
times empty = always on.
Listening, thinking and speaking always show, at any hour and even after
off turned the ring dark: when you say her name at 6 am the yellow comes up,
and the ring goes dark again when she is done. What she sets shows too, so
"a white light for the night" works at 2 am. The board keeps the time from
Sapphire, no internet clock. A Pi body from 0.7.0 takes all of this; an older
one keeps its own looks and hours.
Her answer starts early. A satellite hears her reply one sentence at a time, as she writes it, so the first words come a second or two after she starts instead of after the whole reply is written and rendered. The ring stays on thinking or tool between sentences and goes to idle when she is done. A Pi body (0.7.2) keeps its speaker open for the whole reply, so the sentences run on without a hole. Pressing play/pause once stops the rest of that reply.
She knows where a voice came from. Every question a satellite hears arrives with one line above it, and you see that line in the chat too:
[Voice from device "kitchen" (Kitchen Pi). Location: Kitchen. Your reply is spoken aloud there by itself: just answer, never call say on that device for it.]
What time is it?
The satellite does not wait for her answer. It is told at once that the question was heard. Her answer is spoken when she has one, however long that takes.
The light ring follows its own question only.
| Ring shows | Meaning |
|---|---|
| Thinking | She is working on what this satellite heard |
| Tool | She is using a tool for it |
| Speaking | Her answer is playing here |
| Error, a short red blink | This satellite got no answer. The log says why |
A question typed in the browser, or asked at another satellite, does not move this ring.
A busy chat. If the chat is in the middle of a turn, the question waits up to 20 seconds for it. After that it is dropped and the ring blinks red.
Private chats. A private chat never sends audio to a cloud speech engine, and never sends its reply to a cloud voice engine. The satellite stays silent and the reason is logged.
Backups on its card
A satellite with a card (the ESP32 board's TF slot, a folder on a Pi) gets a
Backup tab. Every night, after the local backup, Sapphire seals a copy
with your backup password and sends it there; the tab's three counts say how
many daily, weekly and monthly copies the card keeps before the oldest goes.
device_action("den","storage","backup") sends one now;
device_action("den","storage","list") says what is there and how much room
is left. For a rhythm of its own (Sundays at 4 AM, say) make a Device task
in Triggers > Scheduled with that same backup action and no AI in the loop
(Continuity). The card is plain FAT32: pull it, put it in any computer, and the
README.txt and open-backup scripts beside the archives open a backup with
your password and nothing else. Nothing ever lands on a card unsealed: Sapphire
checks before sending and the board checks again before writing. A board that
can wipe its card shows a Format button on the tab, for you only, behind
an I UNDERSTAND. No card, no tab. Set the password in Settings > Backup.
Buttons
A board with a real button (the BOOT button on an ESP32 board) gets a Buttons tab. Each button has three presses: short, long (held most of a second) and double. Each is set to one of:
| Set to | What happens |
|---|---|
| Leave it to the board | What the board does with it by itself; the line says what |
| Send Sapphire a message | The words you type there land in the device's chat (Talks in chat) as a turn, under a line that says a button was pressed on that device. Empty = "The boot button on den was pressed." Her reply is shown on the board's screen when it is a pocket terminal, spoken when it has a speaker, and otherwise only in the chat |
| One of the board's own jobs | What the board said it can do: listen now or stop her voice, the ring, the screen, the wake word, the speaker. It does these by itself, at once, with no trip to Sapphire |
| Nothing | The press does nothing |
One job is not the board's own but Sapphire's: Back up to this stick now, on a board with a card that offers it (the backup stick). The press asks her for a fresh backup onto that device. No chat turn is spent on it.
A press you set replaces what the board did with it. A short press fires at once unless that button has a double press set: then it waits a third of a second for the second press. The press line under the settings sends a press from the page, to try a message without walking to the board.
The board learns what is set when it connects and at every save. Before it has reached Sapphire, each press is the board's own.
Using BOOT this way changes nothing about flashing: Sapphire puts a board into its loader over USB by herself, and holding BOOT while plugging in is still the rescue. Do not hold it while the board restarts.
A backup stick
A satellite whose whole job is its card: the LilyGO T-Dongle-S3 with the
tdongle firmware. It is a backup device like any other with storage
(the Backup tab, the nightly copy, Send to devices), and three
things more:
- It checks what it holds. Each backup is read back from the card after it is written and its hash kept beside it. After every start the stick reads every backup back again. One that no longer matches shows as damaged backups in its readings; Sapphire removes it and sends a whole one at her next backup to that stick.
- Its LED and screen are its status, not her thinking: green = safe, blue pulse = writing (do not unplug), cyan = checking, red = no card, damaged or failed, amber = stale or out of reach. The screen's two lines are room used and how many backups with the newest one's date.
- Its button asks for a backup (a first press on a dark screen only lights it).
The check is a board's choice (BOARD_STORAGE_CHECKS in its firmware): it
costs a second read of every backup, so the voice board leaves it off.
A pocket terminal
A satellite with a keyboard and a screen instead of a mic: a small touchscreen board you type at. What you type lands in its chat (the Talks in chat setting, on its first tab) under a line that says it was typed there, and her reply appears on its screen as she writes it. Nothing is spoken. She can put a line across the top of its screen herself:
device_action("pocket","screen","show","Dinner in ten minutes seconds=60")
device_action("pocket","screen","clear")
Its light takes the same words as a ring. The first such board is the
capacitive Cheap Yellow Display: see tmp/pocket-esp32/README.md.
Give a Pi its own key
- Make up a long key. Enter it as Key the satellite sends on the satellite's Mic tab, and save.
-
On the Pi, add two lines to
/etc/default/sapph-body:SAPPH_DEVICE_ID=kitchen SAPPH_BRAIN_TOKEN=the-same-keySAPPH_DEVICE_IDis the device's name in System > Devices. - Restart the Pi:
sudo reboot. Restarting only the service can reset a Pi whose sound card driver has not been fixed.
The Status tab then reads link to Sapphire: connected.
A satellite without a key cannot reach Sapphire at all.
Addresses a satellite can call.
| Address | What it is for |
|---|---|
POST /api/devices/<name>/voice |
What it heard. Proven with its own key |
GET /api/devices/<name>/events |
What its light should show. Proven with its own key |
POST /api/devices/<name>/wake |
It heard the wake word: the room is its for the next words |
POST|GET /api/devices/<name>/text |
What was typed on it, and her reply for its screen |
Coming from the Body plugin
The Body plugin and its /api/body/ addresses are retired. Satellites replace
them. A Pi that still runs the old setup must be moved over before it can be
heard again:
- Update Sapphire first. The new addresses only exist in the new version.
- Add the Pi in System > Devices as a Satellite, with a key.
- Put the new
main.pyandbody_events.pyon the Pi, and give it its two settings as described in "Give a Pi its own key". - Put
device_list,device_statusanddevice_actionin the toolsets she uses, in place of thebody_tools.
| Body tool | Now |
|---|---|
body_speak |
speaker / say, speaker / sound |
body_hear |
mic / listen |
body_see |
camera / look |
body_ring |
light / set, clear, off, options |
body_set_baseline |
light / rest |
body_health |
device_status |
WiFi gadgets
Small boards with a light, a screen, or a button. The gadget plugin ships the program for the board and the setup steps. See its README.
Another Sapphire
A second Sapphire on your network, as a device. She is reached through her
MCP door, so first, over there: Settings > MCP Server, switch it on, and
make a token under System > API Keys. Then here: Add Device > Another
Sapphire: her address (https://192.168.1.102:8073), that token, and the
name of the chat on her side where this Sapphire's words should land. The
chat is made over there the first time it is used.
- Chat:
asklands in that chat with a line saying who is asking, and her answer comes back as the result.telldoes not wait. She is told to answer in her message; a question that came in this way cannot itself ask a Sapphire back, so two of them never go round in circles. - Her tools: whatever her user ticked under MCP Server, by name. Her
words fill the tool's arguments in order, the last one taking the rest:
device_actionwithpi2 light set purple pulse. A wrong guess answers with the list, as it does at home.
Status shows her name when she gave herself one (MCP Server > This Sapphire's name), how many tools she shares, and says so when her door is off or the token is refused.
Phones
A phone running KDE Connect (F-Droid or Play)
becomes a device. Sapphire shows up in the app as a desktop named
"Sapphire
Add Device > Phone (KDE Connect). Open the app on the phone while it is on your network and the phone appears in the pick list within seconds, with its pairing state under it. Pairing happens right there, before the phone is added, either way round:
- Press Pair under the phone. The phone shows an 8-character key, the line under the phone shows the same one. Accept on the phone within 30 seconds.
- Or tap Sapphire in the phone's app and request pairing there. The line under the phone shows the phone's key and an Accept pairing button.
The list keeps looking on its own, so the words change as the phone answers. Once it reads "Paired", Add and test. A phone that is not paired cannot be added. Pairing is once; the phone links by itself from then on. The app has to be a 2025 or newer build (protocol 8); older ones are refused with a word in the log. Unpair on the Link tab forgets the phone.
- Share to her. In the phone's share sheet pick Sapphire. A picture lands
in the chat as a pasted picture would, and she sees it; a document is read
out to her; text and links land as words. A picture or file shared from
the phone on the Share tab says whether it also stays as a file (under
user/plugin_state/kdeconnect_inbox; a kept document also goes into the chat's documents). - Texts. The Text messages tab is locked until you flip its switch: then she can list who texted lately (names, numbers, when), read one conversation by name or number (a number without its area code matches), and send a text as you. Texts wake her, on the same tab, starts a turn for every text that arrives on the phone: she reads it and answers in the chat, and may text back. Names come from the phone's contacts when KDE Connect has that permission. SMS permission is needed too.
- Notify. ping shows a notification on the phone with your words, and find rings the phone until it is found.
- Battery and Contacts (a name's numbers, a number's name; texts are shown with names when the app has Contacts permission).
Everything stays on your network. The phone's certificate is pinned at pairing; a phone that comes back with another one is refused until it is paired again. Unpair forgets it.
Hosted Sapphire
Devices are switched off on a hosted Sapphire. It has no home network to reach.
For plugin authors
See Device Drivers.
Edit this page on GitHub · docs/DEVICES.md @ a5fa790 · synced
