UI updates and improved client connection logic to allow for multiple machines.

This commit is contained in:
mmcwilliams 2024-08-24 16:26:49 -04:00
parent c33aaa2bec
commit 3c68496f5e
13 changed files with 146 additions and 34 deletions

View File

@ -139,7 +139,7 @@ class Client {
private progressText : HTMLElement;
constructor () {
let uri : string = 'ws://localhost:8082';
let uri : string = this.getWebsocketUri();
this.progress = document.getElementById('progress') as HTMLProgressElement;
this.progressText = document.getElementById('progressText');
this.client = new WebSocket(uri);
@ -152,6 +152,14 @@ class Client {
(document.getElementById('manualCtrlForm') as HTMLFormElement ).reset();
this.disableClass('sequenceCtrl');
this.disableClass('manualCtrl');
this.setProgress({ hash: null, progress: 0 });
}
private getWebsocketUri () : string {
const host : string = (window.location.host + '').split(':')[0];
//WEBSOCKET_PORT defined on page via template
//@ts-ignore
return `ws://${host}:${WEBSOCKET_PORT}`
}
private onMessage (event : any) {
@ -245,6 +253,9 @@ class Client {
private cmd (msg : Message) {
switch (msg.cmd) {
case 'ping' :
this.receivePing();
break;
case 'open' :
this.receiveCameraOpen();
break;
@ -283,6 +294,10 @@ class Client {
this.client.send(JSON.stringify({ cmd : 'open' }));
}
private receivePing() {
this.sendPong();
}
private receiveCameraOpen () {
console.log('got camera open');
this.enableClass('manualCtrl');
@ -299,6 +314,10 @@ class Client {
this.enableClass('manualCtrl');
}
private sendPong () {
this.client.send(JSON.stringify({ cmd : 'pong' }));
}
public sendAdvance () {
this.client.send(JSON.stringify({ cmd : 'advance' }));
}

View File

@ -8,7 +8,8 @@ export declare class Camera {
private next;
private port;
private prefix;
constructor();
private mock;
constructor(mock: boolean);
private begin;
private filter;
private enumerate;

11
dist/camera/index.js vendored
View File

@ -53,7 +53,7 @@ class CameraSerialPortMock extends serialport_1.SerialPortMock {
}
}
class Camera {
constructor() {
constructor(mock) {
this.ready = false;
this.connected = false;
this.serial = null;
@ -61,6 +61,8 @@ class Camera {
this.next = null;
this.port = null;
this.prefix = '';
this.mock = false;
this.mock = mock;
this.log = (0, log_1.createLog)('camera');
this.parser = new parser_readline_1.ReadlineParser({ delimiter: '\r\n' });
this.begin();
@ -74,7 +76,7 @@ class Camera {
catch (err) {
this.log.error(this.prefix + 'Error calling enumerate()', err);
}
if (ports.length > 0) {
if (!this.mock && ports.length > 0) {
for (let port of ports) {
this.log.info(this.prefix + `Found USB serial device: ${port} ${selected ? '*' : ''}`);
selected = false;
@ -86,8 +88,13 @@ class Camera {
this.log.error(this.prefix + `Error connecting to ${ports[0]}`, err);
}
}
else {
if (this.mock) {
this.log.info(`Starting camera in MOCK mode due to system setting`);
}
else {
this.log.warn(this.prefix + `No USB serial devices found, connecting to MOCK...`);
}
try {
await this.connectMock();
}

File diff suppressed because one or more lines are too long

23
dist/index.js vendored
View File

@ -42,6 +42,7 @@ const ffprobe_1 = require("./ffprobe");
const camera_1 = require("./camera");
const sequence_1 = require("./sequence");
const image_1 = require("./image");
let mock = false;
const log = (0, log_1.createLog)('fm');
const app = (0, express_1.default)();
let wss;
@ -167,6 +168,15 @@ async function settings() {
}
log.info(`VIDEOS=${videos}`);
}
if (typeof process.env['MOCK'] !== 'undefined') {
if (process.env['MOCK'].trim().toLowerCase() === "true" || process.env['MOCK'].trim() === '1') {
mock = true;
log.info(`MOCK=true`);
}
else {
mock = false;
}
}
}
function onWssConnection(ws, req) {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
@ -193,6 +203,9 @@ async function onClientMessage(data, ws) {
async function cmd(msg) {
let success = false;
switch (msg.cmd) {
case 'pong':
//received keepalive
break;
case 'open':
await cameraOpen();
break;
@ -254,10 +267,13 @@ async function send(msg) {
client.send(msgStr);
});
}
async function keepAlive() {
await send({ cmd: 'ping' });
}
app.get('/', async (req, res, next) => {
const sequencesArr = await files_1.Files.enumerateSequences(sequences);
//const videosArr : VideoObject[] = await Files.enumerateVideos(videos);
const html = index({ sequences: sequencesArr, width, height });
const html = index({ sequences: sequencesArr, width, height, wsPort });
res.send(html);
});
app.get('/:width/:height/image.jpg', async (req, res, next) => {
@ -294,9 +310,9 @@ async function main() {
ffmpeg = new ffmpeg_1.FFMPEG(process.env['FFMPEG']);
ffprobe = new ffprobe_1.FFPROBE();
image = new image_1.Image();
camera = new camera_1.Camera();
camera = new camera_1.Camera(mock);
display = new display_1.Display(width, height);
fd = new fd_1.FD(process.env['FD'], width, height, process.env['FD_HOST'], parseInt(process.env['FD_PORT']), true);
fd = new fd_1.FD(process.env['FD'], width, height, process.env['FD_HOST'], parseInt(process.env['FD_PORT']), mock);
app.listen(port, async () => {
log.info(`filmout_manager HTTP server running on port ${port}`);
});
@ -306,6 +322,7 @@ async function main() {
//ffmpeg.listFormats();
//log.info(await TestImage.Focus(640, 480));
sequence = new sequence_1.Sequence(camera, fd, display, ffprobe, send);
setInterval(keepAlive, 30000);
}
main();
//# sourceMappingURL=index.js.map

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

View File

@ -78,8 +78,10 @@ export class Camera {
private next : Function = null;
private port : string = null;
private prefix : string = '';
private mock : boolean = false;
constructor () {
constructor (mock : boolean) {
this.mock = mock;
this.log = createLog('camera');
this.parser = new ReadlineParser({ delimiter: '\r\n' });
this.begin();
@ -93,7 +95,7 @@ export class Camera {
} catch (err) {
this.log.error(this.prefix + 'Error calling enumerate()', err);
}
if (ports.length > 0) {
if (!this.mock && ports.length > 0) {
for (let port of ports) {
this.log.info(this.prefix + `Found USB serial device: ${port} ${selected ? '*' : ''}`);
selected = false;
@ -103,8 +105,12 @@ export class Camera {
} catch (err) {
this.log.error(this.prefix + `Error connecting to ${ports[0]}`, err);
}
} else {
if (this.mock) {
this.log.info(`Starting camera in MOCK mode due to system setting`);
} else {
this.log.warn(this.prefix + `No USB serial devices found, connecting to MOCK...`)
}
try {
await this.connectMock();
} catch (err) {

View File

@ -29,6 +29,7 @@ import { Camera } from './camera';
import { Sequence } from './sequence';
import { Image } from './image';
let mock : boolean = false;
const log : Logger = createLog('fm');
const app : Express = express();
let wss : Server;
@ -155,6 +156,14 @@ async function settings () {
}
log.info(`VIDEOS=${videos}`);
}
if (typeof process.env['MOCK'] !== 'undefined') {
if (process.env['MOCK'].trim().toLowerCase() === "true" || process.env['MOCK'].trim() === '1') {
mock = true;
log.info(`MOCK=true`);
} else {
mock = false;
}
}
}
function onWssConnection (ws : WebSocketExtended, req : Request) {
@ -182,6 +191,9 @@ async function onClientMessage (data : any, ws : WebSocket) {
async function cmd (msg : Message) {
let success : boolean = false
switch(msg.cmd) {
case 'pong' :
//received keepalive
break;
case 'open' :
await cameraOpen();
break;
@ -252,10 +264,14 @@ async function send (msg : Message) {
});
}
async function keepAlive () {
await send({ cmd : 'ping' });
}
app.get('/', async (req : Request, res : Response, next : NextFunction) => {
const sequencesArr : SequenceObject[] = await Files.enumerateSequences(sequences);
//const videosArr : VideoObject[] = await Files.enumerateVideos(videos);
const html : string = index({ sequences : sequencesArr, width, height });
const html : string = index({ sequences : sequencesArr, width, height, wsPort });
res.send(html);
});
@ -291,9 +307,9 @@ async function main () {
ffmpeg = new FFMPEG(process.env['FFMPEG']);
ffprobe = new FFPROBE();
image = new Image();
camera = new Camera();
camera = new Camera(mock);
display = new Display(width, height);
fd = new FD(process.env['FD'], width, height, process.env['FD_HOST'], parseInt(process.env['FD_PORT']), true);
fd = new FD(process.env['FD'], width, height, process.env['FD_HOST'], parseInt(process.env['FD_PORT']), mock);
app.listen(port, async () => {
log.info(`filmout_manager HTTP server running on port ${port}`);
@ -306,6 +322,7 @@ async function main () {
//ffmpeg.listFormats();
//log.info(await TestImage.Focus(640, 480));
sequence = new Sequence(camera, fd, display, ffprobe, send);
setInterval(keepAlive, 30000);
}

View File

@ -33,8 +33,10 @@ html, body{
}
#frame{
text-align: center;
text-align: center !important;
font-family: monospace;
padding: 0;
text-indent: 5px;
}
#display{
@ -61,13 +63,31 @@ fieldset.inline .field-row {
display: inline-block;
}
fieldset.inline .field-row input {
fieldset.inline .field-row input{
max-width: 50px;
}
fieldset.inline input.medium {
max-width: 70px;
}
progress {
width: 97vw;
position: absolute;
bottom: 28px;
left: 0.5vw;
}
button.small{
width: 35px;
max-width: 35px;
min-width: 35px;
padding: 0 6px;
}
button.medium{
width: 50px;
max-width: 50px;
min-width: 50px;
padding: 0 6px;
}

View File

@ -44,6 +44,7 @@ declare class Client {
private progress;
private progressText;
constructor();
private getWebsocketUri;
private onMessage;
private onOpen;
private onClose;
@ -57,9 +58,11 @@ declare class Client {
disableClass(className: string): void;
enableClass(className: string): void;
sendCameraOpen(): void;
private receivePing;
private receiveCameraOpen;
sendCameraClose(): void;
private receiveCameraClose;
private sendPong;
sendAdvance(): void;
sendRewind(): void;
sendSelect(): void;

View File

@ -114,7 +114,7 @@ class Display {
class Client {
constructor() {
this.connected = false;
let uri = 'ws://localhost:8082';
let uri = this.getWebsocketUri();
this.progress = document.getElementById('progress');
this.progressText = document.getElementById('progressText');
this.client = new WebSocket(uri);
@ -127,6 +127,11 @@ class Client {
document.getElementById('manualCtrlForm').reset();
this.disableClass('sequenceCtrl');
this.disableClass('manualCtrl');
this.setProgress({ hash: null, progress: 0 });
}
getWebsocketUri() {
const host = (window.location.host + '').split(':')[0];
return `ws://${host}:${WEBSOCKET_PORT}`;
}
onMessage(event) {
const msg = JSON.parse(event.data);
@ -206,6 +211,9 @@ class Client {
}
cmd(msg) {
switch (msg.cmd) {
case 'ping':
this.receivePing();
break;
case 'open':
this.receiveCameraOpen();
break;
@ -240,6 +248,9 @@ class Client {
this.disableClass('manualCtrl');
this.client.send(JSON.stringify({ cmd: 'open' }));
}
receivePing() {
this.sendPong();
}
receiveCameraOpen() {
console.log('got camera open');
this.enableClass('manualCtrl');
@ -253,6 +264,9 @@ class Client {
console.log('got camera close');
this.enableClass('manualCtrl');
}
sendPong() {
this.client.send(JSON.stringify({ cmd: 'pong' }));
}
sendAdvance() {
this.client.send(JSON.stringify({ cmd: 'advance' }));
}

File diff suppressed because one or more lines are too long

View File

@ -80,23 +80,28 @@
<fieldset id="displayAdjust" class="inline half">
<legend>Display Adjust</legend>
<form id="displayAdjustForm" onsubmit="return false;">
<button id="offsetXPlus">X +</button>
<button id="offsetXMinus">X -</button>
<button id="offsetYPlus">Y +</button>
<button id="offsetYMinus">Y -</button>
<button class="small sequenceCtrl" id="offsetXPlus">X +</button>
<button class="small sequenceCtrl" id="offsetXMinus">X -</button>
<button class="small sequenceCtrl" id="offsetYPlus">Y +</button>
<button class="small sequenceCtrl" id="offsetYMinus">Y -</button>
<button class="small sequenceCtrl" id="widthPlus">W +</button>
<button class="small sequenceCtrl" id="widthMinus">W -</button>
<button class="small sequenceCtrl" id="heightPlus">H +</button>
<button class="small sequenceCtrl" id="heightMinus">H -</button>
</form>
</fieldset>
</div>
<div>
<fieldset id="sequenceCtrl">
<div class="flex">
<fieldset class="inline half" id="sequenceCtrl">
<legend>Sequence Controls</legend>
<form id="sequenceCtrlForm" onsubmit="return false;">
<button id="start" class="sequenceCtrl" onclick="client.sendStart();" disabled>Start</button>
<button id="stop" class="sequenceCtrl" onclick="client.sendStop();" disabled>Stop</button>
<button id="pause" class="sequenceCtrl" disabled>Pause</button>
<button id="rewind" class="sequenceCtrl" onclick="client.sendRewind();" disabled><<</button>
<input id="frame" value="00000" class="sequenceCtrl" disabled />
<button id="advance" class="sequenceCtrl" onclick="client.sendAdvance()" disabled>>></button>
<button id="start" class="medium sequenceCtrl" onclick="client.sendStart();" disabled>Start</button>
<button id="stop" class="medium sequenceCtrl" onclick="client.sendStop();" disabled>Stop</button>
<button id="rewind" class="small sequenceCtrl" onclick="client.sendToStart();" disabled><<</button>
<button id="rewind" class="small sequenceCtrl" onclick="client.sendRewind();" disabled><</button>
<input id="frame" type="number" value="00000" class="sequenceCtrl medium" disabled />
<button id="advance" class="small sequenceCtrl" onclick="client.sendAdvance()" disabled>></button>
<button id="advance" class="small sequenceCtrl" onclick="client.sendToEnd()" disabled>>></button>
</form>
</fieldset>
</div>
@ -104,8 +109,8 @@
<fieldset id="manualCtrl">
<legend>Manual Controls</legend>
<form id="manualCtrlForm" onsubmit="return false;" >
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open Gate</button>
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close Gate</button>
<button id="open" class="manualCtrl" onclick="client.sendCameraOpen()">Open</button>
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
<button id="focus" class="manualCtrl" onclick="">Focus</button>
<button id="framing" class="manualCtrl" onclick="">Framing</button>
</form>
@ -123,6 +128,9 @@
</div>
</div>
<div id="overlay"></div>
<script>
const WEBSOCKET_PORT = {{wsPort}};
</script>
<script src="/static/js/index.js"></script>
</body>
</html>