Skip to content

control: workflow recipes

Open tool page →

Control connected devices and services, retrieve results, and capture camera snapshots.

Choose exactly one target: id for a specific endpoint/group, or query using the same field-first filter as endpoint_query. Query targeting can control all matching authorized devices in one durable request; it is not restricted to a named device or group. Port OS freezes every selected recipient once, across all pages, with a maximum of 100. Empty selections and larger sets fail before delivery. Do not split or narrow an explicitly requested whole-house action without reporting the coverage.

For all lights off, first discover every inventory page and select the physical lighting controls, including known lamp switches, with no duplicate provider routes. Then use {"idempotencyKey":"<unique intended-action key>","query":{"id":{"in":["<discovered physical light endpoint ID>","<discovered physical lamp switch endpoint ID>"]}},"message":"port1/systems/zero/capability-interfaces/power/messages/turn-off@1.0","payload":{},"waitForResult":true}. A type filter alone is suitable only when the inventory establishes that its matches are the intended physical devices. Use turn-on with a new key for a separate all-lights-on action. Inspect every result and error and fresh observations before claiming that every light changed. Query selection adds no implicit provider, SELF-route or simulator exclusion.

For a specific device, discover it with endpoint_query or the room with group_query. Copy its full id, message and optional routeId; routeId is accepted only with id. Send a matching payload ({} for a command without fields). Preserve the account that returned the IDs and clarify ambiguous targets before writes.

Controls create a durable message request. Inspect status QUEUED, IN_PROGRESS, SUCCEEDED, PARTIALLY_SUCCEEDED or FAILED and its results/errors lists; acceptance alone does not prove physical state. For result-returning commands, such as search, library pages and get-snapshot, set waitForResult=true. A correlated result appears in results; snapshots also return image pixels and timeOfSample. Outbound declarations include events, so they do not guarantee that every command responds. For playback, volume and power, omit waitForResult and verify fresh state using endpoint_query or group_query with declared expand capabilities and forceDeviceAttributeQuery=true.

Live music queue recipe for "set up a playlist and play it on my Sonos": build an active playback queue unless the customer also asks to save a reusable library playlist. This recipe is available to tools-only clients without resources/read or bundled skills.

  1. Discover the Spotify library and the requested speaker or native group. On the library's declared media-search/search-media message, use payload {"query":"<artist or mood>","type":"track"} and waitForResult=true. Copy playable canonical track IDs from the returned tracks; do not invent IDs or pass a search phrase to playback.
  2. Select the target route declaring media-queue, preferring the native Sonos route when available. Check its supportedMediaResources and maxItemsPerPlay. Send one play-queue message with payload {"mediaIds":["<returned track ID>","<returned track ID>"]} and the copied routeId. This starts a new ordered selection. play-queue has no queueVersion field; requiresQueueVersion applies only to add-to-queue. Do not emulate a queue with repeated single-track play-media commands.
  3. Send get-queue with payload {} and waitForResult=true on the same target and route. queue-contents returns currentMediaId, upcoming mediaIds, complete and an optional queueVersion. complete=false is a limited window, not proof that other songs are absent. Read FRESH media-player observations with endpoint_query/group_query, expand=["media-player"] and forceDeviceAttributeQuery=true before claiming playback.
  4. To add music without restarting, search for another track and send add-to-queue once with {"mediaId":"<returned track ID>"}. If requiresQueueVersion=true, first read get-queue and include its exact queueVersion in that append payload. Spotify Connect does not accept queueVersion; omit it there. Read the queue again after each append. A conflict or uncertain write requires inspection, never an automatic retry or replacement selection. No saved-playlist command is needed for this live-queue workflow.

A failed search does not establish that the speaker stopped or the whole connection is unavailable. Preserve current playback, report the failed operation, and use fresh device observations for playback claims. Do not substitute remembered song names or invented IDs for returned playable tracks. The search payload type is lowercase "track", not the uppercase capability configuration label "TRACK".

Room lighting scenes: use group_query with expand:["scene"] and forceDeviceAttributeQuery:true, select the requested native provider group/route, and inspect its declared messages. To recall an available scene, send scene/activate with {"sceneId":"<returned scene ID>"} on that group and route. To save a new scene, first set the requested member lighting states, then send its declared scene/create-scene with {"name":"<scene name>"} and waitForResult=true. This snapshots the group's current light settings; it does not activate the scene. Use the returned scene-created.sceneId for activate, and fresh-query available-scenes before repeating an uncertain create. After recall, verify each affected light's fresh power/brightness and supported color state; dispatch acceptance or a scene label alone does not prove every light changed. Never create or recall a scene on another room or provider route as a fallback.

Use only capabilities and commands declared by the selected device or service. Examples of device classes and providers, subject to the connected integration's support:

  • Lights, switches and plugs: on/off and brightness (Philips Hue, Tuya, TP-Link).
  • Phones, tablets, laptops, wallets and trackers: locate or ring (Apple Find My, Tile).
  • Thermostats and temperature sensors: heat/cool settings; read ambient temperature with endpoint_query (Nest, Tuya, ecobee).
  • Cameras: request a declared get-snapshot command and inspect the returned pixels (Ring, Nest and other cameras). A snapshot is distinct from live video.
  • Connectivity and battery: check declared observations with endpoint_query for phones, watches, locks and other devices.
  • Smart locks and PINs: use declared lock and PIN commands (August, Yale, Ring, Seam).
  • Home appliances: supported controls and running-state observations (Samsung, LG, Xiaomi).
  • Robot vacuums: clean rooms and return to dock (Roomba, Roborock, Dreame). Send clean-room to the robot listing the room in controllableGroups with {"groupIds": [<group ID>]}. Bounded remote driving requires fresh visual feedback; cleaning is not navigation.
  • Speakers and announcements: supported speech and audio playback (Sonos, Alexa, Nest cameras).
  • TVs, remotes and media libraries: playback, volume, search and declared playlist operations (Spotify, Fire TV, YouTube, Chrome, TCL, Samsung, LG).
  • Files and photos: declared browse, download, upload, rename, move and delete commands (iCloud Photos, iCloud Drive, Google Drive, Outlook). download-file returns a URI; catalog presence alone does not establish upload support.
  • Litter robots and pet appliances: declared cleaning, waste and dispensing observations or controls.
  • Water sensors and sprinklers: declared water detection, watering state and controls.
  • Calendars and reminders: declared list, create, complete, reschedule and delete operations (iCloud Calendar and Reminders). Connected reminders are distinct from assistant-created scheduled tasks.

Read the relevant bundled skill reference or portos://guides/index for unfamiliar workflows. File/reminder deletion and PIN changes modify account data. Inspect partial or uncertain writes before another action. TIMED_OUT means unknown outcome: read state before considering a new command. Reuse the same idempotencyKey to inspect or wait on the existing request. MESSAGE_UNSUPPORTED or MESSAGE_AMBIGUOUS means nothing was sent; correct the message from discovery. An unreachable device rejected the command. Never automatically retry a state-changing command or claim success from conflicting observations.

Use endpoint_manage/group_manage to change names, types, membership or merges.