Skip to content

Commit

Permalink
feat: api endpoint to list connected/discovered surfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Feb 2, 2025
1 parent 0d511ad commit 8712618
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 93 deletions.
39 changes: 32 additions & 7 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/ApiStatusResponse'
$ref: '#/components/schemas/StatusResponse'
'400':
description: failed operation
content:
Expand Down Expand Up @@ -46,7 +46,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/ApiConfigData'
$ref: '#/components/schemas/ConfigData'
'400':
description: failed operation
content:
Expand All @@ -60,14 +60,14 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/ApiConfigDataUpdate'
$ref: '#/components/schemas/ConfigDataUpdate'
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiConfigData'
$ref: '#/components/schemas/ConfigData'
'400':
description: failed operation
content:
Expand All @@ -85,7 +85,7 @@ components:
required:
- error

ApiStatusResponse:
StatusResponse:
type: object
properties:
connected:
Expand All @@ -106,7 +106,7 @@ components:
- companionVersion
- companionApiVersion

ApiConfigData:
ConfigData:
type: object
properties:
host:
Expand Down Expand Up @@ -137,7 +137,7 @@ components:
- httpEnabled
- httpPort

ApiConfigDataUpdate:
ConfigDataUpdate:
type: object
properties:
host:
Expand All @@ -153,3 +153,28 @@ components:
mdnsEnabled:
type: boolean
description: Enable mDNS announcement to allow automatic discovery of the Companion Satellite

SurfaceInfo:
type: object
properties:
surfaceId:
type: string
description: ID of the surface
description:
type: string
description: Description of the surface
pluginId:
type: string
description: Plugin ID of the surface
pluginName:
type: string
description: Plugin name of the surface
isOpen:
type: boolean
description: Whether the surface is currently open
required:
- surfaceId
- description
- pluginId
- pluginName
- isOpen
7 changes: 4 additions & 3 deletions satellite/src/apiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { CompanionSatelliteClient } from './client.js'
import { SatelliteConfig } from './config.js'
import type { components as openapiComponents } from './generated/openapi.js'

export type ApiStatusResponse = openapiComponents['schemas']['ApiStatusResponse']
export type ApiConfigData = openapiComponents['schemas']['ApiConfigData']
export type ApiConfigDataUpdate = openapiComponents['schemas']['ApiConfigDataUpdate']
export type ApiStatusResponse = openapiComponents['schemas']['StatusResponse']
export type ApiConfigData = openapiComponents['schemas']['ConfigData']
export type ApiConfigDataUpdate = openapiComponents['schemas']['ConfigDataUpdate']
export type ApiSurfaceInfo = openapiComponents['schemas']['SurfaceInfo']

export type ApiConfigDataUpdateElectron = ApiConfigDataUpdate & Pick<Partial<ApiConfigData>, 'httpEnabled' | 'httpPort'>

