From fd4f9596422c19dd25d17f9eab554039cb152e9c Mon Sep 17 00:00:00 2001
From: Jan Grewe <jan@faked.org>
Date: Sat, 3 Jun 2023 23:46:40 +0200
Subject: [PATCH] MVP webinterface fix OTA display after error

---
 data/favicon.ico   | Bin 1150 -> 1406 bytes
 data/index.html    | 113 +++++++++++++++------------------------------
 data/main.js       |  70 ++++++++++++++++++++++++++++
 data/styles.css    |  24 ++++++++++
 src/gameoflife.cpp |   8 +++-
 src/gameoflife.h   |   3 +-
 src/network.cpp    |  15 ++++++
 7 files changed, 154 insertions(+), 79 deletions(-)
 create mode 100644 data/main.js
 create mode 100644 data/styles.css

diff --git a/data/favicon.ico b/data/favicon.ico
index 71b25fe6ee6012a4c26602977262d217af885520..e625327072d434ecf199703b86f1ac812a4030c2 100644
GIT binary patch
literal 1406
zcmZQzU}Ruq5D;JhgA7&%1~CQ(1`P%V29S^f14y0&Ea$)orZ9;A|Nmo%jS7s0z-S1J
zzz|?$WMpJO5Dbi<@&iF&^3l|z2N}XBFbm0Ou%Y<)Ad}IJLsk!#2b&5u3e1AagB^_|
N4`M>(F$|<k008O11i=6R

literal 1150
zcmZQzU}Ruq5D);-3Je)63=Con3=A3!3=9Gc3=9ek5OD?&U}0bo;)Y-lcQD|#wl=Uc
zoSmHotgWpLEG#Uv?d<G$f`WpWH8eDI6crUym6VjKrKF_d<>loSr%ai`;O6EA)&nDK
zY-}724Gj-!Yiqw%S66?jqN1`_Nl9sul$6wCQBl!<f`Wqo`S|$$^78Ut7ZVc;`S|f8
zql1G3Si8Nwy}Y5J;aM#$t^ca3s{a)f6#mP|$ov-<7ymCRD*7L!m!F^iKQ}k`e`aRp
z|E#R6kA;PWEjc+k!TQb3&BL{|wZAJXEC2WM^7`M=(edBN$mqYJq2YfqF)^?{kU2Ry
zIsZdLL&0`vYHBVF4i4sj@!|!8k&#ignwr`_MMcH`Q>IM$|M>Ca|CN=M|M%|Q``_H$
z{C_||z<*6m&Hvrq-T&|0x%2<jsZ;-V?AY;R(V|5=N=r+%EG#Tmf!u6iVe$Xu$&>%D
zT)Fap*REavZ{EE5-`Cgo|Lobb!R~2qZ~s4Q)~x>*E?oHk^5x6_7cXA?vwZpTYz+;K
z)zZ?^|I5nC{+~E;;{UpJ>;9iTd-ngHJ$wGArKSDv>+1u%dCi(N{|gEVz~*h=z8xh0
z<G_IfahjT%QPR@VA0s0p|Hs6{{7+6!{-2kZ_rI~R5v(30W@l#yc2h+~#sAHlH-qun
zvuAIuS+hpf$jFF8R#vu3NJ!{84-d~@P&jjNaQx@t;rTBoC->jj*!aJXj}JIJwrtq~
zviJX?Lx=t!J9caWKR-XSxw$!my}dn)f`WpMprBwVA0J;K2M5PfP+Wn+-PF_+tiQOp
z807ZP+qZ9Dzj^cKx=E8JNz9u!4;+UuLSJ8>p}xMJQCwU+R8ms%f~l$LPahwjf02=q
zKN1oWE+!`@CxnEAux;MF8Kwn;E-o%+`1<uLgS)%Cl)t~fZ+LikQfg|dM`2;1<c%9Q
w7^Y93j-h8D1^)kMU;yC*><kPI%nS?+Ak2u}MGcG$3?JAT7=G|W^nmmM07-a6+5i9m

diff --git a/data/index.html b/data/index.html
index f167d3a..53830e4 100644
--- a/data/index.html
+++ b/data/index.html
@@ -1,81 +1,42 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
-    <title>WebSocketTester</title>
-    <style type="text/css" media="screen">
-    body {
-      margin:0;
-      padding:0;
-      background-color: black;
-    }
+<!doctype html>
+<html lang="en">
 
-    #dbg, #input_div, #input_el {
-      font-family: monaco;
-      font-size: 12px;
-      line-height: 13px;
-      color: #AAA;
-    }
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>Matrix of Life</title>
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
+  <link href="styles.css" rel="stylesheet">
+</head>
 
-    #dbg, #input_div {
-      margin:0;
-      padding:0;
-      padding-left:4px;
-    }
+<body class="w-100 h-100 d-flex align-items-center">
+
+  <div class="container justify-content-center">
+
+    <div class="col-lg-6 offset-lg-3">
+
+      <div class="row mb-3">
+        <label for="rangeBrightness" class="col-form-label">Brightness</label>
+        <input type="range" class="form-range" id="rangeBrightness" data-name="brightness" min="8" max="255" steps="1">
+      </div>
+      <div class="row mb-3">
+        <label for="rangeSpeed" class="col-form-label">Speed</label>
+        <input type="range" class="form-range" id="rangeSpeed" data-name="interval" min="10" max="1000" steps="10">
+      </div>
+      <button type="button" class="btn btn-primary" id="btnGlider">Add Glider</button>
+
+      <pre id="dbg"></pre>
+      <div id="input_div">
+        $<input type="text" value="" id="input_el">
+      </div>
 
-    #input_el {
-      width:98%;
-      background-color: rgba(0,0,0,0);
-      border: 0px;
-    }
-    #input_el:focus {
-      outline: none;
-    }
-    </style>
-    <script type="text/javascript">
-    var ws = null;
-    function ge(s){ return document.getElementById(s);}
-    function ce(s){ return document.createElement(s);}
-    function stb(){ window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight); }
-    function addMessage(m){
-      var msg = ce("div");
-      msg.innerText = m;
-      ge("dbg").appendChild(msg);
-      stb();
-    }
-    function startSocket(){
-      ws = new WebSocket('ws://'+document.location.host+'/ws',['arduino']);
-      ws.onopen = function(e){
-        addMessage("Connected");
-      };
-      ws.onclose = function(e){
-        addMessage("Disconnected");
-      };
-      ws.onerror = function(e){
-        console.log("ws error", e);
-        addMessage("Error");
-      };
-      ws.onmessage = function(e){
-        var msg = "> "+e.data;
-        addMessage(msg);
-      };
-      ge("input_el").onkeydown = function(e){
-        stb();
-        if(e.keyCode == 13 && ge("input_el").value != ""){
-          ws.send(ge("input_el").value);
-          ge("input_el").value = "";
-        }
-      }
-    }
-    function onBodyLoad(){
-      startSocket();
-    }
-    </script>
-  </head>
-  <body id="body" onload="onBodyLoad()">
-    <pre id="dbg"></pre>
-    <div id="input_div">
-      $<input type="text" value="" id="input_el">
     </div>
