diff --git a/examples/softAP_UI_Test/data/css/style.css b/examples/softAP_UI_Test/data/css/style.css index c632e53..9c35725 100644 --- a/examples/softAP_UI_Test/data/css/style.css +++ b/examples/softAP_UI_Test/data/css/style.css @@ -295,6 +295,7 @@ /* Lists –––––––––––––––––––––––––––––––––––––––––––––––––– */ +/* ul { list-style: circle inside; } ol { @@ -310,7 +311,7 @@ font-size: 90%; } li { margin-bottom: 1rem; } - +*/ /* Code –––––––––––––––––––––––––––––––––––––––––––––––––– */ @@ -398,3 +399,85 @@ content: ""; display: table; clear: both; } + + /* ButtonPad + –––––––––––––––––––––––––––––––––––––––––––––––––– */ + + .control { + background-color: #ddd; + background-image: linear-gradient(hsla(0,0%,0%,.1), hsla(0,0%,100%,.1)); + border-radius: 50%; + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,.5), + 0 0 1px 1px hsla(0,0%,100%,.75), + 0 0 1px 2px hsla(0,0%,100%,.25), + 0 0 1px 3px hsla(0,0%,100%,.25), + 0 0 1px 4px hsla(0,0%,100%,.25), + 0 0 1px 6px hsla(0,0%,0%,.75); + height: 9em; + margin: 3em auto; + position: relative; + width: 9em; +} +.control ul { + height: 100%; + padding: 0; + transform: rotate(45deg); +} +.control li { + border-radius: 100% 0 0 0; + box-shadow: inset -1px -1px 1px hsla(0,0%,100%,.5), + 0 0 1px hsla(0,0%,0%,.75); + display: inline-block; + height: 50%; + overflow: hidden; + width: 50%; +} +.control ul li:nth-child(2) { + transform: rotate(90deg); +} +.control ul li:nth-child(3) { + transform: rotate(-90deg); +} +.control ul li:nth-child(4) { + transform: rotate(180deg); +} +.control ul a { + height: 200%; + position: relative; + transform: rotate(-45deg); + width: 200%; +} +.control a:hover, +.control a:focus { + background-color: hsla(0,0%,100%,.25); +} +.control a { + border-radius: 50%; + color: #333; + display: block; + font: bold 1em/3 sans-serif; + text-align: center; + text-decoration: none; + text-shadow: 0 1px 1px hsla(0,0%,100%,.4); + transition: .15s; +} +.control .confirm { + background-color: #ddd; + background-image: linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,100%,.25)); + box-shadow: inset 0 1px 1px 1px hsla(0,0%,100%,.5), + 0 0 1px 1px hsla(0,0%,100%,.25), + 0 0 1px 2px hsla(0,0%,100%,.25), + 0 0 1px 3px hsla(0,0%,100%,.25), + 0 0 1px 4px hsla(0,0%,100%,.25), + 0 0 1px 6px hsla(0,0%,0%,.85); + left: 50%; + line-height: 3; + margin: -1.5em; + position: absolute; + top: 50%; + width: 3em; +} +.control .confirm:hover, +.control .confirm:focus { + background-color: #eee; +} diff --git a/examples/softAP_UI_Test/data/index.htm b/examples/softAP_UI_Test/data/index.htm index 1539afa..5874070 100644 --- a/examples/softAP_UI_Test/data/index.htm +++ b/examples/softAP_UI_Test/data/index.htm @@ -5,17 +5,18 @@ Control - -

ControlOffline

+ +

Control
Offline


+ diff --git a/examples/softAP_UI_Test/data/js/controls.js b/examples/softAP_UI_Test/data/js/controls.js index a5500e0..8711475 100644 --- a/examples/softAP_UI_Test/data/js/controls.js +++ b/examples/softAP_UI_Test/data/js/controls.js @@ -1,9 +1,20 @@ -// TASKS: - -// Roadmap -// Build changeable Labels +// Roadmap: // Build a serial Console? +const UI_TITEL = 0; +const UI_LABEL = 1; +const UI_BUTTON = 2; +const UI_SWITCHER = 3; +const UI_PAD = 4; +const UI_CPAD = 5; +const UPDATE_LABEL = 6; + +const FOR = 0; +const BACK = 1; +const LEFT = 2; +const RIGHT = 3; +const CENTER = 4; + var websock; function start() { websock = new WebSocket('ws://' + window.location.hostname + '/ws'); @@ -27,29 +38,88 @@ function start() { websock.onmessage = function(evt) { console.log(evt); var data = JSON.parse(evt.data); - console.log(data); var e = document.body; - if (data.type === 'domButton') { - //initial rendering of the Buttons - $('#row').append("
"+data.label+"

"); - } - if (data.type === 'domLabel') { - //initial rendering of the Labels - $('#row').append("
"+data.l_title+"

"+data.label+"

"); - } - else if (data.type === 'value') { - // Display some kind of value - } - else { - console.log('unknown event'); + var center = ""; + switch(data.type){ + case UI_TITEL: + document.title = data.label; + $('#mainHeader').html(data.label); + break; + case UI_LABEL: + $('#row').append("
"+data.label+"
"); + break; + case UI_BUTTON: + $('#row').append("
"+data.label+"

"); + $('#'+data.id).on({ 'touchstart' : function(e){e.preventDefault(); buttonclick(data.id, true) } }); + $('#'+data.id).on({ 'touchend' : function(e){e.preventDefault(); buttonclick(data.id, false) } }); + break; + case UI_CPAD: + center = "OK"; + //NO BREAK + case UI_PAD: + $('#row').append( + "
"+data.label+"

"+ + ""+ + "
"); + + $('#f'+data.id).on({ 'touchstart' : function(e){e.preventDefault(); padclick(FOR, data.id, true) } }); + $('#f'+data.id).on({ 'touchend' : function(e){e.preventDefault(); padclick(FOR, data.id, false) } }); + $('#l'+data.id).on({ 'touchstart' : function(e){e.preventDefault(); padclick(LEFT, data.id, true) } }); + $('#l'+data.id).on({ 'touchend' : function(e){e.preventDefault(); padclick(LEFT, data.id, false) } }); + $('#r'+data.id).on({ 'touchstart' : function(e){e.preventDefault(); padclick(RIGHT, data.id, true) } }); + $('#r'+data.id).on({ 'touchend' : function(e){e.preventDefault(); padclick(RIGHT, data.id, false) } }); + $('#b'+data.id).on({ 'touchstart' : function(e){e.preventDefault(); padclick(BACK, data.id, true) } }); + $('#b'+data.id).on({ 'touchend' : function(e){e.preventDefault(); padclick(BACK,data.id, false) } }); + $('#c'+data.id).on({ 'touchstart' : function(e){e.preventDefault(); padclick(CENTER, data.id, true) } }); + $('#c'+data.id).on({ 'touchend' : function(e){e.preventDefault(); padclick(CENTER,data.id, false) } }); + + break; + case UPDATE_LABEL: + $('#'+data.id).html(data.label); + break; + default: + console.error('Unknown type or event'); + break; } }; } -function buttonclick(e) { - websock.send("bdown:"+e.id); - /* - if release - websock.send("bup:"+e.id); - */ + +function buttonclick(number, isdown) { + if(isdown)websock.send("bdown:"+number); + else websock.send("bup:"+number); +} + +function padclick(type, number, isdown) { + switch(type){ + case CENTER: + if(isdown)websock.send("pcdown:"+number); + else websock.send("pcup:"+number); + break; + case FOR: + if(isdown)websock.send("pfdown:"+number); + else websock.send("pfup:"+number); + break; + case BACK: + if(isdown)websock.send("pbdown:"+number); + else websock.send("pbup:"+number); + break; + case LEFT: + if(isdown)websock.send("pldown:"+number); + else websock.send("plup:"+number); + break; + case RIGHT: + if(isdown)websock.send("prdown:"+number); + else websock.send("prup:"+number); + break; + + } } diff --git a/examples/softAP_UI_Test/softAP_UI_Test.ino b/examples/softAP_UI_Test/softAP_UI_Test.ino index 7d7c152..a3f3f6b 100644 --- a/examples/softAP_UI_Test/softAP_UI_Test.ino +++ b/examples/softAP_UI_Test/softAP_UI_Test.ino @@ -1,36 +1,94 @@ #include #include -const char* ssid = "EasyUI"; +const char* ssid = "LARSUI"; const char* password = ""; +long oldTime = 0; + void setup(void) { Serial.begin(115200); WiFi.mode(WIFI_AP); - WiFi.softAP(ssid, password); - + WiFi.setHostname(ssid); + WiFi.softAP(ssid); + //WiFi.softAP(ssid, password); Serial.println(""); Serial.print("IP address: "); Serial.println(WiFi.softAPIP()); - EasyUI.title("LARSControl"); + EasyUI.label("Status: Maxim Stop"); + EasyUI.label("0"); + EasyUI.button("MaximDance Button", &callback2); + EasyUI.pad("center", true, &callback3); + EasyUI.pad("NoCenter", false, &callback3); + + EasyUI.begin("LARS Control"); - EasyUI.label("Label","123"); - EasyUI.label("Label2","456"); - EasyUI.label("Label3","789"); - EasyUI.button("LED", &callback1); - EasyUI.begin(); } void loop(void) { + if(millis()-oldTime> 5000){ + EasyUI.print(1, String(millis())); + oldTime = millis(); + } } -void callback1(void) { - Serial.println("CALLBACK UNO"); +void callback1(int id, int type) { + switch (type) { + case B_DOWN: + Serial.println("Button DOWN"); + break; + case B_UP: + Serial.println("Button UP"); + break; + } + } -void callback2(void) { - Serial.println("CALLBACK DOS"); + +void callback2(int id, int type) { + switch (type) { + case B_DOWN: + Serial.println("Maxim Start DAnce######################"); + EasyUI.print(0, "Status: Maxim Start"); + break; + case B_UP: + Serial.println("Maxim STOP DAnce######################"); + EasyUI.print(0, "Status: Maxim Start"); + break; + } } -void callback3(void) { - Serial.println("CALLBACK TRES"); +void callback3(int id, int value) { + switch (value) { + case P_LEFT_DOWN: + Serial.println("left down"); + break; + case P_LEFT_UP: + Serial.println("left up"); + break; + case P_RIGHT_DOWN: + Serial.println("right down"); + break; + case P_RIGHT_UP: + Serial.println("right up"); + break; + case P_FOR_DOWN: + Serial.println("for down"); + break; + case P_FOR_UP: + Serial.println("for up"); + break; + case P_BACK_DOWN: + Serial.println("back down"); + break; + case P_BACK_UP: + Serial.println("back up"); + break; + case P_CENTER_DOWN: + Serial.println("center down"); + break; + case P_CENTER_UP: + Serial.println("center up"); + break; + } + Serial.println(id); } diff --git a/src/EasyUI.cpp b/src/EasyUI.cpp index 92d05b1..56dbfd5 100644 --- a/src/EasyUI.cpp +++ b/src/EasyUI.cpp @@ -16,168 +16,124 @@ void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventT } break; case WS_EVT_DATA: - Serial.print("WS Event"); String msg = ""; for (size_t i = 0; i < len; i++) { msg += (char) data[i]; } - Serial.println(msg); - StaticJsonBuffer<200> jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(msg); - String type = root["type"]; - if(type == "t"){ - //Button Action - //TODO: get Button here - EasyUI.buttons[0]->callback(); - //EasyUI.tbuttonStatus(); - } - /* - else if(mode == "tb_click"){ - String status = root["status"]; - String index = root["index"]; - //EasyUI.tbClick(index, status); - } - */ - break; + if(msg.startsWith("bdown:")){ + EasyUI.controls[msg.substring(6).toInt()]->callback(msg.substring(6).toInt(), B_DOWN); + }else if(msg.startsWith("bup:")){ + EasyUI.controls[msg.substring(4).toInt()]->callback(msg.substring(4).toInt(), B_UP); + }else if(msg.startsWith("pfdown:")){ + EasyUI.controls[msg.substring(7).toInt()]->callback(msg.substring(7).toInt(), P_FOR_DOWN); + }else if(msg.startsWith("pfup:")){ + EasyUI.controls[msg.substring(5).toInt()]->callback(msg.substring(5).toInt(), P_FOR_UP); + }else if(msg.startsWith("pldown:")){ + EasyUI.controls[msg.substring(7).toInt()]->callback(msg.substring(7).toInt(), P_LEFT_DOWN); + }else if(msg.startsWith("plup:")){ + EasyUI.controls[msg.substring(5).toInt()]->callback(msg.substring(5).toInt(), P_LEFT_UP); + }else if(msg.startsWith("prdown:")){ + EasyUI.controls[msg.substring(7).toInt()]->callback(msg.substring(7).toInt(), P_RIGHT_DOWN); + }else if(msg.startsWith("prup:")){ + EasyUI.controls[msg.substring(5).toInt()]->callback(msg.substring(5).toInt(), P_RIGHT_UP); + }else if(msg.startsWith("pbdown:")){ + EasyUI.controls[msg.substring(7).toInt()]->callback(msg.substring(7).toInt(), P_BACK_DOWN); + }else if(msg.startsWith("pbup:")){ + EasyUI.controls[msg.substring(5).toInt()]->callback(msg.substring(5).toInt(), P_BACK_UP); + }else if(msg.startsWith("pcdown:")){ + EasyUI.controls[msg.substring(7).toInt()]->callback(msg.substring(7).toInt(), P_CENTER_DOWN); + }else if(msg.startsWith("pcup:")){ + EasyUI.controls[msg.substring(5).toInt()]->callback(msg.substring(5).toInt(), P_CENTER_UP); + } + break; } } -void EasyUIClass::title(const char* _title){ - ui_title = _title; +void EasyUIClass::label(const char* label){ + Control* newL = new Control(); + newL->type = UI_LABEL; + newL->label = label; + newL->oldValue = label; + newL->callback = NULL; + controls[cIndex] = newL; + cIndex++; } -// Create Labels -void EasyUIClass::label(const char* label_name,const char* label_val){ - label_value[l_index] = label_val; - label_title[l_index] = label_name; - l_index++; -} -/* -// Create Toggle Buttons -void EasyUIClass::toggleButton(uint8_t pin, const char* tbutton_label, int start_state, bool swap_state){ - pinMode(pin, OUTPUT); - digitalWrite(pin, start_state); - tbutton_swap[tb_index] = swap_state; - tbutton_pinout[tb_index] = pin; - tbuttontitle[tb_index] = tbutton_label; - tb_index++; -} -*/ -// Create a generic Button -void EasyUIClass::button(const char* bLabel, void(* callBack)()){ - -//TODO: Implement - Button* newB = new Button(); - - newB->label = bLabel; +void EasyUIClass::button(const char* label, void(* callBack)(int, int)){ + Control* newB = new Control(); + newB->type = UI_BUTTON; + newB->label = label; newB->callback = callBack; - buttons[bIndex] = newB; - bIndex++; + controls[cIndex] = newB; + cIndex++; } -/* -// Check Toggle Buttons States and Transfer to Webpage -void EasyUIClass::tbuttonStatus(){ - String json; - StaticJsonBuffer<200> jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - root["mode"] = "t_button_startup"; - root["index"] = tb_index; - for(int i=0; ibroadcastTXT(json); -} -*/ -/* -// Handle Toggle Button Click Response -void EasyUIClass::tbClick(String _index, String _status){ - String json; - StaticJsonBuffer<200> jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - String name = "tb"+_index; - root["mode"] = "t_button_click"; - root["index"] = _index; +void EasyUIClass::switcher(const char* label, int start_state, void(* callBack)(int, int)){ + Control* newS = new Control(); + newS->type = UI_SWITCHER; + newS->label = label; + newS->callback = callBack; + controls[cIndex] = newS; + cIndex++; + //TODO: implement switch state buffer + //tbutton_swap[tb_index] = swap_state; +} - if(_status == "on"){ - root[name] = "1"; +void EasyUIClass::pad(const char* label, bool center, void(* callBack)(int, int)){ + Control* newP = new Control(); + if(center)newP->type = UI_CPAD; + else newP->type = UI_PAD; + newP->label = label; + newP->callback = callBack; + controls[cIndex] = newP; + cIndex++; +} + +void EasyUIClass::print(int labelid, String value){ + if(labelidtype == UI_LABEL){ + controls[labelid]->oldValue = value; + String json; + StaticJsonBuffer<200> jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + root["type"] = UPDATE_LABEL; + root["label"] = value; + root["id"] = String(labelid); root.printTo(json); - webSocket->broadcastTXT(json); - if(tbutton_swap[_index.toInt()]){ - digitalWrite(tbutton_pinout[_index.toInt()], LOW); - }else{ - digitalWrite(tbutton_pinout[_index.toInt()], HIGH); - } - } - else if(_status == "off"){ - root[name] = "0"; - root.printTo(json); - webSocket->broadcastTXT(json); - if(tbutton_swap[_index.toInt()]){ - digitalWrite(tbutton_pinout[_index.toInt()], HIGH); + this->ws->textAll(json); }else{ - digitalWrite(tbutton_pinout[_index.toInt()], LOW); - } + Serial.println(String("Error: ")+ String(labelid) +String(" is no label")); } } -*/ + // Convert & Transfer Arduino elements to JSON elements void EasyUIClass::jsonDom(AsyncWebSocketClient * client){ - //SiteTitle - //TODO: emit here - // Labels - for(int i=0; i jsonBuffer1; - JsonObject& root1 = jsonBuffer1.createObject(); - root1["type"] = "domLabel"; - root1["l_title"] = String(label_title[i]); - root1["label"] = String(label_value[i]); - root1.printTo(json); + StaticJsonBuffer<200> jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + if(i == -1){ + root["type"] = UI_TITEL; + root["label"] = String(ui_title); + }else{ + root["type"] = controls[i]->type; + root["label"] = String(controls[i]->label); + root["id"] = String(i); + if(controls[i]->type == UI_LABEL)root["label"] = controls[i]->oldValue; + } + root.printTo(json); client->text(json); } - // Buttons - for(int i=0; i jsonBuffer2; - JsonObject& root2 = jsonBuffer2.createObject(); - root2["type"] = "domButton"; - root2["index"] = String(i); - root2["label"] = buttons[i]->label; - root2.printTo(json); - client->text(json); - } - } -void EasyUIClass::begin(){ +void EasyUIClass::begin(const char * _title){ + ui_title = _title; server = new AsyncWebServer(80); ws = new AsyncWebSocket("/ws"); - SPIFFS.begin(false); - + SPIFFS.begin(); ws->onEvent(onWsEvent); server->addHandler(ws); - server->serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm"); //Heap for general Servertest diff --git a/src/EasyUI.h b/src/EasyUI.h index 16b02dd..d902273 100644 --- a/src/EasyUI.h +++ b/src/EasyUI.h @@ -16,38 +16,61 @@ #include #include -typedef struct Button +typedef struct Control { + unsigned int type; const char *label; - void (*callback)(); -} Button; + void (*callback)(int, int); + String oldValue; +} Control; + +// Types +#define UI_TITEL 0 +#define UI_LABEL 1 +#define UI_BUTTON 2 +#define UI_SWITCHER 3 +#define UI_PAD 4 +#define UI_CPAD 5 +#define UPDATE_LABEL 6 + +// Values +#define B_DOWN -1 +#define B_UP 1 + +#define P_LEFT_DOWN -2 +#define P_LEFT_UP 2 +#define P_RIGHT_DOWN -3 +#define P_RIGHT_UP 3 +#define P_FOR_DOWN -4 +#define P_FOR_UP 4 +#define P_BACK_DOWN -5 +#define P_BACK_UP 5 +#define P_CENTER_DOWN -6 +#define P_CENTER_UP 6 + + class EasyUIClass{ public: - void begin(); // Begin HTTP Server + WebSocketsServer & Initalize All Elements - void title(const char* _title); // Define Webpage Header Name and title - //void toggleButton(uint8_t pin, const char* tbutton_label, int start_state = 0, bool swap_state = false); // Create Toggle Button - void button(const char* tbutton_label, void(* callBack)()); // Create Event Button - void label(const char* label_name, const char* label_val); // Create Label + void begin(const char* _title); // Setup servers and page + + // Creating Elements + void label(const char* label); // Create Label + void button(const char* label, void(* callBack)(int, int)); // Create Event Button + void switcher(const char* label, int start_state, void(* callBack)(int, int)); // Create Toggle Button + void pad(const char* label, bool centerButton, void(* callBack)(int, int)); // Create Pad Control + + // Update Elements + void print(int labelid, String value); + // Variables --- - const char* ui_title = "EasyUI"; // Store UI Title and Header Name - int bIndex; // How Many Buttons - int l_index; // How Many Labels - - bool tbutton_swap[10]; - Button* buttons[10]; - - const char* label_value[10]; // Stores Label Values - MAX 10 - const char* label_title[10]; // Stores Label Titles - MAX 10 - - String webpage; // Coverts Arduino elements to JSON elements - - void tbClick(String _index, String _status); - void tbuttonStatus(); + const char* ui_title = "ESPUI"; // Store UI Title and Header Name + int cIndex; // Control index + Control* controls[25]; void jsonDom(AsyncWebSocketClient * client); - private: +private: AsyncWebServer* server; AsyncWebSocket* ws; };