ATEM: audio, camera settings and MIDI control watched and fixed against the restore file
atem_watch.js (run with Companion's node + its atem-connection) keeps one connection to the switcher and compares, every second, every Fairlight source's mix option and fader and every camera's settings with atem-reference.xml (the 2026-10-07 14:59:55 restore file). ATEM shows ATEM AUDIO WRONG / ATEM CAMERA WRONG; the hold and Sunday auto-fix send back only what differs. ATEM SW MIDI ON is fixed by quitting ATEM Software Control, switching midiEnabled off and reopening it. Live check: switcher matches the file (0 differences, 1440 camera values). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Read-only snapshot of the ATEM switcher's audio (Fairlight) and camera control (CCU) state,
|
||||
// printed as one JSON line. Uses the atem-connection library inside Companion's ATEM module,
|
||||
// run with Companion's own node. Nothing is sent that changes the switcher.
|
||||
//
|
||||
// node atem_state.js <switcher ip> <path to atem-connection> [seconds to collect CCU values]
|
||||
const [ip, lib, secs] = process.argv.slice(2)
|
||||
const { Atem } = require(lib)
|
||||
const ccu = {}
|
||||
const atem = new Atem({ disableMultithreaded: true })
|
||||
atem.on('receivedCommands', (cmds) => {
|
||||
for (const c of cmds) {
|
||||
if (c.constructor && c.constructor.rawName === 'CCdP') {
|
||||
const p = c.properties
|
||||
const v = p.numberData && p.numberData.length ? p.numberData
|
||||
: p.boolData && p.boolData.length ? p.boolData
|
||||
: p.bigintData && p.bigintData.length ? p.bigintData.map(Number) : p.stringData
|
||||
ccu[`${c.source}/${c.category}/${c.parameter}`] = v
|
||||
}
|
||||
}
|
||||
})
|
||||
const done = (out, code) => {
|
||||
process.stdout.write(JSON.stringify(out) + '\n')
|
||||
atem.disconnect().finally(() => process.exit(code))
|
||||
setTimeout(() => process.exit(code), 2000)
|
||||
}
|
||||
setTimeout(() => done({ error: 'no connection to the switcher' }, 2), 15000)
|
||||
atem.on('connected', () => {
|
||||
setTimeout(() => {
|
||||
const inputs = {}
|
||||
const fl = (atem.state.fairlight && atem.state.fairlight.inputs) || {}
|
||||
for (const [id, input] of Object.entries(fl)) {
|
||||
if (!input) continue
|
||||
for (const [sid, src] of Object.entries(input.sources || {})) {
|
||||
if (!src || !src.properties) continue
|
||||
inputs[`${id}/${sid}`] = { mixOption: src.properties.mixOption, faderGain: src.properties.faderGain }
|
||||
}
|
||||
}
|
||||
done({ model: atem.state.info && atem.state.info.productIdentifier, fairlight: inputs, ccu }, 0)
|
||||
}, (Number(secs) || 3) * 1000)
|
||||
})
|
||||
atem.connect(ip)
|
||||
Reference in New Issue
Block a user