From 406f8acad5ca32323df7914edcea3eb57f993ad5 Mon Sep 17 00:00:00 2001 From: lukejdav Date: Thu, 4 Apr 2024 18:15:37 +0100 Subject: [PATCH] yarn build now runs successfully --- packages/quick-tsr/input/mappings.ts | 24 ++-- packages/quick-tsr/input/timeline.ts | 124 +++++++++--------- .../src/device.ts | 5 + .../src/generated/artnet.ts | 17 ++- .../src/integrations/artnet.ts | 24 +++- .../timeline-state-resolver/src/conductor.ts | 3 + .../artnet/$schemas/mappings.json | 33 +++-- .../integrations/artnet/$schemas/options.json | 80 ++++++----- .../src/integrations/artnet/index.ts | 124 ++++++++++++------ .../src/service/devices.ts | 8 ++ 10 files changed, 279 insertions(+), 163 deletions(-) diff --git a/packages/quick-tsr/input/mappings.ts b/packages/quick-tsr/input/mappings.ts index bfb8d703b..308c4334c 100644 --- a/packages/quick-tsr/input/mappings.ts +++ b/packages/quick-tsr/input/mappings.ts @@ -1,4 +1,4 @@ -import { DeviceType, Mapping, MappingCasparCGType, SomeMappingCasparCG } from 'timeline-state-resolver' +import { DeviceType, Mapping, SomeMappingArtNet } from 'timeline-state-resolver' import { literal } from 'timeline-state-resolver/dist/lib' import type { TSRInput } from '../src' @@ -8,11 +8,11 @@ export const input: TSRInput = { device: DeviceType.ARTNET, deviceId: 'universe0', options: { - universe: 0, + universe: 0, profileMappings: { // Maps dimmer to channel 1: - "dimmer": 1, - } + "dimmer": 1, + } }, }), rgb0: literal>({ @@ -22,8 +22,8 @@ export const input: TSRInput = { universe: 0, profileMappings: { "dimmer": 6, - "RGB": [7,8,9], - } + "RGB": [7,8,9], + } }, }), rgb0_dimmer: literal>({ @@ -33,18 +33,18 @@ export const input: TSRInput = { universe: 0, profileMappings: { "dimmer": 6, - } + } }, }), dimmerGroup0: literal>({ device: DeviceType.ARTNET, deviceId: 'universe0', options: { - universe: 0, + universe: 0, profileMappings: { // Maps dimmers to channel group: - "dimmers": [11, 12, 13, 14, 15, 16, 17, 18], - } + "dimmers": [11, 12, 13, 14, 15, 16, 17, 18], + } }, }), @@ -56,8 +56,8 @@ export const input: TSRInput = { profileMappings: { // "everything": ['1-50', '100-512'], "everything": '1-512' - - } + + } }, }), }, diff --git a/packages/quick-tsr/input/timeline.ts b/packages/quick-tsr/input/timeline.ts index 7ab745364..5c121052a 100644 --- a/packages/quick-tsr/input/timeline.ts +++ b/packages/quick-tsr/input/timeline.ts @@ -1,7 +1,9 @@ import { - DeviceType, - TimelineContentTypeCasparCg, - TimelineContentCCGMedia, + // DeviceType, + // TimelineContentTypeCasparCg, + // TimelineContentCCGMedia, + TimelineContentArtNetAny, + TimelineContentArtNetValues, TSRTimelineObj, } from 'timeline-state-resolver' import { TSRInput } from '../src' @@ -10,7 +12,7 @@ import { literal } from 'timeline-state-resolver/dist/lib' export const input: TSRInput = { timeline: [ - literal>({ + literal>({ id: 'artnet0', enable: { start: Date.now(), @@ -18,7 +20,7 @@ export const input: TSRInput = { }, layer: 'dimmer00', content: { - values: { + values: { dimmer: 255 } } @@ -102,66 +104,60 @@ export const input: TSRInput = { everything: 255 } } - }) - - - - - - + }), - literal>({ - id: 'video0', - enable: { - start: Date.now(), - duration: 20 * 1000, - }, - layer: 'casparLayer0', - content: { - deviceType: DeviceType.CASPARCG, - type: TimelineContentTypeCasparCg.MEDIA, - file: 'amb.mp4', - mixer: { - rotation: 0, - // anchor: { - // x: 0.5, - // y: 0.5, - // }, - fill: { - x: 0.5, - y: 0.5, - xScale: 0.7, - yScale: 1, - }, - }, + // literal>({ + // id: 'video0', + // enable: { + // start: Date.now(), + // duration: 20 * 1000, + // }, + // layer: 'casparLayer0', + // content: { + // deviceType: DeviceType.CASPARCG, + // type: TimelineContentTypeCasparCg.MEDIA, + // file: 'amb.mp4', + // mixer: { + // rotation: 0, + // // anchor: { + // // x: 0.5, + // // y: 0.5, + // // }, + // fill: { + // x: 0.5, + // y: 0.5, + // xScale: 0.7, + // yScale: 1, + // }, + // }, - // $references: { - // 'mixer.fill.xScale': { - // // Local path to overwrite - // datastoreKey: 'scale', // Reference key in datastore - // overwrite: false, - // }, - // 'mixer.fill.yScale': { - // // Local path to overwrite - // datastoreKey: 'scale', // Reference key in datastore - // overwrite: false, - // }, - // }, - }, - keyframes: [ - { - id: 'kf0', - enable: { - while: true, - // start: '#video0.start + 10', - }, - content: { - mixer: { - rotation: 90 - } - } - } - ] - }), + // // $references: { + // // 'mixer.fill.xScale': { + // // // Local path to overwrite + // // datastoreKey: 'scale', // Reference key in datastore + // // overwrite: false, + // // }, + // // 'mixer.fill.yScale': { + // // // Local path to overwrite + // // datastoreKey: 'scale', // Reference key in datastore + // // overwrite: false, + // // }, + // // }, + // }, + // keyframes: [ + // { + // id: 'kf0', + // enable: { + // while: true, + // // start: '#video0.start + 10', + // }, + // content: { + // mixer: { + // rotation: 90 + // } + // } + // } + // ] + // }), ], } diff --git a/packages/timeline-state-resolver-types/src/device.ts b/packages/timeline-state-resolver-types/src/device.ts index 02343fa9a..1faee26c1 100644 --- a/packages/timeline-state-resolver-types/src/device.ts +++ b/packages/timeline-state-resolver-types/src/device.ts @@ -22,6 +22,7 @@ import { TelemetricsOptions, TriCasterOptions, MultiOSCOptions, + ArtNetOptions, } from '.' import { DeviceCommonOptions } from './generated/common-options' @@ -76,6 +77,7 @@ export type DeviceOptionsAny = | DeviceOptionsTelemetrics | DeviceOptionsTriCaster | DeviceOptionsMultiOSC + | DeviceOptionsArtNet export interface DeviceOptionsAbstract extends DeviceOptionsBase { type: DeviceType.ABSTRACT @@ -143,3 +145,6 @@ export interface DeviceOptionsTriCaster extends DeviceOptionsBase { type: DeviceType.MULTI_OSC } +export interface DeviceOptionsArtNet extends DeviceOptionsBase { + type: DeviceType.ARTNET +} diff --git a/packages/timeline-state-resolver-types/src/generated/artnet.ts b/packages/timeline-state-resolver-types/src/generated/artnet.ts index bf5a129bb..5601e36fd 100644 --- a/packages/timeline-state-resolver-types/src/generated/artnet.ts +++ b/packages/timeline-state-resolver-types/src/generated/artnet.ts @@ -7,8 +7,11 @@ export interface ArtNetOptions { host: string - mode: Mode - fps: number + mode?: Mode + fps?: number + channelBehavious?: { + [k: string]: unknown + } } export enum Mode { @@ -21,8 +24,16 @@ export interface MappingArtnetUniverse { mappingType: MappingArtnetType.Universe } +export interface MappingArtnetProfileMappings { + ID: string + channels: string + mappingType: MappingArtnetType.ProfileMappings + [k: string]: unknown +} + export enum MappingArtnetType { Universe = 'universe', + ProfileMappings = 'profileMappings', } -export type SomeMappingArtnet = MappingArtnetUniverse +export type SomeMappingArtnet = MappingArtnetUniverse | MappingArtnetProfileMappings diff --git a/packages/timeline-state-resolver-types/src/integrations/artnet.ts b/packages/timeline-state-resolver-types/src/integrations/artnet.ts index 333e998da..8651c4cd4 100644 --- a/packages/timeline-state-resolver-types/src/integrations/artnet.ts +++ b/packages/timeline-state-resolver-types/src/integrations/artnet.ts @@ -21,13 +21,23 @@ export enum TimelineContentTypeArtNet { export interface TimelineContentArtNet { deviceType: DeviceType.ARTNET type: TimelineContentTypeArtNet - channel: number - value: number - trasition?: { - duration: number, - type: ArtNetEasingType, - direction: 'In' | 'Out' | 'InOut' | 'None' - } + channel: number + value: number + trasition?: { + duration: number, + type: ArtNetEasingType, + direction: 'In' | 'Out' | 'InOut' | 'None' + } +} + +export interface ArtNetDeviceCommand { + channel: number + value: number +} + +export interface ArtNetCommandContent { + ID: string + values: number | Array } export type TimelineContentArtNetAny = TimelineContentArtNet diff --git a/packages/timeline-state-resolver/src/conductor.ts b/packages/timeline-state-resolver/src/conductor.ts index 059c83ac2..01d4baeba 100644 --- a/packages/timeline-state-resolver/src/conductor.ts +++ b/packages/timeline-state-resolver/src/conductor.ts @@ -33,6 +33,7 @@ import { DeviceOptionsHyperdeck, DeviceOptionsPanasonicPTZ, DeviceOptionsLawo, + DeviceOptionsArtNet, } from 'timeline-state-resolver-types' import { DoOnTime } from './devices/doOnTime' @@ -592,6 +593,7 @@ export class Conductor extends EventEmitter { threadedClassOptions ) case DeviceType.ABSTRACT: + case DeviceType.ARTNET: case DeviceType.ATEM: case DeviceType.HTTPSEND: case DeviceType.HTTPWATCHER: @@ -1527,6 +1529,7 @@ export type DeviceOptionsAnyInternal = | DeviceOptionsTelemetrics | DeviceOptionsTriCasterInternal | DeviceOptionsMultiOSC + | DeviceOptionsArtNet function removeParentFromState( o: Timeline.TimelineState diff --git a/packages/timeline-state-resolver/src/integrations/artnet/$schemas/mappings.json b/packages/timeline-state-resolver/src/integrations/artnet/$schemas/mappings.json index d9a502447..f20f45ffd 100644 --- a/packages/timeline-state-resolver/src/integrations/artnet/$schemas/mappings.json +++ b/packages/timeline-state-resolver/src/integrations/artnet/$schemas/mappings.json @@ -1,22 +1,35 @@ { "$schema": "../../../$schemas/mapping-schema.json", - "default": "universe", + "default": "mappings", "mappings": { "universe": { "type": "object", "properties": { - "universe": { - "type": "integer", - "ui:title": "Universe", - "ui:description": "The artnet universe to output to (0-32767)", - "ui:summaryTitle": "Universe", - "default": 0, - "min": 0, - "max": 32767 - } + "universe": { + "type": "integer", + "ui:title": "Universe", + "ui:description": "The artnet universe to output to (0-32767)", + "ui:summaryTitle": "Universe", + "default": 0, + "min": 0, + "max": 32767 + } }, "required": ["universe"], "additionalProperties": false + }, + "profileMappings": { + "type": "object", + "properties": { + "ID": { + "type": "string" + }, + "channels": { + "type": "string" + } + }, + "required": ["ID", "channels"], + "additionalProperties": true } } } diff --git a/packages/timeline-state-resolver/src/integrations/artnet/$schemas/options.json b/packages/timeline-state-resolver/src/integrations/artnet/$schemas/options.json index 7184ffbf5..a6a1f8ccf 100644 --- a/packages/timeline-state-resolver/src/integrations/artnet/$schemas/options.json +++ b/packages/timeline-state-resolver/src/integrations/artnet/$schemas/options.json @@ -1,32 +1,52 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "ArtNet Options", - "type": "object", - "properties": { - "host": { - "type": "string", - "ui:title": "Host", - "default": "127.0.0.1" - }, - "mode": { - "type": "string", - "ui:title": "Transmission Mode", - "ui:description": "Use Full or Partial transmission mode. Partial mode updates only changed values other than keyframes, reducing network traffic.", - "ui:summaryTitle": "Transmission Mode", - "enum": ["full", "partial"], - "tsEnumNames": ["FULL", "PARTIAL"], - "default": "full" - }, - "fps": { - "type": "integer", - "ui:title": "Refresh Rate", - "ui:description": "Art Net universe fps", - "ui:summaryTitle": "Refresh Rate", - "default": 44, - "min": 1, - "max": 120 - } - }, - "required": ["host"], - "additionalProperties": false + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ArtNet Options", + "type": "object", + "properties": { + "host": { + "type": "string", + "ui:title": "Host", + "default": "127.0.0.1" + }, + "mode": { + "type": "string", + "ui:title": "Transmission Mode", + "ui:description": "Use Full or Partial transmission mode. Partial mode updates only changed values other than keyframes, reducing network traffic.", + "ui:summaryTitle": "Transmission Mode", + "enum": ["full", "partial"], + "tsEnumNames": ["FULL", "PARTIAL"], + "default": "full" + }, + "fps": { + "type": "integer", + "ui:title": "Refresh Rate", + "ui:description": "Art Net universe fps", + "ui:summaryTitle": "Refresh Rate", + "default": 44, + "min": 1, + "max": 120 + }, + "channelBehavious": { + "ui:title": "Options for setting specific channel behavious", + "ui:description": "Set channel behavious for non highest takes priority channels", + ".+": { + "channel": { + "type": "string", + "ui:title": "Channel to modify", + "ui:description": "Use the form 'Universe':'Address' to secify a channel e.g. 0:15" + }, + "priority": { + "type": "string", + "ui:title": "Priority Mode", + "ui:description": "The priority mode to use for the specfied channel", + "enum": ["highest", "lowest", "last"], + "tsEnumNames": ["HIGHEST", "LOWEST", "LAST"], + "default": "highest" + } + }, + "additionalProperties": true + } + }, + "required": ["host"], + "additionalProperties": false } \ No newline at end of file diff --git a/packages/timeline-state-resolver/src/integrations/artnet/index.ts b/packages/timeline-state-resolver/src/integrations/artnet/index.ts index 9f2c7a878..adad8079c 100644 --- a/packages/timeline-state-resolver/src/integrations/artnet/index.ts +++ b/packages/timeline-state-resolver/src/integrations/artnet/index.ts @@ -1,21 +1,24 @@ import { - ActionExecutionResult, + // ActionExecutionResult, DeviceStatus, DeviceType, Timeline, TSRTimelineContent, ArtNetCommandContent, - ArtNetOptions, + ArtNetOptions, + StatusCode, + ActionExecutionResult, + ArtNetDeviceCommand } from 'timeline-state-resolver-types' import { CommandWithContext, Device } from '../../service/device' -import * as artnet from 'artnet' +// import * as artnet from 'artnet' -import Debug from 'debug' -import _ = require('underscore') -import { Easing } from '../../devices/transitions/easings' -import { assertNever } from '../../lib' -import { StatusCode } from 'timeline-state-resolver-types' -const debug = Debug('timeline-state-resolver:artnet') +// import Debug from 'debug' +// const debug = Debug('timeline-state-resolver:artnet') +// import _ = require('underscore') +// import { Easing } from '../../devices/transitions/easings' +// import { assertNever } from '../../lib' +// import { StateHandler } from 'src/service/stateHandler' export interface ArtNetDeviceState { [address: string]: ArtNetDeviceStateContent @@ -25,23 +28,42 @@ interface ArtNetDeviceStateContent extends ArtNetCommandContent { fromTLObject: string } -export interface ArtNetCommandWithContext { - command: any // todo - context: string +export interface ArtNetCommandWithContext extends CommandWithContext{ + command: ArtNetDeviceCommand + context: string timelineObjId: string } +// needs somthing to resolvew timeline names, this may not be the place +export interface TimelineContentArtNetValues extends ArtNetCommandContent { + +} + export class ArtNetDevice extends Device{ + + actions!: Record | undefined) => Promise> + + options!: ArtNetOptions + + deviceState!: ArtNetDeviceState + - // private _oscClient!: - // private _ArtNetClientStatus: 'connected' | 'disconnected' = 'disconnected' + // private _ArtNetClient!: + private _ArtNetClientStatus: 'connected' | 'disconnected' = 'disconnected' // private transitions: { // [value: number]: { // started: number // } & ArtNetDeviceStateContent // } + get status() { + return this._ArtNetClientStatus + } + + get DeviceType() { + return DeviceType.ARTNET + } async init(options: ArtNetOptions): Promise { this.options = options @@ -60,18 +82,31 @@ export class ArtNetDevice extends Device): ArtNetDeviceState { // TODO: Convert the timeline state into your own (internal) ArtNetState // Tip: This is where you put the logic for "highest takes precedence" + const addrToArtNetMessage: ArtNetDeviceState = {} - Object.values>(state.layer).forEach((layer) => { + // const artNetGroup = state.id + // console.log("layer:", artNetGroup) + console.log(state) + + Object.values>(state.layers).forEach((layer) => { + if (layer.content.deviceType === DeviceType.ARTNET) { + + console.log("yes") + } }) + return addrToArtNetMessage } - diffStates(oldState: ArtNetDeviceState | undefined, newState: ArtNetDeviceState): Array { - const commands: Array = [] + + // returns basic information for testing, doesn't currently compare + diffStates(oldState: ArtNetDeviceState | undefined, newState: ArtNetDeviceState): Array { + const commands: Array = [] // TODO: compare the new state with the old state, and then output the COMMANDS needed in order to acheive the new state. @@ -85,51 +120,66 @@ export class ArtNetDevice extends Device { + // placeholder + async sendCommand(/*cmd: ArtNetDeviceCommand*/): Promise { // This is called when it's time to send the command - + // console.log(cmd) // Send the command + console.log("something sent") + // this.sendCommand(22) } - private async updateArtNet() { - // updates sendArtnet with new values only - return - } + // additonal methods for good implementation, currently unused - private async sendArtNetUniverse() { - // sends entire artnet universe data with appropriate parameters - } + // private async updateArtNet() { + // // updates sendArtnet with new values only + // } + + // private async sendArtNetUniverse() { + // // sends entire artnet universe data with appropriate parameters + // } } -interface ArtNetDeviceState { - [universe: string]: { - [channel: string]: { - value: number - } - } -} \ No newline at end of file +// unsure if useful + +// interface ArtNetDeviceState { +// [universe: string]: { +// [channel: string]: { +// value: number +// } +// } +// } \ No newline at end of file diff --git a/packages/timeline-state-resolver/src/service/devices.ts b/packages/timeline-state-resolver/src/service/devices.ts index 8a5770fa5..203288f14 100644 --- a/packages/timeline-state-resolver/src/service/devices.ts +++ b/packages/timeline-state-resolver/src/service/devices.ts @@ -12,6 +12,7 @@ import { HyperdeckDevice } from '../integrations/hyperdeck' import { OBSDevice } from '../integrations/obs' import { PanasonicPtzDevice } from '../integrations/panasonicPTZ' import { LawoDevice } from '../integrations/lawo' +import { ArtNetDevice } from '../integrations/artnet' export interface DeviceEntry { deviceClass: new (context: DeviceContextAPI) => Device @@ -22,6 +23,7 @@ export interface DeviceEntry { export type ImplementedServiceDeviceTypes = | DeviceType.ABSTRACT + | DeviceType.ARTNET | DeviceType.ATEM | DeviceType.HTTPSEND | DeviceType.HTTPWATCHER @@ -42,6 +44,12 @@ export const DevicesDict: Record = { deviceName: (deviceId: string) => 'Abstract ' + deviceId, executionMode: () => 'salvo', }, + [DeviceType.ARTNET]: { + deviceClass: ArtNetDevice, + canConnect: false, + deviceName: (deviceId: string) => 'ArtNet ' + deviceId, + executionMode: () => 'salvo', + }, [DeviceType.ATEM]: { deviceClass: AtemDevice, canConnect: true,