Skip to main content

The Surface Instance

While the plugin manages a whole type of surface, each individual connected device is a surface instance. Companion creates one by calling your plugin's openSurface() when it decides to use a device that discovery reported.

openSurface

openSurface(surfaceId, pluginInfo, context) is where you actually open the hardware. pluginInfo is the object you returned from discovery; context is the SurfaceContext you use to talk back to Companion. It returns two things:

  • surface — your SurfaceInstance implementation (below).
  • registerProps — a description of the device's capabilities: its layout, whether it supports brightness, its pincode map, any config fields and transfer variables, and an optional user-facing location.
async openSurface(surfaceId, pluginInfo, context) {
const surface = new MySurface(surfaceId, pluginInfo, context)
return {
surface,
registerProps: {
brightness: true,
surfaceLayout: myLayout, // see Layout
pincodeMap: { type: 'single-page', /* … */ }, // see Locking & Pincode
location: null,
configFields: null,
},
}
}
tip

If opening the hardware can throw partway through, make sure you don't leak the underlying device handle — open inside a try/catch and close what you've opened before re-throwing, so a failed open doesn't leave a dangling connection.

Implementing SurfaceInstance

The instance carries a surfaceId (a stable id, typically the serial number — Companion uses it to re-associate the device with the user's config across reconnects) and a productName. Beyond that it implements the lifecycle and operation methods Companion calls:

  • init() — open and prepare the hardware. Called once after creation.
  • ready() — Companion is about to start drawing; transition into normal operation.
  • draw(signal, drawProps) — render a control — see Rendering.
  • setBrightness(percent) / blank() — backlight and clear, also covered in Rendering.
  • close() — clean up and disconnect. Stop any timers and release handles here.
  • Optional: updateConfig(config), onVariableValue(name, value) (see Input & variables), showLockedStatus(...) (see Locking & pincode) and checkForFirmwareUpdates(...) (see Firmware updates).

Disconnecting

When the device goes away (unplugged, network dropped), call context.disconnect(error) so Companion knows it is gone. For the detection and remote flows you also emit the relevant "removed" event so the reserved id is released.

See the generated reference for the full SurfaceInstance and SurfaceRegisterProps definitions, and the Elgato Stream Deck module for a complete implementation.