Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion for-developers/core-development/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"label": "Core Companion",
"position": 4,
"position": 5,
"link": {
"type": "generated-index"
}
Expand Down
2 changes: 1 addition & 1 deletion for-developers/maintenance-team/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"label": "Maintenance Team Tasks",
"position": 5,
"position": 6,
"link": {
"type": "generated-index"
}
Expand Down
2 changes: 1 addition & 1 deletion for-developers/module-development/_category_.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"label": "Module Development",
"label": "Connection Development",
"position": 3,
"link": {
"type": "doc",
Expand Down
14 changes: 10 additions & 4 deletions for-developers/module-development/home.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
---
title: Getting Started with Modules
sidebar_label: Getting Started with Modules
title: Getting Started with Connections
sidebar_label: Getting Started with Connections
sidebar_position: 1
description: Developer environment setup specific to module development.
description: Developer environment setup specific to connection module development.
---

So, you want to develop a module for Companion? Welcome!
So, you want to develop a connection module for Companion? Welcome!

Companion uses plug-ins to expand its capabilities, we call these plug-ins "modules". For every device you can control with Companion there is a "module" that manages the connection. This page describes how to set up your computer for developing Companion modules. Subsequent pages will provide details on the contents of the module and its lifecycle.

:::note
This section covers **connection** modules. If you want to add support for a physical control
surface instead, see the [Surface Development](../surface-development/home.md) section — it shares
much of the same tooling and links back here for the common setup steps.
:::

## Prerequisites

Before you start, make sure you have [Installed the Development Tools](../setting-up-developer-environment.md) and familiarized yourself with [Git Workflows](../git-workflows/git-crashcourse.md).
Expand Down
12 changes: 8 additions & 4 deletions for-developers/module-development/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
---
title: Companion Module Developers' Guide
description: Outline of the Module Development section.
title: Companion Connection Developers' Guide
description: Outline of the Connection Development section.
auto_toc: 2
---

This section describes everything you need to know to develop your own modules for Companion. Below is
an outline of the top-level pages and folders in this section. For pages, the main headings inside each file are listed as bulleted lines. Folders are shown preceded by '> ', and the immediate contents of that folder are shown below it using "└─ " to indicate pages (or subfolders) inside that folder.
This section describes everything you need to know to develop your own **connection** modules for
Companion — the plugins that let Companion control a device or piece of software. If instead you
want to add support for a physical control surface, see the [Surface Development](../surface-development/home.md)
section.

Below is an outline of the top-level pages and folders in this section. For pages, the main headings inside each file are listed as bulleted lines. Folders are shown preceded by '> ', and the immediate contents of that folder are shown below it using "└─ " to indicate pages (or subfolders) inside that folder.
11 changes: 11 additions & 0 deletions for-developers/surface-development/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"label": "Surface Development",
"position": 4,
"link": {
"type": "doc",
"id": "index"
},
"customProps": {
"description": "Everything you need to develop a surface module for Companion."
}
}
72 changes: 72 additions & 0 deletions for-developers/surface-development/home.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Getting Started with Surfaces
sidebar_label: Getting Started with Surfaces
sidebar_position: 1
description: Developer environment setup and orientation for surface module development.
---

So, you want to develop a surface module for Companion? Welcome!

A **surface** module teaches Companion how to talk to a physical control surface — reading button
presses and encoder turns, and drawing button graphics, indicators and brightness onto the
hardware. Surface modules are plugins, just like connection modules, and they are built with the
same tooling and released through the same workflows.

:::tip Most tooling is shared with connection modules
Surface and connection modules share almost all of their development environment, repository
tooling and release process. Rather than duplicate that here, this section links you to the
relevant [Connection Development](../module-development/home.md) pages and concentrates on what is
genuinely different for surfaces. Connection modules are far more common, so if a topic isn't
covered here, the connection docs are almost always the right place to look.
:::

## Prerequisites

Before you start, make sure you have [installed the development tools](../setting-up-developer-environment.md)
and are comfortable with [Git workflows](../git-workflows/git-crashcourse.md). These are the same
for all Companion module development.

## Shared setup — reuse the connection docs

The following steps are identical for surface and connection modules. Follow the connection pages
and come back here for the surface-specific API:

