From 98a548fd860f9d991d0be79b8a91fd90737d8c4b Mon Sep 17 00:00:00 2001 From: Jens Noack Date: Sat, 3 Oct 2020 16:06:25 +0200 Subject: [PATCH] Version with web page interface --- vscode/OmobiLEDdisplay/.vscode/settings.json | 5 + vscode/OmobiLEDdisplay/include/omobi_html.h | 2 + vscode/OmobiLEDdisplay/platformio.ini | 2 + vscode/OmobiLEDdisplay/src/index.html | 323 ++++++++++++++++ vscode/OmobiLEDdisplay/src/main.cpp | 380 ++++++++++++++++--- 5 files changed, 656 insertions(+), 56 deletions(-) create mode 100644 vscode/OmobiLEDdisplay/.vscode/settings.json create mode 100644 vscode/OmobiLEDdisplay/include/omobi_html.h create mode 100644 vscode/OmobiLEDdisplay/src/index.html diff --git a/vscode/OmobiLEDdisplay/.vscode/settings.json b/vscode/OmobiLEDdisplay/.vscode/settings.json new file mode 100644 index 0000000..9e37c85 --- /dev/null +++ b/vscode/OmobiLEDdisplay/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "functional": "cpp" + } +} \ No newline at end of file diff --git a/vscode/OmobiLEDdisplay/include/omobi_html.h b/vscode/OmobiLEDdisplay/include/omobi_html.h new file mode 100644 index 0000000..862edf6 --- /dev/null +++ b/vscode/OmobiLEDdisplay/include/omobi_html.h @@ -0,0 +1,2 @@ + + diff --git a/vscode/OmobiLEDdisplay/platformio.ini b/vscode/OmobiLEDdisplay/platformio.ini index 71f558a..c32b618 100644 --- a/vscode/OmobiLEDdisplay/platformio.ini +++ b/vscode/OmobiLEDdisplay/platformio.ini @@ -15,3 +15,5 @@ framework = arduino lib_deps = Wire SPI + adafruit/Adafruit GFX Library@^1.10.1 + adafruit/Adafruit BusIO@1.4.1 diff --git a/vscode/OmobiLEDdisplay/src/index.html b/vscode/OmobiLEDdisplay/src/index.html new file mode 100644 index 0000000..075a48c --- /dev/null +++ b/vscode/OmobiLEDdisplay/src/index.html @@ -0,0 +1,323 @@ +const char index_html[] PROGMEM = R"rawliteral( + + + + + + + + + + +)rawliteral"; \ No newline at end of file diff --git a/vscode/OmobiLEDdisplay/src/main.cpp b/vscode/OmobiLEDdisplay/src/main.cpp index 92c1f5f..e7c2248 100644 --- a/vscode/OmobiLEDdisplay/src/main.cpp +++ b/vscode/OmobiLEDdisplay/src/main.cpp @@ -2,85 +2,353 @@ // 'Howdy' across three 10x8 NeoPixel grids that were created using // NeoPixel 60 LEDs per meter flex strip. +#include #include #include #include #ifndef PSTR #define PSTR // Make Arduino Due happy #endif +#include +#include +#include +#include +#include "omobi_html.h" #define PIN D8 -// MATRIX DECLARATION: -// Parameter 1 = width of EACH NEOPIXEL MATRIX (not total display) -// Parameter 2 = height of each matrix -// Parameter 3 = number of matrices arranged horizontally -// Parameter 4 = number of matrices arranged vertically -// Parameter 5 = pin number (most are valid) -// Parameter 6 = matrix layout flags, add together as needed: -// NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT: -// Position of the FIRST LED in the FIRST MATRIX; pick two, e.g. -// NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner. -// NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs WITHIN EACH MATRIX are -// arranged in horizontal rows or in vertical columns, respectively; -// pick one or the other. -// NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns WITHIN -// EACH MATRIX proceed in the same order, or alternate lines reverse -// direction; pick one. -// NEO_TILE_TOP, NEO_TILE_BOTTOM, NEO_TILE_LEFT, NEO_TILE_RIGHT: -// Position of the FIRST MATRIX (tile) in the OVERALL DISPLAY; pick -// two, e.g. NEO_TILE_TOP + NEO_TILE_LEFT for the top-left corner. -// NEO_TILE_ROWS, NEO_TILE_COLUMNS: the matrices in the OVERALL DISPLAY -// are arranged in horizontal rows or in vertical columns, respectively; -// pick one or the other. -// NEO_TILE_PROGRESSIVE, NEO_TILE_ZIGZAG: the ROWS/COLUMS OF MATRICES -// (tiles) in the OVERALL DISPLAY proceed in the same order for every -// line, or alternate lines reverse direction; pick one. When using -// zig-zag order, the orientation of the matrices in alternate rows -// will be rotated 180 degrees (this is normal -- simplifies wiring). -// See example below for these values in action. -// Parameter 7 = pixel type flags, add together as needed: -// NEO_RGB Pixels are wired for RGB bitstream (v1 pixels) -// NEO_GRB Pixels are wired for GRB bitstream (v2 pixels) -// NEO_KHZ400 400 KHz bitstream (e.g. FLORA v1 pixels) -// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip) +#include "index.html" + -// Example with three 10x8 matrices (created using NeoPixel flex strip -- -// these grids are not a ready-made product). In this application we'd -// like to arrange the three matrices side-by-side in a wide display. -// The first matrix (tile) will be at the left, and the first pixel within -// that matrix is at the top left. The matrices use zig-zag line ordering. -// There's only one row here, so it doesn't matter if we declare it in row -// or column order. The matrices use 800 KHz (v2) pixels that expect GRB -// color data. Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(8, 8, 6, 1, PIN, NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_ROWS + NEO_TILE_PROGRESSIVE + NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_TILE_PROGRESSIVE, NEO_GRB + NEO_KHZ800); const uint16_t colors[] = { - matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(0, 0, 255) }; + matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(0, 0, 255), matrix.Color(255, 255, 255) }; + +enum text_align_t {TEXTLEFT, TEXTCENTER, TEXTRIGHT}; +enum color_t {RED, GREEN, BLUE, WHITE}; + +const uint16_t text_nr_sets = 5; +const uint16_t MAX_TXT_LENGTH = 256; +typedef struct text_set_t { + const char text[MAX_TXT_LENGTH]; + uint16_t time_ms; + color_t color; + text_align_t align; + bool text_scroll; + uint16_t text_scroll_pass; + bool active; +} text_set_t; + +typedef struct sets_t { + text_set_t sets[text_nr_sets]; + char valid[3]; +} sets_t; + +const int nr_param_names = 7; +const String set_param_name[nr_param_names] = {"text_", "time_", "color_", "align_", "scroll_", "scroll_runs_", "active_"}; +enum set_param_index_t {PTEXT, PTIME, PCOLOR, PALIGN, PSCROLL, PSCROLL_RUNS, PACTIVE}; +const uint16_t DISP_STRUCT_SIZE = sizeof(sets_t); +sets_t text_sets = +{ + { +// TEXT , SHOWTIME, COLOR, ALIGNMENT, SCROLL, SCROLLNR, ACTIVE + {"itsblue",5000, BLUE, TEXTCENTER, false, 0, true}, + {"",0, RED, TEXTCENTER, false, 4, false}, + {"",0, RED, TEXTCENTER, false, 8, false}, + {"",0, RED, TEXTCENTER, false, 1, false}, + {"",0, RED, TEXTCENTER, false, 0, false}, + }, + "OK" +}; + +uint16_t text_curr_nr = 0; +uint32_t text_set_starttime = 0; + +int text_pos = matrix.width(); +unsigned int text_pass = 0; +unsigned int textpixel = 0; + +bool disp_show = false; + + +AsyncWebServer server(80); +const char* ssid = "OmobiLeds"; +const char* password = "OmobiLeds"; + +void notFound(AsyncWebServerRequest *request) { + request->send(404, "text/plain", "URL not found"); +} + +void disp_scroll_text(); +void disp_switch_text(); +void disp_start_set(); +void disp_init(); +void show_matrix(const char* text, int pos, uint16_t color); +String get_paramstring_from_struct(String name); +void set_param_to_struct(String name, String value); +String getset_param_at_struct(String name, String value, bool set); +void storeDisplaySet(); +bool loadDisplaySet(); void setup() { + +//ESP.eraseConfig(); +//ESP.reset(); + + Serial.begin(9600); matrix.begin(); matrix.setTextWrap(false); matrix.setBrightness(40); - matrix.setTextColor(colors[0]); + + loadDisplaySet(); + + Serial.printf("Los\n"); + + WiFi.softAP(ssid, password); + + IPAddress IP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(IP); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ + request->send(200, "text/html",index_html); + Serial.println("webpage sent"); + }); + + server.on("/loadcurrent", HTTP_GET, [] (AsyncWebServerRequest *request) { + String message = "nrsets=" + String(text_nr_sets); + for(uint16_t set = 0; set < text_nr_sets; set++) + { + for(uint16_t parm = 0; parm < nr_param_names; parm++ ) + { + message += "&" + get_paramstring_from_struct(set_param_name[parm]+String(set)); + } + } + Serial.printf("Got load currentvalues request.\n"); + request->send(200, "text/plain", message); + }); + + server.on("/setcurrent", HTTP_GET, [] (AsyncWebServerRequest *request) { + int paramsNr = request->params(); + Serial.printf("Got set currentvalues request.\n"); + for(int i=0;igetParam(i); + set_param_to_struct(String(p->name()), String(p->value())); + } + request->send(200, "text/plain", "OK"); + storeDisplaySet(); + disp_init(); + }); + + server.onNotFound(notFound); + + server.begin(); + + disp_init(); + } -int x = matrix.width(); -int pass = 0; -String scroll_text = "OMOBI-Ortsbus ... ab Juni 2020 EINFACH einsteigen!!!"; - void loop() { - matrix.fillScreen(0); - matrix.setCursor(x, 0); - matrix.print(scroll_text.c_str()); - if(--x < (int)(-6*scroll_text.length())) { - x = matrix.width(); - if(++pass >= 3) pass = 0; - matrix.setTextColor(colors[pass]); + if(true == disp_show) + { + disp_start_set(); + if(true == text_sets.sets[text_curr_nr].active) + { + if(text_sets.sets[text_curr_nr].text !='\0') + { + if(text_sets.sets[text_curr_nr].text_scroll) + { + disp_scroll_text(); + } + } + } + } +} + +void disp_init() +{ + text_curr_nr = 0; + text_set_starttime = 0; + text_pass = 0; + disp_show = true; +} + +void disp_scroll_text() +{ + matrix.fillScreen(0); + show_matrix(text_sets.sets[text_curr_nr].text, text_pos, text_sets.sets[text_curr_nr].color); + (int)text_pos--; + if(int(text_pos + textpixel) < 0) { + text_pos = matrix.width(); + text_pass++; + Serial.printf("Pass[%d] - set nr %d, Text: '%s' \n", text_pass, text_curr_nr, text_sets.sets[text_curr_nr].text); } - matrix.show(); delay(100); -} \ No newline at end of file +} + +void disp_start_set() +{ + if( (0 == text_set_starttime) || + (text_sets.sets[text_curr_nr].text =='\0') || text_sets.sets[text_curr_nr].active == false || + ((text_sets.sets[text_curr_nr].text_scroll == false) && (text_sets.sets[text_curr_nr].time_ms > 0) && ((millis() - text_set_starttime ) >= text_sets.sets[text_curr_nr].time_ms)) || + ((text_sets.sets[text_curr_nr].text_scroll == true) && (text_sets.sets[text_curr_nr].text_scroll_pass > 0) && ( text_pass >= text_sets.sets[text_curr_nr].text_scroll_pass)) || + (((text_sets.sets[text_curr_nr].text_scroll_pass == 0) || text_sets.sets[text_curr_nr].text_scroll == false) && (text_sets.sets[text_curr_nr].time_ms == 0) && ((millis() - text_set_starttime ) >= 10000)) + ) + { + //Serial.printf("[%lu] Meet start set condition. Curr set is %d. \n", millis(), text_curr_nr); + if(0 < text_set_starttime || text_sets.sets[text_curr_nr].text =='\0' || text_sets.sets[text_curr_nr].active == false ) text_curr_nr++; + if(text_curr_nr == text_nr_sets) text_curr_nr = 0; + text_pass = 0; + if(text_sets.sets[text_curr_nr].text !='\0' && text_sets.sets[text_curr_nr].active == true) + { + Serial.printf("[%lu] Set %d. Runtime %lu. Text:'%s'\n", millis(), text_curr_nr, text_sets.sets[text_curr_nr].time_ms, text_sets.sets[text_curr_nr].text); + matrix.fillScreen(0); + textpixel = 6*strlen(text_sets.sets[text_curr_nr].text); + switch(text_sets.sets[text_curr_nr].align) + { + case TEXTLEFT: + text_pos = 0; + break; + case TEXTRIGHT: + text_pos = matrix.width(); + break; + case TEXTCENTER: + text_pos = matrix.width() - textpixel; + text_pos = text_pos / 2; + break; + } + + show_matrix(text_sets.sets[text_curr_nr].text, text_pos, text_sets.sets[text_curr_nr].color); + text_set_starttime = millis(); + } + } +} + +void show_matrix(const char* text, int pos, uint16_t color) +{ + //Serial.printf("TEXT: %s (pos=%d, color=%d)\n", text, pos, color); + matrix.setTextColor(color); + matrix.setCursor(pos, 0); + matrix.print(text); + matrix.show(); +} + + +void storeDisplaySet() +{ + // write conf to EEPROM + EEPROM.begin(DISP_STRUCT_SIZE); + //for (size_t i = 0 ; i < DISP_STRUCT_SIZE ; i++) + //{ + // EEPROM.write(i, 0); + //} + strncpy( text_sets.valid , "OK", sizeof(text_sets.valid) ); + EEPROM.put(0, text_sets); + EEPROM.commit(); + EEPROM.end(); +} + +bool loadDisplaySet() +{ + bool rc = false; + sets_t buf = {}; + // read conf from EEPROM + EEPROM.begin(DISP_STRUCT_SIZE); + EEPROM.get(0, buf); + EEPROM.end(); + if (strcmp(buf.valid, "OK") == 0) + { + rc = true; + memcpy(&text_sets,&buf,sizeof(text_sets)); + } + else + { + memset(&text_sets,0,sizeof(text_sets)); + } + + return rc; + +} + +String get_paramstring_from_struct(String name) +{ + return(getset_param_at_struct(name, "", false)); +} + +void set_param_to_struct(String name, String value) +{ + getset_param_at_struct(name, value, true); +} + +String getset_param_at_struct(String name, String value, bool set) +{ + String name_value = ""; + int name_setnr_index = name.lastIndexOf("_"); + int name_setnr = -1; + int name_index = -1; + String name_name = "unknown"; + if(name_setnr_index > 0) + { + name_setnr = name.substring(name_setnr_index+1).toInt(); + name_name = name.substring(0, name_setnr_index+1); + + for(int pnr = 0; pnr < nr_param_names; pnr++) + { + if(name_name == set_param_name[pnr]) + { + name_index = pnr; + break; + } + } + //Serial.printf("Param: (name=%s,set=%d, index=%d) %s = %s \n", name_name.c_str(), name_setnr, name_index, name.c_str(), value.c_str()); + if(name_index != -1 && name_setnr != -1 && name_name != "unknown") + { + name_value += name_name + String(name_setnr) + "="; + switch(name_index) + { + case PCOLOR: + if(true == set) + text_sets.sets[name_setnr].color = (color_t)value.toInt(); + name_value += String(text_sets.sets[name_setnr].color); + break; + case PTEXT: + if(true == set) + snprintf((char*)text_sets.sets[name_setnr].text, MAX_TXT_LENGTH, value.c_str()); + name_value += String(text_sets.sets[name_setnr].text); + break; + case PTIME: + if(true == set) + text_sets.sets[name_setnr].time_ms = value.toInt()*1000; + name_value += String(text_sets.sets[name_setnr].time_ms /1000); + break; + case PSCROLL: + if(true == set) + text_sets.sets[name_setnr].text_scroll = (value=="true")?true:false; + name_value += String(text_sets.sets[name_setnr].text_scroll); + break; + case PACTIVE: + if(true == set) + text_sets.sets[name_setnr].active = (value=="true")?true:false; + name_value += String(text_sets.sets[name_setnr].active); + break; + case PALIGN: + if(true == set) + text_sets.sets[name_setnr].align = (text_align_t)value.toInt(); + name_value += String(text_sets.sets[name_setnr].align); + break; + case PSCROLL_RUNS: + if(true == set) + text_sets.sets[name_setnr].text_scroll_pass = value.toInt(); + name_value += String(text_sets.sets[name_setnr].text_scroll_pass); + break; + } + //Serial.printf("get/set %s\n", name_value.c_str()); + } + } + return(name_value); +} +