Przejdź do treści

Device API

Calling the connected device from an app, handling results and errors, and the device.on event model

3 min czytaniaTen poradnik jest dostępny tylko po angielsku.
Na tej stronie

The device object represents the hardware you have connected — or the built-in simulator, when nothing is plugged in. You use it to ask the device to perform an operation and get the result back, and to subscribe to events the device pushes while it runs.

Calling pattern

Every device operation is called the same way, however it's named: device.<namespace>.<method>(params?, timeoutMs?), or the equivalent flattened form device.rpc("<namespace>.<method>", params?, timeoutMs?). Both reach the same operation — pick whichever reads better for the call you're making.

// Dotted form
const s = await device.state.read()

// Equivalent flattened form
const s = await device.rpc("state.read")

// With params and a timeout
await device.led.set({ r: 255, g: 0, b: 0 }, 5000)

Every call returns a Promise, so use await inside an async handler (a button's onClick, a control's onChange, a ui.every timer). Nothing about the shape of a call tells you whether the device is actually connected — calling into a disconnected device rejects the promise the same way a failed operation would, so the error-handling pattern below covers both.

Handling results and errors

Wrap a call in try/catch (or .catch(...)) and report failures to the Console rather than letting them disappear:

ui.button({
  label: "Read state",
  onClick: async () => {
    try {
      const s = await device.rpc("state.read")
      console.log("op:", s.op, "battery:", s.battery_pct + "%")
    } catch (e) {
      console.error("state.read failed:", e.message || e)
    }
  },
})

You don't strictly have to catch every call yourself — an error thrown inside a button's onClick, a control's onChange, a ui.every/ui.after timer, or a device.on callback is caught by the runtime and reported to the Console regardless, including a rejected promise from an async handler. Catching explicitly is still worth doing when you want a specific, readable message instead of a raw error object, or want the rest of the handler to keep running after a failure.

Subscribing to events (device.on)

device.on(event, callback) subscribes to a stream of events the device pushes on its own — ongoing activity, not the result of a specific call. It returns a handle with .off() to unsubscribe early; otherwise every subscription from the current run is cleared automatically before the next Run, the same way timers are.

const sub = device.on("scan.hit", (hit) => {
  console.log("saw", hit.mac, hit.rssi)
})

// Later, if you want to stop early:
// sub.off()

What operations a device offers

The operations available depend on which device is connected — an Echo exposes sub-GHz operations; an AirLeak Pro exposes capture, radio, and location operations. The exact operation set, and what each one's result contains, is documented per device rather than duplicated here:

Running without hardware

When no device is connected, the App Builder can run your app against a built-in simulator instead — it answers the same calls and can emit the same events, so you can build and test the shape of an app before you're at your bench. Simulated and real devices are called exactly the same way from your script; nothing in the code above needs to change to point at real hardware later.

Wczytywanie indeksu…

↑↓wybierz↵otwórzesczamknij