249 lines
8.0 KiB
C++
249 lines
8.0 KiB
C++
/*
|
|
WiFlash_esp32 - Concept & electronics: Phil Abeyta
|
|
- System design & firmware: Kevin Matz
|
|
|
|
Uses a GPIO to control a lighting console over OSC, whilst also
|
|
controlling an LED strobe light with DMX data recieved over sACN.
|
|
|
|
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
#include <Arduino.h>
|
|
#include <WiFi.h>
|
|
#include <ESPmDNS.h>
|
|
#include <SPIFFS.h>
|
|
#include <ArduinoOSC.h>
|
|
#include <NeoPixelBus.h>
|
|
#include <ESPAsyncWebServer.h>
|
|
#include "configure.h"
|
|
#include "status.h"
|
|
#include "sacn.h"
|
|
#include "strobe_esp32.h"
|
|
#include "dmx_universe.h"
|
|
|
|
|
|
//// device objects
|
|
Strobe *strobe;
|
|
NeoPixelBus<NeoGrbwFeature, Neo800KbpsMethod> *strip;
|
|
ESPAsyncE131 *e131 = new ESPAsyncE131();
|
|
AsyncWebServer *httpd = new AsyncWebServer(80);
|
|
|
|
|
|
//// Global button variables
|
|
bool pressed = false; // track button state
|
|
|
|
|
|
/*
|
|
Start the async web server
|
|
*/
|
|
void startHTTPD() {
|
|
httpd->on("/api/config", HTTP_GET, [](AsyncWebServerRequest * request) {
|
|
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/template/configuration.json", "application/json", false, config::getString);
|
|
response->addHeader("Access-Control-Allow-Origin", "*");
|
|
request->send(response);
|
|
});
|
|
|
|
httpd->on("/api/status", HTTP_GET, [](AsyncWebServerRequest * request) {
|
|
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/template/status.json", "application/json", false, status::getString);
|
|
response->addHeader("Access-Control-Allow-Origin", "*");
|
|
request->send(response);
|
|
});
|
|
|
|
httpd->on("/api/reboot", HTTP_POST, [](AsyncWebServerRequest * request) {
|
|
String url = "http://" + config::settings().hostname + ".local";
|
|
request->redirect(url.c_str());
|
|
httpd->end();
|
|
ESP.restart();
|
|
});
|
|
|
|
httpd->on("/api/set", HTTP_POST, [] (AsyncWebServerRequest * request) {
|
|
if (!request->hasParam("key", true) ||
|
|
!request->hasParam("value", true)) {
|
|
request->send(404, "text/plain", "Missing parameter.");
|
|
return;
|
|
}
|
|
String key = request->getParam("key", true)->value();
|
|
const String& val = request->getParam("value", true)->value();
|
|
key.toUpperCase();
|
|
if (val == config::getString(key)) {
|
|
// already at value
|
|
request->send(204);
|
|
} else if (config::set(key, val) > 0) {
|
|
// change accepted OK
|
|
request->send(205);
|
|
} else {
|
|
// change failed, return current value
|
|
String json = "{\"" + key + "\": \"" + config::getString(key) + "\"}";
|
|
request->send(403, "application/json", json);
|
|
}
|
|
});
|
|
|
|
httpd->serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.html");
|
|
|
|
httpd->onNotFound([](AsyncWebServerRequest * request) {
|
|
request->send(404, "text/plain", "Not found");
|
|
});
|
|
|
|
httpd->begin();
|
|
}
|
|
|
|
|
|
/*
|
|
change pixel strip colours on DMX change
|
|
*/
|
|
void recvPixelData(Universe *universe) {
|
|
for (int i = 0; i < config::settings().strip_led_count; i++) {
|
|
uint8_t r, g, b, w;
|
|
r = universe->data()->data[config::settings().strip_address + (i * 4) + 0];
|
|
g = universe->data()->data[config::settings().strip_address + (i * 4) + 1];
|
|
b = universe->data()->data[config::settings().strip_address + (i * 4) + 2];
|
|
w = universe->data()->data[config::settings().strip_address + (i * 4) + 3];
|
|
strip->SetPixelColor(i, RgbwColor(r, g, b, w));
|
|
}
|
|
strip->Show();
|
|
}
|
|
|
|
|
|
/*
|
|
Arduino powerup
|
|
*/
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
while (!Serial); // wait for serial attach
|
|
Serial.println("Serial started!");
|
|
|
|
Serial.println("Loading Prefferences from NVM.");
|
|
config::loadConfig();
|
|
|
|
//// start WiFi:
|
|
// set IPv4
|
|
Serial.println("Starting WiFi.");
|
|
WiFi.mode(config::settings().mode);
|
|
IPAddress ip_, gateway_, subnet_;
|
|
if (!config::settings().dhcp) {
|
|
ip_.fromString(config::settings().ip);
|
|
gateway_.fromString(config::settings().gateway);
|
|
subnet_.fromString(config::settings().subnet);
|
|
}
|
|
switch (config::settings().mode) {
|
|
case WIFI_AP: {
|
|
WiFi.softAPsetHostname(config::settings().hostname.c_str());
|
|
if (!config::settings().dhcp) {
|
|
WiFi.softAPConfig(ip_, gateway_, subnet_);
|
|
}
|
|
WiFi.softAP(config::settings().ssid.c_str(), config::settings().pwd.c_str());
|
|
}
|
|
break;
|
|
case WIFI_STA: {
|
|
WiFi.setHostname(config::settings().hostname.c_str());
|
|
if (!config::settings().dhcp) {
|
|
WiFi.config(ip_, gateway_, subnet_);
|
|
}
|
|
WiFi.begin(config::settings().ssid.c_str(), config::settings().pwd.c_str());
|
|
}
|
|
break;
|
|
}
|
|
Serial.print("Access the configuration web page at http://");
|
|
Serial.print(config::settings().hostname.c_str());
|
|
Serial.println(".local");
|
|
|
|
Serial.println("Disabling Bluetooth.");
|
|
btStop();
|
|
|
|
Serial.println("Mounting SPI Flash FS.");
|
|
SPIFFS.begin();
|
|
|
|
Serial.println("Starting HTTP interface.");
|
|
startHTTPD();
|
|
|
|
Serial.println("Starting mDNS responder.");
|
|
if (MDNS.begin(config::settings().hostname.c_str())) {
|
|
MDNS.addService("http", "tcp", 80);
|
|
}
|
|
|
|
//// start fixtures hardware:
|
|
// battery monitor
|
|
pinMode(status::battery_sense, INPUT);
|
|
|
|
// button
|
|
if (config::settings().button_enable) {
|
|
Serial.println("Initializing OSC button");
|
|
pinMode(config::settings().button_pin, INPUT_PULLUP);
|
|
}
|
|
|
|
// strobe
|
|
if (config::settings().strobe_enable) {
|
|
strobe = new Strobe(config::settings().strobe_address);
|
|
Serial.println("Initializing DMX Strobe");
|
|
if (!strobe->begin(config::settings().strobe_led_pin, 0)) {
|
|
Serial.println("Strobe failed to configure.");
|
|
}
|
|
if (e131->subscribe(config::settings().strobe_universe)) {
|
|
e131->universe(config::settings().strobe_universe)->onData(std::bind(&Strobe::recvData,
|
|
strobe, std::placeholders::_1));
|
|
}
|
|
}
|
|
|
|
// pixels
|
|
if (config::settings().strip_enable) {
|
|
Serial.println("Initializing Pixelmapped LEDs.");
|
|
|
|
strip = new NeoPixelBus<NeoGrbwFeature, Neo800KbpsMethod>(config::settings().strip_led_count, config::settings().strip_data_pin);
|
|
strip->Begin();
|
|
strip->Show();
|
|
if (e131->subscribe(config::settings().strip_universe)) {
|
|
e131->universe(config::settings().strip_universe)->onData(std::bind(&recvPixelData,
|
|
std::placeholders::_1));
|
|
}
|
|
}
|
|
|
|
Serial.println("Setup complete!");
|
|
}
|
|
|
|
|
|
/*
|
|
Arduino process loop
|
|
*/
|
|
void loop() {
|
|
if (config::settings().mode == WIFI_STA &&
|
|
WiFi.status() != WL_CONNECTED) {
|
|
Serial.println("Waiting for WiFi...");
|
|
delay(1000);
|
|
return;
|
|
}
|
|
|
|
// Be a remote trigger
|
|
//
|
|
bool val = !digitalRead(config::settings().button_pin);
|
|
if (val != pressed && config::settings().button_enable) {
|
|
pressed = val;
|
|
if (pressed) {
|
|
Serial.println("Pressed");
|
|
OscWiFi.send(config::settings().osc_host, config::settings().osc_port,
|
|
config::settings().osc_pressed_addr, config::settings().osc_pressed_value);
|
|
} else {
|
|
Serial.println("Released");
|
|
OscWiFi.send(config::settings().osc_host, config::settings().osc_port,
|
|
config::settings().osc_released_addr, config::settings().osc_released_value);
|
|
}
|
|
}
|
|
}
|