diff --git a/ESPixelStick.h b/ESPixelStick.h index 30d0d42bd..ff4e2eeda 100644 --- a/ESPixelStick.h +++ b/ESPixelStick.h @@ -41,6 +41,7 @@ const char BUILD_DATE[] = __DATE__; #endif #include "EffectEngine.h" +#include "OLEDEngine.h" #define HTTP_PORT 80 /* Default web server port */ #define MQTT_PORT 1883 /* Default MQTT port */ @@ -80,7 +81,8 @@ enum class DataSource : uint8_t { E131, MQTT, WEB, - IDLEWEB + IDLEWEB, + CP }; // Configuration structure @@ -89,6 +91,7 @@ typedef struct { String id; /* Device ID */ DevCap devmode; /* Used for reporting device mode, not stored */ DataSource ds; /* Used to track current data source, not stored */ + DataSource prevds; /* Previous ds in case of Pixel Count */ /* Network */ @@ -178,6 +181,7 @@ void dsDeviceConfig(JsonObject &json); void dsEffectConfig(JsonObject &json); void saveConfig(); void dsGammaConfig(JsonObject &json); +void dsPixelCount(JsonObject &json); void connectWifi(); void onWifiConnect(const WiFiEventStationModeGotIP &event); diff --git a/ESPixelStick.ino b/ESPixelStick.ino index f643e71ec..777365e53 100644 --- a/ESPixelStick.ino +++ b/ESPixelStick.ino @@ -34,6 +34,7 @@ const char passphrase[] = "ENTER_PASSPHRASE_HERE"; #include #include "ESPixelStick.h" #include "EFUpdate.h" +#include "OLEDDisplay.h" #include "wshandler.h" #include "gamma.h" #include "udpraw.h" @@ -109,6 +110,7 @@ EffectEngine effects; // Effects Engine Ticker sendTimer; UdpRaw udpraw; + // Output Drivers #if defined(ESPS_MODE_PIXEL) PixelDriver pixels; // Pixel object @@ -138,6 +140,13 @@ RF_PRE_INIT() { } void setup() { + // Enable SPIFFS + SPIFFS.begin(); +#if defined(ESPS_SUPPORT_OLED) + initDisplay(); + showDisplay("dee_boot","Starting up..."); +#endif //ESPS_SUPPORT_OLED + // Configure SDK params wifi_set_sleep_type(NONE_SLEEP_T); setupWebGpio(); @@ -153,9 +162,9 @@ void setup() { ets_install_putc1((void *) &_u0_putc); system_set_os_print(1); #endif - - // Enable SPIFFS - SPIFFS.begin(); +#if defined(ESPS_SUPPORT_OLED) + showDisplay("dee_boot","Loading configuration..."); +#endif //ESPS_SUPPORT_OLED // Set default data source to E131 config.ds = DataSource::E131; @@ -232,6 +241,9 @@ void setup() { // If we fail again, go SoftAP or reboot if (WiFi.status() != WL_CONNECTED) { if (config.ap_fallback) { +#if defined(ESPS_SUPPORT_OLED) + showDisplay("dee_boot","Starting SoftAP..."); +#endif //ESPS_SUPPORT_OLED LOG_PORT.println(F("*** FAILED TO ASSOCIATE WITH AP, GOING SOFTAP ***")); WiFi.mode(WIFI_AP); String ssid = "ESPixelBoard " + String(config.hostname); @@ -276,7 +288,6 @@ void setup() { #if defined(ESPS_ENABLE_BUTTONS) setupButtons(); #endif - } ///////////////////////////////////////////////////////// @@ -315,7 +326,13 @@ void connectWifi() { WiFi.begin(config.ssid.c_str(), config.passphrase.c_str()); if (config.dhcp) { LOG_PORT.print(F("Connecting with DHCP")); +#if defined(ESPS_SUPPORT_OLED) + showDisplay("dee_boot","Connecting to " + config.ssid + " with DHCP"); +#endif //ESPS_SUPPORT_OLED } else { +#if defined(ESPS_SUPPORT_OLED) + showDisplay("dee_boot","Connecting to " + config.ssid + " with Static IP"); +#endif //ESPS_SUPPORT_OLED // We don't use DNS, so just set it to our gateway WiFi.config(IPAddress(config.ip[0], config.ip[1], config.ip[2], config.ip[3]), IPAddress(config.gateway[0], config.gateway[1], config.gateway[2], config.gateway[3]), @@ -330,7 +347,7 @@ void onWifiConnect(__attribute__ ((unused)) const WiFiEventStationModeGotIP &eve LOG_PORT.println(""); LOG_PORT.print(F("Connected with IP: ")); LOG_PORT.println(WiFi.localIP()); - +// showDisplay("dee_boot","Connected to " + config.ssid + " with IP" + WiFi.localIP()); // Setup MQTT connection if enabled if (config.mqtt) connectToMqtt(); @@ -676,6 +693,9 @@ void initWeb() { // Raw config file Handler - but only on station // web.serveStatic("/config.json", SPIFFS, "/config.json").setFilter(ON_STA_FILTER); + // Raw config file Handler + web.serveStatic("/config.json", SPIFFS, "/config.json"); + web.serveStatic("/display.json", SPIFFS, "/display.json"); web.onNotFound([](AsyncWebServerRequest *request) { if (request->method() == HTTP_OPTIONS) { @@ -1215,6 +1235,43 @@ void dsGammaConfig(JsonObject &json) { } #endif +void dsPixelCount(JsonObject &json) { + if (json.containsKey("pixelcount")) { + JsonObject& pcjson = json["pixelcount"]; + uint16_t ptcount = pcjson["count"]; + int cmdtype = pcjson["commandtype"].as(); + int channelLength = (ptcount * 3); + switch (cmdtype) + { + case 0: {/* init pixel count by setting pixelc count to max */ + config.prevds = config.ds; + config.ds = DataSource::CP; + pixels.begin(config.pixel_type, config.pixel_color, 680); // set pixels to max + // break; + } + case 1: {/* render pixels per UI */ + + // effects.clearAll(); does not work for max length, manually clear all + for (int i = channelLength; i < 2040; i++) { + pixels.setValue(i, 0); + } + for (int i = 0; i < channelLength; i++) { + pixels.setValue(i, 255); + } + break; + } + case 2: {/* closed the pixel count UI hence reset pixel config. + /* code */ + for (int i = channelLength; i < 2040; i++) { + pixels.setValue(i, 0); + } + config.ds = config.prevds; + pixels.begin(config.pixel_type, config.pixel_color, config.channel_count / 3); // reset pixels count per current config + break; + } + } + } +} // Save configuration JSON file void saveConfig() { // Update Config @@ -1254,7 +1311,6 @@ void idleTimeout() { // ///////////////////////////////////////////////////////// void loop() { - /* check for rotary encoder and buttons */ #if defined(ESPS_ENABLE_BUTTONS) handleButtons(); @@ -1375,6 +1431,16 @@ void loop() { } MDNS.update(); + //Show Display +#if defined(ESPS_SUPPORT_OLED) + if (config.ds == DataSource::WEB || config.ds == DataSource::IDLEWEB){ + showDisplay("dee_idle",""); + } else if (config.ds == DataSource::MQTT) { + showDisplay("dee_mqtt",""); + } else if (config.ds == DataSource::E131) { + showDisplay("dee_e131",""); + } +#endif //ESPS_SUPPORT_OLED } void resolveHosts() { diff --git a/EffectEngine.h b/EffectEngine.h index a503e4f97..8754ebc11 100644 --- a/EffectEngine.h +++ b/EffectEngine.h @@ -41,7 +41,7 @@ struct dCHSV { */ typedef uint16_t (EffectEngine::*EffectFunc)(void); struct EffectDesc { - String name; + String name; EffectFunc func; const char* htmlid; bool hasColor; diff --git a/Mode.h b/Mode.h index 6c823abea..3848d9a6b 100644 --- a/Mode.h +++ b/Mode.h @@ -33,4 +33,7 @@ /* Enable support for udpraw packets on port 2801 */ #define ESPS_ENABLE_UDPRAW +/* Enable OLED Display */ +#define ESPS_SUPPORT_OLED + #endif // MODE_H_ diff --git a/OLEDEngine.cpp b/OLEDEngine.cpp new file mode 100644 index 000000000..cae23fed6 --- /dev/null +++ b/OLEDEngine.cpp @@ -0,0 +1,334 @@ +#include +#include "OLEDEngine.h" +#include "ESPixelStick.h" +#include +#include +#include // Only needed for Arduino 1.6.5 and earlier +#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"` +#include + +#if defined(ESPS_SUPPORT_OLED) + +#if defined(ESPS_ENABLE_UDPRAW) +#include "udpraw.h" +extern UdpRaw udpraw; +#endif + +extern config_t config; // Current configuration +extern EffectEngine effects; // EffectEngine for test modes +extern ESPAsyncE131 e131; // ESPAsyncE131 with X buffers +extern uint32_t *seqError; // Sequence error tracking for each universe +extern uint16_t uniLast; // Last Universe to listen for +extern unsigned long mqtt_last_seen; // millis() timestamp of last message +extern uint32_t mqtt_num_packets; // count of message rcvd + +dispconf_t dispconfig; +SSD1306Wire display(0x3c, 4, 5); + +void initDisplay () { + LOG_PORT.println("Init Display called:"); + display.init(); + display.flipScreenVertically(); + display.setFont(ArialMT_Plain_10); + + DynamicJsonBuffer jsonBuffer; + File file = SPIFFS.open(DISP_CONFIG_FILE, "r"); + if (file) { + // Parse CONFIG_FILE json + size_t size = file.size(); + char buffer[size]; + file.readBytes(buffer, size); + + JsonObject &json = jsonBuffer.parseObject(buffer); + + if (!json.success()) { + LOG_PORT.println(F("*** Display Configuration File Format Error ***")); + } else { + LOG_PORT.println("Found Display config"); + JsonArray &jevents = json.get("displayconfig"); + dispconfig.events = new event_t[jevents.size()]; + dispconfig.size = jevents.size(); + LOG_PORT.println("# of Events " + String(dispconfig.size)); + for(size_t i = 0; i < jevents.size(); i++) + { + String tmp = jevents[i]["eventid"]; + JsonObject &joelms = jevents[i]; + JsonArray &jaelms = joelms.get("elements"); + dispconfig.events[i].elements = new element_t[jaelms.size()]; + + dispconfig.events[i].eventid = tmp; + dispconfig.events[i].size = jaelms.size(); + LOG_PORT.println(dispconfig.events[i].eventid + " has # of elements " + String(dispconfig.events[i].size)); + for(size_t j = 0; j < jaelms.size(); j++) + { + JsonObject &joelm = jaelms.get(j); + element_t elm; + elm.enabled = joelm.get("enabled"); + elm.elementid = joelm.get("elementid"); + elm.px = joelm.get("px"); + elm.py = joelm.get("py"); + elm.format = joelm.get("format"); + if (elm.elementid == "de_gnstr") { + elm.text = joelm.get("text"); + } + dispconfig.events[i].elements[j] = elm; + } + } + } + } else { + LOG_PORT.println(F("*** Display Configuration File does not exist ***")); + } +} + +void showDisplay(const String event, const String data) { + display.clear(); + for(size_t i = 0; i < dispconfig.size; i++) + { + if (event == dispconfig.events[i].eventid){ + for(size_t j = 0; j < dispconfig.events[i].size; j++) + { + if (dispconfig.events[i].elements[j].enabled) { + const element_t elm = dispconfig.events[i].elements[j]; + showElementValue(elm, data); + } + } + display.display(); + break; + } + } +} +String getDisplayElements() { + return "\"displayelements\": [ " + "{\"name\": \"Label\", \"id\": \"de_gnstr\", \"type\": 0, \"formats\": [\"string\"], \"sample\": [\"AP\"]}, " + "{\"name\": \"CustomString\", \"id\": \"de_gnsrl\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"String\"]}, " + "{\"name\": \"BootLogo\", \"id\": \"de_gnbotico\", \"type\": 1, \"formats\": [\"icon\"], \"sample\": [\"^\"]}, " + "{\"name\": \"FW_Version\", \"id\": \"de_ver\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"String\"]}, " + "{\"name\": \"NetWorkMode\", \"id\": \"de_nsmode\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"AP\"]}, " + "{\"name\": \"SSID\", \"id\": \"de_nsssid\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"WifiSSID\"]}, " + "{\"name\": \"Hostname\", \"id\": \"de_nshost\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"esps-12a345\"]}, " + "{\"name\": \"Gateway\", \"id\": \"de_nsgatewy\", \"type\": 1, \"formats\": [\"IP\"], \"sample\": [\"192.168.4.1\"]}, " + "{\"name\": \"IP\", \"id\": \"de_nsip\", \"type\": 1, \"formats\": [\"IP\"], \"sample\": [\"192.168.4.101\"]}, " + "{\"name\": \"MAC\", \"id\": \"de_nsmac\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"12:34:56:78:A9:01\"]}, " + "{\"name\": \"RSSI\", \"id\": \"de_nsrssi\", \"type\": 1, \"formats\": [\"rssis\",\"percent\",\"icon\"], \"sample\": [\"-40dBm\", \"60%\", \"^\"]}, " + "{\"name\": \"FreeHeap\", \"id\": \"de_nsheap\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"24760\"]}, " + "{\"name\": \"UpTime\", \"id\": \"de_nsuptime\", \"type\": 1, \"formats\": [\"d hh:mm:ss\"], \"sample\": [\"13d, 22:03:42\"]}, " + "{\"name\": \"DataSource\", \"id\": \"de_nsds\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"E1.31\"]}, " + "{\"name\": \"EffectName\", \"id\": \"de_nseffect\", \"type\": 1, \"formats\": [\"string\"], \"sample\": [\"Rainbow\"]}, " + "{\"name\": \"E131_UniverseRange\", \"id\": \"de_e1univs\", \"type\": 1, \"formats\": [\"UFrom - UTo\"], \"sample\": [\"1-1\"]}, " + "{\"name\": \"E131_TotalPackets\", \"id\": \"de_e1totpkt\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"0\"]}, " + "{\"name\": \"E131_SequenceErrors\", \"id\": \"de_e1seqerr\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"0\"]}, " + "{\"name\": \"E131_PacketErrors\", \"id\": \"de_e1pkterr\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"0\"]}, " + "{\"name\": \"E131_SourceIP\", \"id\": \"de_e1srcip\", \"type\": 1, \"formats\": [\"IP\"], \"sample\": [\"192.168.4.100\"]}, " + "{\"name\": \"E131_LastSeen\", \"id\": \"de_e1lastseen\", \"type\": 1, \"formats\": [\"d hh:mm:ss\"], \"sample\": [\"13d, 22:03:42\"]}, " + "{\"name\": \"E131_#Channels\", \"id\": \"de_e1chcount\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"510\"]}, " + "{\"name\": \"MQTT_#Packets\", \"id\": \"de_mqtpkt\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"512\"]}, " + "{\"name\": \"MQTT_LastSeen\", \"id\": \"de_mqtls\", \"type\": 1, \"formats\": [\"d hh:mm:ss\"], \"sample\": [\"13d, 22:03:42\"]}, " + "{\"name\": \"UDP_#Packets\", \"id\": \"de_udppkt\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"512\"]}, " + "{\"name\": \"UDP_ShortPackets\", \"id\": \"de_udpspkt\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"512\"]}, " + "{\"name\": \"UDP_LongPackets\", \"id\": \"de_udplpkts\", \"type\": 1, \"formats\": [\"number\"], \"sample\": [\"512\"]}, " + "{\"name\": \"UDP_LastSeen\", \"id\": \"de_udpls\", \"type\": 1, \"formats\": [\"d hh:mm:ss\"], \"sample\": [\"13d, 22:03:42\"]}, " + "{\"name\": \"UDP_ClientIP\", \"id\": \"de_udpsrc\", \"type\": 1, \"formats\": [\"IP\"], \"sample\": [\"192.168.4.100\"]} ]"; + +} +String getDisplayConfig() { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + JsonArray& events = jsonBuffer.createArray(); + + for(size_t i = 0; i < dispconfig.size; i++) + { + JsonObject& event = events.createNestedObject(); + event["eventid"] = dispconfig.events[i].eventid; + JsonArray& elements = event.createNestedArray("elements"); + for(size_t j = 0; j < dispconfig.events[i].size; j++) + { + JsonObject& element = elements.createNestedObject(); + element["enabled"] = dispconfig.events[i].elements[j].enabled; + element["elementid"] = dispconfig.events[i].elements[j].elementid; + element["px"] = dispconfig.events[i].elements[j].px; + element["py"] = dispconfig.events[i].elements[j].py; + element["format"] = dispconfig.events[i].elements[j].format; + if (element["elementid"] == "de_gnstr"){ + element["text"] = dispconfig.events[i].elements[j].text; + } + } + event["elements"] = elements; + } + root["displayconfig"] = events; + String response; + root.printTo(response); + response = response.substring(1, response.length() - 1); + + return response; +} +String getDisplayEvents() { + return "\"displayevents\": [" + "{\"name\": \"While Booting\", \"id\": \"dee_boot\"}," + "{\"name\": \"On E1.31 data\", \"id\": \"dee_e131\"}," + "{\"name\": \"On MQTT data\", \"id\": \"dee_mqtt\"}," + "{\"name\": \"When Idle\", \"id\": \"dee_idle\"}" + "]"; +} +void saveDisplayConfig(JsonObject &data) { +//Update config var + for(size_t i = 0; i < dispconfig.size; i++) + { + if (data["eventid"] == dispconfig.events[i].eventid) { + JsonArray &jaes = data.get("elements"); + dispconfig.events[i].elements = new element_t[jaes.size()]; + dispconfig.events[i].size = jaes.size(); + for(size_t j = 0; j < jaes.size(); j++) + { + JsonObject &joelm = jaes.get(j); + element_t elm; + elm.enabled = joelm.get("enabled"); + elm.elementid = joelm.get("elementid"); + elm.px = joelm.get("px"); + elm.py = joelm.get("py"); + elm.format = joelm.get("format"); + if (elm.elementid == "de_gnstr") { + elm.text = joelm.get("text"); + } + dispconfig.events[i].elements[j] = elm; + } + break; + } + } + // Parse config var + String jsonString = getDisplayConfig(); + LOG_PORT.println("Deserialize successful"); + // Save data to file. + File file = SPIFFS.open(DISP_CONFIG_FILE, "w"); + if (!file) { + LOG_PORT.println(F("*** Error creating configuration file ***")); + return; + } else { + file.println("{" + jsonString + "}"); + LOG_PORT.println(F("* Configuration saved.")); + } +} +void showElementValue(const element_t elem, const String custData) { + String disptext = ""; + display.setTextAlignment(TEXT_ALIGN_LEFT); + if(elem.elementid == "de_gnsrl"){ + display.setFont(ArialMT_Plain_10); + display.drawStringMaxWidth(elem.px, elem.py, 128, custData); + } else if (elem.elementid == "de_gnbotico") { + display.drawXbm(elem.px, elem.py, ico_logo_w, ico_logo_h, ico_logo); + } else if (elem.elementid == "de_gnstr"){ + disptext = elem.text; + } else if (elem.elementid == "de_ver"){ + disptext = (String)VERSION; + } else if (elem.elementid == "de_nsssid"){ + String cssid = config.ssid; + if (WiFi.localIP()[0] == 0) { + cssid = WiFi.softAPSSID(); + } + display.setFont(ArialMT_Plain_10); + display.drawString(elem.px, elem.py, cssid); + } else if (elem.elementid == "de_nshost"){ + disptext = (String)WiFi.hostname(); + } else if (elem.elementid == "de_nsgatewy"){ + disptext = IPAddress(config.gateway[0], config.gateway[1], config.gateway[2], config.gateway[3]).toString(); + } else if (elem.elementid == "de_nsip"){ + if (WiFi.localIP()[0] == 0) { + disptext = WiFi.softAPIP().toString(); + } else { + disptext = WiFi.localIP().toString(); + } + } else if (elem.elementid == "de_nsmac"){ + disptext = WiFi.macAddress(); + } else if (elem.elementid == "de_nsrssi"){ + display.setTextAlignment(TEXT_ALIGN_RIGHT); + int32_t rssi = WiFi.RSSI(); + if (elem.format == 0){ //format rssis + disptext = ((String)rssi) + "dbm"; + } else if (elem.format == 1 ) { // format percent + if (rssi <= -100){ + disptext = "0%"; + } else if (rssi >= -50){ + disptext = "100%"; + } else { + int32_t quality = 2 * (rssi + 100); + disptext = ((String)quality) + "%"; + } + } else if (elem.format == 2 ){ //format icon + int32_t quality = 2 * (rssi + 100); + if (quality > 80) { + //Wifi_1 bitmap + display.drawXbm(elem.px, elem.py, ico_wifi_w, ico_wifi_h, ico_wifi1); + } else if (quality > 60) { + //Wifi_2 bitmap + display.drawXbm(elem.px, elem.py, ico_wifi_w, ico_wifi_h, ico_wifi2); + } else if (quality > 40) { + //Wifi_3 bitmap + display.drawXbm(elem.px, elem.py, ico_wifi_w, ico_wifi_h, ico_wifi3); + } else if (quality > 20) { + //Wifi_4 itmap + display.drawXbm(elem.px, elem.py, ico_wifi_w, ico_wifi_h, ico_wifi4); + } else { + //Do not render anything + } + } + } else if (elem.elementid == "de_nsheap"){ + disptext = (String)ESP.getFreeHeap(); + } else if (elem.elementid == "de_nsuptime"){ + disptext = (String)millis(); + } else if (elem.elementid == "de_nsds"){ + switch (config.ds) { + case DataSource::E131: + disptext = "E131"; + break; + case DataSource::MQTT: + disptext = "MQTT"; + break; + case DataSource::WEB: + disptext = "web"; + break; + case DataSource::IDLEWEB: + disptext = "Idle"; + break; + default: + disptext = "None"; + break; + } + } else if (elem.elementid == "de_nseffect"){ + disptext = (String)effects.getEffect(); + } else if (elem.elementid == "de_e1univs"){ + disptext = (String)config.universe + " - " + (String)uniLast; + } else if (elem.elementid == "de_e1totpkt"){ + disptext = (String)e131.stats.num_packets; + } else if (elem.elementid == "de_e1seqerr"){ + int32_t seqErrors = 0; + for (int i = 0; i < ((uniLast + 1) - config.universe); i++) + seqErrors =+ seqError[i]; + disptext = (String)seqErrors; + } else if (elem.elementid == "de_e1pkterr"){ + disptext = (String)e131.stats.packet_errors; + } else if (elem.elementid == "de_e1srcip"){ + disptext = e131.stats.last_clientIP.toString(); + } else if (elem.elementid == "de_e1lastseen"){ + disptext = e131.stats.last_seen ? (String) (millis() - e131.stats.last_seen) : "never"; + } else if (elem.elementid == "de_e1chcount"){ + disptext = config.channel_count; + } else if (elem.elementid == "de_mqtpkt"){ + disptext = (String)mqtt_num_packets; + } else if (elem.elementid == "de_mqtls"){ + disptext = mqtt_last_seen ? (String) (millis() - mqtt_last_seen) : "never"; + } else if (elem.elementid == "de_udppkt"){ + disptext = (String)udpraw.stats.num_packets; + } else if (elem.elementid == "de_udpspkt"){ + disptext = (String)udpraw.stats.short_packets; + } else if (elem.elementid == "de_udplpkts"){ + disptext = (String)udpraw.stats.long_packets; + } else if (elem.elementid == "de_udpls"){ + disptext = udpraw.stats.last_seen ? (String) (millis() - udpraw.stats.last_seen) : "never"; + } else if (elem.elementid == "de_udpsrc"){ + disptext = udpraw.stats.last_clientIP.toString(); + } + if (disptext != ""){ + display.setFont(ArialMT_Plain_16); + display.drawString(elem.px, elem.py, disptext); + } +} +#endif // ESPS_SUPPORT_OLED diff --git a/OLEDEngine.h b/OLEDEngine.h new file mode 100644 index 000000000..302dbb491 --- /dev/null +++ b/OLEDEngine.h @@ -0,0 +1,36 @@ +#ifndef OLEDENGINE_H_ +#define OLEDENGINE_H_ +#include +#include "images.h" +#define LOG_PORT Serial + +const char DISP_CONFIG_FILE[] = "/display.json"; + +typedef struct { + int16_t enabled; + String elementid; + int16_t px; + int16_t py; + int16_t format; + String text; +} element_t; + +typedef struct { + String eventid; + element_t* elements; + size_t size; +} event_t; + +typedef struct { + event_t* events; + size_t size; +} dispconf_t; + +void initDisplay(); +String getDisplayElements(); +String getDisplayConfig(); +String getDisplayEvents(); +void saveDisplayConfig(JsonObject &data); +void showDisplay(const String event, const String data); +void showElementValue(const element_t elem, const String custData); +#endif // OLEDENGINE_H_ diff --git a/data/config.json b/data/config.json index cfdd4a96e..c7ad128d4 100644 --- a/data/config.json +++ b/data/config.json @@ -1,7 +1,7 @@ { "network": { - "ssid": "", - "passphrase": "", + "ssid": "NETGEAR75", + "passphrase": "sillytulip502", "ip": [ 192, 168, diff --git a/data/config.json.h801 b/data/config.json.h801 deleted file mode 100644 index e16b8ed97..000000000 --- a/data/config.json.h801 +++ /dev/null @@ -1,149 +0,0 @@ -{ - "network": { - "ssid": "", - "passphrase": "", - "ip": [ - 192, - 168, - 1, - 10 - ], - "netmask": [ - 255, - 255, - 255, - 0 - ], - "gateway": [ - 192, - 168, - 1, - 1 - ], - "dhcp": true, - "ap_fallback": true - }, - - "device": { - "id": "ESPixelStick" - }, - - "e131": { - "universe": 1, - "universe_limit": 512, - "channel_start": 1, - "channel_count": 512, - "multicast": false - }, - - "pixel": { - "type": 0, - "color": 1, - "gamma": true - }, - - "serial": { - "type": 0, - "baudrate": 57600 - }, - - "pwm": { - "enabled": true, - "freq": 0, - "gamma": false, - "gpio": { - "0": { - "comment": "H801: J3 header", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "1": { - "comment": "H801: internal green LED", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "2": { - "comment": "H801: J1 header RX" - }, - "3": { - "comment": "H801: J1 header TX", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "4": { - "comment": "H801: White2 Output", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "5": { - "comment": "H801: internal red LED", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "6": { - "comment": "" - }, - "7": { - "comment": "" - }, - "8": { - "comment": "" - }, - "9": { - "comment": "" - }, - "10": { - "comment": "" - }, - "11": { - "comment": "" - }, - "12": { - "comment": "H801: Blue Output", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "13": { - "comment": "H801: Green Output", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "14": { - "comment": "H801: White1 Output", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "15": { - "comment": "H801: Red Output", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - }, - "16": { - "comment": "H801: Unconnected", - "channel": 0, - "enabled": false, - "invert": false, - "digital": false - } - } - } -} - diff --git a/data/config.json.orig b/data/config.json.orig deleted file mode 100644 index 654212866..000000000 --- a/data/config.json.orig +++ /dev/null @@ -1,49 +0,0 @@ -{ - "network": { - "ssid": "", - "passphrase": "", - "ip": [ - 192, - 168, - 1, - 10 - ], - "netmask": [ - 255, - 255, - 255, - 0 - ], - "gateway": [ - 192, - 168, - 1, - 1 - ], - "dhcp": true, - "ap_fallback": false - }, - - "device": { - "id": "ESPixelStick" - }, - - "e131": { - "universe": 1, - "universe_limit": 512, - "channel_start": 1, - "channel_count": 512, - "multicast": false - }, - - "pixel": { - "type": 0, - "color": 1, - "gamma": true - }, - - "serial": { - "type": 0, - "baudrate": 57600 - } -} diff --git a/data/display.json b/data/display.json new file mode 100644 index 000000000..af133c472 --- /dev/null +++ b/data/display.json @@ -0,0 +1,115 @@ +{ + "displayconfig": [ + { + "eventid": "dee_boot", + "elements": [ + { + "enabled": 1, + "elementid": "de_gnstr", + "px": 1, + "py": 1, + "format": 0, + "text": "Warming up..." + }, + { + "enabled": 1, + "elementid": "de_gnbotico", + "px": 80, + "py": 16, + "format": 0 + } + ] + }, + { + "eventid": "dee_e131", + "elements": [ + { + "enabled": 1, + "elementid": "de_nsssid", + "px": 1, + "py": 1, + "format": 0 + }, + { + "enabled": 1, + "elementid": "de_nsrssi", + "px": 112, + "py": 1, + "format": 2 + }, + { + "enabled": 1, + "elementid": "de_gnstr", + "px": 1, + "py": 16, + "format": 0, + "text": "IP:" + }, + { + "enabled": 1, + "elementid": "de_nsip", + "px": 20, + "py": 16, + "format": 0 + }, + { + "enabled": 1, + "elementid": "de_gnstr", + "px": 1, + "py": 32, + "format": 0, + "text": "Src:" + }, + { + "enabled": 1, + "elementid": "de_e1srcip", + "px": 26, + "py": 32, + "format": 0 + }, + { + "enabled": 1, + "elementid": "de_gnstr", + "px": 1, + "py": 48, + "format": 0, + "text": "U:" + }, + { + "enabled": 1, + "elementid": "de_e1univs", + "px": 16, + "py": 48, + "format": 0 + }, + { + "enabled": 1, + "elementid": "de_e1chcount", + "px": 64, + "py": 48, + "format": 0 + } + ] + }, + { + "eventid": "dee_idle", + "elements": [ + { + "enabled": 1, + "elementid": "de_e1lastseen", + "px": 1, + "py": 1, + "format": 1 + }, + { + "enabled": 1, + "elementid": "de_nseffect", + "px": 1, + "py": 1, + "format": 0 + } + ] + }, + { "eventid": "dee_mqtt", "elements": [] } + ] +} diff --git a/data/lu_disp.json b/data/lu_disp.json new file mode 100644 index 000000000..3f6430a2d --- /dev/null +++ b/data/lu_disp.json @@ -0,0 +1,124 @@ +{ + "displayelements": [ + { + "name": "NetS_Mode", + "id": "de_nsmode", + "formats": ["string"], + "sample": ["AP"] + }, + { + "name": "NetS_SSID", + "id": "de_nsssid", + "formats": ["string"], + "sample": ["WifiSSID"] + }, + { + "name": "NetS_Hostname", + "id": "de_nshost", + "formats": ["string"], + "sample": ["esps-12a345"] + }, + { + "name": "NetS_Gateway", + "id": "de_nsgatewy", + "formats": ["IP"], + "sample": ["192.168.4.1"] + }, + { + "name": "NetS_IP", + "id": "de_nsip", + "formats": ["IP"], + "sample": ["192.168.4.101"] + }, + { + "name": "NetS_MAC", + "id": "de_nsmac", + "formats": ["string"], + "sample": ["12:34:56:78:A9:01"] + }, + { + "name": "NetS_RSSI", + "id": "de_nsrssi", + "formats": ["rssis", "percent", "icon"], + "sample": ["-40dBm", "60%", "^"] + }, + { + "name": "NetS_FreeHeap", + "id": "de_nsheap", + "formats": ["number"], + "sample": ["24760"] + }, + { + "name": "NetS_UpTime", + "id": "de_nsuptime", + "formats": ["d hh:mm:ss"], + "sample": ["13d, 22:03:42"] + }, + { + "name": "NetS_DataSource", + "id": "de_nsds", + "formats": ["string"], + "sample": ["E1.31"] + }, + { + "name": "NetS_EffectName", + "id": "de_nseffect", + "formats": ["string"], + "sample": ["Rainbow"] + }, + { + "name": "E131_UniverseRange", + "id": "de_e1univs", + "formats": ["UFrom - UTo"], + "sample": ["1-1"] + }, + { + "name": "E131_TotalPackets", + "id": "de_e1totpkt", + "formats": ["number"], + "sample": ["0"] + }, + { + "name": "E131_SequenceErrors", + "id": "de_e1seqerr", + "formats": ["number"], + "sample": ["0"] + }, + { + "name": "E131_PacketErrors", + "id": "de_e1pkterr", + "formats": ["number"], + "sample": ["0"] + }, + { + "name": "E131_SourceIP", + "id": "de_e1srcip", + "formats": ["IP"], + "sample": ["192.168.4.100"] + }, + { + "name": "E131_LastSeen", + "id": "de_e1lastseen", + "formats": ["hours", "d hh:mm:ss"], + "sample": ["3hours", "13d, 22:03:42"] + }, + { + "name": "E131_#Channels", + "id": "de_e1chcount", + "formats": ["number"], + "sample": ["510"] + }, + { + "name": "E131_#Pixels", + "id": "de_e1pxcount", + "formats": ["number"], + "sample": ["170"] + }, + { + "name": "UDPS_", + "id": "de_e1srcip", + "formats": ["string"], + "sample": ["192.168.4.100"] + } + ] +} diff --git a/html/index.html b/html/index.html index a0cd2fa05..df83cb071 100644 --- a/html/index.html +++ b/html/index.html @@ -5,10 +5,10 @@ - + + + @@ -32,6 +32,9 @@
  • Device Setup
  • Effects
  • Diagnostics
  • +
  • Effects
  • + +
  • Live View