-  </body>
+
+  </div>
+
+  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
+  <script src="https://code.jquery.com/jquery-3.7.0.slim.min.js" integrity="sha256-tG5mcZUtJsZvyKAxYLVXrmjKBVLd6VpVccqz/r4ypFE=" crossorigin="anonymous"></script>
+  <script src="main.js"></script>
+</body>
+
 </html>
diff --git a/data/main.js b/data/main.js
new file mode 100644
index 0000000..8540a25
--- /dev/null
+++ b/data/main.js
@@ -0,0 +1,70 @@
+var ws = null;
+function ge(s) { return document.getElementById(s); }
+function ce(s) { return document.createElement(s); }
+function addMessage(m) {
+    var msg = ce("div");
+    msg.innerText = m;
+    ge("dbg").appendChild(msg);
+}
+
+var config = {
+    brightness: 0,
+    interval: 0,
+};
+
+$(document).ready(function() {
+    startSocket();
+});
+
+$(document).on('input change', '#rangeBrightness, #rangeSpeed', function() {
+    config[$(this).data('name')] = $(this).val();
+    var payload = {
+        config: config
+    };
+    ws.send(JSON.stringify(payload));
+});
+
+$('#btnGlider').on('click', function() {
+    var payload = {
+        action: "addGlider"
+    };
+    ws.send(JSON.stringify(payload));
+})
+
+function startSocket() {
+    ws = new WebSocket('ws://' + document.location.host + '/ws', ['arduino']);
+    ws.onopen = function (e) {
+        addMessage("Connected");
+    };
+    ws.onclose = function (e) {
+        addMessage("Disconnected");
+    };
+    ws.onerror = function (e) {
+        console.log("ws error", e);
+        addMessage("Error");
+    };
+    ws.onmessage = function (e) {
+        var msg = "> " + e.data;
+        addMessage(msg);
+        var data = jQuery.parseJSON(e.data);
+        console.log(data);
+        if(data.config) {
+            loadConfig(data.config);
+        } else {
+            console.log("no config");
+        }
+    };
+    ge("input_el").onkeydown = function (e) {
+        if (e.keyCode == 13 && ge("input_el").value != "") {
+            ws.send(ge("input_el").value);
+            ge("input_el").value = "";
+        }
+    }
+}
+
+function loadConfig(data) {
+    config.brightness = data.brightness;
+    config.interval = data.interval;
+    $('#rangeBrightness').val(data.brightness);
+    $('#rangeSpeed').val(data.interval);
+}
diff --git a/data/styles.css b/data/styles.css
new file mode 100644
index 0000000..3bee046
--- /dev/null
+++ b/data/styles.css
@@ -0,0 +1,24 @@
+html {
+  width: 100%;
+  height: 100%;
+}
+
+#dbg, #input_div, #input_el {
+  font-family: monaco;
+}
+
+#dbg, #input_div {
+  margin:0;
+  padding:0;
+  padding-left:4px;
+}
+
+#input_el {
+  width:98%;
+  background-color: rgba(0,0,0,0);
+  border: 0px;
+}
+
+#input_el:focus {
+  outline: none;
+}
diff --git a/src/gameoflife.cpp b/src/gameoflife.cpp
index fde4397..d5d57e2 100644
--- a/src/gameoflife.cpp
+++ b/src/gameoflife.cpp
@@ -34,7 +34,7 @@ void setupGameOfLife()
   createRandomMatrix(g);
   for (int i = 0; i < 10; i++)
   {
-    addGlider(random(SCREEN_HEIGHT), random(SCREEN_WIDTH), g);
+    addGlider();
   }
   logLine("Starting Game " + String(gameEra));
 }
