Remote — remote
A handheld remote, and the one input whose buttons already mean something.
This is the distinction from keypad, and the whole reason it is a separate contract. A keypad
reports that key 3 was clicked, and key 3 means whatever a rule says it means — which is correct
for a Pico on a wall, where the buttons are blank and the intent lives in the project. A remote is
the opposite: it has Play, Vol + and a d-pad printed on it, the person holding it already knows
what they will do, and making somebody author fifty rules to say so is the programming step this
contract exists to delete.
So a remote emits named commands from a fixed vocabulary, and the vocabulary is deliberately
the command names room, media_player and tv already use. A volume_up from a remote bound to
the Living Room is room::volume_up in the Living Room — the pathfinder already knows which device
owns that room's volume, and it changes when somebody watches something else. Nothing about the
remote had to be reprogrammed, because the remote never named a device.
That is the property worth protecting: a remote addresses a room, never a device. Point it at a device and it is a learning remote with a macro list, which is the thing every one of these systems was built to replace.
Not every button is universal, and pretending otherwise is how contracts like this go wrong. A
softkey, a colored teletext key and a "List" button mean nothing outside the box that shipped
them, so they do not get forced into the enum — they arrive as custom, carrying the label the
device prints on itself, and a rule binds them exactly as it would a keypad's key. One contract,
two honest halves: what the house can route on its own, and what still needs somebody to say.
Like keypad, this resolves to no commands at all. There is nothing to ask of a remote.
Capabilities
Declared in the driver manifest under [[proxy]] capabilities. Anything not declared takes the default below.
| Capability | Type | Default | Meaning |
|---|---|---|---|
custom_labels | string | "" | What the non-universal keys are called, comma separated, in the order the device reports them — |
"Soft Lft,Red,Green,List". These are the labels a custom notification carries, and a rule editor | |||
| offers them by name rather than by index. | |||
has_battery | bool | false | |
has_channel | bool | false | Channel up/down, which is not the same as skip — see channel_up |
has_dimming | bool | false | Brighter and dimmer keys. A four-button dimmer's middle pair, and the reason they are here rather |
than folded into volume: room::dim_up is relative to wherever each light already is, which is the | |||
one thing an absolute level cannot express — see that command's note. A remote with has_repeat | |||
| gets a ramp from the same rule for free. | |||
has_dpad | bool | false | Arrows and a select key |
has_hold | bool | false | Tells a held key from a tapped one, which is what turns a volume step into a ramp |
has_menu | bool | false | Menu, guide, info, exit — the keys that open something |
has_numeric | bool | false | Digits 0-9, and usually enter |
has_power | bool | false | Discrete on and off keys rather than a single toggle |
has_repeat | bool | false | Reports repeatedly while a key is held |
has_transport | bool | false | Play, pause, stop and the scan/skip keys |
has_volume | bool | false |
Notifications
battery_changed
Only present when
has_batteryis declared true.
| Parameter | Type | Notes |
|---|---|---|
percent | u8 0–100 |
command
A button with a universal meaning was used. This is the notification the house routes without being
told how: command names an intent that room, media_player or tv already accepts, so it
resolves against whatever the room is currently doing.
action is what was done to the key, and it matters as much as which key it was. A click on
volume_up is a step; a hold on it is a ramp, and the consumer answers that with
media_player::hold { what = "volume_up" } rather than by re-sending forty steps — see that
command's note on why those are not the same thing. release closes a hold; repeat is for
hardware that streams while a key is down, which a step-per-tick rule wants and a ramp does not.
The vocabulary is closed on purpose. An open string would mean every consumer carrying a table of
spellings, and the first remote that said vol_up instead of volume_up would fail silently at
the far end. A button that does not fit sends custom instead, which is exactly what that is for.
| Parameter | Type | Notes |
|---|---|---|
action | one of click · double · hold · release · repeat | |
command | one of play (needs has_transport) · pause (needs has_transport) · play_pause (needs has_transport) · stop (needs has_transport) · record (needs has_transport) · skip_forward (needs has_transport) · skip_back (needs has_transport) · scan_forward (needs has_transport) · scan_reverse (needs has_transport) · up (needs has_dpad) · down (needs has_dpad) · left (needs has_dpad) · right (needs has_dpad) · select (needs has_dpad) · back (needs has_menu) · exit (needs has_menu) · menu (needs has_menu) · home (needs has_menu) · guide (needs has_menu) · info (needs has_menu) · volume_up (needs has_volume) · volume_down (needs has_volume) · mute_toggle (needs has_volume) · dim_up (needs has_dimming) · dim_down (needs has_dimming) · channel_up (needs has_channel) · channel_down (needs has_channel) · previous_channel (needs has_channel) · power_on (needs has_power) · power_off (needs has_power) · power_toggle (needs has_power) · enter (needs has_numeric) |
custom
A button with no universal meaning: a softkey, a colored key, a vendor's own function. It carries the label the device prints, so a rule reads "Red" rather than "key 46", and an index so two keys printed the same are still distinguishable.
This is the escape hatch that keeps the command vocabulary honest. Without it, every device-
specific button would either be dropped or crammed into the enum under a name nothing else uses —
and an enum that means something different per device is a string with extra steps.
| Parameter | Type | Notes |
|---|---|---|
action | one of click · double · hold · release · repeat | |
index | u32 ≥1 | Position in custom_labels, from 1. |
label | string | What the device prints on it. |
digit
Only present when
has_numericis declared true.
A number key. Separate from command because a digit is a value rather than an intent — ten more
entries in that enum would say the same thing ten times, and a consumer that wants to build a
channel number wants to accumulate an integer, not switch on "digit_7".
| Parameter | Type | Notes |
|---|---|---|
action | one of click · double · hold · release · repeat | |
value | u8 0–9 |
online_changed
| Parameter | Type | Notes |
|---|---|---|
online | bool |
State
Last-known values core keeps for a binding of this proxy.
| Key | Type | Meaning |
|---|---|---|
battery | u8 | |
last_command | string | What the remote last sent, action included — "volume_up hold". A remote that is working and a remote that is not look identical until this is on screen. |
online | bool |