- [Installing Companion and setting up the development folder](../module-development/home.md)
- [Setting up a dev folder](../module-development/local-modules.md) so Companion loads your module
while you work
- [Repository file structure](../module-development/module-setup/file-structure.md)
- [The `manifest.json` file](../module-development/module-setup/manifest.json.md) — note that
surface modules declare some surface-specific fields; see [Surface Plugin Overview](./surface-basics/overview.md)
- [Module development 101](../module-development/module-development-101.md) for the general
build → release → maintain lifecycle
- [Packaging](../module-development/module-lifecycle/module-packaging.md) and
[releasing](../module-development/module-lifecycle/releasing-your-module.md) a module

## What's different for surfaces

Where a connection module defines actions, feedbacks and variables, a surface module implements
the [`SurfacePlugin`](./surface-basics/overview.md) interface and is responsible for:

- [Discovering and connecting to surfaces](./surface-basics/discovery.md)
- Representing [each connected surface](./surface-basics/the-surface-instance.md)
- Declaring the surface's [physical layout](./surface-basics/layout.md)
- [Rendering](./surface-basics/rendering.md) the images Companion pushes, plus brightness and LEDs
- Reporting [input events](./surface-basics/input.md) back to Companion
- Handling the [lock screen / pincode entry](./surface-basics/locking-and-pincode.md)

Read on in [Surfaces: Basics](./surface-basics/index.md).

## Reference material

