Can CasparCG read an external timer/clock serial input

A clock/timer is being sent to our PC every second, can CasparCG read and load this on the fly so I can have it as a key?

That is sure possible but will need a little programming.

Hi there,

Thanks so much for the reply.
Is there anything you can link me to that shows this process, or something similar?

Not really, as this is custom programming. Dependent on the format of that serial input the code needs to parse it, reformat it in the way you need it in the graphic and send it to Caspar, where a custom template displays it. As I explained here, Caspar is not an end user product out of the box.

1 Like

As didikunz correctly states, the process depends on many factors including the choice of computer language, the chosen method of updating the data in the template etc.

The runnable example below is just to illustrate one possible process. The solution uses a node.js application to generate an RS232 serial data stream of ISO date/time (eg “2021-03-27T16:45:03.462Z”). It receives that stream via a second serial port, parses the received data to extract the minutes and seconds segment sending this to a web page using a web socket connection. The two serial ports require connection via a null modem, or crossover, cable.

Node has a wide set of support libraries, including one that can read and partially parse a serial data stream. In the example the output stream uses a ‘\r\n’ (carriage return line feed) sequence to terminate each message sent, and the input is programmed to use that same line termination to detect when a message has been received. The parsing uses Javascripts built in string functions to split the date ad time sections of the message, then extract the minutes and seconds segment. The web socket library allows the Node application to act as the server end of a web socket connection whilst the web page or CasparCG template is the client for that connection. Web Sockets provides a full duplex high speed communications channel, hence why I used it in this example.

The block of code below is the node.js application - called app.js

'use strict';
const SerialPort = require('serialport');
const Readline = require('@serialport/parser-readline');
const WebSocket = require('ws');

// const myTxPort = '/dev/tty.usbserial-FTDDTJLX';  // macOS serial port for data output
// const myRxPort = '/dev/tty.usbserial-FTDDTJM1';  // macOS serial port for data input
const myTxPort = 'com2';  // Windows serial port for data output
const myRxPort = 'com1';  // Windows serial port for data input

const myTx = new SerialPort(myTxPort,{ 'baudRate':9600, 'dataBits':8, 'stopBits':1, 'parity':'even' });
const myRx = new SerialPort(myRxPort,{ 'baudRate':9600, 'dataBits':8, 'stopBits':1, 'parity':'even' });
const myRxLine = myRx.pipe(new Readline({ delimiter: '\r\n' })); // Define the end of line characters
const server = new WebSocket.Server({port: 4000}); // Create websocket listening on port 4000

let wssActive = false;  // Sets true when web-socket connection occurs
let client = null;
let timeMsg = { mode: 1, time: '00:00'};  // JSON object to carry data to client.

myTx.on('open', () => {
   setInterval(sendData, 1000);   // Start a 1 second timer, call sendData() on each tick.
});

myRxLine.on('data', (theTime) => {
  // Input text format is "2021-03-27T19:59:07.237Z"
  let td = theTime.split('T'); // Split the data and time segments. Time is td[1]
  let ms = td[1].slice(3,8);  // Extract the minutes and seconds from hh:mm:ss.abcZ
  if (wssActive) { // If websocket connection is active, send time value and color mode
    timeMsg.time = ms;
    timeMsg.mode = 2;   // Will cause green time display
    client.send(JSON.stringify(timeMsg));
  }
});

server.on ('connection', (socket) => {
   wssActive = true;
   client = socket;  // Note kust one single socket connection supported here.
   console.log('Client webpage has connected');

   socket.on('close', () => {
     wssActive = false;
     client = null;
     console.log('Client webpage has disconnected');
   });

   timeMsg.mode = 1; // Set colour mode to red text
   timeMsg.time = "--:--";
   socket.send(JSON.stringify(timeMsg));
});

// Output serial data to be read by the receive function.
function sendData() {
  let cdate = new Date();
  let fmtDate = cdate.toISOString();   // Format date as "yyyy-mm-ddT10:15:21.347Z"
  myTx.write(fmtDate + '\r\n');        // Send serial data via com port adding <cr><lf>
}

The block of html code below is the web page or CasparCG template. This can be saved as webpage.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Simple demo of websocket data receive</title>