@@ -96,7 +96,7 @@ void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
   }
 }
 
-void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
+void createGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
 {
   // 010
   // 001
@@ -111,6 +111,10 @@ void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH])
   }
 }
 
+void addGlider() {
+  createGlider(random(SCREEN_HEIGHT), random(SCREEN_WIDTH), g);
+}
+
 void gameLoop()
 {
   if (runGame == false)
diff --git a/src/gameoflife.h b/src/gameoflife.h
index 2e0e14c..2af799f 100644
--- a/src/gameoflife.h
+++ b/src/gameoflife.h
@@ -16,7 +16,8 @@ extern int defaultBrightness;
 void setupGameOfLife();
 void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
 void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
-void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
+void createGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]);
+void addGlider();
 void gameLoop();
 void endGame();
 void resetGame();
diff --git a/src/network.cpp b/src/network.cpp
index fc1d8b1..a13222b 100644
--- a/src/network.cpp
+++ b/src/network.cpp
@@ -4,6 +4,7 @@
 #include "utils.h"
 #include "network.h"
 #include "display.h"
+#include "gameoflife.h"
 
 MDNSResponder mdns;
 AsyncWebServer server(80);
@@ -62,6 +63,7 @@ void setupOTA()
                       clearDisplay(); });
   ArduinoOTA.onEnd([]()
                    {
+                    otaProgress = 0;
                     runGame = true; 
                     logLine("Update End");
                     clearDisplay(); });
@@ -85,6 +87,7 @@ void setupOTA()
     else if(error == OTA_RECEIVE_ERROR) logLine("OTA Receive Failed");
     else if(error == OTA_END_ERROR) logLine("OTA End Failed");
     clearDisplay();
+    otaProgress = 0;
     runGame = true; });
   ArduinoOTA.setHostname(HOSTNAME);
   ArduinoOTA.begin();
@@ -244,6 +247,18 @@ void handleJson(uint8_t *data)
   {
     updateConfig(doc);
   }
+
+  if (doc.containsKey("action"))
+  {
+    if (doc["action"] == "addGlider")
+    {
+      addGlider();
+    }
+    else if (doc["action"] == "reboot")
+    {
+      ESP.restart();
+    }
+  }
 }
 
 void updateConfig(StaticJsonDocument<200U> doc)
-- 
GitLab