|
|
/*
|
|
|
vTally for vMix
|
|
|
Copyright 2022 by VID-PRO
|
|
|
https://www.vid-pro.de
|
|
|
*/
|
|
|
|
|
|
#include <EEPROM.h>
|
|
|
#include <ESP8266WiFi.h>
|
|
|
#include <ESP8266WebServer.h>
|
|
|
#include <WiFiClient.h>
|
|
|
#include <Adafruit_NeoPixel.h>
|
|
|
#include <SoftwareSerial.h>
|
|
|
#include "ESPAsyncUDP.h"
|
|
|
#include "FS.h"
|
|
|
|
|
|
// Constants
|
|
|
const float vers = 2.0;
|
|
|
|
|
|
const int SsidMaxLength = 24;
|
|
|
const int PassMaxLength = 24;
|
|
|
const int HostNameMaxLength = 24;
|
|
|
const int TallyNumberMaxValue = 64;
|
|
|
|
|
|
// LED setting
|
|
|
//#define LED_DATA D8
|
|
|
//bool data_state = false;
|
|
|
#define LED_PIN D2
|
|
|
#define LED_NUM 1
|
|
|
Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_NUM, LED_PIN, NEO_GRB + NEO_KHZ800);
|
|
|
|
|
|
// Settings object
|
|
|
struct Settings
|
|
|
{
|
|
|
char ssid[SsidMaxLength];
|
|
|
char pass[PassMaxLength];
|
|
|
char hostName[HostNameMaxLength];
|
|
|
int tallyNumber;
|
|
|
int intensFull;
|
|
|
int intensDim;
|
|
|
int prgred;
|
|
|
int prggreen;
|
|
|
int prgblue;
|
|
|
int prvred;
|
|
|
int prvgreen;
|
|
|
int prvblue;
|
|
|
int offred;
|
|
|
int offgreen;
|
|
|
int offblue;
|
|
|
unsigned int viscabaud;
|
|
|
unsigned int viscaport;
|
|
|
};
|
|
|
|
|
|
// Default settings object
|
|
|
Settings defaultSettings = {
|
|
|
"SSID",
|
|
|
"PASSWORD",
|
|
|
"vmix_hostname",
|
|
|
1,
|
|
|
254,
|
|
|
128,
|
|
|
0,
|
|
|
254,
|
|
|
0,
|
|
|
254,
|
|
|
128,
|
|
|
0,
|
|
|
0,
|
|
|
0,
|
|
|
254,
|
|
|
9600,
|
|
|
52381
|
|
|
};
|
|
|
|
|
|
Settings settings;
|
|
|
|
|
|
// HTTP Server settings
|
|
|
ESP8266WebServer httpServer(80);
|
|
|
char deviceName[32];
|
|
|
int status = WL_IDLE_STATUS;
|
|
|
bool apEnabled = false;
|
|
|
char apPass[64];
|
|
|
|
|
|
// vMix settings
|
|
|
int port = 8099;
|
|
|
|
|
|
//// Tally info
|
|
|
char currentState = -1;
|
|
|
char oldState = -1;
|
|
|
const char tallyStateProgram = 1;
|
|
|
const char tallyStatePreview = 2;
|
|
|
|
|
|
// The WiFi client
|
|
|
WiFiClient client;
|
|
|
const int timeout = 10;
|
|
|
const int delayTime = 10000;
|
|
|
int vmixcon = 0;
|
|
|
|
|
|
// Time measure
|
|
|
const int interval = 5000;
|
|
|
unsigned long lastCheck = 0;
|
|
|
|
|
|
// VISCAoIP 2 serial
|
|
|
SoftwareSerial viscaSerial;
|
|
|
int udpstate = 0;
|
|
|
|
|
|
//// RS232 Serial Settings
|
|
|
const int txpin = D5;
|
|
|
const int rxpin = D6;
|
|
|
|
|
|
//// Use the following constants and functions to modify the speed of PTZ commands
|
|
|
const double ZOOMMULT = 0.3; // speed multiplier for the zoom functions
|
|
|
const double ZOOMEXP = 1.5; // exponential curve for the speed modification
|
|
|
const double PTZMULT = 0.3; // speed multiplier for the pan and tilt functions
|
|
|
const double PTZEXP = 1.0; // exponential curve for the speed modification
|
|
|
|
|
|
//// STATE VARIABLES
|
|
|
AsyncUDP udp;
|
|
|
int lastclientport = 0;
|
|
|
IPAddress lastclientip;
|
|
|
bool pwr_is_on = false;
|
|
|
|
|
|
//// memory buffers for VISCA commands
|
|
|
size_t lastudp_len = 0;
|
|
|
uint8_t lastudp_in[16];
|
|
|
size_t lastser_len = 0;
|
|
|
uint8_t lastser_in[16];
|
|
|
|
|
|
//// quick use VISCA commands
|
|
|
const uint8_t pwr_on[] = {0x81, 0x01, 0x04, 0x00, 0x02, 0xff};
|
|
|
const uint8_t pwr_off[] = {0x81, 0x01, 0x04, 0x00, 0x03, 0xff};
|
|
|
const uint8_t addr_set[] = {0x88, 0x30, 0x01, 0xff}; // address set
|
|
|
const uint8_t if_clear[] = {0x88, 0x01, 0x00, 0x01, 0xff}; // if clear
|
|
|
const uint8_t ifClear[] = {0x88, 0x01, 0x00, 0x01, 0xff}; // Checks to see if communication line is clear
|
|
|
const uint8_t irOff[] = {0x81, 0x01, 0x06, 0x09, 0x03, 0xff}; // Turn off IR control (required for speed control of Pan/Tilt on TelePresence cameras)
|
|
|
const uint8_t callLedOn[] = {0x81, 0x01, 0x33, 0x01, 0x01, 0xff};
|
|
|
const uint8_t callLedOff[] = {0x81, 0x01, 0x33, 0x01, 0x00, 0xff};
|
|
|
const uint8_t callLedBlink[] = {0x81, 0x01, 0x33, 0x01, 0x02, 0xff};
|
|
|
const uint8_t ack[] = {0x90, 0x41, 0xff};
|
|
|
const uint8_t ack2[] = {0x90, 0x42, 0xff};
|
|
|
const uint8_t complete[] = {0x90, 0x51, 0xff};
|
|
|
const uint8_t complete2[] = {0x90, 0x52, 0xff};
|
|
|
const uint8_t ifclearcompl[] = {0x90, 0x50, 0xff};
|
|
|
int ifclearcomplength = 3;
|
|
|
|
|
|
/*
|
|
|
Video formats values:
|
|
|
Value HDMI SDI
|
|
|
0x00 1080p25 1080p25
|
|
|
0x01 1080p30 1080p30
|
|
|
0x02 1080p50 720p50
|
|
|
0x03 1080p60 720p60
|
|
|
0x04 720p25 720p25
|
|
|
0x05 720p30 720p30
|
|
|
0x06 720p50 720p50
|
|
|
0x07 720p60 720p60
|
|
|
*/
|
|
|
const uint8_t format = 0x01;
|
|
|
const uint8_t videoFormat[] = { 0x81, 0x01, 0x35, 0x00, format, 0x00, 0xff }; // 8x 01 35 0p 0q 0r ff p = reserved, q = video mode, r = Used in PrecisionHD 720p camera.
|
|
|
|
|
|
|
|
|
// Load settings from EEPROM
|
|
|
void loadSettings()
|
|
|
{
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| Loading settings |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
|
|
|
long ptr = 0;
|
|
|
|
|
|
for (int i = 0; i < SsidMaxLength; i++)
|
|
|
{
|
|
|
settings.ssid[i] = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < PassMaxLength; i++)
|
|
|
{
|
|
|
settings.pass[i] = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < HostNameMaxLength; i++)
|
|
|
{
|
|
|
settings.hostName[i] = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
}
|
|
|
|
|
|
settings.tallyNumber = EEPROM.read(ptr);
|
|
|
|
|
|
ptr++;
|
|
|
settings.intensFull = EEPROM.read(ptr);
|
|
|
|
|
|
ptr++;
|
|
|
settings.intensDim = EEPROM.read(ptr);
|
|
|
|
|
|
ptr++;
|
|
|
settings.prgred = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
settings.prggreen = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
settings.prgblue = EEPROM.read(ptr);
|
|
|
|
|
|
ptr++;
|
|
|
settings.prvred = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
settings.prvgreen = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
settings.prvblue = EEPROM.read(ptr);
|
|
|
|
|
|
ptr++;
|
|
|
settings.offred = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
settings.offgreen = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
settings.offblue = EEPROM.read(ptr);
|
|
|
|
|
|
ptr++;
|
|
|
byte low = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
byte high = EEPROM.read(ptr);
|
|
|
settings.viscabaud = low + ((high << 8) & 0xFF00);
|
|
|
ptr++;
|
|
|
low = EEPROM.read(ptr);
|
|
|
ptr++;
|
|
|
high = EEPROM.read(ptr);
|
|
|
settings.viscaport = low + ((high << 8) & 0xFF00);
|
|
|
|
|
|
|
|
|
if (strlen(settings.ssid) == 0 || strlen(settings.pass) == 0 || strlen(settings.hostName) == 0 || settings.tallyNumber == 0 || settings.intensFull == 0 || settings.intensDim == 0 || settings.viscabaud == 0 || settings.viscaport == 0)
|
|
|
{
|
|
|
Serial.println(F("| No settings found"));
|
|
|
Serial.println(F("| Loading default settings"));
|
|
|
settings = defaultSettings;
|
|
|
saveSettings();
|
|
|
restart();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Serial.println(F("| Settings loaded"));
|
|
|
printSettings();
|
|
|
Serial.println(F("+---------------------"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Save settings to EEPROM
|
|
|
void saveSettings()
|
|
|
{
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| Saving settings |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
|
|
|
long ptr = 0;
|
|
|
|
|
|
for (int i = 0; i < 512; i++)
|
|
|
{
|
|
|
EEPROM.write(i, 0);
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < SsidMaxLength; i++)
|
|
|
{
|
|
|
EEPROM.write(ptr, settings.ssid[i]);
|
|
|
ptr++;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < PassMaxLength; i++)
|
|
|
{
|
|
|
EEPROM.write(ptr, settings.pass[i]);
|
|
|
ptr++;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < HostNameMaxLength; i++)
|
|
|
{
|
|
|
EEPROM.write(ptr, settings.hostName[i]);
|
|
|
ptr++;
|
|
|
}
|
|
|
|
|
|
EEPROM.write(ptr, settings.tallyNumber);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.intensFull);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.intensDim);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.prgred);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.prggreen);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.prgblue);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.prvred);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.prvgreen);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.prvblue);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.offred);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.offgreen);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.offblue);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.viscabaud & 0xFF);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, (settings.viscabaud >> 8) & 0xFF);
|
|
|
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, settings.viscaport & 0xFF);
|
|
|
ptr++;
|
|
|
EEPROM.write(ptr, (settings.viscaport >> 8) & 0xFF);
|
|
|
|
|
|
EEPROM.commit();
|
|
|
|
|
|
Serial.println(F("| Settings saved"));
|
|
|
printSettings();
|
|
|
Serial.println(F("+---------------------"));
|
|
|
}
|
|
|
|
|
|
// Print settings
|
|
|
void printSettings()
|
|
|
{
|
|
|
Serial.print(F("| SSID : "));
|
|
|
Serial.println(settings.ssid);
|
|
|
Serial.print(F("| SSID Password : "));
|
|
|
Serial.println(settings.pass);
|
|
|
Serial.print(F("| vMix Hostname/IP: "));
|
|
|
Serial.println(settings.hostName);
|
|
|
Serial.print(F("| Tally number : "));
|
|
|
Serial.println(settings.tallyNumber);
|
|
|
Serial.print(F("| Intensity Full : "));
|
|
|
Serial.println(settings.intensFull);
|
|
|
Serial.print(F("| Intensity Dim : "));
|
|
|
Serial.println(settings.intensDim);
|
|
|
Serial.print(F("| Program-Color : "));
|
|
|
Serial.print(settings.prgred);
|
|
|
Serial.print(F(","));
|
|
|
Serial.print(settings.prggreen);
|
|
|
Serial.print(F(","));
|
|
|
Serial.println(settings.prgblue);
|
|
|
Serial.print(F("| Preview-Color : "));
|
|
|
Serial.print(settings.prvred);
|
|
|
Serial.print(F(","));
|
|
|
Serial.print(settings.prvgreen);
|
|
|
Serial.print(F(","));
|
|
|
Serial.println(settings.prvblue);
|
|
|
Serial.print(F("| Off-Color : "));
|
|
|
Serial.print(settings.offred);
|
|
|
Serial.print(F(","));
|
|
|
Serial.print(settings.offgreen);
|
|
|
Serial.print(F(","));
|
|
|
Serial.println(settings.offblue);
|
|
|
Serial.print(F("| VISCA baud : "));
|
|
|
Serial.println(settings.viscabaud);
|
|
|
Serial.print(F("| VISCA port : "));
|
|
|
Serial.println(settings.viscaport);
|
|
|
}
|
|
|
|
|
|
// Set led intensity from 0 to 255
|
|
|
void ledSetIntensity(int intensity)
|
|
|
{
|
|
|
leds.setBrightness(intensity);
|
|
|
}
|
|
|
|
|
|
// Set LED's off
|
|
|
void ledSetOff()
|
|
|
{
|
|
|
leds.setPixelColor(0, leds.Color(0, 0, 0));
|
|
|
ledSetIntensity(0);
|
|
|
leds.show();
|
|
|
}
|
|
|
|
|
|
// Draw corner dots
|
|
|
void ledSetCornerDots()
|
|
|
{
|
|
|
leds.setPixelColor(0, leds.Color(settings.offred, settings.offgreen, settings.offblue));
|
|
|
ledSetIntensity(settings.intensDim);
|
|
|
leds.show();
|
|
|
}
|
|
|
|
|
|
// Draw L(ive) with LED's
|
|
|
void ledSetProgram()
|
|
|
{
|
|
|
leds.setPixelColor(0, leds.Color(settings.prgred, settings.prggreen, settings.prgblue));
|
|
|
ledSetIntensity(settings.intensFull);
|
|
|
leds.show();
|
|
|
}
|
|
|
|
|
|
// Draw P(review) with LED's
|
|
|
void ledSetPreview()
|
|
|
{
|
|
|
leds.setPixelColor(0, leds.Color(settings.prvred, settings.prvgreen, settings.prvblue));
|
|
|
ledSetIntensity(settings.intensFull);
|
|
|
leds.show();
|
|
|
}
|
|
|
|
|
|
// Draw C(onnecting) with LED's
|
|
|
void ledSetConnecting()
|
|
|
{
|
|
|
leds.setPixelColor(0, leds.Color(0, 255, 255));
|
|
|
ledSetIntensity(settings.intensDim);
|
|
|
leds.show();
|
|
|
}
|
|
|
|
|
|
// Draw S(ettings) with LED's
|
|
|
void ledSetSettings()
|
|
|
{
|
|
|
leds.setPixelColor(0, leds.Color(255, 0, 255));
|
|
|
ledSetIntensity(settings.intensDim);
|
|
|
leds.show();
|
|
|
}
|
|
|
|
|
|
// Set tally to off
|
|
|
void tallySetOff()
|
|
|
{
|
|
|
Serial.println(F("| Tally off"));
|
|
|
|
|
|
ledSetCornerDots();
|
|
|
send_visca(callLedOff);
|
|
|
}
|
|
|
|
|
|
// Set tally to program
|
|
|
void tallySetProgram()
|
|
|
{
|
|
|
Serial.println(F("| Tally program"));
|
|
|
|
|
|
ledSetProgram();
|
|
|
send_visca(callLedOn);
|
|
|
}
|
|
|
|
|
|
// Set tally to preview
|
|
|
void tallySetPreview()
|
|
|
{
|
|
|
Serial.println(F("| Tally preview"));
|
|
|
|
|
|
ledSetPreview();
|
|
|
send_visca(callLedBlink);
|
|
|
}
|
|
|
|
|
|
// Set tally to connecting
|
|
|
void tallySetConnecting()
|
|
|
{
|
|
|
ledSetConnecting();
|
|
|
}
|
|
|
|
|
|
// Handle incoming data
|
|
|
void handleData(String data)
|
|
|
{
|
|
|
// Check if server data is tally data
|
|
|
if (data.indexOf("TALLY OK") == 0)
|
|
|
{
|
|
|
vmixcon = 1;
|
|
|
char newState = data.charAt(settings.tallyNumber + 8);
|
|
|
|
|
|
// Check if tally state has changed
|
|
|
if (currentState != newState)
|
|
|
{
|
|
|
currentState = newState;
|
|
|
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
tallySetOff();
|
|
|
break;
|
|
|
case '1':
|
|
|
tallySetProgram();
|
|
|
break;
|
|
|
case '2':
|
|
|
tallySetPreview();
|
|
|
break;
|
|
|
default:
|
|
|
tallySetOff();
|
|
|
}
|
|
|
/*
|
|
|
if (data_state) {
|
|
|
digitalWrite(LED_DATA, data_state);
|
|
|
data_state = false;
|
|
|
} else {
|
|
|
digitalWrite(LED_DATA, data_state);
|
|
|
data_state = true;
|
|
|
}
|
|
|
*/
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
vmixcon = 1;
|
|
|
Serial.print(F("| Response from vMix: "));
|
|
|
Serial.println(data);
|
|
|
|
|
|
//Serial.print(F("| FreeHeap: "));
|
|
|
//Serial.println(ESP.getFreeHeap(),DEC);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Start access point
|
|
|
void apStart()
|
|
|
{
|
|
|
ledSetSettings();
|
|
|
Serial.println(F("(+--------------------+"));
|
|
|
Serial.println(F("(| AP Start |"));
|
|
|
Serial.println(F("(+--------------------+"));
|
|
|
Serial.print(F("| AP SSID : "));
|
|
|
Serial.println(deviceName);
|
|
|
Serial.print(F("| AP password : "));
|
|
|
Serial.println(apPass);
|
|
|
|
|
|
WiFi.mode(WIFI_AP);
|
|
|
WiFi.hostname(deviceName);
|
|
|
WiFi.softAP(deviceName, apPass);
|
|
|
delay(100);
|
|
|
IPAddress myIP = WiFi.softAPIP();
|
|
|
Serial.print(F("| IP address : "));
|
|
|
Serial.println(myIP);
|
|
|
Serial.println(F("+---------------------"));
|
|
|
|
|
|
|
|
|
apEnabled = true;
|
|
|
}
|
|
|
|
|
|
// Handle http server Tally request
|
|
|
void tallyPageHandler()
|
|
|
{
|
|
|
String response_message = F("<!DOCTYPE html>");
|
|
|
|
|
|
response_message += F("<html lang='en'>");
|
|
|
response_message += F("<head>");
|
|
|
response_message += F("<title>vTally by VID-PRO - ") + String(deviceName) + F("</title>");
|
|
|
response_message += F("<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>");
|
|
|
response_message += F("<meta charset='utf-8'>");
|
|
|
response_message += F("<link rel='icon' type='image/x-icon' href='favicon.ico'>");
|
|
|
response_message += F("<link rel='stylesheet' href='styles.css'>");
|
|
|
response_message += F("<style>body {width: 100%;height: 100%;padding: 0px;}</style>");
|
|
|
response_message += F("</head>");
|
|
|
|
|
|
response_message += F("<body class='bg-light'>");
|
|
|
|
|
|
response_message += F("<table class='table'><tbody style='border-radius: 0px 0px 10px 10px;background-color:#d5dadd;'>");
|
|
|
|
|
|
response_message += F("<tr><th style='background-color:rgb(");
|
|
|
|
|
|
if (vmixcon == 0) {
|
|
|
currentState = '3';
|
|
|
}
|
|
|
if (vmixcon == 1 && (currentState != '0' && currentState != '1' && currentState != '2')) {
|
|
|
currentState = 4;
|
|
|
}
|
|
|
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //off
|
|
|
break;
|
|
|
case '1':
|
|
|
response_message += String(settings.prgred) + F(",") + String(settings.prggreen) + F(",") + String(settings.prgblue); //prg
|
|
|
break;
|
|
|
case '2':
|
|
|
response_message += String(settings.prvred) + F(",") + String(settings.prvgreen) + F(",") + String(settings.prvblue); //prv
|
|
|
break;
|
|
|
case '3':
|
|
|
response_message += F("255,0,0"); // no vMix Server
|
|
|
break;
|
|
|
case '4':
|
|
|
response_message += F("255,255,0"); // no vMix Server
|
|
|
break;
|
|
|
default:
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //default off
|
|
|
}
|
|
|
response_message += F(");'> </th><tr>");
|
|
|
|
|
|
|
|
|
response_message += F("<tr><th style='text-align:center;background-color:rgb(");
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //off
|
|
|
break;
|
|
|
case '1':
|
|
|
response_message += String(settings.prgred) + F(",") + String(settings.prggreen) + F(",") + String(settings.prgblue); //prg
|
|
|
break;
|
|
|
case '2':
|
|
|
response_message += String(settings.prvred) + F(",") + String(settings.prvgreen) + F(",") + String(settings.prvblue); //prv
|
|
|
break;
|
|
|
case '3':
|
|
|
response_message += F("255,0,0"); // no vMix Server
|
|
|
break;
|
|
|
case '4':
|
|
|
response_message += F("255,255,0"); // no vMix Server
|
|
|
break;
|
|
|
default:
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //default off
|
|
|
}
|
|
|
response_message += F(");color:");
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
response_message += F("#ffffff"); //off
|
|
|
break;
|
|
|
case '1':
|
|
|
response_message += F("#ffffff"); //prg
|
|
|
break;
|
|
|
case '2':
|
|
|
response_message += F("#ffffff"); //prv
|
|
|
break;
|
|
|
case '3':
|
|
|
response_message += F("#ffffff"); // no vMix Server
|
|
|
break;
|
|
|
case '4':
|
|
|
response_message += F("#ffffff"); // no vMix Server
|
|
|
break;
|
|
|
default:
|
|
|
response_message += F("#ffffff"); //default off
|
|
|
}
|
|
|
response_message += F("'>");
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
response_message += F("OFF"); //off
|
|
|
break;
|
|
|
case '1':
|
|
|
response_message += F("PROGRAM"); //prg
|
|
|
break;
|
|
|
case '2':
|
|
|
response_message += F("PREVIEW"); //prv
|
|
|
break;
|
|
|
case '3':
|
|
|
response_message += F("vMix Server not found!"); // no vMix Server
|
|
|
break;
|
|
|
case '4':
|
|
|
response_message += F("connected to vMix Server, waiting for data."); // no vMix Server
|
|
|
break;
|
|
|
default:
|
|
|
response_message += F("OFF"); //default off
|
|
|
}
|
|
|
response_message += F("</th></tr>");
|
|
|
|
|
|
|
|
|
response_message += F("<tr><th style='background-color:rgb(");
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //off
|
|
|
break;
|
|
|
case '1':
|
|
|
response_message += String(settings.prgred) + F(",") + String(settings.prggreen) + F(",") + String(settings.prgblue); //prg
|
|
|
break;
|
|
|
case '2':
|
|
|
response_message += String(settings.prvred) + F(",") + String(settings.prvgreen) + F(",") + String(settings.prvblue); //prv
|
|
|
break;
|
|
|
case '3':
|
|
|
response_message += F("255,0,0"); // no vMix Server
|
|
|
break;
|
|
|
case '4':
|
|
|
response_message += F("255,255,0"); // no vMix Server
|
|
|
break;
|
|
|
default:
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //default off
|
|
|
}
|
|
|
response_message += F(");'> </th><tr>");
|
|
|
|
|
|
response_message += F("<tr><th style='border-radius: 0px 0px 10px 10px;background-color:rgb(");
|
|
|
switch (currentState)
|
|
|
{
|
|
|
case '0':
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //off
|
|
|
break;
|
|
|
case '1':
|
|
|
response_message += String(settings.prgred) + F(",") + String(settings.prggreen) + F(",") + String(settings.prgblue); //prg
|
|
|
break;
|
|
|
case '2':
|
|
|
response_message += String(settings.prvred) + F(",") + String(settings.prvgreen) + F(",") + String(settings.prvblue); //prv
|
|
|
break;
|
|
|
case '3':
|
|
|
response_message += F("255,0,0"); // no vMix Server
|
|
|
break;
|
|
|
case '4':
|
|
|
response_message += F("255,255,0"); // no vMix Server
|
|
|
break;
|
|
|
default:
|
|
|
response_message += String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue); //default off
|
|
|
}
|
|
|
response_message += F(");'> </th><tr>");
|
|
|
|
|
|
response_message += F("</tbody></table>");
|
|
|
|
|
|
response_message += F("</body></html>");
|
|
|
|
|
|
httpServer.sendHeader("Connection", "close");
|
|
|
httpServer.send(200, "text/html", String(response_message));
|
|
|
|
|
|
//Serial.print(F("| FreeHeap: "));
|
|
|
//Serial.println(ESP.getFreeHeap(),DEC);
|
|
|
}
|
|
|
|
|
|
// Handle http server root request
|
|
|
void rootPageHandler()
|
|
|
{
|
|
|
String response_message = F("<!DOCTYPE html>");
|
|
|
response_message += F("<html lang='en'>");
|
|
|
response_message += F("<head>");
|
|
|
response_message += F("<title>vTally by CaliHC - ") + String(deviceName) + F("</title>");
|
|
|
response_message += F("<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>");
|
|
|
response_message += F("<meta charset='utf-8'>");
|
|
|
response_message += F("<link rel='icon' type='image/x-icon' href='favicon.ico'>");
|
|
|
response_message += F("<link rel='stylesheet' href='styles.css'>");
|
|
|
response_message += F("<script src='jquery.slim.min.js'></script>");
|
|
|
response_message += F("<script type='text/javascript'>");
|
|
|
response_message += F("var ESPurl = 'http://") + WiFi.localIP().toString() + F("/zend';");
|
|
|
response_message += F("if(typeof(EventSource) !== 'undefined') {");
|
|
|
response_message += F(" var source = new EventSource(ESPurl);");
|
|
|
response_message += F(" source.onmessage = function(event) {");
|
|
|
response_message += F(" if(event.data == 'refresh0' || event.data == 'refresh1') {");
|
|
|
response_message += F(" $('#tally').html(\"<object type='text/html' data='/tally' style='height:100%;width:100%;'></oject>\");");
|
|
|
response_message += F(" if(event.data == 'refresh1') {");
|
|
|
response_message += F(" $('#vmixstatus').html(\"Connected\");");
|
|
|
response_message += F(" $('#vmixstatus').css(\"background-color\",\"green\");");
|
|
|
response_message += F(" }");
|
|
|
response_message += F(" if(event.data == 'refresh0') {");
|
|
|
response_message += F(" $('#vmixstatus').html(\"Disconnected\");");
|
|
|
response_message += F(" $('#vmixstatus').css(\"background-color\",\"red\");");
|
|
|
response_message += F(" }");
|
|
|
response_message += F(" }");
|
|
|
response_message += F(" }");
|
|
|
response_message += F("} else {");
|
|
|
response_message += F(" document.getElementById('tally').innerHTML('Your browser does not support EventSource!')");
|
|
|
response_message += F("}");
|
|
|
|
|
|
response_message += F("</script>");
|
|
|
response_message += F("<style>body {width: 100%;height: 100%;padding: 25px;}</style>");
|
|
|
response_message += F("</head>");
|
|
|
|
|
|
response_message += F("<body class='bg-light'>");
|
|
|
|
|
|
response_message += F("<h1 style='border-radius: 10px 10px 0px 0px;background-color:#0066ff;color:#FFFFFF;text-align:center;padding:5px;margin-bottom:0px;'><span style='vertical-align:text-top;'>vTally by </span><a href=https://www.calihc.de target=_new><img src='logo.png' style='vertical-align:bottom;'></a></h1>");
|
|
|
|
|
|
response_message += F("<h1 style='border-radius:0px 0px 10px 10px;background-color:#c6cdd2;text-align:center;'>vTally ID: ") + String(settings.tallyNumber) + F("</h1>");
|
|
|
|
|
|
response_message += F("<form action='/save' method='post' enctype='multipart/form-data' data-ajax='false'>");
|
|
|
|
|
|
response_message += F("<div data-role='content' class='row' style='margin-bottom:.5rem;'>");
|
|
|
|
|
|
response_message += F("<div class='col-md-6'>");
|
|
|
response_message += F("<h2 style='border-radius: 10px 10px 0px 0px;margin-bottom:0px;background-color:#99c2ff;padding:2px;'> Network/vMix/VISCA Settings</h2>");
|
|
|
|
|
|
response_message += F("<table class='table' style='border-radius: 0px 0px 10px 10px;'><tbody style='border-radius: 0px 0px 10px 10px;background-color:#d5dadd;'><tr style='border-radius: 0px 0px 10px 10px;'><td style='border-radius: 0px 0px 10px 10px;'>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='ssid' class='col-sm-4 col-form-label'>WiFi SSID</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='ssid' class='form-control' type='text' size='64' maxlength='32' name='ssid' value='") + String(settings.ssid) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='ssidpass' class='col-sm-4 col-form-label'>WiFi Passphrase</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='ssidpass' class='form-control' type='password' autocomplete='current-password' size='64' maxlength='32' name='ssidpass' value='") + String(settings.pass) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<hr>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='hostname' class='col-sm-4 col-form-label'>vMix Server Hostname/IP</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='hostname' class='form-control' type='text' size='64' maxlength='32' name='hostname' value='") + String(settings.hostName) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='inputnumber' class='col-sm-4 col-form-label'>Tally number (1-") + String(TallyNumberMaxValue) + F(")</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='inputnumber' class='form-control' type='number' size='64' min='0' max='") + String(TallyNumberMaxValue) + F("' name='inputnumber' value='") + String(settings.tallyNumber) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<hr>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='inputnumber' class='col-sm-4 col-form-label'>VISCA Baudrate (9600)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<select id='viscabaud' name='viscabaud' class='form-control'>");
|
|
|
response_message += F("<option value='4800' ");
|
|
|
(String(settings.viscabaud) == "4800") ? response_message += "selected" : response_message += "";
|
|
|
response_message += F(">4800</option>");
|
|
|
response_message += F("<option value='9600' ");
|
|
|
(String(settings.viscabaud) == "9600") ? response_message += "selected" : response_message += "";
|
|
|
response_message += F(">9600</option>");
|
|
|
response_message += F("<option value='14400' ");
|
|
|
(String(settings.viscabaud) == "14400") ? response_message += "selected" : response_message += "";
|
|
|
response_message += F(">14400</option>");
|
|
|
response_message += F("<option value='19200' ");
|
|
|
(String(settings.viscabaud) == "19200") ? response_message += "selected" : response_message += "";
|
|
|
response_message += F(">19200</option>");
|
|
|
response_message += F("<option value='57600' ");
|
|
|
(String(settings.viscabaud) == "57600") ? response_message += "selected" : response_message += "";
|
|
|
response_message += F(">57600</option>");
|
|
|
response_message += F("<option value='115200' ");
|
|
|
(String(settings.viscabaud) == "115200") ? response_message += "selected" : response_message += "";
|
|
|
response_message += F(">115200</option>");
|
|
|
response_message += F("</select>");
|
|
|
//response_message += F("<input id='viscabaud' class='form-control' type='number' size='64' min='2400' max='115200' name='viscabaud' value='") + String(settings.viscabaud) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='viscaport' class='col-sm-4 col-form-label'>VISCA UDP Port (52381)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='viscaport' class='form-control' type='number' size='64' min='1024' max='65554' name='viscaport' value='") + String(settings.viscaport) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row' style='border-radius:0px 0px 0px 10px;background-color:c6cdd2;'>");
|
|
|
response_message += F("<label for='save' class='col-sm-4 col-form-label'> </label>");
|
|
|
response_message += F("<div class='col-sm-8' style='border-radius:0px 0px 10px 0px;text-align:center;'>");
|
|
|
response_message += F("<input type='submit' value='SAVE' class='btn btn-primary'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("</td></tr></tbody></table>");
|
|
|
|
|
|
response_message += F("</div>");
|
|
|
|
|
|
response_message += F("<div class='col-md-6'>");
|
|
|
response_message += F("<h2 style='border-radius: 10px 10px 0px 0px;margin-bottom:0px;background-color:#99c2ff;padding:2px;'> vMix Tally Settings</h2>");
|
|
|
|
|
|
response_message += F("<table class='table' style='height:90%;border-radius: 0px 0px 10px 10px;'><tbody style='border-radius: 0px 0px 10px 10px;background-color:#d5dadd;'><tr style='border-radius: 0px 0px 10px 10px;'><td style='border-radius: 0px 0px 10px 10px;'>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='prg' class='col-sm-4 col-form-label'>Program Color (0-254)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<div class='form-group row' style='margin-bottom:0px;'>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> R </div><div>");
|
|
|
response_message += F("<input id='prgred' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='prgred' value='") + String(settings.prgred) + F("' onchange=\"document.getElementById('pprg').style.backgroundColor = 'rgb('+document.getElementById('prgred').value+','+document.getElementById('prggreen').value+','+document.getElementById('prgblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> G </div><div>");
|
|
|
response_message += F("<input id='prggreen' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='prggreen' value='") + String(settings.prggreen) + F("'onchange=\"document.getElementById('pprg').style.backgroundColor = 'rgb('+document.getElementById('prgred').value+','+document.getElementById('prggreen').value+','+document.getElementById('prgblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> B </div><div>");
|
|
|
response_message += F("<input id='prgblue' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='prgblue' value='") + String(settings.prgblue) + F("'onchange=\"document.getElementById('pprg').style.backgroundColor = 'rgb('+document.getElementById('prgred').value+','+document.getElementById('prggreen').value+','+document.getElementById('prgblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div> </div>");
|
|
|
response_message += F("<div id='pprg' style='display: -webkit-flex;display: flex;align-items: center;color:#ffffff;background-color:rgb(") + String(settings.prgred) + F(",") + String(settings.prggreen) + F(",") + String(settings.prgblue) + F(")'> Program </div>");
|
|
|
response_message += F("</div></div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='prv' class='col-sm-4 col-form-label'>Preview Color (0-254)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<div class='form-group row' style='margin-bottom:0px;'>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> R </div><div>");
|
|
|
response_message += F("<input id='prvred' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='prvred' value='") + String(settings.prvred) + F("' onchange=\"document.getElementById('pprv').style.backgroundColor = 'rgb('+document.getElementById('prvred').value+','+document.getElementById('prvgreen').value+','+document.getElementById('prvblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> G </div><div>");
|
|
|
response_message += F("<input id='prvgreen' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='prvgreen' value='") + String(settings.prvgreen) + F("' onchange=\"document.getElementById('pprv').style.backgroundColor = 'rgb('+document.getElementById('prvred').value+','+document.getElementById('prvgreen').value+','+document.getElementById('prvblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> B </div><div>");
|
|
|
response_message += F("<input id='prvblue' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='prvblue' value='") + String(settings.prvblue) + F("' onchange=\"document.getElementById('pprv').style.backgroundColor = 'rgb('+document.getElementById('prvred').value+','+document.getElementById('prvgreen').value+','+document.getElementById('prvblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div> </div>");
|
|
|
response_message += F("<div id='pprv' style='display: -webkit-flex;display: flex;align-items: center;color:#ffffff;background-color:rgb(") + String(settings.prvred) + F(",") + String(settings.prvgreen) + F(",") + String(settings.prvblue) + F(")'> Preview </div>");
|
|
|
response_message += F("</div></div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='off' class='col-sm-4 col-form-label'>Off Color (0-254)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<div class='form-group row' style='margin-bottom:0px;'>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> R </div><div>");
|
|
|
response_message += F("<input id='offred' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='offred' value='") + String(settings.offred) + F("' onchange=\"document.getElementById('poff').style.backgroundColor = 'rgb('+document.getElementById('offred').value+','+document.getElementById('offgreen').value+','+document.getElementById('offblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> G </div><div>");
|
|
|
response_message += F("<input id='offgreen' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='offgreen' value='") + String(settings.offgreen) + F("' onchange=\"document.getElementById('poff').style.backgroundColor = 'rgb('+document.getElementById('offred').value+','+document.getElementById('offgreen').value+','+document.getElementById('offblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div style='display: -webkit-flex;display: flex;align-items: center'> B </div><div>");
|
|
|
response_message += F("<input id='offblue' class='form-control' type='number' size='21' min='0' max='254' style='width:5em;' name='offblue' value='") + String(settings.offblue) + F("' onchange=\"document.getElementById('poff').style.backgroundColor = 'rgb('+document.getElementById('offred').value+','+document.getElementById('offgreen').value+','+document.getElementById('offblue').value+')'\">");
|
|
|
response_message += F("</div>");
|
|
|
response_message += F("<div> </div>");
|
|
|
response_message += F("<div id='poff' style='display: -webkit-flex;display: flex;align-items: center;color:#ffffff;background-color:rgb(") + String(settings.offred) + F(",") + String(settings.offgreen) + F(",") + String(settings.offblue) + F(")'> Off </div>");
|
|
|
response_message += F("</div></div></div>");
|
|
|
|
|
|
response_message += F("<hr>");
|
|
|
|
|
|
response_message += F("<div class='form-group row' style='background-color=#dcdcdc'>");
|
|
|
response_message += F("<label for='intensFull' class='col-sm-4 col-form-label'>Brightness Program/Preview (0-254)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='intensFull' class='form-control' type='number' style='width:5em;' size='8' min='0' max='254' name='intensFull' value='") + String(settings.intensFull) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label for='intensDim' class='col-sm-4 col-form-label'>Brightness Off (0-254)</label>");
|
|
|
response_message += F("<div class='col-sm-8'>");
|
|
|
response_message += F("<input id='intensDim' class='form-control' type='number' style='width:5em;' size='8' min='0' max='254' name='intensDim' value='") + String(settings.intensDim) + F("'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("<hr>");
|
|
|
|
|
|
response_message += F("<div class='form-group row'>");
|
|
|
response_message += F("<label class='col-sm-4 col-form-label'> </label>");
|
|
|
response_message += F("<div class='col-sm-8'> </div></div>");
|
|
|
|
|
|
response_message += F("<div class='form-group row' style='background-color:c6cdd2;'>");
|
|
|
response_message += F("<label for='save' class='col-sm-4 col-form-label'> </label>");
|
|
|
response_message += F("<div class='col-sm-8' style='text-align:center;'>");
|
|
|
response_message += F("<input type='submit' value='SAVE' class='btn btn-primary'>");
|
|
|
response_message += F("</div></div>");
|
|
|
|
|
|
response_message += F("</td></tr></tbody></table>");
|
|
|
|
|
|
response_message += F("</div></div></div>");
|
|
|
response_message += F("</form>");
|
|
|
|
|
|
response_message += F("<div data-role='content' class='row'>");
|
|
|
response_message += F(" </div>");
|
|
|
|
|
|
response_message += F("<div data-role='content' class='row'>");
|
|
|
|
|
|
response_message += F("<div class='col-md-6'>");
|
|
|
response_message += F("<h2 style='border-radius: 10px 10px 0px 0px;margin-bottom:0px;background-color:#99c2ff;padding:2px;'> Device Information</h2>");
|
|
|
response_message += F("<table class='table'><tbody style='border-radius: 0px 0px 10px 10px;background-color:#d5dadd;'>");
|
|
|
|
|
|
char ip[13];
|
|
|
sprintf(ip, "%d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
|
|
|
response_message += F("<tr><th>IP</th><td>") + String(ip) + F("</td><th>WiFi Signal Strength</th><td style='background-color:");
|
|
|
|
|
|
String color = "#ff0000";
|
|
|
|
|
|
if (WiFi.RSSI() > -80) {
|
|
|
color = "#ff0000";
|
|
|
}
|
|
|
if (WiFi.RSSI() > -67) {
|
|
|
color = "#ffff00";
|
|
|
}
|
|
|
if (WiFi.RSSI() > -50) {
|
|
|
color = "#00ff00";
|
|
|
}
|
|
|
|
|
|
response_message += color;
|
|
|
|
|
|
response_message += F(";'>") + String(WiFi.RSSI()) + F(" dBm</td></tr>");
|
|
|
|
|
|
response_message += F("<tr><th>MAC</th><td>") + String(WiFi.macAddress()) + F("</td>");
|
|
|
|
|
|
response_message += F("<th>WiFi AP</th>");
|
|
|
if (apEnabled)
|
|
|
{
|
|
|
sprintf(ip, "%d.%d.%d.%d", WiFi.softAPIP()[0], WiFi.softAPIP()[1], WiFi.softAPIP()[2], WiFi.softAPIP()[3]);
|
|
|
response_message += F("<td style='background-color:green;color:white;'>Active (") + String(ip) + F(")");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
response_message += F("<td style='background-color:yellow;'>Inactive");
|
|
|
}
|
|
|
response_message += F("</td>");
|
|
|
|
|
|
response_message += F("</tr>");
|
|
|
|
|
|
response_message += F("<tr><th>Device Name</th><td>") + String(deviceName) + F("</td>");
|
|
|
response_message += F("<th>vMix Status</th><td id='vmixstatus'");
|
|
|
if (vmixcon == 1)
|
|
|
{
|
|
|
response_message += F("style='background-color:green;color:white;'>Connected");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
response_message += F("style='background-color:red;color:white;'>Disconnected");
|
|
|
}
|
|
|
response_message += F("</td>");
|
|
|
|
|
|
response_message += F("</tr>");
|
|
|
|
|
|
response_message += F("<tr><th style='border-radius: 0px 0px 0px 10px;'> </th><td> </td>");
|
|
|
response_message += F("<th>VISCA IP2SERIAL Status</th><td id='viscastatus'");
|
|
|
if (udpstate == 1)
|
|
|
{
|
|
|
response_message += F("style='border-radius: 0px 0px 10px 0px;background-color:green;color:white;'>Running");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
response_message += F("style='border-radius: 0px 0px 10px 0px;background-color:red;color:white;'>Not Running");
|
|
|
}
|
|
|
response_message += F("</td>");
|
|
|
|
|
|
response_message += F("</tr>");
|
|
|
|
|
|
response_message += F("</tbody></table>");
|
|
|
response_message += F("</div>");
|
|
|
|
|
|
|
|
|
|
|
|
response_message += F("<div class='col-md-6'>");
|
|
|
response_message += F("<h2 style='border-radius: 10px 10px 0px 0px;margin-bottom:0px;background-color:#99c2ff;padding:2px;'> vMix Tally</h2>");
|
|
|
|
|
|
response_message += F("<div id='tally' style='height:90%;'></div>");
|
|
|
response_message += F("<script>document.getElementById('tally').innerHTML=\"<object type='text/html' data='/tally' style='height:100%;width:100%;'></object>\";</script>");
|
|
|
|
|
|
response_message += F("</div>");
|
|
|
|
|
|
|
|
|
|
|
|
response_message += F("</div>");
|
|
|
|
|
|
response_message += F("<h4 style='border-radius: 10px 10px 10px 10px;background-color:#c8c8c8;text-align:center;margin-bottom:0px;'>vTally v") + String(vers) + F(" © 2022 by <a href=https://www.vid-pro.de target=_new>VID-PRO</a></h4>");
|
|
|
|
|
|
response_message += F("</body>");
|
|
|
response_message += F("</html>");
|
|
|
|
|
|
httpServer.sendHeader("Connection", "close");
|
|
|
httpServer.send(200, "text/html", String(response_message));
|
|
|
|
|
|
//Serial.print(F("| FreeHeap: "));
|
|
|
//Serial.println(ESP.getFreeHeap(),DEC);
|
|
|
}
|
|
|
|
|
|
// Settings POST handler
|
|
|
void handleSave()
|
|
|
{
|
|
|
bool doRestart = false;
|
|
|
|
|
|
httpServer.sendHeader("Location", String("/"), true);
|
|
|
httpServer.send(302, "text/plain", "Redirected to: /");
|
|
|
|
|
|
if (httpServer.hasArg("ssid"))
|
|
|
{
|
|
|
if (httpServer.arg("ssid").length() <= SsidMaxLength)
|
|
|
{
|
|
|
httpServer.arg("ssid").toCharArray(settings.ssid, SsidMaxLength);
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("ssidpass"))
|
|
|
{
|
|
|
if (httpServer.arg("ssidpass").length() <= PassMaxLength)
|
|
|
{
|
|
|
httpServer.arg("ssidpass").toCharArray(settings.pass, PassMaxLength);
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("hostname"))
|
|
|
{
|
|
|
if (httpServer.arg("hostname").length() <= HostNameMaxLength)
|
|
|
{
|
|
|
httpServer.arg("hostname").toCharArray(settings.hostName, HostNameMaxLength);
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("inputnumber"))
|
|
|
{
|
|
|
if (httpServer.arg("inputnumber").toInt() > 0 and httpServer.arg("inputnumber").toInt() <= TallyNumberMaxValue)
|
|
|
{
|
|
|
settings.tallyNumber = httpServer.arg("inputnumber").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("intensFull"))
|
|
|
{
|
|
|
if (httpServer.arg("intensFull").toInt() >= 0 and httpServer.arg("intensFull").toInt() < 255)
|
|
|
{
|
|
|
settings.intensFull = httpServer.arg("intensFull").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("intensDim"))
|
|
|
{
|
|
|
if (httpServer.arg("intensDim").toInt() >= 0 and httpServer.arg("intensDim").toInt() < 255)
|
|
|
{
|
|
|
settings.intensDim = httpServer.arg("intensDim").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("prgred"))
|
|
|
{
|
|
|
if (httpServer.arg("prgred").toInt() >= 0 and httpServer.arg("prgred").toInt() < 255)
|
|
|
{
|
|
|
settings.prgred = httpServer.arg("prgred").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
if (httpServer.hasArg("prggreen"))
|
|
|
{
|
|
|
if (httpServer.arg("prggreen").toInt() >= 0 and httpServer.arg("prggreen").toInt() < 255)
|
|
|
{
|
|
|
settings.prggreen = httpServer.arg("prggreen").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
if (httpServer.hasArg("prgblue"))
|
|
|
{
|
|
|
if (httpServer.arg("prgblue").toInt() >= 0 and httpServer.arg("prgblue").toInt() < 255)
|
|
|
{
|
|
|
settings.prgblue = httpServer.arg("prgblue").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("prvred"))
|
|
|
{
|
|
|
if (httpServer.arg("prvred").toInt() >= 0 and httpServer.arg("prvred").toInt() < 255)
|
|
|
{
|
|
|
settings.prvred = httpServer.arg("prvred").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
if (httpServer.hasArg("prvgreen"))
|
|
|
{
|
|
|
if (httpServer.arg("prvgreen").toInt() >= 0 and httpServer.arg("prvgreen").toInt() < 255)
|
|
|
{
|
|
|
settings.prvgreen = httpServer.arg("prvgreen").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
if (httpServer.hasArg("prvblue"))
|
|
|
{
|
|
|
if (httpServer.arg("prvblue").toInt() >= 0 and httpServer.arg("prvblue").toInt() < 255)
|
|
|
{
|
|
|
settings.prvblue = httpServer.arg("prvblue").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("offred"))
|
|
|
{
|
|
|
if (httpServer.arg("offred").toInt() >= 0 and httpServer.arg("offred").toInt() < 255)
|
|
|
{
|
|
|
settings.offred = httpServer.arg("offred").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
if (httpServer.hasArg("offgreen"))
|
|
|
{
|
|
|
if (httpServer.arg("offgreen").toInt() >= 0 and httpServer.arg("offgreen").toInt() < 255)
|
|
|
{
|
|
|
settings.offgreen = httpServer.arg("offgreen").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
if (httpServer.hasArg("offblue"))
|
|
|
{
|
|
|
if (httpServer.arg("offblue").toInt() >= 0 and httpServer.arg("offblue").toInt() < 255)
|
|
|
{
|
|
|
settings.offblue = httpServer.arg("offblue").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("viscabaud"))
|
|
|
{
|
|
|
if (httpServer.arg("viscabaud").toInt() >= 2400 and httpServer.arg("viscabaud").toInt() <= 115200)
|
|
|
{
|
|
|
settings.viscabaud = httpServer.arg("viscabaud").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (httpServer.hasArg("viscaport"))
|
|
|
{
|
|
|
if (httpServer.arg("viscaport").toInt() >= 1024 and httpServer.arg("viscaport").toInt() <= 65554)
|
|
|
{
|
|
|
settings.viscaport = httpServer.arg("viscaport").toInt();
|
|
|
doRestart = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (doRestart == true)
|
|
|
{
|
|
|
restart();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Connect to WiFi
|
|
|
void connectToWifi()
|
|
|
{
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| Connecting to WiFi |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.print(F("| SSID : "));
|
|
|
Serial.println(settings.ssid);
|
|
|
Serial.print(F("| Passphrase : "));
|
|
|
Serial.println(settings.pass);
|
|
|
Serial.println(F("|"));
|
|
|
|
|
|
int timeout = 15;
|
|
|
|
|
|
WiFi.mode(WIFI_STA);
|
|
|
WiFi.hostname(deviceName);
|
|
|
WiFi.begin(settings.ssid, settings.pass);
|
|
|
|
|
|
Serial.print(F("| Waiting for connection ."));
|
|
|
while (WiFi.status() != WL_CONNECTED and timeout > 0)
|
|
|
{
|
|
|
delay(1000);
|
|
|
timeout--;
|
|
|
Serial.print(F("."));
|
|
|
}
|
|
|
|
|
|
Serial.println(F(""));
|
|
|
|
|
|
if (WiFi.status() == WL_CONNECTED)
|
|
|
{
|
|
|
Serial.println(F("| WiFi connected"));
|
|
|
Serial.println(F("|"));
|
|
|
Serial.print(F("| IP address : "));
|
|
|
Serial.println(WiFi.localIP());
|
|
|
Serial.print(F("| Device name : "));
|
|
|
Serial.println(deviceName);
|
|
|
Serial.println(F("+---------------------"));
|
|
|
Serial.println(F(""));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (WiFi.status() == WL_IDLE_STATUS)
|
|
|
Serial.println(F("| Idle"));
|
|
|
else if (WiFi.status() == WL_NO_SSID_AVAIL)
|
|
|
Serial.println(F("| No SSID Available"));
|
|
|
else if (WiFi.status() == WL_SCAN_COMPLETED)
|
|
|
Serial.println(F("| Scan Completed"));
|
|
|
else if (WiFi.status() == WL_CONNECT_FAILED)
|
|
|
Serial.println(F("| Connection Failed"));
|
|
|
else if (WiFi.status() == WL_CONNECTION_LOST)
|
|
|
Serial.println(F("| Connection Lost"));
|
|
|
else if (WiFi.status() == WL_DISCONNECTED)
|
|
|
Serial.println(F("| Disconnected"));
|
|
|
else
|
|
|
Serial.println(F("| Unknown Failure"));
|
|
|
|
|
|
Serial.println(F("+---------------------"));
|
|
|
apStart();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Connect to vMix instance
|
|
|
void connectTovMix()
|
|
|
{
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| Connecting to vMix |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.print(F("| Connecting to "));
|
|
|
Serial.println(settings.hostName);
|
|
|
|
|
|
if (client.connect(settings.hostName, port))
|
|
|
{
|
|
|
Serial.println(F("| Connected to vMix"));
|
|
|
|
|
|
Serial.println(F("+---------------------"));
|
|
|
Serial.println(F(""));
|
|
|
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| vMix Message Log |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
|
|
|
tallySetOff();
|
|
|
|
|
|
// Subscribe to the tally events
|
|
|
client.println(F("SUBSCRIBE TALLY"));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
vmixcon = 0;
|
|
|
currentState = '3';
|
|
|
Serial.println(F("| vMix Server not found!"));
|
|
|
Serial.println(F("+---------------------"));
|
|
|
Serial.println(F(""));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void restart()
|
|
|
{
|
|
|
saveSettings();
|
|
|
|
|
|
Serial.println(F(""));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| RESTART |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F(""));
|
|
|
|
|
|
ESP.restart();
|
|
|
//start();
|
|
|
}
|
|
|
|
|
|
void banner()
|
|
|
{
|
|
|
Serial.println(F(""));
|
|
|
Serial.println(F(""));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.print(F("| vTally v"));
|
|
|
Serial.print(String(vers));
|
|
|
Serial.println(F(" |"));
|
|
|
Serial.println(F("| (c)2022 by VID-PRO |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F(""));
|
|
|
}
|
|
|
|
|
|
void start()
|
|
|
{
|
|
|
tallySetConnecting();
|
|
|
|
|
|
loadSettings();
|
|
|
|
|
|
Serial.println(F(""));
|
|
|
sprintf(deviceName, "vTally_%d", settings.tallyNumber);
|
|
|
sprintf(apPass, "%s%s", deviceName, "_pwd");
|
|
|
|
|
|
connectToWifi();
|
|
|
|
|
|
if (WiFi.status() == WL_CONNECTED)
|
|
|
{
|
|
|
viscaSerial.begin(settings.viscabaud, SWSERIAL_8N1, rxpin, txpin, false, 200);
|
|
|
start_visca();
|
|
|
visca_power(true);
|
|
|
connectTovMix();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
double zoomcurve(int v)
|
|
|
{
|
|
|
return ZOOMMULT * pow(v, ZOOMEXP);
|
|
|
}
|
|
|
|
|
|
double ptzcurve(int v)
|
|
|
{
|
|
|
return PTZMULT * pow(v, PTZEXP);
|
|
|
}
|
|
|
|
|
|
void debug(char c)
|
|
|
{
|
|
|
Serial.print(c);
|
|
|
}
|
|
|
|
|
|
void debug(int n, int base)
|
|
|
{
|
|
|
Serial.print(n, base);
|
|
|
Serial.print(F(""));
|
|
|
}
|
|
|
|
|
|
void debug(uint8_t *buf, int len)
|
|
|
{
|
|
|
for (uint8_t i = 0; i < len; i++)
|
|
|
{
|
|
|
uint8_t elem = buf[i];
|
|
|
debug(elem, HEX);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void send_bytes(uint8_t *b, int len)
|
|
|
{
|
|
|
for (int i = 0; i < len; i++)
|
|
|
{
|
|
|
uint8_t elem = b[i];
|
|
|
viscaSerial.println(elem);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void send_visca(uint8_t *c, size_t len)
|
|
|
{
|
|
|
int i = 0;
|
|
|
uint8_t elem;
|
|
|
do
|
|
|
{
|
|
|
elem = c[i++];
|
|
|
viscaSerial.print(elem);
|
|
|
} while (i < len && elem != 0xff);
|
|
|
Serial.println(F("| VISCA IP->SER"));
|
|
|
}
|
|
|
|
|
|
void send_visca(const uint8_t *c)
|
|
|
{
|
|
|
int i = 0;
|
|
|
uint8_t elem;
|
|
|
do
|
|
|
{
|
|
|
elem = c[i++];
|
|
|
viscaSerial.print(elem);
|
|
|
} while (elem != 0xff);
|
|
|
Serial.println(F("| VISCA IP->SER"));
|
|
|
}
|
|
|
|
|
|
void visca_power(bool turnon)
|
|
|
{
|
|
|
if (turnon)
|
|
|
{
|
|
|
Serial.println(F("| VISCA Power On"));
|
|
|
send_visca(addr_set);
|
|
|
delay(500);
|
|
|
send_visca(pwr_on);
|
|
|
delay(2000);
|
|
|
send_visca(if_clear);
|
|
|
delay(500);
|
|
|
send_visca(irOff);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Serial.println(F("| VISCA Power Off"));
|
|
|
send_visca(if_clear);
|
|
|
delay(2000);
|
|
|
send_visca(pwr_off);
|
|
|
}
|
|
|
pwr_is_on = turnon;
|
|
|
}
|
|
|
|
|
|
void handle_visca(uint8_t *buf, size_t len)
|
|
|
{
|
|
|
uint8_t modified[18];
|
|
|
size_t lastelement = 0;
|
|
|
|
|
|
if ((buf[0] == 0x01 && buf[1] == 0x00 && buf[2] == 0x00)) { // && buf[3] == 0x09) || (buf[0] == 0x01 && buf[1] == 0x00 && buf[2] == 0x00 && buf[3] == 0x06)) {
|
|
|
int j = 0;
|
|
|
for (int i = 8; (i < len && i < 18); i++)
|
|
|
{
|
|
|
modified[j] = buf[i];
|
|
|
lastelement = j;
|
|
|
j++;
|
|
|
}
|
|
|
//modified[0] = 0x01;
|
|
|
} else {
|
|
|
for (int i = 0; (i < len && i < 18); i++)
|
|
|
{
|
|
|
modified[i] = buf[i];
|
|
|
lastelement = i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// is this a PTZ?
|
|
|
if (modified[1] == 0x01 && modified[2] == 0x06 && modified[3] == 0x01)
|
|
|
{
|
|
|
Serial.println(F("| PTZ CONTROL DETECTED"));
|
|
|
//modified[4] = (int)ptzcurve(modified[4]);
|
|
|
//modified[5] = (int)ptzcurve(modified[5]);
|
|
|
}
|
|
|
|
|
|
// is this ZOOM?
|
|
|
if (modified[1] == 0x01 && modified[2] == 0x04 && modified[3] == 0x07)
|
|
|
{
|
|
|
Serial.println(F("| ZOOM CONTROL DETECTED"));
|
|
|
//int zoomspeed = modified[4] & 0b00001111;
|
|
|
//zoomspeed = (int)zoomcurve(zoomspeed);
|
|
|
//int zoomval = (modified[4] & 0b11110000) + zoomspeed;
|
|
|
//modified[4] = zoomval;
|
|
|
}
|
|
|
|
|
|
if (modified[1] == 0x01 && modified[2] == 0x04 && modified[3] == 0x08)
|
|
|
{
|
|
|
Serial.println(F("| FOCUS CONTROL DETECTED"));
|
|
|
}
|
|
|
|
|
|
viscaSerial.write(modified, lastelement + 1);
|
|
|
//Serial.println(F("| VISCA IP: Send ACK"));
|
|
|
udp.writeTo(modified, lastelement + 1, lastclientip, lastclientport);
|
|
|
|
|
|
/*
|
|
|
if (data_state) {
|
|
|
digitalWrite(LED_DATA, data_state);
|
|
|
data_state = false;
|
|
|
} else {
|
|
|
digitalWrite(LED_DATA, data_state);
|
|
|
data_state = true;
|
|
|
}
|
|
|
*/
|
|
|
}
|
|
|
|
|
|
void start_visca()
|
|
|
{
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.println(F("| VISCA server |"));
|
|
|
Serial.println(F("+--------------------+"));
|
|
|
Serial.print(F("| starting on UDP port "));
|
|
|
Serial.println(settings.viscaport);
|
|
|
udp.close(); // will close only if needed
|
|
|
if (udp.listen(settings.viscaport))
|
|
|
{
|
|
|
udpstate = 1;
|
|
|
Serial.println(F("| Server is Running!"));
|
|
|
udp.onPacket([](AsyncUDPPacket packet) {
|
|
|
// debug(packet);
|
|
|
lastclientip = packet.remoteIP();
|
|
|
lastclientport = packet.remotePort();
|
|
|
|
|
|
Serial.print(F("| Type of UDP datagram: "));
|
|
|
Serial.print(packet.isBroadcast() ? "Broadcast" : packet.isMulticast() ? "Multicast"
|
|
|
: "Unicast");
|
|
|
Serial.print(F(", Sender: "));
|
|
|
Serial.print(lastclientip);
|
|
|
Serial.print(F(":"));
|
|
|
Serial.print(lastclientport);
|
|
|
Serial.print(F(", Receiver: "));
|
|
|
Serial.print(packet.localIP());
|
|
|
Serial.print(F(":"));
|
|
|
Serial.print(packet.localPort());
|
|
|
Serial.print(F(", Message length: "));
|
|
|
Serial.print(packet.length());
|
|
|
Serial.print(F(" Payload (hex):"));
|
|
|
debug(packet.data(), packet.length());
|
|
|
Serial.println(F(""));
|
|
|
|
|
|
handle_visca(packet.data(), packet.length());
|
|
|
});
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
udpstate = 0;
|
|
|
Serial.println(F("| Server failed to start"));
|
|
|
}
|
|
|
Serial.println(F("+---------------------"));
|
|
|
Serial.println(F(""));
|
|
|
}
|
|
|
|
|
|
void check_serial()
|
|
|
{
|
|
|
int available = viscaSerial.available();
|
|
|
while (available > 0)
|
|
|
{
|
|
|
Serial.println(F("| VISCA SER -> IP"));
|
|
|
int actual = viscaSerial.readBytesUntil(0xff, lastser_in, available); // does not include the terminator char
|
|
|
if (actual < 16)
|
|
|
{
|
|
|
lastser_in[actual] = 0xff;
|
|
|
actual++;
|
|
|
}
|
|
|
debug(lastser_in, actual);
|
|
|
if (lastclientport > 0)
|
|
|
udp.writeTo(lastser_in, actual, lastclientip, lastclientport);
|
|
|
|
|
|
available = viscaSerial.available();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void setup()
|
|
|
{
|
|
|
Serial.begin(9600);
|
|
|
EEPROM.begin(512);
|
|
|
SPIFFS.begin();
|
|
|
leds.begin();
|
|
|
leds.setBrightness(50);
|
|
|
leds.show();
|
|
|
|
|
|
//pinMode(LED_DATA, OUTPUT);
|
|
|
|
|
|
httpServer.on("/", HTTP_GET, rootPageHandler);
|
|
|
httpServer.on("/save", HTTP_POST, handleSave);
|
|
|
httpServer.on("/tally", HTTP_GET, tallyPageHandler);
|
|
|
httpServer.on("/zend", []() {
|
|
|
//httpServer.sendHeader("Connection", "close");
|
|
|
httpServer.sendHeader("Cache-Control", "no-cache");
|
|
|
httpServer.sendHeader("Access-Control-Allow-Origin", "*");
|
|
|
|
|
|
if (currentState != oldState) {
|
|
|
httpServer.send(200, "text/event-stream", "event: message\ndata: refresh" + String(vmixcon) + "\nretry: 500\n\n");
|
|
|
oldState = currentState;
|
|
|
} else {
|
|
|
httpServer.send(200, "text/event-stream", "event: message\ndata: norefresh\nretry: 500\n\n");
|
|
|
}
|
|
|
|
|
|
//Serial.print(F("| FreeHeap: "));
|
|
|
//Serial.println(ESP.getFreeHeap(),DEC);
|
|
|
});
|
|
|
httpServer.serveStatic("/", SPIFFS, "/", "max-age=315360000");
|
|
|
httpServer.begin();
|
|
|
|
|
|
banner();
|
|
|
|
|
|
start();
|
|
|
}
|
|
|
|
|
|
void loop()
|
|
|
{
|
|
|
httpServer.handleClient();
|
|
|
|
|
|
while (client.available())
|
|
|
{
|
|
|
String data = client.readStringUntil('\r\n');
|
|
|
handleData(data);
|
|
|
}
|
|
|
if (!client.connected() && !apEnabled && millis() > lastCheck + interval)
|
|
|
{
|
|
|
tallySetConnecting();
|
|
|
|
|
|
client.stop();
|
|
|
|
|
|
connectTovMix();
|
|
|
lastCheck = millis();
|
|
|
}
|
|
|
|
|
|
check_serial();
|
|
|
}
|