<style>
html {
   -webkit-box-sizing: border-box;
   Box-Sizing:border-box;	/* Set all elements to be the actual set dimensions, disregard padding and borders */
   -webkit-backface-visibility: hidden;
   backface-visibility: hidden;
}
html, body {
   Margin:0;				      /* Use all available space */
   Padding:0;						/* Use all available space */
   Background:transparent;		/* The HTML consumer actually makes your background transparent by default */
   Overflow:hidden;				/* Hide overflowing elements to disable scollbars */
   -webkit-font-smoothing:antialiased !important;	 /* Set aliasing of fonts */
}
.myTime {
   position:absolute; top: 80vh; left: 80vw; color: brown;
   font-family: sans-serif; font-size: 8vh; font-weight:700
}
.greenTime { color:chartreuse }
</style>

<script>
   const webSocketServer = 'ws://127.0.0.1:4000';
   let ws = null;
   let timeMode = 0; // 1 = red text, 2 = green text;

   function startUI() {
      try {
            ws = new WebSocket(webSocketServer); // Open connection to data source

            // Define actions when stringified JSON message is received from the server
            ws.onmessage = function(e) {
               let rxdata = e.data;
               let jsObj = JSON.parse(rxdata);
               let mtdisplay = document.getElementById('clock');
               if (timeMode != jsObj.mode) {
                  timeMode = jsObj.mode;
                  if (timeMode === 1) 
                    { mtdisplay.classList.remove('greenTime'); }
                  else
                    { mtdisplay.classList.add('greenTime'); }
               }
               mtdisplay.innerText = jsObj.time;
            }
        }
        catch (error) {
            console.log("Tried to open %s but error was thrown %s", loc, error.data);
        }
   }
   // CasparCG interface functions. Most are null operations for this demo script.
   function play() {};
   function update(newData) {};
   function next() {};
   function invoke() {};
   function stop() {
      window.close();
   }
</script>

</head>
<body onload="startUI()">
   <div class="myTime" id="clock">??:??</div>
</body>
</html>

Finally the code below is the package.json file needed to load the libraries needed by node.

{
  "name": "serialtime",
  "version": "1.0.0",
  "description": "Demo serial data rx send to web display",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Andy Woodhouse",
  "license": "MIT",
  "dependencies": {
    "serialport": "^9.0.7",
    "ws": "^7.4.4"
  }
}

Please note that this example is just a proof of concept as it has almost zero error handling.

To run the example on a computer system create a named folder (e.g. c:\nodejs\serialtime) on a host computer that already has a node.js system installed. In that named folder save the three code blocks above using the names given before each block. Use a terminal window and change the active folder to be the named folder. Type the command

>npm install

and press the return key. All the libraries needed by the application, and their dependancies, are added to the folder. There may be a warning about a missing repository name, but ignore this. To start the applcation type the command:

>node app.js

Select the webpage.html file and open it in a browser such as Chrome. The terminal window will show a message if the web service connects, and the web page shows a momentary ??:?? text in dark red. As soon as the time messages arrive the text changes to green and the time updates every second.

The colour change command is part of the data sent from the node application to the web page. The message to the web page uses a text JSON object that carries both the colour index (1 means red, 2 means green) and the text that is the time.

The web page can be used as a template the CasparCG templates folder, but if the node application and the CasparCG are not running on the same host PC the web code line that says

const webSocketServer = 'ws://127.0.0.1:4000';

must be edited to have the ip address of the node app host in place of the 127.0.0.1.

The running node application can be stopped by typing a Ctrl-C in the terminal window.

If you need to know more about node.js, Javascript and html to understand the above code there are many resources on the web as both text pages and Youtube videos. I recommend the free tutorials on Youtube by someone called “The Net Ninja”. He has courses on Node.js, HTML, CSS and Javascript. I also recommend w3schools tutorials and the Mozilla web references at https://developer.mozilla.org/en-US/docs/Web/JavaScript

4 Likes

I usually receive data from serial port, first write a programe get data and parse data, then connect with casparCG Server with TCP, play and update your template, then done, I write some of App such as connect Omega ARES21, Swimming and DAKSTATS BASKETBALL and IceHockey Score and Timming Device.

Nice, your solution same with me, i do these before connect CasparCG many years ago, by the way, CasparCG is a great work, I prepare transfer my work to it. :grinning:

Hi, could you show me how to do it? Export data from Omega Ares21 GP to send live graphic?
Gorazd