- Generated API reference: [bitfocus.github.io/companion-surface-api](https://bitfocus.github.io/companion-surface-api/)
- [companion-surface-api wiki](https://github.com/bitfocus/companion-surface-api/wiki)

Existing modules are the best reference for a real, working implementation. Which one to look at
depends on how your surface connects — there's no single "canonical" example because the discovery
flows differ:

- USB (HID) and remote/network: [`companion-surface-elgato-stream-deck`](https://github.com/bitfocus/companion-surface-elgato-stream-deck)
(comprehensive, but a large codebase)
- Serial port: [`companion-surface-loupedeck`](https://github.com/bitfocus/companion-surface-loupedeck)

Questions? Reach out on [Slack](https://l.companion.free/q/zYXXxnGyd)! :)
22 changes: 22 additions & 0 deletions for-developers/surface-development/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Companion Surface Developers' Guide
description: Outline of the Surface Development section.
auto_toc: 2
---

This section describes how to develop your own **surface** modules for Companion — the plugins
that let Companion drive a physical control surface (buttons, encoders, displays and indicators)
and receive input back from it.

Surface and connection modules share most of their tooling and workflow, so these pages focus on
what is _specific to surfaces_ and link back to the [Connection Development](../module-development/home.md)
section for the common setup, packaging and release steps. If you are building a module that
controls a device or piece of software instead of a control surface, you want the
[Connection Development](../module-development/home.md) section.

The authoritative, autogenerated API reference lives at
[bitfocus.github.io/companion-surface-api](https://bitfocus.github.io/companion-surface-api/).
Existing modules make good real-world references — which one fits depends on how your surface
connects (see [Getting Started with Surfaces](./home.md)).

Below is an outline of the top-level pages and folders in this section.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"label": "Surfaces: Advanced",
"position": 17,
"link": {
"type": "doc",
"id": "index"
},
"customProps": {
"description": "Advanced and special-purpose topics for surface modules."
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: Custom Discovery Flows
sidebar_label: Custom Discovery
sidebar_position: 2
description: Active scanning and plugin-owned detection for non-HID surfaces.
---

The [common discovery flows](../surface-basics/discovery.md) — USB HID and remote/network — cover
most hardware. For surfaces that don't fit either, the API provides two more mechanisms. Reach for
these only when the common flows don't work.

## Active scan: `scanForSurfaces`

Some surfaces aren't USB HID devices, so they won't be picked up by Companion's USB hotplug
watcher. When there's no hotplug notification for your device, implement `scanForSurfaces()` on your
plugin to look for them on demand; Companion calls it (for example when the user triggers a scan)
and you return the devices you found:

```typescript
async scanForSurfaces() {
const ports = await listSerialPorts()
return ports
.filter(isMyDevice)
.map((port) => ({
surfaceId: port.serialNumber,
deviceHandle: port.path, // stable handle used to re-identify the device between scans
description: 'My Serial Surface',
pluginInfo: { path: port.path },
}))
}
```

Each result is a `DetectionSurfaceInfo` — like the HID `DiscoveredSurfaceInfo`, but with an extra
**`deviceHandle`**: a stable identifier (a serial path, etc.) Companion uses to recognise the same
physical device between scans. Companion then calls
[`openSurface()`](../surface-basics/the-surface-instance.md) for the ones it wants.

This is the right flow for **serial-port** surfaces. See the
[Loupedeck module](https://github.com/bitfocus/companion-surface-loupedeck) for a real serial-port
implementation.

## Plugin-owned detection: `SurfacePluginDetection`

When a device or its vendor library insists on running its _own_ detection (for example a wireless
dongle that surfaces appear and disappear behind), implement the `detection` property — an
`EventEmitter` that:

- emits **`surfacesAdded`** as devices appear and **`surfacesRemoved`** as they go (emitting
`surfacesRemoved` is important — it releases the unique id reserved for that device),
- implements **`triggerScan()`** to refresh when the user asks for a rescan, and
- implements **`rejectSurface()`** to release resources for a surface Companion chose not to open.

```typescript
class MyDetection extends EventEmitter<SurfacePluginDetectionEvents<MyDeviceInfo>> /* … */ {
private onDeviceArrived(dev) {
this.emit('surfacesAdded', [
{
surfaceId: dev.serial,
deviceHandle: dev.handle,
description: 'My Surface',
pluginInfo: {
/* … */
},
},
])
}
async triggerScan() {
/* ask the library to re-enumerate */
}
rejectSurface(info) {
/* release resources for this surface */
}
}
```

:::note
This mechanism is discouraged where avoidable — the built-in [HID](../surface-basics/discovery.md)
and `scanForSurfaces` abstractions exist to reduce the cost of scanning. Use `detection` only when
the hardware or library gives you no choice. As with all discovery, **don't emit events before
`init()`** has run.
:::

See the [generated reference](https://bitfocus.github.io/companion-surface-api/) for the exact
`SurfacePluginDetection` and `DetectionSurfaceInfo` definitions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: Firmware Updates
sidebar_label: Firmware Updates
sidebar_position: 3
description: Reporting available firmware updates for a surface.
---

If your hardware can report its firmware version and you know where newer firmware lives, you can
let Companion surface that to the user. This is optional — implement
`checkForFirmwareUpdates()` on your [surface instance](../surface-basics/the-surface-instance.md)
only if it applies to your device.

Companion calls it with a small cache helper and expects either update info or `null`:

```typescript
async checkForFirmwareUpdates(versionsCache) {
// fetchJson is shared/cached across all surfaces, so several devices of the same
// type don't each hit the network.
const latest = await versionsCache.fetchJson('https://example.com/my-surface/firmware.json')

if (compareVersions(this.currentFirmware, latest.version) >= 0) {
return null // already up to date
}

return {
updateUrl: 'https://example.com/my-surface/update', // where to send the user to update
}
}
```

The current API points the user at an `updateUrl` to perform the update themselves; the actual
update process is whatever your hardware and that page require.

:::warning Use the provided cache for fetches
We strongly encourage using the supplied `SurfaceFirmwareUpdateCache.fetchJson()` (and the other
caching/util helpers) for any version lookups, rather than fetching directly. This check runs at
startup and again whenever surfaces connect and on an interval, so without caching a user with
several of your surfaces can generate a burst of duplicate requests.
:::

See the [generated reference](https://bitfocus.github.io/companion-surface-api/) for the
`SurfaceFirmwareUpdateInfo` and `SurfaceFirmwareUpdateCache` definitions.
12 changes: 12 additions & 0 deletions for-developers/surface-development/surface-advanced/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Surface Module Advanced Topics
description: Advanced and special-purpose topics for Companion surface modules.
auto_toc: 2
---

This section collects topics beyond the [basics](../surface-basics/index.md): the special-purpose
[discovery flows](./custom-discovery.md) that exist to solve specific modules' needs, and
[firmware updates](./firmware-updates.md).

Most surface modules will not need everything here — reach for these pages when the common
patterns in [Surfaces: Basics](../surface-basics/index.md) don't fit your hardware.
11 changes: 11 additions & 0 deletions for-developers/surface-development/surface-basics/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"label": "Surfaces: Basics",
"position": 15,
"link": {
"type": "doc",
"id": "index"
},
"customProps": {
"description": "The core concepts and API needed to program a surface module."
}
}
Loading