Expand Down
7 changes: 5 additions & 2 deletions satellite/src/device-types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface DeviceRegisterProps {

export interface DiscoveredSurfaceInfo<T> {
surfaceId: string
// description: string
description: string
pluginInfo: T
}

Expand All @@ -48,6 +48,7 @@ export interface SurfacePluginDetection<TInfo> extends EventEmitter<SurfacePlugi
*/
export interface SurfacePlugin<TInfo> {
readonly pluginId: string
readonly pluginName: string

/**
* Some plugins are forced to use a builtin detection mechanism by their surfaces or inner library
Expand Down Expand Up @@ -96,7 +97,9 @@ export interface WrappedSurfaceEvents {
}

export interface WrappedSurface extends EventEmitter<WrappedSurfaceEvents> {
readonly deviceId: SurfaceId
readonly pluginId: string

readonly surfaceId: SurfaceId
readonly productName: string

getRegisterProps(): DeviceRegisterProps
Expand Down
16 changes: 11 additions & 5 deletions satellite/src/device-types/infinitton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ export interface InfinittonDeviceInfo {
path: string
}

const PLUGIN_ID = 'infinitton'

export class InfinittonPlugin implements SurfacePlugin<InfinittonDeviceInfo> {
readonly pluginId = 'infinitton'
readonly pluginId = PLUGIN_ID
readonly pluginName = 'Infinitton'

async init(): Promise<void> {
// Nothing to do
Expand All @@ -37,6 +40,7 @@ export class InfinittonPlugin implements SurfacePlugin<InfinittonDeviceInfo> {
) {
return {
surfaceId: device.serialNumber,
description: `Infinitton`,
pluginInfo: { path: device.path },
}
} else {
Expand All @@ -55,13 +59,15 @@ export class InfinittonPlugin implements SurfacePlugin<InfinittonDeviceInfo> {
}

export class InfinittonWrapper extends EventEmitter<WrappedSurfaceEvents> implements WrappedSurface {
readonly pluginId = PLUGIN_ID

readonly #cardGenerator: CardGenerator
readonly #panel: Infinitton
readonly #deviceId: string

#currentStatus: string | null = null

public get deviceId(): string {
public get surfaceId(): string {
return this.#deviceId
}
public get productName(): string {
Expand Down Expand Up @@ -92,9 +98,9 @@ export class InfinittonWrapper extends EventEmitter<WrappedSurfaceEvents> implem
this.#panel.close()
}
async initDevice(client: CompanionClient, status: string): Promise<void> {
console.log('Registering key events for ' + this.deviceId)
this.#panel.on('down', (key: number) => client.keyDown(this.deviceId, key))
this.#panel.on('up', (key: number) => client.keyUp(this.deviceId, key))
console.log('Registering key events for ' + this.surfaceId)
this.#panel.on('down', (key: number) => client.keyDown(this.surfaceId, key))
this.#panel.on('up', (key: number) => client.keyUp(this.surfaceId, key))

// Start with blanking it
await this.blankDevice()
Expand Down
23 changes: 13 additions & 10 deletions satellite/src/device-types/loupedeck-live-s.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import {
} from './api.js'
import { parseColor } from './lib.js'
import { EventEmitter } from 'events'
import { LOUPEDECK_PLUGIN_ID } from './loupedeck-plugin.js'

export class LoupedeckLiveSWrapper extends EventEmitter<WrappedSurfaceEvents> implements WrappedSurface {
readonly pluginId = LOUPEDECK_PLUGIN_ID

readonly #cardGenerator: CardGenerator
readonly #deck: LoupedeckDevice
readonly #deviceId: string
Expand All @@ -31,7 +34,7 @@ export class LoupedeckLiveSWrapper extends EventEmitter<WrappedSurfaceEvents> im
#companionSupportsScaling = false
#companionSupportsCombinedEncoders = false

public get deviceId(): string {
public get surfaceId(): string {
return this.#deviceId
}
public get productName(): string {
Expand Down Expand Up @@ -133,25 +136,25 @@ export class LoupedeckLiveSWrapper extends EventEmitter<WrappedSurfaceEvents> im
// Discard
return 99
}
console.log('Registering key events for ' + this.deviceId)
this.#deck.on('down', (info) => client.keyDown(this.deviceId, convertButtonId(info.type, info.index)))
this.#deck.on('up', (info) => client.keyUp(this.deviceId, convertButtonId(info.type, info.index)))
console.log('Registering key events for ' + this.surfaceId)
this.#deck.on('down', (info) => client.keyDown(this.surfaceId, convertButtonId(info.type, info.index)))
this.#deck.on('up', (info) => client.keyUp(this.surfaceId, convertButtonId(info.type, info.index)))
this.#deck.on('rotate', (info, delta) => {
if (info.type !== LoupedeckControlType.Rotary) return

const id2 = convertButtonId(info.type, info.index)
if (id2 < 90) {
if (delta < 0) {
if (this.#companionSupportsCombinedEncoders) {
client.rotateLeft(this.deviceId, id2)
client.rotateLeft(this.surfaceId, id2)
} else {
client.keyUp(this.deviceId, id2)
client.keyUp(this.surfaceId, id2)
}
} else if (delta > 0) {
if (this.#companionSupportsCombinedEncoders) {
client.rotateRight(this.deviceId, id2)
client.rotateRight(this.surfaceId, id2)
} else {
client.keyDown(this.deviceId, id2)
client.keyDown(this.surfaceId, id2)
}
}
}
Expand All @@ -164,14 +167,14 @@ export class LoupedeckLiveSWrapper extends EventEmitter<WrappedSurfaceEvents> im
this.#deck.on('touchstart', (data) => {
for (const touch of data.changedTouches) {
if (touch.target.key !== undefined) {
client.keyDown(this.deviceId, translateKeyIndex(touch.target.key))
client.keyDown(this.surfaceId, translateKeyIndex(touch.target.key))
}
}
})
this.#deck.on('touchend', (data) => {
for (const touch of data.changedTouches) {
if (touch.target.key !== undefined) {
client.keyUp(this.deviceId, translateKeyIndex(touch.target.key))
client.keyUp(this.surfaceId, translateKeyIndex(touch.target.key))
}
}
})
Expand Down
23 changes: 13 additions & 10 deletions satellite/src/device-types/loupedeck-live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import {
} from './api.js'
import { parseColor } from './lib.js'
import { EventEmitter } from 'events'
import { LOUPEDECK_PLUGIN_ID } from './loupedeck-plugin.js'

export class LoupedeckLiveWrapper extends EventEmitter<WrappedSurfaceEvents> implements WrappedSurface {
readonly pluginId = LOUPEDECK_PLUGIN_ID

readonly #cardGenerator: CardGenerator
readonly #deck: LoupedeckDevice
readonly #deviceId: string
Expand All @@ -31,7 +34,7 @@ export class LoupedeckLiveWrapper extends EventEmitter<WrappedSurfaceEvents> imp
#companionSupportsScaling = false
#companionSupportsCombinedEncoders = true

public get deviceId(): string {
public get surfaceId(): string {
return this.#deviceId
}
public get productName(): string {
Expand Down Expand Up @@ -152,25 +155,25 @@ export class LoupedeckLiveWrapper extends EventEmitter<WrappedSurfaceEvents> imp
// Discard
return 99
}
console.log('Registering key events for ' + this.deviceId)
this.#deck.on('down', (info) => client.keyDown(this.deviceId, convertButtonId(info.type, info.index, true)))
this.#deck.on('up', (info) => client.keyUp(this.deviceId, convertButtonId(info.type, info.index, true)))
console.log('Registering key events for ' + this.surfaceId)
this.#deck.on('down', (info) => client.keyDown(this.surfaceId, convertButtonId(info.type, info.index, true)))
this.#deck.on('up', (info) => client.keyUp(this.surfaceId, convertButtonId(info.type, info.index, true)))
this.#deck.on('rotate', (info, delta) => {
if (info.type !== LoupedeckControlType.Rotary) return

const id2 = convertButtonId(info.type, info.index, false)
if (id2 < 90) {
if (delta < 0) {
if (this.#companionSupportsCombinedEncoders) {
client.rotateLeft(this.deviceId, id2)
client.rotateLeft(this.surfaceId, id2)
} else {
client.keyUp(this.deviceId, id2)
client.keyUp(this.surfaceId, id2)
}
} else if (delta > 0) {
if (this.#companionSupportsCombinedEncoders) {
client.rotateRight(this.deviceId, id2)
client.rotateRight(this.surfaceId, id2)
} else {
client.keyDown(this.deviceId, id2)
client.keyDown(this.surfaceId, id2)
}
}
}
Expand All @@ -183,14 +186,14 @@ export class LoupedeckLiveWrapper extends EventEmitter<WrappedSurfaceEvents> imp
this.#deck.on('touchstart', (data) => {
for (const touch of data.changedTouches) {
if (touch.target.key !== undefined) {
client.keyDown(this.deviceId, translateKeyIndex(touch.target.key))
client.keyDown(this.surfaceId, translateKeyIndex(touch.target.key))
}
}
})
this.#deck.on('touchend', (data) => {
for (const touch of data.changedTouches) {
if (touch.target.key !== undefined) {
client.keyUp(this.deviceId, translateKeyIndex(touch.target.key))
client.keyUp(this.surfaceId, translateKeyIndex(touch.target.key))
}
}
})
Expand Down
6 changes: 5 additions & 1 deletion satellite/src/device-types/loupedeck-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import { assertNever } from '../lib.js'
import { LoupedeckLiveSWrapper } from './loupedeck-live-s.js'
import { RazerStreamControllerXWrapper } from './razer-stream-controller-x.js'

export const LOUPEDECK_PLUGIN_ID = 'loupedeck'

export class LoupedeckPlugin implements SurfacePlugin<LoupedeckDeviceInfo> {
readonly pluginId = 'loupedeck'
readonly pluginId = LOUPEDECK_PLUGIN_ID
readonly pluginName = 'Loupedeck'

async init(): Promise<void> {
// Nothing to do
Expand All @@ -31,6 +34,7 @@ export class LoupedeckPlugin implements SurfacePlugin<LoupedeckDeviceInfo> {

result.push({
surfaceId: device.serialNumber,
description: device.model, // TODO: Better description
pluginInfo: device,
})
}
Expand Down
11 changes: 7 additions & 4 deletions satellite/src/device-types/razer-stream-controller-x.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import {
WrappedSurfaceEvents,
} from './api.js'
import { EventEmitter } from 'events'
import { LOUPEDECK_PLUGIN_ID } from './loupedeck-plugin.js'

export class RazerStreamControllerXWrapper extends EventEmitter<WrappedSurfaceEvents> implements WrappedSurface {
readonly pluginId = LOUPEDECK_PLUGIN_ID

readonly #cardGenerator: CardGenerator
readonly #deck: LoupedeckDevice
readonly #deviceId: string
Expand All @@ -23,7 +26,7 @@ export class RazerStreamControllerXWrapper extends EventEmitter<WrappedSurfaceEv

#companionSupportsScaling = false

public get deviceId(): string {
public get surfaceId(): string {
return this.#deviceId
}
public get productName(): string {
Expand Down Expand Up @@ -109,9 +112,9 @@ export class RazerStreamControllerXWrapper extends EventEmitter<WrappedSurfaceEv
// Discard
return 99
}
console.log('Registering key events for ' + this.deviceId)
this.#deck.on('down', (info) => client.keyDown(this.deviceId, convertButtonId(info.type, info.index)))
this.#deck.on('up', (info) => client.keyUp(this.deviceId, convertButtonId(info.type, info.index)))
console.log('Registering key events for ' + this.surfaceId)
this.#deck.on('down', (info) => client.keyDown(this.surfaceId, convertButtonId(info.type, info.index)))
this.#deck.on('up', (info) => client.keyUp(this.surfaceId, convertButtonId(info.type, info.index)))

// Start with blanking it
await this.blankDevice()
Expand Down
Loading

0 comments on commit 8712618

Please sign in to comment.