I'm working on a sketch that will use a NodeMCU ESP8266 to connect via wifi to a Telnet Server (vMix video production software) to receive continuous updates of the status of all inputs and depending on status make an LED strip change colors.
In a nutshell.. the client connects to the server via wifi, receives a successful connection response. Then the client issues a command telling the server to give continuous status updates to the client anytime a source is previewed or transitioned to program.
I have the script working to the point of it will connect successfully and issue the "subscribe" command and is receiving the status response.
The server response is always formatted in the following way: "TALLY OK 20100." Each integer after the "TALLY OK " indicates the status of each input.. the more inputs, the more integers. The only integers used are 0, 1 or 2.
0 = input not in use, 1 = input in preview, or 2 = input on program output.
My code so far does reflect the latest status, but it's just printing to the serial monitor one character at a time as it loops. My brain is stuck on how best to analyze each response for a particular input's status. I then want to send the proper RBG values to the LED strip for tally purposes.
I'm returning to coding after a 30 year break and my old brain is just stuck. I feel like I'm close, but just need a little push to get me over this hurdle.
Although not reading from the Serial line but form the client, a similar technique to what is described in this tutorial can apply: Serial Input Basics --> every time client.available() tells you something is available add it to a buffer
Thanks for that link J-M-L. It was the resource I needed but couldn't seem to find. I finally made my code work and plugged in my LED strip code and I have a working tally system! The only trouble I am having now is it seems to work OK as long as it's in use. Once I walk away from it for a short time (only a few minutes) the sketch stops working. Could the NodeMCU be losing the WiFi signal somehow? It's only feet from the router so signal strength shouldn't be an issue. I have a alternate version of my script that runs on a Mega2560 connected via Ethernet that is working continuously, so I believe I can eliminate a server problem
I'm working on inserting some debugging code to see if I can spot what makes it stop while the system is not in use. So far I've found nothing. While I continue to debug here I am posting my sketch to see if any other eyeballs spot a problem.
Thanks for the help guys!
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <Adafruit_NeoPixel.h>
#define PIN D2 //Sets Digital pin 2 as LED signal pin
#define NUMPIXELS 14 //Number of LED clusters on my stip
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int delayval = 10; //Makes the color change "chase" for easy periferal sight when camera change occurs
ESP8266WiFiMulti WiFiMulti;
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
IPAddress server(172, 16, 3, 30); //IP address of the vMix production system
WiFiClient client;
void setup() {
Serial.begin(9600);
WiFiMulti.addAP("SSID", "PASSWORD"); //Replace with SSID and PASSWORD of local wifi
while (WiFiMulti.run() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
// the following lines are for serial debugging of wifi connection and connection to vMix server
Serial.println("");
Serial.println("WiFi Connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(500);
Serial.println("Connecting to VMIX...");
if (client.connect(server, 8099)) { //8099 is the vMix TCP/IP API port
Serial.println("VMIX Connected");
delay(500);
}
client.print("SUBSCRIBE TALLY\r\n"); //issues the command to vMix to start pushing any tally status changes to client
pixels.begin();
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (client.available() > 0 && newData == false) {
rc = client.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... "); //for debugging the recieved information
Serial.println(receivedChars); //and determining if it's what is expected
if ( ( receivedChars[10] == '0' ) ) { //char 10 is input 2 status... 0 is NOT IN USE and LED should glow dim white (grey).
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(1, 1, 1));
pixels.show();
delay(delayval);
}
}
if ( ( receivedChars[10] == '2' ) ) { //2 = input 2 is PREVIEW and should light LED dim GREEN
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 50, 0));
pixels.show();
delay(delayval);
}
}
if ( ( receivedChars[10] == '1' ) ) { //1 = input 2 is ON AIR and should light LED dim RED
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(50, 0, 0));
pixels.show();
delay(delayval);
}
}
newData = false;
}
}
That did it!! Over two hours left alone today and it's still up and working fine! Thank you for that quick and painless exchange of information. Here is my final script.
Again, thank you all for making this happen for me!
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <Adafruit_NeoPixel.h>
#define PIN D2 //Sets Digital pin 2 as LED signal pin
#define NUMPIXELS 14 //Number of LED clusters on my stip
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int delayval = 10; //Makes the color change "chase" for easy periferal sight when camera change occurs
ESP8266WiFiMulti WiFiMulti;
const byte numChars = 32;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
IPAddress server(172, 16, 3, 30); //IP address of the vMix production system
WiFiClient client;
void setup() {
Serial.begin(9600);
WiFiMulti.addAP("SSID", "PASSWORD"); //Replace with SSID and PASSWORD of local wifi
while (WiFiMulti.run() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
// the following lines are for serial debugging of wifi connection and connection to vMix server
Serial.println("");
Serial.println("WiFi Connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
WiFi.setSleepMode(WIFI_NONE_SLEEP); // to keep the WiFi connection alive always
delay(500);
Serial.println("Connecting to VMIX...");
if (client.connect(server, 8099)) { //8099 is the vMix TCP/IP API port
Serial.println("VMIX Connected");
delay(500);
}
client.print("SUBSCRIBE TALLY\r\n"); //issues the command to vMix to start pushing any tally status changes to client
pixels.begin();
}
void loop() {
recvWithEndMarker();
showNewData();
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
while (client.available() > 0 && newData == false) {
rc = client.read();
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... "); //for debugging the recieved information
Serial.println(receivedChars); //and determining if it's what is expected
if ( ( receivedChars[10] == '0' ) ) { //char 10 is input 2 status... 0 is NOT IN USE and LED should glow dim white (grey).
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(1, 1, 1));
pixels.show();
delay(delayval);
}
}
if ( ( receivedChars[10] == '2' ) ) { //2 = input 2 is PREVIEW and should light LED dim GREEN
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(0, 50, 0));
pixels.show();
delay(delayval);
}
}
if ( ( receivedChars[10] == '1' ) ) { //1 = input 2 is ON AIR and should light LED dim RED
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(50, 0, 0));
pixels.show();
delay(delayval);
}
}
newData = false;
}
}
Or if you want to save the planet and not burn too much energy (and ensure resilience) then your code should not rely on the connection to be always there and check / re-establish it if needed.
I'll attempt to include those improvements in the next version along with fixing another little hiccup.. If I reboot or for some reason close and relaunch the server software, connection to the server is lost. The sketch has to be restarted to reconnect. I need to build in some code that will somehow test the connection repeatedly and, if lost, reestablish the connection.
Another option could be to use a macro in my vMix software (it can execute VBscript) that will run on software start to push a reset command over the wifi to the clients, if that's even possible.