Slider0007 2 лет назад
Родитель
Сommit
d7a507ca05
39 измененных файлов с 3192 добавлено и 1875 удалено
  1. 32 33
      sd-card/html/backup.html
  2. 2 2
      sd-card/html/common.js
  3. 29 15
      sd-card/html/data.html
  4. 132 77
      sd-card/html/edit_alignment.html
  5. 345 168
      sd-card/html/edit_analog.html
  6. 0 136
      sd-card/html/edit_check.html
  7. 61 61
      sd-card/html/edit_config.html
  8. 378 217
      sd-card/html/edit_config_param.html
  9. 314 138
      sd-card/html/edit_digits.html
  10. 30 25
      sd-card/html/edit_explain_0.html
  11. 74 0
      sd-card/html/edit_explain_7.html
  12. 18 23
      sd-card/html/edit_explain_7_abort.html
  13. 227 111
      sd-card/html/edit_reference.html
  14. 16 17
      sd-card/html/explain_1.html
  15. 4 17
      sd-card/html/explain_2.html
  16. 4 19
      sd-card/html/explain_3.html
  17. 4 18
      sd-card/html/explain_4.html
  18. 6 16
      sd-card/html/explain_5.html
  19. 23 1
      sd-card/html/explain_6.html
  20. 1 0
      sd-card/html/explain_7.html
  21. 154 123
      sd-card/html/file_server.html
  22. 4 2
      sd-card/html/firework.css
  23. 1 1
      sd-card/html/firework.js
  24. 56 24
      sd-card/html/graph.html
  25. 146 67
      sd-card/html/index.html
  26. 476 177
      sd-card/html/info.html
  27. 19 10
      sd-card/html/log.html
  28. 14 16
      sd-card/html/ota_page.html
  29. 110 71
      sd-card/html/overview.html
  30. 129 77
      sd-card/html/prevalue_set.html
  31. 13 9
      sd-card/html/readconfigcommon.js
  32. 28 19
      sd-card/html/readconfigparam.js
  33. 7 8
      sd-card/html/reboot_page.html
  34. 304 110
      sd-card/html/setup.html
  35. 24 26
      sd-card/html/style.css
  36. 0 33
      sd-card/html/test.html
  37. 0 1
      sd-card/html/testcnn.html
  38. 1 1
      sd-card/html/timezones.html
  39. 6 6
      sd-card/html/wlan_config.html

+ 32 - 33
sd-card/html/backup.html

@@ -1,42 +1,41 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<title>Backup/Restore Configuration</title>
-<meta charset="utf-8">
-
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em;}
-h3 {font-size: 1.2em;} 
-p {font-size: 1em;}
-
-input[type=number] {
-	width: 138px;
-	padding: 10px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+    <title>Backup/Restore Configuration</title>
+    <meta charset="UTF-8" />
+
+    <style>
+        h1 {font-size: 2em;}
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
+        p {font-size: 1em;}
+
+        input[type=number] {
+            width: 138px;
+            padding: 10px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-.button {
-	padding: 10px 20px;
-    width: 211px;
-	font-size: 16px;
-}
-</style>
+        .button {
+            padding: 5px 10px;
+            width: 205px;
+            font-size: 16px;
+        }
+    </style>
 
 
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
-<h2>Backup Configuration</h2>
-<p>With the following action the <a href="/fileserver/config/" target="_self">config</a> folder on the SD-card gets zipped and provided as a download.</p>
-
-<button class="button" id="startBackup" type="button" onclick="startBackup()">Create Config backup</button>
-<p id=progress></p>
-<hr>
-<h2>Restore Configuration</h2>
-<p>Use the <a href="/fileserver/config/" target="_self">File Server</a> to upload individual files.</p>
+    <h2>Backup Configuration</h2>
+    <p>With the following action the <a href="/fileserver/config/" target="_self">config</a> folder on the SD-card gets zipped and provided as a download.</p>
+
+    <button class="button" id="startBackup" type="button" onclick="startBackup()">Create Backup</button>
+    <p id=progress></p>
+    <hr>
+    <h2>Restore Configuration</h2>
+    <p>Use the <a href="/fileserver/config/" target="_self">File Server</a> to upload individual files.</p>
 </body>
 </body>
 
 
 
 
@@ -105,7 +104,7 @@ function fetchFiles(urls, filesData, index, retry, zipFilename) {
 
 
 //    console.log(url + " started (" + index + "/" + urls.length + ")");
 //    console.log(url + " started (" + index + "/" + urls.length + ")");
     if (retry == 0) {
     if (retry == 0) {
-        setStatus("&nbsp;- " + getFilenameFromUrl(urls[index]) + " (" + index + "/" + urls.length + ")...");
+        setStatus("&nbsp;- " + getFilenameFromUrl(urls[index]) + " (" + (index+1) + "/" + urls.length + ")...");
     }
     }
     else {
     else {
         setStatus("<span style=\"color: gray\">&nbsp;&nbsp;&nbsp;Retrying (" + retry + ")...</span>");
         setStatus("<span style=\"color: gray\">&nbsp;&nbsp;&nbsp;Retrying (" + retry + ")...</span>");

+ 2 - 2
sd-card/html/common.js

@@ -145,8 +145,8 @@ function compareVersions() {
     console.log("FW Hash: " + fWGitHash + ", Web UI Hash: " + webUiHash);
     console.log("FW Hash: " + fWGitHash + ", Web UI Hash: " + webUiHash);
     
     
     if (fWGitHash != webUiHash) {
     if (fWGitHash != webUiHash) {
-        firework.launch("The Version of the Web Interface (" + webUiHash + 
-            ") does not match the Firmware Version (" + 
+        firework.launch("The version of the web interface (" + webUiHash + 
+            ") does not match the firmware version (" + 
             fWGitHash + ")! It is suggested to keep them on the same version!", 'warning', 30000);
             fWGitHash + ")! It is suggested to keep them on the same version!", 'warning', 30000);
     }
     }
 }
 }

+ 29 - 15
sd-card/html/data.html

@@ -1,17 +1,26 @@
-<html>
+<!DOCTYPE html>
+<html lang="en" xml:lang="en"> 
     <head>
     <head>
+        <title>Data Viewer</title>
+        <meta charset="UTF-8" />
+
         <style>
         <style>
+            h1 {font-size: 2em;}
+            h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+            h3 {font-size: 1.2em;}
+            p {font-size: 1em;}
+
             html,
             html,
             body {
             body {
                 height: 100%;
                 height: 100%;
-                margin: 2px;
+                margin: 1px;
                 font-family: Arial, Helvetica, sans-serif;
                 font-family: Arial, Helvetica, sans-serif;
             }
             }
 
 
             .box {
             .box {
                 display: flex;
                 display: flex;
                 flex-flow: column;
                 flex-flow: column;
-                height: 100%;
+                height: 99.75%;
             }
             }
 
 
             .box .row.header {
             .box .row.header {
@@ -30,26 +39,31 @@
                 font-family: 'Courier New', Courier, monospace;
                 font-family: 'Courier New', Courier, monospace;
                 font-size: small;
                 font-size: small;
             }
             }
+
+            .button {
+                padding: 5px 10px;
+                width: 160px;
+                font-size: 16px;
+            }
         </style>
         </style>
         <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
         <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     </head>
     </head>
     <body>
     <body>
-            <h3>Todays Data</h3>
-            <h4>Last part of Todays Data</h4>
+            <h2>Data Viewer</h2>
+            <h4>Today's latest data</h4>
         <div class="box">
         <div class="box">
             <div class="row header">
             <div class="row header">
-                <button onClick="reload();">Refresh</button>
-                <button onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
-                <button onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
-                <button onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
+                <button class="button" onClick="reload();">Refresh</button>
+                <button class="button" onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
+                <button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
+                <button class="button" onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
             </div>
             </div>
-            <div class="row content" id="data"><br><br><br><b>Loading Data file, please wait...</b></div>
+            <div class="row content" id="data"><br><br><br><b>Loading data file, please wait...</b></div>
             <div class="row footer">
             <div class="row footer">
-                <button onClick="reload();">Refresh</button>
-                <button onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
-                <button onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
-                <button onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
-                <p></p>
+                <button class="button" onClick="reload();">Refresh</button>
+                <button class="button" onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
+                <button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
+                <button class="button" onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
             </div>
             </div>
           </div>
           </div>
     </body>
     </body>

+ 132 - 77
sd-card/html/edit_alignment.html

@@ -1,101 +1,135 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<title>Alignment Marks</title>
-<meta charset="utf-8"/>
-	
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
-
-input[type=number] {
-	width: 100px;
-	margin-right: 10px;
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+    <title>Alignment marker</title>
+    <meta charset="UTF-8" />
+        
+    <style>
+        h1 {font-size: 2em;}
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
+        p {font-size: 1em;}
+
+        input[type=number] {
+            width: 60px;
+            margin-right: 10px;
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-input[type=text] {
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+        input[type=text] {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-select {
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-	margin-right: 10px;
-}
+        input:out-of-range {
+        background-color: rgba(255, 0, 0, 0.25);
+        border: 1px solid red;
+        }
 
 
-.button {
-	padding: 5px 10px;
-    width: 210px;
-	font-size: 16px;
-}
-</style>	
-<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
-<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
-<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
+        select {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+            margin-right: 10px;
+            min-width: 100px;
+            vertical-align: middle;
+        }
+
+        .button {
+            padding: 5px 10px;
+            width: 205px;
+            font-size: 16px;
+        }
+
+        th, td {
+            padding: 5px 5px 5px 0px;
+        }
+
+        table {
+            width: 660px;
+            padding: 5px;
+        }
+    </style>	
+    <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
+    <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
+    <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
 	
 	
-	<h2>Alignment Marks</h2>
-    <p>On this page you define two Reference Marks.
-        See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/</a> for explanations.</p>
-    <p>After saving the Reference Marks, you can define the <a href=edit_digits.html>digit</a> resp. <a href=edit_analog.html>analog</a> ROI's.<br>
-    Only after those steps a reboot is required.</p>
-
-	<table>
-	  <tr>
-		<td><canvas id="canvas" crossorigin></canvas></td>
-	  </tr>
-	</table>
+	<h2>Alignment Marker</h2>
+    <details id="desc_details" style="font-size:16px">
+        <summary><b>CLICK HERE</b> for usage description. More infos in documentation:   
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/ target=_blank>Alignment</a>
+        </summary>
+        <p>
+            Two alignment marker with clear contour and proper contrast are needed to identify unique "fix points" on the image. 
+            The marker area should be not be part of the variable area of ROI evaluation. Please find more information in documenation:
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/ target=_blank>Alignment</a>
+        </p>
+        <p>
+            Select an alignment marker area using drag and dop feature by mouse operation or by manually entering the coordinates and sizes in the fields below the image.
+            After you selected a suitable first alignment marker area, push the <b>"Update Marker"</b> button. Switch to second alignment marker with <b>"Marker"</b>
+            and repeat the procedure.
+        </p>
+        <p>
+            After definition of both alignment marker is completed don't forget to save with the <b>"Save New Marker"</b> button!<br>
+            <b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps 
+            (reference image, alignment, ROI configuration) are completed to activate new configuration.
+        </p>
+    </details>
+    <hr />
 
 
 	<table>
 	<table>
+    <colgroup>
+        <col span="1" style="width: 33.3%;">
+        <col span="1" style="width: 33.3%;">
+        <col span="1" style="width: 33.3%;">
+    </colgroup>
 	  <tr>
 	  <tr>
-		<td>Select Reference: 
+		<td>Marker: 
 			<select id="index" name="reference" onchange="ChangeSelection()">
 			<select id="index" name="reference" onchange="ChangeSelection()">
-			  <option value="0" selected>Reference 0</option>
-			  <option value="1" >Reference 1</option>
+			  <option value="0" selected>Marker 1</option>
+			  <option value="1" >Marker 2</option>
 			</select>
 			</select>
 		</td>
 		</td>
-		<td colspan="2">Storage Path/Name: <input type="text" name="name" id="name" onchange="namechanged()"></td>
+		<td colspan="2" style="padding-left: 22px; color: grey;">Filename: <output type="text" name="name" id="name" onchange="namechanged()"></td>
 	  </tr>
 	  </tr>
 	  <tr>
 	  <tr>
 		<td style="padding-top: 10px">x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()"></td>
 		<td style="padding-top: 10px">x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()"></td>
 		<td style="padding-top: 10px">dx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchanged()"></td>
 		<td style="padding-top: 10px">dx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchanged()"></td>
-		<td rowspan="2" style="padding-top: 10px"><input class="button" type="button" value="Update Reference Image" onclick="CutOutReference()"></td>	
+		<td rowspan="2" style="padding-top: 10px;"><input class="button" type="button" value="Update Marker" onclick="CutOutReference()"></td>	
 	  </tr>
 	  </tr>
 	  <tr>
 	  <tr>
 		<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()"></td>
 		<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()"></td>
 		<td>dy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()"></td>
 		<td>dy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()"></td>
 	  </tr>
 	  </tr>
 	  <tr>
 	  <tr>
-		<td style="padding-top: 10px">Original Image:</td>
-		<td style="padding-top: 10px">Reference Image:</td>
-		<td rowspan="2"><input class="button" type="button" id="enhancecontrast" value="Enhance Contrast" onclick="EnhanceContrast()"></td>	
+		<td style="vertical-align: bottom;">Selected Image Area:</td>
+		<td style="vertical-align: bottom;">Resulting Marker:</td>
+        <td><input class="button" type="button" id="enhancecontrast" value="Enhance Image Contrast" onclick="EnhanceContrast()"></td>	
 	  </tr> 
 	  </tr> 
 	  <tr>
 	  <tr>
-		<td><img id="img_ref_org" src = "/img_tmp/ref_zw_org.jpg"></td>
-		<td><img id="img_ref" src = "/img_tmp/ref_zw.jpg"></td>
-	  </tr>   
-	</table>
-
-	<table>
-	  <tr>
-		<td><input class="button" type="submit" name="saveroi" onclick="SaveToConfig()" value="Save">
-            <p>Proceed to update the <a href=edit_digits.html>digit</a> resp. <a href=edit_analog.html>analog</a> ROI's when you are done.</p></td>
+		<td style="height:70px; vertical-align: top;"><img id="img_ref_org" src = ""></td>    <!--/img_tmp/ref_zw_org.jpg-->
+		<td style="height:70px; vertical-align: top;"><img id="img_ref" src = ""></td>        <!--/img_tmp/ref_zw.jpg-->
 	  </tr> 
 	  </tr> 
-	</table>
+        <tr>
+            <td style="vertical-align:bottom;"><b>Reference Image:</b></td>
+            <td></td>
+            <td><input style="font-weight:bold;" class="button" type="submit" name="saveroi" id="savemarker" onclick="SaveToConfig()" value="Save New Marker">
+            </td>
+        </tr> 
+        <tr>
+            <td colspan="3"><canvas id="canvas" crossorigin></canvas></td>
+        </tr>
+    </table>
+
 
 
 <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
 <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
@@ -130,10 +164,15 @@ function ChangeSelection(){
 }
 }
 
 
 function SaveToConfig(){
 function SaveToConfig(){
-    WriteConfigININew();
-    UpdateConfigReference(domainname)
-    SaveConfigToServer(domainname);
-    firework.launch('Reference Marks got updated. The change will get applied after the next reboot!', 'success', 5000);
+    if (confirm("Are you sure you want to save the new alignment marker configuration?")) {
+        WriteConfigININew();
+        UpdateConfigReference(domainname)
+        SaveConfigToServer(domainname);
+        document.getElementById("savemarker").disabled = true;
+        document.getElementById("enhancecontrast").disabled = true;
+        
+        firework.launch('Alignment marker saved. They will get applied after next reboot', 'success', 5000);
+    }
 }
 }
 
 
 function EnhanceContrast(){
 function EnhanceContrast(){
@@ -146,6 +185,7 @@ function EnhanceContrast(){
     enhanceCon = true;
     enhanceCon = true;
     if (MakeContrastImageZW(refInfo[aktindex], enhanceCon, domainname)) {
     if (MakeContrastImageZW(refInfo[aktindex], enhanceCon, domainname)) {
         UpdateReference();
         UpdateReference();
+        document.getElementById("enhancecontrast").disabled = true;
     }
     }
 }
 }
 
 
@@ -174,7 +214,6 @@ function UpdateReference(){
     document.getElementById("refy").value = refInfo[aktindex]["y"];  
     document.getElementById("refy").value = refInfo[aktindex]["y"];  
     rect.startX = document.getElementById("refx").value;
     rect.startX = document.getElementById("refx").value;
     rect.startY = document.getElementById("refy").value; 
     rect.startY = document.getElementById("refy").value; 
-    document.getElementById("enhancecontrast").disabled = true;
     draw();      
     draw();      
 }
 }
 			
 			
@@ -215,14 +254,27 @@ function dataURLtoBlob(dataurl) {
             return { top: Math.round(top), left: Math.round(left) };
             return { top: Math.round(top), left: Math.round(left) };
         }
         }
    
    
+
+        /* hash #description open the details part of the page */
+        function openDescription() {
+        if(window.location.hash) {
+            var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
+            if(hash == 'description')
+                document.getElementById("desc_details").open = true;
+            }
+        }
+
     
     
-    
-        function init() { 
+        function init() {
+            openDescription();
             domainname = getDomainname();
             domainname = getDomainname();
             loadConfig(domainname); 
             loadConfig(domainname); 
             ParseConfig();
             ParseConfig();
             param = getConfigParameters();
             param = getConfigParameters();
 
 
+            document.getElementById("savemarker").disabled = true;
+            document.getElementById("enhancecontrast").disabled = true;
+
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mouseup', mouseUp, false);
             canvas.addEventListener('mouseup', mouseUp, false);
             canvas.addEventListener('mousemove', mouseMove, false);
             canvas.addEventListener('mousemove', mouseMove, false);
@@ -235,6 +287,8 @@ function dataURLtoBlob(dataurl) {
 
 
             drawImage();
             drawImage();
         }
         }
+
+
         function drawImage(){
         function drawImage(){
             var canvas = document.getElementById('canvas');
             var canvas = document.getElementById('canvas');
             var context = canvas.getContext('2d');
             var context = canvas.getContext('2d');
@@ -254,6 +308,7 @@ function dataURLtoBlob(dataurl) {
             if (MakeRefZW(refInfo[aktindex], domainname)) {
             if (MakeRefZW(refInfo[aktindex], domainname)) {
                 UpdateReference();
                 UpdateReference();
                 document.getElementById("enhancecontrast").disabled = false;
                 document.getElementById("enhancecontrast").disabled = false;
+                document.getElementById("savemarker").disabled = false;
             }
             }
         }
         }
 
 

+ 345 - 168
sd-card/html/edit_analog.html

@@ -1,142 +1,221 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<meta charset="utf-8"/>
-<title>Analog ROI's</title>
-
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
-
-input[type=number] {
-	width: 100px;
-	margin-right: 10px;
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+    <meta charset="UTF-8" />
+    <title>Analog ROI</title>
+
+    <style>
+        h1 {font-size: 2em;}
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
+        p {font-size: 1em;}
+
+        input[type=number] {
+            width: 60px;
+            margin-right: 10px;
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-input[type=text] {
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+        input[type=text] {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-select {
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-	margin-right: 10px;
-}
+        input:out-of-range {
+        background-color: rgba(255, 0, 0, 0.25);
+        border: 1px solid red;
+        }
 
 
-.button {
-	padding: 5px 10px;
-    width: 210px;
-	font-size: 16px;
-}
+        select {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+            margin-right: 10px;
+            min-width: 100px;
+            max-width: 100%;
+            vertical-align: middle;
+            overflow: hidden;
+        }
 
 
-.move {
-	padding: 4px 4px;
-    width: 100px;
-	font-size: 12px;
-}
+        .button {
+            padding: 5px 10px;
+            width: 160px;
+            font-size: 16px;
+        }
 
 
-th, td {
-  padding: 5px 5px 5px 0px;
-}
+        .multiplier {
+            padding: 0px 0px;
+            font-size: 12px;
+        }
+
+        th, td {
+        padding: 5px 5px 5px 0px;
+        }
+
+        #div2{
+        background-color:#777;
+        margin-bottom:20px;
+        }
+
+        .disabledDiv {
+            pointer-events: none;
+            opacity: 0.4;
+        }
+
+        table {
+            width: 660px;
+            padding: 5px;
+            table-layout: fixed;
+        }
+    </style>
+
+    <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
+    <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
+    <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
 
 
-#div2{
-  background-color:#777;
-  margin-bottom:20px;
-}
-.disabledDiv {
-    pointer-events: none;
-    opacity: 0.4;
-}
-</style>
-<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
-<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
-<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
 
 
-    <h2>Analog ROI's</h2>
-    <p>On this page you define ROI's for the analog counters.
-        See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/</a> for explanations.</p>
-    
-        <input type="checkbox" id="Category_Analog_enabled" value="1"  onclick = 'EnDisableAnalog()' checked ><label for="Category_Analog_enabled">Enable Analog ROI's</label></p>
-   
+    <h2>Analog ROI</h2>
+    <details id="desc_details" style="font-size:16px">
+        <summary><b>CLICK HERE</b> for usage description. More infos in documentation: 
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>
+        </summary>
+        <p>
+            <b>R</b>egion <b>O</b>f <b>I</b>nterest (ROI) for analog pointer counter can be defined on this page. If no analog pointer counter need to be 
+            processed, disable analog pointer counter processing by deselecting <b>"Analog ROI Processing"</b>.
+        </p>
+        <p>
+            By default one number sequence (a number seqence contains of 1-x digit ROIs + 1-x analog counter ROIs which are processed together) is 
+            predefined and already selected in the drop down <b>"Number Sequence"</b>. If you need more than one number sequence additional
+            one's can be added with the buttons next to the drop down. Each number sequence will be processed separately.
+        </p>
+        <p>
+            Using drag and drop by mouse of by manually entering the parameters into the given fields the analog ROIs can be positined to the analog pointer
+            counters on the reference image. To have proper ROI definition please check the documentation: 
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>. It's very important to be
+            really precise to have reliable processing. With the drop down <b>"ROI"</b> you can change between the different ROIs in the selected
+            number sequence. To create new ROIs use <b>"New ROI"</b>.
+        </p>
+        <p>
+            The order of the ROIs defines the position (and therefore the multiplication factor) within the reading sequence. The position
+            in the number sequence can be changed with the buttons <b>"Move ROI Lower"</b> and <b>"Move ROI Higher"</b>. The multiplication factor which is
+            shown below the ROI drop down is the multiplication factor of pure position/order in number sequence and the factor right-hand side to this is 
+            the additionally corrected by decimal shift setting (configuration, expert parameter, default: 0). 
+        </p>
+        <p>
+            After definition of digit ROIs is completed don't forget to save with the <b>"Save Config"</b> button!<br>
+            <b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps 
+            (reference image, alignment, ROI configuration) are completed to activate new configuration.
+        </p>
+    </details>
+    <hr />
+
+    <p>   
+        <input type="checkbox" id="Category_Analog_enabled" value="1"  onclick = 'EnDisableAnalog()' checked >
+            <label style="font-weight: bold; font-size: larger;" for="Category_Analog_enabled">Analog ROI Processing</label>
+    </p>
+
+
 <div id="div1">
 <div id="div1">
-	<table>
-	  <tr>
-		<td><canvas id="canvas" crossorigin></canvas></td>
-	  </tr>
-	</table>	
-
-    <p>
-        <table>
-            <tr>
-                <class id="Numbers_text" style="color:black;"><b>Number: </b></class>
+
+    <table>
+        <colgroup>
+            <col span="1" style="width: 22%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+        </colgroup>
+        <tr>
+            <td colspan="4" style="padding: 0px"><class id="Numbers_text" style="color:black;">Number Sequence:</class></td>
+        </tr>
+        <tr>
+            <td>
                 <select id="Numbers_value1" onchange="numberChanged()">
                 <select id="Numbers_value1" onchange="numberChanged()">
                 </select>
                 </select>
-                <input class="move" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename">  
-                <input class="move" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New">  
-                <input class="move" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Remove">
-            </tr>
-        </table>
-    </p>
+            </td>
+            <td><input class="button" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New Sequence"></td>
+            <td><input class="button" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename Sequence"></td> 
+            <td><input class="button" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Delete Sequence"></td>
+        </tr>
+    </table>
+
+    <hr />
+
+    <table>
+        <colgroup>
+            <col span="1" style="width: 22%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+        </colgroup>
+        <tr>
+            <td style="padding: 0px">ROI:</td>
+        </tr>
+        <tr>
+            <td><select id="index" name="index" onchange="ChangeSelection()" tabindex=1></select></td>
+            <td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI"></td>
+            <td><input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename ROI"></td>	  
+            <td><input class="button" type="submit" id="deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
+        </tr>
+        <tr>       
+            <td class="multiplier">Multiplier: <output type="text" id="multiplier" name="multiplier"></output><br>
+                (only based on order)
+            </td>
+            <td class="multiplier">Multiplier: <output type="text" id="multiplier_decshift" name="multiplier_decshift"></output><br>
+                (order + decimal shift: <output type="text" id="decimalShift" name="decimalShift"></output>)
+            </td>
+            <td><input class="button" type="submit" id="movePrevious" onclick="movePrevious()" value="Move ROI Higher"></td> 
+            <td><input class="button" type="submit" id="moveNext" onclick="moveNext()" value="Move ROI Lower"></td>
+        </tr>
+    </table>
 
 
 	<table>
 	<table>
-	  <tr>
-		<td><input class="button" type="submit" id= "newROI" name="newROI" onclick="newROI()" value="New ROI (after current)"></td>	  
-		<td><input class="button" type="submit" id= "deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
-		<td></td>
-	  </tr>
-	  <tr>
-		<td>
-			<select id="index" name="index" onchange="ChangeSelection()" tabindex=1>
-            </select>
-		</td>
-		<td>                
-            <input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename">  
-        </td>
-		<td>
-		<input class="move" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
-		<input class="move" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">  
-		</td>	
-	  </tr>
-	  <tr>
-        <td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>	  
-		<td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
-		<td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio</label></td>
-	  </tr>
-	  <tr>
-		<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>	
-		<td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
-		<td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize Δx and Δy between ROIs</label></td>
-	  </tr>
-      <tr>
-        <td colspan="2"></td>
-        <td><input type="checkbox" id="CCW" name="CCW" value="0" onclick="changeCCW()" unchecked tabindex=8><label for="CCW"> Counter-Clockwise Rotation: </label></td>
-      </tr>
-	</table>			 
-</div>	 
-
-	<table>
-	  <tr>
-		<td><input class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save" tabindex=9>
-	  </tr>  
-	  <tr>
-                <td><button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate the changes</button></td>
-	  </tr>  
-    </table>	
+        <colgroup>
+            <col span="1" style="width: 18%;">
+            <col span="1" style="width: 18%;">
+            <col span="1" style="width: 64%;">
+        </colgroup>
+        <tr>
+            <td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>	  
+            <td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
+            <td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label></td>
+        </tr>
+        <tr>
+            <td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>	
+            <td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
+            <td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label></td>
+        </tr>
+        <tr>
+            <td colspan="2"></td>
+            <td><input type="checkbox" id="CCW" name="CCW" value="0" onclick="changeCCW()" unchecked tabindex=8><label for="CCW">Counter clockwise rotation (CCW)</label></td>
+        </tr>
+    </table>		 
+</div>
+
+    <table>
+        <colgroup>
+            <col span="1" style="width: 22%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+        </colgroup>
+        <tr>
+            <td colspan="3" style="vertical-align: bottom;"><b>Reference Image:</b></td>
+            <!---<td><button class="button" id="reboot" type="button" onclick="doReboot()">Reboot device</button></td>-->
+            <td><input style="font-weight:bold;" class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save Config" tabindex=10></td>
+        </tr>
+        <tr>
+            <td colspan="4"><canvas id="canvas" crossorigin></canvas></td>
+        </tr>
+    </table>
 
 
 
 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
@@ -158,16 +237,15 @@ th, td {
             lockSizes = false;
             lockSizes = false;
             domainname = getDomainname();
             domainname = getDomainname();
 
 
-    
-function doReboot() {
-    if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
-            var stringota = getDomainname() + "/reboot";
-            window.location = stringota;
-            window.location.href = stringota;
-            window.location.assign(stringota);
-            window.location.replace(stringota);
+    function doReboot() {
+        if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
+                var stringota = getDomainname() + "/reboot";
+                window.location = stringota;
+                window.location.href = stringota;
+                window.location.assign(stringota);
+                window.location.replace(stringota);
+        }
     }
     }
-}
     
     
 function EnDisableAnalog() {
 function EnDisableAnalog() {
         isEnabled = document.getElementById("Category_Analog_enabled").checked;
         isEnabled = document.getElementById("Category_Analog_enabled").checked;
@@ -186,9 +264,9 @@ function EnDisableAnalog() {
 		
 		
         sah1(document.getElementById("div1"), !isEnabled);
         sah1(document.getElementById("div1"), !isEnabled);
 
 
-
         cofcat["Analog"]["enabled"] = isEnabled;
         cofcat["Analog"]["enabled"] = isEnabled;
-        
+        document.getElementById("saveroi").disabled = false;
+                
         if (isEnabled)
         if (isEnabled)
         {
         {
             UpdateROIs();
             UpdateROIs();
@@ -212,6 +290,10 @@ function onNameChange(){
 }
 }
 
 
 function deleteROI(){
 function deleteROI(){
+    if (!confirm("Delete the selected ROI?")) {
+        return; //break out of the function early because prompt was aborted
+    }
+
     ROIInfo.splice(aktindex, 1);
     ROIInfo.splice(aktindex, 1);
     if (aktindex > ROIInfo.length - 1){
     if (aktindex > ROIInfo.length - 1){
         aktindex = ROIInfo.length - 1;
         aktindex = ROIInfo.length - 1;
@@ -220,18 +302,21 @@ function deleteROI(){
     draw();
     draw();
 }
 }
 
 
-function newROI(){
+function newROI() {
     var sel = document.getElementById("Numbers_value1");
     var sel = document.getElementById("Numbers_value1");
     var _number= sel.options[sel.selectedIndex].text;
     var _number= sel.options[sel.selectedIndex].text;
     sel = document.getElementById("index");
     sel = document.getElementById("index");
     var _roialt= sel.options[sel.selectedIndex].text;
     var _roialt= sel.options[sel.selectedIndex].text;
 
 
-    var _roinew = prompt("Please enter name of new ROI", "name");
+    var _roinew = prompt("Please enter a name for the new ROI", "name");
+    if (_roinew === null) {
+        return; //break out of the function early because prompt was aborted
+    }
 
 
     if (ROIInfo.length > 0)
     if (ROIInfo.length > 0)
-        erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 1, 1, ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], ROIInfo[aktindex]["CCW"]=="true");
+        erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 15, 30, ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], ROIInfo[aktindex]["CCW"]=="true");
     else
     else
-        erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 1, 1, 30, 30, false);
+        erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 15, 30, 30, 30, false);
 
 
     if (erg != "")
     if (erg != "")
         firework.launch(erg, 'danger', 30000);
         firework.launch(erg, 'danger', 30000);
@@ -275,7 +360,9 @@ function changeCCW(){
         ROIInfo[aktindex]["CCW"] = "true";
         ROIInfo[aktindex]["CCW"] = "true";
     else
     else
         ROIInfo[aktindex]["CCW"] = "false";
         ROIInfo[aktindex]["CCW"] = "false";
-	UpdateROIs();
+	
+    UpdateROIs();
+
 }
 }
 
 
 function ChangeSelection(){
 function ChangeSelection(){
@@ -285,11 +372,47 @@ function ChangeSelection(){
 }
 }
 
 
 function SaveToConfig(){
 function SaveToConfig(){
-//    _zwcat = getConfigCategory();
-    cofcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
-    WriteConfigININew();
-    SaveConfigToServer(domainname);  
-    firework.launch('Configuration got updated. It will get applied after the next reboot!', 'success', 5000);
+    if (confirm("Are you sure you want to save the new analog ROI configuration?")) {
+        //_zwcat = getConfigCategory();
+        cofcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
+        WriteConfigININew();
+        SaveConfigToServer(domainname);
+        UpdateROIs();
+        document.getElementById("saveroi").disabled = true;
+
+        firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
+    }
+}
+
+
+function ShowMultiplier(){
+    var decimalShift = 0;
+    var multiplier = multiplier_decshift = aktindex+1-Number(decimalShift);
+    var fixedDecimals = fixedDecimals_decshift = aktindex+1;
+    var NumberInfo = getNUMBERInfo();
+
+    var sel = document.getElementById("Numbers_value1");
+    var _number= sel.options[sel.selectedIndex].text;
+    var NumbersIndex = 0;
+    for (var i = 0; i < NumberInfo.length; ++i)
+        if (NumberInfo[i]["name"] == _number)
+            NumbersIndex = i;
+
+    if (NumberInfo[NumbersIndex]["PostProcessing"]["DecimalShift"]["enabled"]) {
+        decimalShift = NumberInfo[NumbersIndex]["PostProcessing"]["DecimalShift"]["value1"];
+        document.getElementById("decimalShift").value=decimalShift;   
+        multiplier_decshift = aktindex+1-Number(decimalShift);
+        fixedDecimals_decshift = fixedDecimals_decshift-Number(decimalShift); // set to fixed decimals to avoid rounding issues
+
+        if (fixedDecimals_decshift < 0)
+        fixedDecimals_decshift = 0;
+    }
+    else {
+        document.getElementById("decimalShift").value=0;
+    }
+    
+    document.getElementById("multiplier").value="x" + Number(10 ** (-1*multiplier)).toFixed(fixedDecimals);
+    document.getElementById("multiplier_decshift").value="x" + Number(10 ** (-1*multiplier_decshift)).toFixed(fixedDecimals_decshift);
 }
 }
 
 
 
 
@@ -305,19 +428,28 @@ function UpdateROIs(_sel){
     {
     {
         document.getElementById("Category_Analog_enabled").checked = false;
         document.getElementById("Category_Analog_enabled").checked = false;
         EnDisableAnalog();
         EnDisableAnalog();
-        firework.launch('Analog ROIs are disabled - please enable first (Check box top left)', 'warning', 10000);
+        firework.launch('Analog ROI processing is disabled. Activate with checkbox if needed', 'warning', 10000);
         return;
         return;
     }
     }
 
 
     if (ROIInfo.length == 0){
     if (ROIInfo.length == 0){
-        firework.launch('There are no ROIs defined. Please first create a new ROI ("New ROIs ...")', 'danger', 10000);
+        firework.launch('No analog ROIs defined in selected number sequence', 'warning', 10000);
         document.getElementById("newROI").disabled = false;
         document.getElementById("newROI").disabled = false;
         document.getElementById("deleteROI").disabled = true;
         document.getElementById("deleteROI").disabled = true;
-        document.getElementById("index").disabled = true;
-        document.getElementById("saveroi").disabled = true;
         document.getElementById("renameROI").disabled = true;
         document.getElementById("renameROI").disabled = true;
+        document.getElementById("index").disabled = true;
+        document.getElementById("multiplier").style.display = "none";
+        document.getElementById("multiplier_decshift").style.display = "none";
+        document.getElementById("refx").disabled = true;
+        document.getElementById("refdx").disabled = true;
+        document.getElementById("refy").disabled = true;
+        document.getElementById("refdy").disabled = true;
+        document.getElementById("lockSizes").disabled = true;
+        document.getElementById("lockAspectRatio").disabled = true;
+        document.getElementById("CCW").disabled = true;
         document.getElementById("moveNext").disabled = true;
         document.getElementById("moveNext").disabled = true;
         document.getElementById("movePrevious").disabled = true;
         document.getElementById("movePrevious").disabled = true;
+        document.getElementById("saveroi").disabled = false;
         return;
         return;
     }
     }
     else
     else
@@ -326,6 +458,15 @@ function UpdateROIs(_sel){
         document.getElementById("deleteROI").disabled = false;
         document.getElementById("deleteROI").disabled = false;
         document.getElementById("renameROI").disabled = false;
         document.getElementById("renameROI").disabled = false;
         document.getElementById("index").disabled = false;
         document.getElementById("index").disabled = false;
+        document.getElementById("multiplier").style.display = "";
+        document.getElementById("multiplier_decshift").style.display = "";
+        document.getElementById("refx").disabled = false;
+        document.getElementById("refdx").disabled = false;
+        document.getElementById("refy").disabled = false;
+        document.getElementById("refdy").disabled = false;
+        document.getElementById("lockSizes").disabled = false;
+        document.getElementById("lockAspectRatio").disabled = false;
+        document.getElementById("CCW").disabled = false;
         document.getElementById("saveroi").disabled = false;
         document.getElementById("saveroi").disabled = false;
     }
     }
 
 
@@ -335,7 +476,7 @@ function UpdateROIs(_sel){
     }
     }
 
 
     if (aktindex > ROIInfo.length)
     if (aktindex > ROIInfo.length)
-        aktindex = ROIInfo.length;
+        aktindex = ROIInfo.length-1;
 
 
     for (var i = 0; i < ROIInfo.length; ++i){
     for (var i = 0; i < ROIInfo.length; ++i){
         var option = document.createElement("option");
         var option = document.createElement("option");
@@ -358,7 +499,9 @@ function UpdateROIs(_sel){
     document.getElementById("moveNext").disabled = false;
     document.getElementById("moveNext").disabled = false;
     if (aktindex == (ROIInfo.length-1)){
     if (aktindex == (ROIInfo.length-1)){
         document.getElementById("moveNext").disabled = true;
         document.getElementById("moveNext").disabled = true;
-    }  
+    }
+
+    ShowMultiplier();
     
     
     document.getElementById("lockAspectRatio").checked = lockAspectRatio;
     document.getElementById("lockAspectRatio").checked = lockAspectRatio;
     document.getElementById("lockSizes").checked = lockSizes;
     document.getElementById("lockSizes").checked = lockSizes;
@@ -373,8 +516,7 @@ function UpdateROIs(_sel){
     rect.startY = ROIInfo[aktindex]["y"];
     rect.startY = ROIInfo[aktindex]["y"];
     rect.w = ROIInfo[aktindex]["dx"];
     rect.w = ROIInfo[aktindex]["dx"];
     rect.h = ROIInfo[aktindex]["dy"];
     rect.h = ROIInfo[aktindex]["dy"];
-    draw();      
-
+    draw();
 }
 }
     
     
         function loadCanvas(dataURL) {
         function loadCanvas(dataURL) {
@@ -404,10 +546,20 @@ function UpdateROIs(_sel){
             var left = box.left + scrollLeft - clientLeft;
             var left = box.left + scrollLeft - clientLeft;
             return { top: Math.round(top), left: Math.round(left) };
             return { top: Math.round(top), left: Math.round(left) };
         }
         }
-   
-    
+
+
+        /* hash #description open the details part of the page */
+        function openDescription() {
+        if(window.location.hash) {
+            var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
+            if(hash == 'description')
+                document.getElementById("desc_details").open = true;
+            }
+        }
     
     
+
         function init() {
         function init() {
+            openDescription();
             domainname = getDomainname();
             domainname = getDomainname();
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mouseup', mouseUp, false);
             canvas.addEventListener('mouseup', mouseUp, false);
@@ -440,11 +592,12 @@ function UpdateROIs(_sel){
                 console.log("Not all ROI have the same dX and dY, unticking the sync checkbox!");
                 console.log("Not all ROI have the same dX and dY, unticking the sync checkbox!");
             }
             }
 
 
+            document.getElementById("saveroi").disabled = true;
 
 
             drawImage();
             drawImage();
             draw();
             draw();
         }
         }
-        
+
         function drawImage(){
         function drawImage(){
             var canvas = document.getElementById('canvas');
             var canvas = document.getElementById('canvas');
             var context = canvas.getContext('2d');
             var context = canvas.getContext('2d');
@@ -483,10 +636,13 @@ function UpdateNUMBERS(_sel){
 
 
 function renameNumber(){
 function renameNumber(){
     var sel = document.getElementById("Numbers_value1");
     var sel = document.getElementById("Numbers_value1");
-    var _delte= sel.options[sel.selectedIndex].text;
-    var _numbernew = prompt("Please enter new name", _delte);
+    var _delete= sel.options[sel.selectedIndex].text;
+    var _numbernew = prompt("Please enter a new name for the selected number sequence", _delete);
+    if (_numbernew === null) {
+        return; //break out of the function early because prompt was aborted
+    }
 
 
-    erg = RenameNUMBER(_delte, _numbernew);
+    erg = RenameNUMBER(_delete, _numbernew);
     if (erg != "")
     if (erg != "")
         firework.launch(erg, 'danger', 30000);
         firework.launch(erg, 'danger', 30000);
     else
     else
@@ -494,7 +650,10 @@ function renameNumber(){
 }
 }
 
 
 function newNumber(){
 function newNumber(){
-    var _numbernew = prompt("Please enter name of new number", "name");
+    var _numbernew = prompt("Please enter a name for the new number sequence", "name");
+    if (_numbernew === null) {
+        return; //break out of the function early because prompt was aborted
+    }
 
 
     erg = CreateNUMBER(_numbernew);
     erg = CreateNUMBER(_numbernew);
     if (erg != "")
     if (erg != "")
@@ -505,10 +664,13 @@ function newNumber(){
 
 
 
 
 function removeNumber(){
 function removeNumber(){
-	if (confirm("This will remove the number complete (analog and digital).\nIf you only want to remove the digital ROIs, please use \"Delete ROIs\".\nDo you want to proceed?")) {
+	if (confirm("The entire number sequence will be removed (digit + analog parts). " +
+                "To remove single ROI of the number sequence, use \"Delete ROI\" instead.\n" +
+                "Do you really want to proceed?")) 
+    {
         var sel = document.getElementById("Numbers_value1");
         var sel = document.getElementById("Numbers_value1");
-        var _delte= sel.options[sel.selectedIndex].text;
-        erg = DeleteNUMBER(_delte);
+        var _delete= sel.options[sel.selectedIndex].text;
+        erg = DeleteNUMBER(_delete);
         if (erg != "")
         if (erg != "")
             firework.launch(erg, 'danger', 30000);
             firework.launch(erg, 'danger', 30000);
         UpdateNUMBERS();
         UpdateNUMBERS();
@@ -576,8 +738,12 @@ function drawTextBG(context, txt, x, y, padding) {
                     var dx = parseInt(ROIInfo[_nb].dx) + parseInt(lw);
                     var dx = parseInt(ROIInfo[_nb].dx) + parseInt(lw);
                     var dy = parseInt(ROIInfo[_nb].dy) + parseInt(lw);
                     var dy = parseInt(ROIInfo[_nb].dy) + parseInt(lw);
                     context.strokeRect(x0, y0, dx, dy);
                     context.strokeRect(x0, y0, dx, dy);
-                    drawTextBG(context, ROIInfo[_nb]["name"], x0+dx/2-0.5, y0-13, 5);
-
+                    
+                    if (ROIInfo[_nb]["CCW"] != "true")
+                        drawTextBG(context, ROIInfo[_nb]["name"], x0+dx/2-0.5, y0-13, 5);
+                    else
+                        drawTextBG(context, ROIInfo[_nb]["name"]+" (CCW)", x0+dx/2-0.5, y0-13, 5);
+                    
                     lw = 1;
                     lw = 1;
                     var x0 = parseInt(ROIInfo[_nb].x) - parseInt(lw/2);
                     var x0 = parseInt(ROIInfo[_nb].x) - parseInt(lw/2);
                     var y0 = parseInt(ROIInfo[_nb].y) - parseInt(lw/2);
                     var y0 = parseInt(ROIInfo[_nb].y) - parseInt(lw/2);
@@ -602,8 +768,13 @@ function drawTextBG(context, txt, x, y, padding) {
             var y0 = parseInt(rect.startY) - parseInt(lw/2);
             var y0 = parseInt(rect.startY) - parseInt(lw/2);
             var dx = parseInt(rect.w) + parseInt(lw);
             var dx = parseInt(rect.w) + parseInt(lw);
             var dy = parseInt(rect.h) + parseInt(lw);
             var dy = parseInt(rect.h) + parseInt(lw);
-            context.strokeRect(x0, y0, dx, dy); 
-            drawTextBG(context, ROIInfo[aktindex]["name"], x0+dx/2, y0-11, 5);
+            context.strokeRect(x0, y0, dx, dy);
+
+            if (ROIInfo[aktindex]["CCW"] != "true")
+                drawTextBG(context, ROIInfo[aktindex]["name"], x0+dx/2, y0-11, 5);
+            else
+                drawTextBG(context, ROIInfo[aktindex]["name"] + " (CCW)", x0+dx/2, y0-11, 5);
+
             context.lineWidth = 1;
             context.lineWidth = 1;
             context.beginPath();
             context.beginPath();
             context.arc(x0+dx/2, y0+dy/2, dx/2, 0, 2 * Math.PI);
             context.arc(x0+dx/2, y0+dy/2, dx/2, 0, 2 * Math.PI);
@@ -706,6 +877,7 @@ function drawTextBG(context, txt, x, y, padding) {
             rect.startY = document.getElementById("refy").value; 
             rect.startY = document.getElementById("refy").value; 
             draw();            
             draw();            
         }
         }
+        document.getElementById("saveroi").disabled = false;
     }
     }
 
 
     function valuemanualchangeddx(){
     function valuemanualchangeddx(){
@@ -721,6 +893,7 @@ function drawTextBG(context, txt, x, y, padding) {
             rect.startY = document.getElementById("refy").value; 
             rect.startY = document.getElementById("refy").value; 
             draw();            
             draw();            
         }
         }
+        document.getElementById("saveroi").disabled = false;
     }
     }
 
 
 
 
@@ -730,8 +903,10 @@ function drawTextBG(context, txt, x, y, padding) {
         sel = document.getElementById("index");
         sel = document.getElementById("index");
         var _roialt= sel.options[sel.selectedIndex].text;
         var _roialt= sel.options[sel.selectedIndex].text;
 
 
-
-        var _roinew = prompt("Please enter new name", _roialt);
+        var _roinew = prompt("Please enter a new name for the selected ROI", _roialt);
+        if (_roinew === null) {
+            return; //break out of the function early because prompt was aborted
+        }
 
 
         erg = RenameROI(_number, "analog", _roialt, _roinew);
         erg = RenameROI(_number, "analog", _roialt, _roinew);
         if (erg != "")
         if (erg != "")
@@ -742,13 +917,15 @@ function drawTextBG(context, txt, x, y, padding) {
 
 
     function numberChanged()
     function numberChanged()
     {
     {
+        aktindex = 0;
         UpdateROIs();
         UpdateROIs();
     }    
     }    
 
 
 
 
 
 
-    
     init();
     init();
+
 </script>
 </script>
+
 </body>
 </body>
 </html>
 </html>

+ 0 - 136
sd-card/html/edit_check.html

@@ -1,136 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<meta charset="utf-8"/>
-<title>Check</title>
-
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
-
-.button {
-	padding: 5px 10px;
-    width: 210px;
-	font-size: 16px;
-}
-
-</style>
-
-</head>
-
-<body style="font-family: arial">
- 
-<table>
-    <tr><td colspan="2">Result:</td></tr>
-    <tr>
-        <td>
-            <iframe name="maincontent" id ="maincontent" width="700px" height="700px"></iframe> 
-        </td>
-        <td style="padding-left: 15px;">
-            <p>
-                <input class="button" type="submit" id="take" onclick="doTake()" value="1. Take Picture">
-            </p>
-            <p>
-                <input class="button" type="submit" id="align" onclick="doAlign()" value="2. Align Image"><br>
-            </p>
-            <p>
-                Takes up to 2 Minutes!
-            </p>			
-            Digits and Analog recognition not yet implemented.
-            <p>
-                <input class="button" type="submit" id="digits" onclick="doDigits()" value="3a. Analyse Digits">    
-            </p>
-            <p>
-                <input class="button" type="submit" id="analog" onclick="doAnalog()" value="3b Analyse Analog">    
-            </p>
-        </td>
-    </tr>
-</table>
-
-<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
-<script type="text/javascript" src="readconfig.js?v=$COMMIT_HASH"></script>  
- 
-<script type="text/javascript">
-    var domainname = getDomainname();
-
-    function doAnalog(){
-        var xhttp = new XMLHttpRequest();
-        url = domainname + "/editflow?task=test_analog";
-        if (domainname.length > 0){
-            url = url + "&host=" + domainname;
-        }        
-        xhttp.open("GET", url, false);
-        xhttp.send();
-        var html = xhttp.responseText;
-        html = html.replace("src=\"/", "src=\"" + domainname + "/");
-
-        document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
-    }
-
-
-    function doDigits(){
-        var xhttp = new XMLHttpRequest();
-        url = domainname + "/editflow?task=test_digits";
-        if (domainname.length > 0){
-            url = url + "&host=" + domainname;
-        }        
-        xhttp.open("GET", url, false);
-        xhttp.send();
-        var html = xhttp.responseText;
-        html = html.replace("src=\"/", "src=\"" + domainname + "/");
-
-        document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
-    }
-
-
-    function doAlign(){
-        var xhttp = new XMLHttpRequest();
-        url = domainname + "/editflow?task=test_align";
-        if (domainname.length > 0){
-            url = url + "&host=" + domainname;
-        }        
-        xhttp.open("GET", url, false);
-        xhttp.send();
-        var html = xhttp.responseText;
-        html = html.replace("src=\"/", "src=\"" + domainname + "/");
-
-        document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
-
-        document.getElementById("align").disabled = false;
-//        document.getElementById("digits").disabled = false;
-//        document.getElementById("analog").disabled = false;    
-    }
-
-
-    function doTake(){
-        var xhttp = new XMLHttpRequest();
-        url = domainname + "/editflow?task=test_take";
-        if (domainname.length > 0){
-            url = url + "&host=" + domainname;
-        }
-        xhttp.open("GET", url, false);
-        xhttp.send();
-        var html = xhttp.responseText;
-        document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
-
-        document.getElementById("align").disabled = false;
-        document.getElementById("digits").disabled = true;
-        document.getElementById("analog").disabled = true;    
-    }
-
-    function Init(){
-        domainname = getDomainname();
-        document.getElementById("align").disabled = true;
-        document.getElementById("digits").disabled = true;
-        document.getElementById("analog").disabled = true;
-    }
-
-    Init();
-    
-</script>
- 
-</body>
-</html>

+ 61 - 61
sd-card/html/edit_config.html

@@ -1,25 +1,24 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>Edit Config</title>
 <title>Edit Config</title>
-<meta charset="utf-8">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
+	h1 {font-size: 2em;}
+	h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+	h3 {font-size: 1.2em;}
+	p {font-size: 1em;}
 
 
-.button {
-	padding: 5px 20px;
-    width: 211px;
-	font-size: 16px;	
-}
+	.button {
+		padding: 5px 10px;
+		width: 220px;
+		font-size: 16px;	
+	}
 
 
-textarea {
-	font-size: 14px;
-}
+	textarea {
+		font-size: 15px;
+	}
 </style>
 </style>
 <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
 <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
 <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
 <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
@@ -28,59 +27,60 @@ textarea {
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
  
  
-<table>
-    <tr><td><h2>Config.ini:</h2></td></tr>
-    <tr>
-        <td colspan="3">
-            <textarea id="inputTextToSave" cols="100" rows="33"></textarea>
-        </td>
-    </tr>
-    <tr>
-		<td><button class="button" onclick="saveTextAsFile()">Save</button></td>
-	</tr>
-	<tr>
-		<td><button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate changes</button></td>
-	</tr>
-</table>
+	<table style="width:660px">
+		<h2>Configuration - "Config.ini" Editor</h2>
+		<td>
+			<textarea id="inputTextToSave" rows="30" style="width:100%"></textarea>
+		</td>
+	</table>
 
 
-<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
-<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>  
- 
-<script type="text/javascript">
-	var canvas = document.getElementById('canvas'),
-		domainname = getDomainname(); 
+	<table>
+		<td>
+			<button class="button" onclick="saveTextAsFile()">Save Config</button>
+		</td>
+	    <td>
+	        <button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate changes</button>
+		</td>
+	</table>
 
 
+	<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
+	<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>  
+	
+	<script type="text/javascript">
+		var canvas = document.getElementById('canvas'),
+			domainname = getDomainname(); 
 
 
-function LoadConfigNeu() {
-	domainname = getDomainname();  
-    loadConfig(domainname); 	
-	document.getElementById("inputTextToSave").value = getConfig();
-	}
 
 
-function saveTextAsFile()
-{
-	if (confirm("Are you sure you want to update \"config.ini\"?")) {
-		FileDeleteOnServer("/config/config.ini", domainname);
-		var textToSave = document.getElementById("inputTextToSave").value;
-		FileSendContent(textToSave, "/config/config.ini", domainname);
-		firework.launch('Configuration got updated. It will get applied after the next reboot!', 'success', 5000);
-	}
-}
+	function LoadConfigNeu() {
+		domainname = getDomainname();  
+		loadConfig(domainname); 	
+		document.getElementById("inputTextToSave").value = getConfig();
+		}
 
 
-function doReboot() {
-	if (confirm("Are you sure you want to reboot the ESP32?")) {
-		var stringota = "/reboot";
-		window.location = stringota;
-		window.location.href = stringota;
-		window.location.assign(stringota);
-		window.location.replace(stringota);
+	function saveTextAsFile()
+	{
+		if (confirm("Are you sure you want to save the configuration?")) {
+			FileDeleteOnServer("/config/config.ini", domainname);
+			var textToSave = document.getElementById("inputTextToSave").value;
+			FileSendContent(textToSave, "/config/config.ini", domainname);
+
+			firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
+		}
 	}
 	}
-}
 
 
- 
-LoadConfigNeu();
- 
-</script>
+	function doReboot() {
+		if (confirm("Are you sure you want to reboot?")) {
+			var stringota = "/reboot";
+			window.location = stringota;
+			window.location.href = stringota;
+			window.location.assign(stringota);
+			window.location.replace(stringota);
+		}
+	}
+	
+	LoadConfigNeu();
+	
+	</script>
  
  
 </body>
 </body>
 </html>
 </html>

Разница между файлами не показана из-за своего большого размера
+ 378 - 217
sd-card/html/edit_config_param.html


+ 314 - 138
sd-card/html/edit_digits.html

@@ -1,137 +1,212 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<meta charset="utf-8"/>
-<title>Digit ROI's</title>
-
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
-
-input[type=number] {
-	width: 100px;
-	margin-right: 10px;
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+    <meta charset="UTF-8" />
+    <title>Digit ROI</title>
+
+    <style>
+        h1 {font-size: 2em;}
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
+        p {font-size: 1em;}
+
+        input[type=number] {
+            width: 60px;
+            margin-right: 10px;
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-input[type=text] {
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+        input[type=text] {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+        }
 
 
-select {
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-	margin-right: 10px;
-}
+        input:out-of-range {
+        background-color: rgba(255, 0, 0, 0.25);
+        border: 1px solid red;
+        }
 
 
-.button {
-	padding: 5px 10px;
-    width: 210px;
-	font-size: 16px;
-}
+        select {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+            margin-right: 10px;
+            min-width: 100px;
+            max-width: 100%;
+            vertical-align: middle;
+            overflow: hidden;
+        }
 
 
-.move {
-	padding: 4px 4px;
-    width: 100px;
-	font-size: 12px;
-}
+        .button {
+            padding: 5px 10px;
+            width: 160px;
+            font-size: 16px;
+        }
+
+        .multiplier {
+            padding: 0px 0px;
+            font-size: 12px;
+        }
+
+        th, td {
+            padding: 5px 5px 5px 0px;
+        }
+
+        table {
+            width: 660px;
+            padding: 5px;
+            table-layout: fixed;
+        }
+    </style>
+
+    <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
+    <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
+    <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
 
 
-th, td {
-  padding: 5px 5px 5px 0px;
-}
-</style>
-<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
-<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
-<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
 
 
-    <h2>Digit ROI's</h2>
-        <p>On this page you define ROI's for the digits.
-            See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/</a> for explanations.</p>
-        
-        <p><input type="checkbox" id="Category_Digits_enabled" value="1"  onclick = 'EnDisableDigits()' checked><label for="Category_Digits_enabled">Enable Digit ROI's</label></p>
+    <h2>Digit ROI</h2>
+    <details id="desc_details" style="font-size:16px">
+        <summary><b>CLICK HERE</b> for usage description. More infos in documentation: 
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>
+        </summary>
+        <p>
+            <b>R</b>egion <b>O</b>f <b>I</b>nterest (ROI) for digit numbers can be defined on this page. If no digit numbers need to be processed, 
+            disable digit processing by deselecting <b>"Digit ROI Processing"</b>.
+        </p>
+        <p>
+            By default one number sequence (a number seqence contains of 1-x digit ROIs + 1-x analog counter ROIs which are processed together) is 
+            predefined and already selected in the drop down <b>"Number sequence"</b>. If you need more than one number sequence additional
+            one's can be added with the buttons next to the drop down. Each number sequence will be processed separately.
+        </p>
+        <p>
+            Using drag and drop by mouse of by manually entering the parameters into the given fields the digit ROIs can be positined to the digit numbers
+            on the reference image. To have proper ROI definition please check the documentation: 
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>. It's very important to be
+            really precise to have reliable processing. With the drop down <b>"ROI"</b> you can change between the different ROIs in the selected
+            number sequence. To create new ROIs use <b>"New ROI"</b>.
+        </p>
+        <p>
+            The order of the ROIs defines the position (and therefore the multiplication factor) within the reading sequence. The position
+            in the number sequence can be changed with the buttons <b>"Move ROI Lower"</b> and <b>"Move ROI Higher"</b>. The multiplication factor which is
+            shown below the ROI drop down is the multiplication factor of pure position/order in number sequence and the factor right-hand side to this is 
+            the additionally corrected by decimal shift setting (configuration, expert parameter, default: 0). 
+        </p>
+        <p>
+            After definition of digit ROIs is completed don't forget to save with the <b>"Save Config"</b> button!<br>
+            <b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps 
+            (reference image, alignment, ROI configuration) are completed to activate new configuration.
+        </p>
+    </details>
+    <hr />
+
+    <p>
+        <input type="checkbox" id="Category_Digits_enabled" value="1"  onclick = 'EnDisableDigits()' checked>
+            <label style="font-weight: bold; font-size: larger;" for="Category_Digits_enabled">Digit ROI Processing</label>
+    </p>   
 
 
-        <p>After saving the digit ROI's, you can define the <a href=edit_analog.html>analog</a> ROI's if your meter has analog counters.<br>
-            Only after those steps a reboot is required.</p>
-    
 
 
 <div id="div1">
 <div id="div1">
 
 
-	<table>
-	  <tr>
-		<canvas id="canvas" crossorigin></canvas>
-	  </tr>
-	</table>
-    
-    <p>
-        <table>
-            <tr>
-                <class id="Numbers_text" style="color:black;"><b>Number:</b> </class>
+    <table>
+        <colgroup>
+            <col span="1" style="width: 22%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+        </colgroup>
+        <tr>
+            <td colspan="4" style="padding: 0px"><class id="Numbers_text" style="color:black;">Number Sequence:</class></td>
+        </tr>
+        <tr>
+            <td>
                 <select id="Numbers_value1" onchange="numberChanged()">
                 <select id="Numbers_value1" onchange="numberChanged()">
                 </select>
                 </select>
-                <input class="move" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename">  
-                <input class="move" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New">  
-                <input class="move" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Remove">
-            </tr>
-        </table>
-    </p>
-    
+            </td>
+            <td><input class="button" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New Sequence"></td>
+            <td><input class="button" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename Sequence"></td> 
+            <td><input class="button" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Delete Sequence"></td>
+        </tr>
+    </table>
+
+    <hr />
+
+    <table>
+        <colgroup>
+            <col span="1" style="width: 22%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+        </colgroup>
+        <tr>
+            <td style="padding: 0px">ROI:</td>
+        </tr>
+        <tr>
+            <td><select id="index" name="index" onchange="ChangeSelection()" tabindex=1></select></td>
+            <td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI"></td>
+            <td><input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename ROI"></td>	  
+            <td><input class="button" type="submit" id="deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
+        </tr>
+        <tr>       
+            <td class="multiplier">Multiplier: <output type="text" id="multiplier" name="multiplier"></output><br>
+                (only based on order)
+            </td>
+            <td class="multiplier">Multiplier: <output type="text" id="multiplier_decshift" name="multiplier_decshift"></output><br>
+                (order + decimal shift: <output type="text" id="decimalShift" name="decimalShift"></output>)
+            </td>
+            <td><input class="button" type="submit" id="movePrevious" onclick="movePrevious()" value="Move ROI Higher"></td> 
+            <td><input class="button" type="submit" id="moveNext" onclick="moveNext()" value="Move ROI Lower"></td>
+        </tr>
+    </table>
+
 	<table>
 	<table>
-	  <tr>
-		<td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI (after current)"></td>	  
-		<td><input class="button" type="submit" id="deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
-		<td></td>
-	  </tr>
-	  <tr>
-		<td>
-			<select id="index" name="index" onchange="ChangeSelection()" tabindex=1>
-			</select>
-		</td>
-		<td>                
-            <input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename">  
-		<td>
-		<input class="move" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
-		<input class="move" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">  
-		</td>	
-	  </tr>
-	  <tr>
-        <td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>	  
-		<td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
-		<td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label></td>
-	  </tr>
-	  <tr>
-		<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>	
-		<td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
-        <td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label></td>
-    </tr>
-    <tr>
-      <td colspan="2"></td>
-      <td ><input type="checkbox" id="lockSpaceEquidistant" name="lockSpaceEquidistant" value="1" onclick="changeLockSpaceEquidistant()" checked tabindex=9>
-        <label for="lockSpaceEquidistant">Keep equidistance of <input type="number" name="space" id="space" step=1 onchange="valuemanualchangedspace()" tabindex=8> between all ROIs</label></td>
-    </tr>
+        <colgroup>
+            <col span="1" style="width: 18%;">
+            <col span="1" style="width: 18%;">
+            <col span="1" style="width: 64%;">
+        </colgroup>
+        <tr>
+            <td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>	  
+            <td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
+            <td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label></td>
+        </tr>
+        <tr>
+            <td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>	
+            <td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
+            <td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label></td>
+        </tr>
+        <tr>
+            <td colspan="2"></td>
+            <td><input type="checkbox" id="lockSpaceEquidistant" name="lockSpaceEquidistant" value="1" onclick="changeLockSpaceEquidistant()" checked tabindex=8>
+                <label for="lockSpaceEquidistant">Keep equidistance of <input type="number" name="space" id="space" step=1 onchange="valuemanualchangedspace()" tabindex=9> between all ROIs</label>
+            </td>
+        </tr>
     </table>	
     </table>	
-    
 </div>
 </div>
-			 
+
 	<table>
 	<table>
-	  <tr>
-		<td><input class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save" tabindex=10>
-            <p>Proceed to update the <a href=edit_analog.html>analog</a> ROI's when you are done or <a href=reboot_page.html>reboot</a> if there are no analogue counters.</p></td>
-	  </tr> 
-	</table>
+        <colgroup>
+            <col span="1" style="width: 22%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+            <col span="1" style="width: 26%;">
+        </colgroup>
+	    <tr>
+            <td colspan="3" style="vertical-align: bottom;"><b>Reference Image:</b></td>
+            <td><input style="font-weight:bold;" class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save Config" tabindex=10></td>
+	    </tr> 
+        <tr>
+            <td colspan="4"><canvas id="canvas" crossorigin></canvas></td>
+        </tr>
+    </table>
 
 
 <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
 <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
@@ -183,6 +258,7 @@ function EnDisableDigits() {
         sah1(document.getElementById("div1"), !isEnabled);
         sah1(document.getElementById("div1"), !isEnabled);
 
 
         cofcat["Digits"]["enabled"] = isEnabled;
         cofcat["Digits"]["enabled"] = isEnabled;
+        document.getElementById("saveroi").disabled = false;
                 
                 
         if (isEnabled)
         if (isEnabled)
         {
         {
@@ -208,6 +284,10 @@ function onNameChange(){
 }
 }
 
 
 function deleteROI(){
 function deleteROI(){
+    if (!confirm("Delete the selected ROI?")) {
+        return; //break out of the function early because prompt was aborted
+    }
+
     ROIInfo.splice(aktindex, 1);
     ROIInfo.splice(aktindex, 1);
     if (aktindex > ROIInfo.length - 1){
     if (aktindex > ROIInfo.length - 1){
         aktindex = ROIInfo.length - 1;
         aktindex = ROIInfo.length - 1;
@@ -222,7 +302,10 @@ function newROI() {
     sel = document.getElementById("index");
     sel = document.getElementById("index");
     var _roialt= sel.options[sel.selectedIndex].text;
     var _roialt= sel.options[sel.selectedIndex].text;
 
 
-    var _roinew = prompt("Please enter name of new ROI", "name");
+    var _roinew = prompt("Please enter a name for the new ROI", "name");
+    if (_roinew === null) {
+        return; //break out of the function early because prompt was aborted
+    }
 
 
     if (ROIInfo.length > 0) {
     if (ROIInfo.length > 0) {
         if (ROIInfo.length > 1) {
         if (ROIInfo.length > 1) {
@@ -232,7 +315,7 @@ function newROI() {
                 parseInt(ROIInfo[sel.selectedIndex].y), ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], 0);
                 parseInt(ROIInfo[sel.selectedIndex].y), ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], 0);
     }
     }
     else
     else
-        erg = CreateROI(_number, "digit", sel.selectedIndex, _roinew, 1, 1, 30, 51, 0);
+        erg = CreateROI(_number, "digit", sel.selectedIndex, _roinew, 15, 30, 30, 51, 0);
 
 
     if (erg != "")
     if (erg != "")
         firework.launch(erg, 'danger', 30000);
         firework.launch(erg, 'danger', 30000);
@@ -274,7 +357,7 @@ function changelockSizes(){
     valuemanualchangedspace();
     valuemanualchangedspace();
 
 
     if (!lockSizes) {
     if (!lockSizes) {
-        firework.launch("For best results it is in most cases advised to keep the y, Δx and Δy identical!", 'warning', 10000);
+        firework.launch("In most cases it's advised to keep the y, Δx and Δy identical!", 'warning', 10000);
     }
     }
 }
 }
 
 
@@ -296,11 +379,56 @@ function ChangeSelection(){
 }
 }
 
 
 function SaveToConfig(){
 function SaveToConfig(){
-//    _zwcat = getConfigCategory();
-    cofcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
-    WriteConfigININew();
-    SaveConfigToServer(domainname); 
-    firework.launch('Configuration got updated. It will get applied after the next reboot!', 'success', 5000);
+    if (confirm("Are you sure you want to save the new digit ROI configuration?")) {
+        // _zwcat = getConfigCategory();
+        cofcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
+        WriteConfigININew();
+        SaveConfigToServer(domainname);
+        UpdateROIs();
+        document.getElementById("saveroi").disabled = true;
+
+        firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
+    }
+}
+
+
+function ShowMultiplier(){
+    var decimalShift = 0;
+    var negShift = false;
+    var multiplier = multiplier_decshift = ROIInfo.length-1-aktindex;
+    var fixedDecimals_decshift = ROIInfo.length-1-aktindex;
+    var NumberInfo = getNUMBERInfo();
+
+    var sel = document.getElementById("Numbers_value1");
+    var _number= sel.options[sel.selectedIndex].text;
+    var NumbersIndex = 0;
+    for (var i = 0; i < NumberInfo.length; ++i)
+        if (NumberInfo[i]["name"] == _number)
+            NumbersIndex = i;
+
+    if (NumberInfo[NumbersIndex]["PostProcessing"]["DecimalShift"]["enabled"]) {
+        decimalShift = NumberInfo[NumbersIndex]["PostProcessing"]["DecimalShift"]["value1"];
+        document.getElementById("decimalShift").value=decimalShift;
+        multiplier_decshift = multiplier_decshift+Number(decimalShift);
+        fixedDecimals_decshift = fixedDecimals_decshift+Number(decimalShift); // set to fixed decimals to avoid rounding issues
+
+        if (fixedDecimals_decshift < 0) {
+            negShift = true
+            fixedDecimals_decshift = -1*fixedDecimals_decshift;
+        }
+    }
+    else {
+        document.getElementById("decimalShift").value=0;
+    }
+    
+    if (!negShift) {
+        document.getElementById("multiplier").value="x" + Number(10 ** multiplier).toFixed(0);
+        document.getElementById("multiplier_decshift").value="x" + Number(10 ** multiplier_decshift).toFixed(0);
+    }
+    else {
+        document.getElementById("multiplier").value="x" + Number(10 ** multiplier).toFixed(0);
+        document.getElementById("multiplier_decshift").value="x" + Number(10 ** multiplier_decshift).toFixed(fixedDecimals_decshift);
+    }
 }
 }
 
 
 
 
@@ -316,19 +444,28 @@ function UpdateROIs(_sel){
     {
     {
         document.getElementById("Category_Digits_enabled").checked = false;
         document.getElementById("Category_Digits_enabled").checked = false;
         EnDisableDigits();
         EnDisableDigits();
-        firework.launch('Digital ROIs are disabled - please enable first (Check box top left)', 'warning', 10000);
+        firework.launch('Digit ROI processing is disabled. Activate with checkbox if needed', 'warning', 10000);
         return;
         return;
     }
     }
 
 
     if (ROIInfo.length == 0){
     if (ROIInfo.length == 0){
-        firework.launch('There are no ROIs defined. Please first create a new ROI ("New ROIs ...")', 'danger', 10000);
+        firework.launch('No digit ROIs defined in selected number sequence', 'warning', 10000);
         document.getElementById("newROI").disabled = false;
         document.getElementById("newROI").disabled = false;
         document.getElementById("deleteROI").disabled = true;
         document.getElementById("deleteROI").disabled = true;
-        document.getElementById("index").disabled = true;
-        document.getElementById("saveroi").disabled = true;
         document.getElementById("renameROI").disabled = true;
         document.getElementById("renameROI").disabled = true;
+        document.getElementById("index").disabled = true;
+        document.getElementById("multiplier").style.display = "none";
+        document.getElementById("multiplier_decshift").style.display = "none";
+        document.getElementById("refx").disabled = true;
+        document.getElementById("refdx").disabled = true;
+        document.getElementById("refy").disabled = true;
+        document.getElementById("refdy").disabled = true;
+        document.getElementById("lockSizes").disabled = true;
+        document.getElementById("lockAspectRatio").disabled = true;
+        document.getElementById("lockSpaceEquidistant").disabled = true;
         document.getElementById("moveNext").disabled = true;
         document.getElementById("moveNext").disabled = true;
         document.getElementById("movePrevious").disabled = true;
         document.getElementById("movePrevious").disabled = true;
+        document.getElementById("saveroi").disabled = false;
         return;
         return;
     }
     }
     else
     else
@@ -337,6 +474,15 @@ function UpdateROIs(_sel){
         document.getElementById("deleteROI").disabled = false;
         document.getElementById("deleteROI").disabled = false;
         document.getElementById("renameROI").disabled = false;
         document.getElementById("renameROI").disabled = false;
         document.getElementById("index").disabled = false;
         document.getElementById("index").disabled = false;
+        document.getElementById("multiplier").style.display = "";
+        document.getElementById("multiplier_decshift").style.display = "";
+        document.getElementById("refx").disabled = false;
+        document.getElementById("refdx").disabled = false;
+        document.getElementById("refy").disabled = false;
+        document.getElementById("refdy").disabled = false;
+        document.getElementById("lockSizes").disabled = false;
+        document.getElementById("lockAspectRatio").disabled = false;
+        document.getElementById("lockSpaceEquidistant").disabled = false;
         document.getElementById("saveroi").disabled = false;
         document.getElementById("saveroi").disabled = false;
     }
     }
 
 
@@ -346,7 +492,7 @@ function UpdateROIs(_sel){
     }
     }
 
 
     if (aktindex > ROIInfo.length)
     if (aktindex > ROIInfo.length)
-        aktindex = ROIInfo.length;
+        aktindex = ROIInfo.length-1;
 
 
     for (var i = 0; i < ROIInfo.length; ++i){
     for (var i = 0; i < ROIInfo.length; ++i){
         var option = document.createElement("option");
         var option = document.createElement("option");
@@ -369,7 +515,9 @@ function UpdateROIs(_sel){
     document.getElementById("moveNext").disabled = false;
     document.getElementById("moveNext").disabled = false;
     if (aktindex == (ROIInfo.length-1)){
     if (aktindex == (ROIInfo.length-1)){
         document.getElementById("moveNext").disabled = true;
         document.getElementById("moveNext").disabled = true;
-    }  
+    }
+
+    ShowMultiplier();
     
     
     document.getElementById("lockAspectRatio").checked = lockAspectRatio;
     document.getElementById("lockAspectRatio").checked = lockAspectRatio;
     document.getElementById("lockSizes").checked = lockSizes;
     document.getElementById("lockSizes").checked = lockSizes;
@@ -390,7 +538,7 @@ function UpdateROIs(_sel){
     rect.startY = ROIInfo[aktindex]["y"];
     rect.startY = ROIInfo[aktindex]["y"];
     rect.w = ROIInfo[aktindex]["dx"];
     rect.w = ROIInfo[aktindex]["dx"];
     rect.h = ROIInfo[aktindex]["dy"];
     rect.h = ROIInfo[aktindex]["dy"];
-    draw();      
+    draw();
 }
 }
     
     
         function loadCanvas(dataURL) {
         function loadCanvas(dataURL) {
@@ -420,8 +568,20 @@ function UpdateROIs(_sel){
             var left = box.left + scrollLeft - clientLeft;
             var left = box.left + scrollLeft - clientLeft;
             return { top: Math.round(top), left: Math.round(left) };
             return { top: Math.round(top), left: Math.round(left) };
         }
         }
+
+
+        /* hash #description open the details part of the page */
+        function openDescription() {
+        if(window.location.hash) {
+            var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
+            if(hash == 'description')
+                document.getElementById("desc_details").open = true;
+            }
+        }
     
     
+
         function init() {
         function init() {
+            openDescription();
             domainname = getDomainname();
             domainname = getDomainname();
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mouseup', mouseUp, false);
             canvas.addEventListener('mouseup', mouseUp, false);
@@ -481,6 +641,8 @@ function UpdateROIs(_sel){
                 document.getElementById("space").value = space;
                 document.getElementById("space").value = space;
             }
             }
 
 
+            document.getElementById("saveroi").disabled = true;
+
             drawImage();
             drawImage();
             draw();
             draw();
         }
         }
@@ -523,10 +685,13 @@ function UpdateNUMBERS(_sel){
 
 
 function renameNumber(){
 function renameNumber(){
     var sel = document.getElementById("Numbers_value1");
     var sel = document.getElementById("Numbers_value1");
-    var _delte= sel.options[sel.selectedIndex].text;
-    var _numbernew = prompt("Please enter new name", _delte);
+    var _delete= sel.options[sel.selectedIndex].text;
+    var _numbernew = prompt("Please enter a new name for the selected number sequence", _delete);
+    if (_numbernew === null) {
+        return; //break out of the function early because prompt was aborted
+    }
 
 
-    erg = RenameNUMBER(_delte, _numbernew);
+    erg = RenameNUMBER(_delete, _numbernew);
     if (erg != "")
     if (erg != "")
         firework.launch(erg, 'danger', 30000);
         firework.launch(erg, 'danger', 30000);
     else
     else
@@ -534,21 +699,27 @@ function renameNumber(){
 }
 }
 
 
 function newNumber(){
 function newNumber(){
-    var _numbernew = prompt("Please enter name of new number", "name");
+    var _numbernew = prompt("Please enter a name for the new number sequence", "name");
+    if (_numbernew === null) {
+        return; //break out of the function early because prompt was aborted
+    }
 
 
     erg = CreateNUMBER(_numbernew);
     erg = CreateNUMBER(_numbernew);
     if (erg != "")
     if (erg != "")
-            firework.launch(erg, 'danger', 30000);
+        firework.launch(erg, 'danger', 30000);
     else
     else
         UpdateNUMBERS(_numbernew);
         UpdateNUMBERS(_numbernew);
 }
 }
 
 
 
 
 function removeNumber(){
 function removeNumber(){
-	if (confirm("This will remove the number complete (analog and digital).\nIf you only want to remove the digital ROIs, please use \"Delete ROIs\".\nDo you want to proceed?")) {
+	if (confirm("The entire number sequence will be removed (digit + analog parts). " +
+                "To remove single ROI of the number sequence, use \"Delete ROI\" instead.\n" +
+                "Do you really want to proceed?")) 
+    {
         var sel = document.getElementById("Numbers_value1");
         var sel = document.getElementById("Numbers_value1");
-        var _delte= sel.options[sel.selectedIndex].text;
-        erg = DeleteNUMBER(_delte);
+        var _delete= sel.options[sel.selectedIndex].text;
+        erg = DeleteNUMBER(_delete);
         if (erg != "")
         if (erg != "")
             firework.launch(erg, 'danger', 30000);
             firework.launch(erg, 'danger', 30000);
         UpdateNUMBERS();
         UpdateNUMBERS();
@@ -755,6 +926,7 @@ function draw() {
             }   
             }   
             draw();      
             draw();      
         }
         }
+        document.getElementById("saveroi").disabled = false;
     }
     }
 
 
     function valuemanualchangeddx(){
     function valuemanualchangeddx(){
@@ -780,6 +952,7 @@ function draw() {
 
 
             draw();            
             draw();            
         }
         }
+        document.getElementById("saveroi").disabled = false;
     }
     }
 
 
     function valuemanualchangedspace(){
     function valuemanualchangedspace(){
@@ -821,8 +994,10 @@ function draw() {
         sel = document.getElementById("index");
         sel = document.getElementById("index");
         var _roialt= sel.options[sel.selectedIndex].text;
         var _roialt= sel.options[sel.selectedIndex].text;
 
 
-
-        var _roinew = prompt("Please enter new name", _roialt);
+        var _roinew = prompt("Please enter a new name for the selected ROI", _roialt);
+        if (_roinew === null) {
+            return; //break out of the function early because prompt was aborted
+        }
 
 
         erg = RenameROI(_number, "digit", _roialt, _roinew);
         erg = RenameROI(_number, "digit", _roialt, _roinew);
         if (erg != "")
         if (erg != "")
@@ -833,6 +1008,7 @@ function draw() {
 
 
     function numberChanged()
     function numberChanged()
     {
     {
+        aktindex = 0;
         UpdateROIs();
         UpdateROIs();
     }    
     }    
 
 

+ 30 - 25
sd-card/html/edit_explain_0.html

@@ -1,10 +1,8 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
@@ -19,7 +17,7 @@ p {font-size: 1em;}
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-    <h2>Welcome to the Setup of the Digitizer</h2>
+    <h2>Welcome to the setup of the AI-on-the-edge-device</h2>
 
 
 
 
     <p>
     <p>
@@ -27,41 +25,48 @@ p {font-size: 1em;}
     </p>
     </p>
 
 
     <p>
     <p>
-        This is the first time you started the digitizer after the initial installation. You have been automatically routed to the <b>initial setup procedure</b>. 
-        Here you adjust the settings for your meter within five steps. In the final step the inital setup will be disabled and it will restart to the normal mode.
-        All settings will also be accessible there. See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/initial-setup target=_blank>
-            https://jomjol.github.io/AI-on-the-edge-device-docs/initial-setup</a> for additional explanations.</p>
+        This is the first time you started the device after the initial installation. You have been automatically routed to the <b>initial setup procedure</b>. 
+        With the prodecure the basic setup of your device within seven steps will be performed. After completion of all steps the setup mode will be completed
+        and the device restarts automatically to the regular web interface.<br>
+        Note: All settings of the initial setup will be also accessible using regular web interface.
+        See documentation: <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/initial-setup target=_blank>Initial setup procedure</a> for additional explanations.</p>
     </p>
     </p>
-    <p>You can navigate forward and backward during the setup with the buttons "Next" and "Previous".<br><br>
-        <span color=red>Do not forget to save in each step before heading to another step!</span><br>
+    <p> You can navigate forward and backward during the setup with the buttons "Next Step" and "Previous Step".<br>
+        With the button "Abort Setup" the setup will be skipped and abort screen will be presented.<br>
+        To restart the setup process, push the button "Restart Setup".
     </p>
     </p>
     <p>
     <p>
-        This is an overview over the five steps:
+        This is an overview over the seven steps:
     </p>    
     </p>    
-
     <p>
     <p>
     <ol>
     <ol>
-    <li><p>Create the <b>Reference Image</b>.<br>
+    <li><p>Adjust <b>lens focus</b> and check for <b>reflections of flashlight</b>.<br>
+        Ensure you camera lens has proper focus to object and flashlight do not create any distoring reflections.</p></li>
+    <li><p>Create the <b>reference image</b>.<br>
         It is the base for the position referencing and the identification of the digits and counters.</p></li>
         It is the base for the position referencing and the identification of the digits and counters.</p></li>
-    <li><p>Define two unique <b>Reference Marks</b>.<br>
-        They is used to align the individual camera images and identify the absolut positions.</p></li>
-    <li></p>Define <b>ROI's</b> for the <b>Digits</b>.<br>
+    <li><p>Define two unique <b>alignment marker</b>.<br>
+        They are used to perform an orientation alignment of the taken camera images before further processing</p></li>
+    <li></p>Define <b>ROI's</b> for the <b>digits</b>.<br>
         They will be used to digitize the digit part of your meter.<br>
         They will be used to digitize the digit part of your meter.<br>
-        If your meter has no digits, this step can be skipped.</p></li>
-    <li>Define <b>ROI's</b>> for the <b>Analog Counters</b>.<br>
+        NOTE: If your meter has no digits, this step can be skipped.</p></li>
+    <li>Define <b>ROI's</b> for the <b>analog counters</b>.<br>
         They will be used to digitize the analog part of your meter.<br>
         They will be used to digitize the analog part of your meter.<br>
-        If your meter has no analog counters, this step can be skipped.</p></li>
-    <li><p><b>General Settings</b><br>
-        Further configuration of your device.</p></li>
+        NOTE: If your meter has no analog counters, this step can be skipped.</p></li>
+    <li><p><b>Additional configuration:</b> List of all parameters<br>
+        Further configuration of your device can be done here.<br>
+        NOTE: This can also be performed later with regular web interface, e.g. to setup any publishing service like MQTT</p>
+    </li>
+    <li><p><b>Setup Completion:</b> End/Abort setup mode<br>
+        In the final step the setup mode needs to be properly terminated by pushing the button in this page.<br>
+        NOTE: This is important, otherwise the setup mode is recalled again after reboot.</p>
+    </li>
     </ol>
     </ol>
 
 
 <p>Please be patient when switching to another step. The device takes some time to load all needed information!</p>
 <p>Please be patient when switching to another step. The device takes some time to load all needed information!</p>
 
 
-<p>After step 5 the setup is completed, you then can reboot and starts into the normal operation mode.</p>
-
 <p>If you need support, have a look to the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs target=_blank>documentation</a> or the <a href=https://github.com/jomjol/AI-on-the-edge-device/discussions target=_blank>discussion</a> pages.</p>
 <p>If you need support, have a look to the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs target=_blank>documentation</a> or the <a href=https://github.com/jomjol/AI-on-the-edge-device/discussions target=_blank>discussion</a> pages.</p>
 
 
-<p><b>Have fun with your digitizer!</b></p>
+<p><b>Have fun with your AI-on-the-edge-device!</b></p>
 
 
 </body>
 </body>
 </html>
 </html>

+ 74 - 0
sd-card/html/edit_explain_7.html

@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="en" xml:lang="en"> 
+<head>
+<title>AI on the edge</title>
+<meta charset="UTF-8" />
+
+<style>
+h1 {font-size: 2em; margin-block-end: 0.3em;}
+h2 {font-size: 1.5em;margin-block-start: 0.3em;}
+h3 {font-size: 1.2em;}
+p {font-size: 1em;}
+
+
+.button {
+	padding: 5px 10px;
+    width: 205px;
+	font-size: 16px;	
+}
+
+
+</style>
+<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
+<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
+<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
+</head>
+
+<body style="font-family: arial">
+
+    <h4>Step 7 / 7: Initial setup completed!</h4>
+
+    <p>
+        Congratulations! You have completed the initial setup and you are now ready to restart to the regular operation mode!
+    </p>
+    <p>
+        Once you push the button below, the setup mode will be completed and the device will be automatically restart to regular web interface. 
+       If configuration is error free, the device will automatically start with first processing. It will take some time until you get the first reading.
+    </p>
+    <p>
+        <button class="button" onclick="reboot()">Complete Setup + Reboot</button>
+    </p>
+
+    <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
+    <script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script> 
+    <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script> 
+
+    <script type="text/javascript">
+    
+    function reboot() {
+        if (confirm("Do you want to complete the setup mode and switch to regular web interface?")) {
+            domainname = getDomainname(); 
+            if (!loadConfig(domainname)) {
+                firework.launch('Setup mode could not be deactivated! Please try again!', 'danger', 30000);
+                return;
+            } 
+            ParseConfig();	
+            param = getConfigParameters();
+            param["System"]["SetupMode"]["enabled"] = true;
+            param["System"]["SetupMode"]["value1"] = "false";
+
+            WriteConfigININew();
+            SaveConfigToServer(domainname);  
+
+            var stringota = getDomainname();
+            parent.location = stringota;
+            parent.location.href = stringota;
+            parent.location.assign(stringota);
+            parent.location.replace(stringota);
+        }
+    }
+
+    </script>
+
+</body>
+</html>

+ 18 - 23
sd-card/html/edit_explain_6.html → sd-card/html/edit_explain_7_abort.html

@@ -1,10 +1,8 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
@@ -14,8 +12,8 @@ p {font-size: 1em;}
 
 
 
 
 .button {
 .button {
-	padding: 5px 20px;
-    width: 211px;
+	padding: 5px 10px;
+    width: 205px;
 	font-size: 16px;	
 	font-size: 16px;	
 }
 }
 
 
@@ -28,15 +26,16 @@ p {font-size: 1em;}
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-    <h4>Step 6: Setup Completed!</h4>
+    <h4>Initial setup aborted!</h4>
 
 
-    <p>Congratulations, you completed the setup and are now ready to reboot to the normal mode!</p>
-    <p>Once you have pushed the button below, the setup modus will be left and the digitizer will restart to normal operation mode.<br>
-        The Web Interface will automatically reload. It will take some minutes until you get the first reading.
+    <p>You have <b>aborted</b> the initial setup!</p>
+    <p>Once you push the button below, the setup mode will be ended and the device will be automatically restart to regular web interface. 
+       Please be aware: The configuration of the device is not or only parly adapted to your needs!<br>
+       Configuration can still be adapted / completed using regular web interface.
     </p>
     </p>
 
 
     <p>
     <p>
-        <button class="button" onclick="reboot()">Leave Setup Modus and Reboot to Normal modus</button>
+        <button class="button" onclick="reboot()">Abort Setup + Reboot</button>
     </p>
     </p>
 
 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
@@ -44,15 +43,12 @@ p {font-size: 1em;}
     <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script> 
     <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script> 
 
 
     <script type="text/javascript">
     <script type="text/javascript">
-        var canvas = document.getElementById('canvas'),
-            domainname = getDomainname(); 
-            aktstatu = 0;
-    
+   
     function reboot() {
     function reboot() {
-        if (confirm("Do you want to leave the configuration mode and restart the ESP32?")) {
+        if (confirm("Do you want to abort the setup mode and switch to regular web interface?")) {
             domainname = getDomainname(); 
             domainname = getDomainname(); 
             if (!loadConfig(domainname)) {
             if (!loadConfig(domainname)) {
-                firework.launch('Setup Modus could not be deactivated! Please try again!', 'danger', 30000);
+                firework.launch('Setup mode could not be deactivated! Please try again!', 'danger', 30000);
                 return;
                 return;
             } 
             } 
             ParseConfig();	
             ParseConfig();	
@@ -63,12 +59,11 @@ p {font-size: 1em;}
             WriteConfigININew();
             WriteConfigININew();
             SaveConfigToServer(domainname);    
             SaveConfigToServer(domainname);    
 
 
-
-            var stringota = "/reboot";
-            window.location = stringota;
-            window.location.href = stringota;
-            window.location.assign(stringota);
-            window.location.replace(stringota);
+            var stringota = getDomainname();
+            parent.location = stringota;
+            parent.location.href = stringota;
+            parent.location.assign(stringota);
+            parent.location.replace(stringota); 
         }
         }
     }
     }
 
 

+ 227 - 111
sd-card/html/edit_reference.html

@@ -1,100 +1,175 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<title>Reference Image</title>
-<meta charset="utf-8"/>
-	
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
-
-input[type=number] {
-	width: 100px;
-	margin-right: 10px;
-	padding: 3px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
-
-.button {
-	padding: 5px 10px;
-    width: 210px;
-	font-size: 16px;
-}
-
-table {
-	padding: 5px;
-}
-</style>
-<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
-<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
-<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
+    <title>Reference Image</title>
+    <meta charset="utf-8"/>
+        
+    <style>
+        h1 {font-size: 2em;}
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
+        p {font-size: 1em;}
+
+        input[type=number] {
+            width: 60px;
+            margin-right: 10px;
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px;
+            vertical-align: middle;
+        }
+
+		input:out-of-range {
+			background-color: rgba(255, 0, 0, 0.25);
+			border: 1px solid red;
+        }
+
+		input:invalid {
+			background-color: rgba(255, 0, 0, 0.25);
+			border: 1px solid red;
+        }
+
+        .button {
+            padding: 5px 10px;
+            width: 205px;
+            font-size: 16px;
+        }
+
+        th, td {
+            padding: 5px 5px 5px 0px;
+        }
+
+        table {
+            width: 660px;
+            padding: 5px;
+        }
+    </style>
+
+    <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
+    <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
+    <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
     <h2>Reference Image</h2>
     <h2>Reference Image</h2>
-    <p>On this page you define the Reference Image.
-        See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/</a> for explanations.</p>
-    <p>After saving a new Reference Image, make sure to update the <a href=edit_alignment.html>Alignment Marks</a> and then
-        the <a href=edit_digits.html>digit</a> resp. <a href=edit_analog.html>analog</a> ROI's.<br>
-    Only after those steps a reboot is required.</p>
+    <details id="desc_details" style="font-size:16px">
+        <summary><b>CLICK HERE</b> for usage description. More infos in documentation: 
+                <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/ target=_blank>Reference Image</a>
+        </summary>
+        <p>
+            The reference image is the base image on which the alignment markers, digit ROIs and anlog ROIs will be defined.
+        </p>        
+        <p>
+            Firstly the actual saved reference image is shown. If you start with the setup from scratch a default image is shown as placeholder.
+            Use the button <b>"Create New Reference"</b> to start creation of your own reference image. After selecting the button all configured parameter
+            will be applied to the shown image. With the button <b>"Update Image"</b> you can update the image (still all parameter
+            get applied to the new image).
+        </p>        
+        <p>
+            To have reliable evaluation processing a properly horizontal aligned evaluation area is mandatory. Using the parameters "Rotation angle" and
+            "Rotation angle (Fine-tune)" the image can be rotated in both directions. The resulting rotation anlge is used to prerotate the image before
+            the alignment algorithm is processed to compensate only small misalignments. Further information can be found in documenation:
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/ target=_blank>Reference Image</a>
+        </p>
+        <p>
+            After setting up your reference image don't forget to save with the <b>"Save New Reference"</b> button!<br>
+            <b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps 
+            (reference image, alignment, ROI configuration) are completed to activate new configuration.
+        </p>
+    </details>
+    <hr />
 
 
 	<table>
 	<table>
-	  <tr>
-		<td><input class="button" type="button" value="Show Actual Reference" onclick="showReference(param)"></td>	  
-		<td><input class="button" type="button" value="Create New Reference" onclick="loadRawImage()"></td>
-		<td><input class="button" type="submit" id="take" onclick="doTake()" value="Take Image"></td>
-	  </tr> 
-	  <tr>
-		<td style="padding-top: 10px"><label for="mirror" id="labelmirror">Mirror Image:</label></td>
-        <td style="padding-top: 10px"><input type="checkbox" id="mirror" name="mirror" value="1" onchange="drawRotated()"></td>
-        <td>
-            <class id="TakeImage_LEDIntensity_text" style="color:black;">LEDIntensity: </class>
-            <input type="number" id="TakeImage_LEDIntensity_value1" size="13" value=0  min="0" max="100" style="float: right; clear: both;">
-        </td>
-      </tr>
-      <tr>
-
-		<td><label for="flip" id="labelflip">Flip Image Size:</label></td>
-        <td><input type="checkbox" id="flip" name="flip" value="1" onchange="drawRotated()"></td>
-        <td>
-            <class id="TakeImage_Brightness_text" style="color:black;">Brightness: </class>
-            <input type="number" id="TakeImage_Brightness_value1" size="13" value=0  min="-2" max="2" style="float: right; clear: both;">
-        </td>
-        
-	  </tr>
-	  <tr>
-        <td><label for="mirror">Pre-rotate Angle:</label></td>	  
-		<td><input type="number" id="prerotateangle" name="prerotateangle" value="0" min="-360" max="360" onchange="drawRotated()">Degrees</td>
-        <td>
-            <class id="TakeImage_Contrast_text" style="color:black;">Contrast</class>
-            <input type="number" id="TakeImage_Contrast_value1" size="13" value=0  min="-2" max="2" style="float: right; clear: both;">
-        </td>
-	  </tr>
-	  <tr>
-		<td><label for="mirror">Fine Alignment:</label></td>	
-		<td><input type="number" id="finerotate" name="finerotate" value=0.0 min="-1" max="1" step="0.2" onchange="drawRotated()">Degrees</td>
-        <td>
-            <class id="TakeImage_Saturation_text" style="color:black;">Saturation</class>
-            <input type="number" id="TakeImage_Saturation_value1" size="13" value=0   min="-2" max="2" style="float: right; clear: both;">
-        </td>
-
-    </tr>
-	</table>
-
-	<table>
-		<tr>			
-			<td><canvas id="canvas"></canvas></td>
-		</tr>			
-		<tr>		
-			<td><input class="button" type="button" id="updatereferenceimage" value="Save" onclick="SaveReference()">
-                <p>Proceed to update the <a href=edit_alignment.html>Alignment Marks</a> when you are done.</p></td>
-		</tr>
-	</table>
+        <colgroup>
+            <col span="1" style="width: 33.3%;">
+            <col span="1" style="width: 33.3%;">
+            <col span="1" style="width: 33.3%;">
+        </colgroup>
+        <tr>
+            <td><input class="button" type="button" value="Show Actual Reference" onclick="showReference(param)"></td>	  
+            <td><input class="button" type="button" id="startreference" value="Create New Reference" onclick="loadRawImage(false)"></td>
+            <td><input class="button" type="submit" id="take" onclick="doTake()" value="Update Image">
+        </tr>
+    </table>
+    <table>
+        <colgroup>
+            <col span="1" style="width: 32%;">
+            <col span="1" style="width: 28%;">
+            <col span="1" style="width: 18%;">
+            <col span="1" style="width: 22%;">
+        </colgroup>
+        <tr>
+            <td><label for="mirror" id="labelmirror">Mirror image:</label></td>
+            <td><input type="checkbox" id="mirror" name="mirror" value="1" onchange="drawRotated()"></td>
+            <td>
+                <class id="TakeImage_LEDIntensity_text" style="color:black;">LED intensity:</class>
+            </td>
+            <td>
+                <input required style="clear: both" type="number" id="TakeImage_LEDIntensity_value1" size="13" value="0"  min="0" max="100" 
+                    oninput="(!validity.rangeOverflow||(value=100)) && (!validity.rangeUnderflow||(value=0)) && 
+                        (!validity.stepMismatch||(value=parseInt(this.value)));">
+            </td>
+        </tr>
+        <tr>
+            <td><label for="flip" id="labelflip">Flip image size:</label></td>
+            <td><input type="checkbox" id="flip" name="flip" value="1" onchange="drawRotated()"></td>
+            <td>
+                <class id="TakeImage_Brightness_text" style="color:black;">Brightness:</class>
+            </td>
+            <td>
+                <input style="clear: both; width: 80%;vertical-align:middle" type="range" id="TakeImage_Brightness_value1" size="13" value=0  min="-2" max="2" oninput="this.nextElementSibling.value = this.value">
+                <output id="TakeImage_Brightness_value1_output" style="vertical-align:middle; min-width:15px; padding-right:5px; text-align:right; float:left">0</output>
+            </td>
+        </tr>
+        <tr>
+            <td><label for="prerotateangle">Rotation angle:</label></td>	  
+            <td>
+                <input required type="number" id="prerotateangle" name="prerotateangle" value="0" min="-360" max="360" onchange="drawRotated()"
+                        oninput="(!validity.rangeOverflow||(value=360)) && (!validity.rangeUnderflow||(value=-360)) && 
+                            (!validity.stepMismatch||(value=parseInt(this.value)));">degree
+                </td>
+            <td>
+                <class id="TakeImage_Contrast_text" style="color:black;">Contrast:</class>
+            </td>
+            <td>
+                <input style="clear: both; width: 80%;vertical-align:middle" type="range" id="TakeImage_Contrast_value1" size="13" value=0  min="-2" max="2" oninput="this.nextElementSibling.value = this.value">
+                <output id="TakeImage_Contrast_value1_output" style="vertical-align:middle; min-width:15px; padding-right:5px; text-align:right; float:left">0</output>
+            </td>
+        </tr>
+        <tr>
+            <td><label for="finerotate">Rotation angle (Fine-tune):</label></td>	
+            <td>
+                <input required type="number" id="finerotate" name="finerotate" value=0.0 min="-1" max="1" step="0.1" onchange="drawRotated()"
+                        oninput="(!validity.rangeOverflow||(value=1)) && (!validity.rangeUnderflow||(value=-1)) && 
+                            (!validity.stepMismatch||(value=parseInt(this.value)));">degree
+            </td>
+            <td>
+                <class id="TakeImage_Saturation_text" style="color:black;">Saturation:</class>
+            </td>
+            <td>
+                <input  style="clear: both; width: 80%;vertical-align:middle" type="range" id="TakeImage_Saturation_value1" size="13" value=0 min="-2" max="2" oninput="this.nextElementSibling.value = this.value">
+                <output id="TakeImage_Saturation_value1_output" style="vertical-align:middle; min-width:15px; padding-right:5px; text-align:right; float:left">0</output>
+            </td>
+        </tr>
+    </table>
+    <table>
+        <colgroup>
+            <col span="1" style="width: 33.3%;">
+            <col span="1" style="width: 33.3%;">
+            <col span="1" style="width: 33.3%;">
+        </colgroup>
+        <tr>
+            <td style="vertical-align: bottom;"><b>Reference Image:</b></td>
+            <td></td>
+            <td>
+                <input style="font-weight:bold;" class="button" type="button" id="updatereferenceimage" value="Save New Reference" onclick="SaveReference()">
+            </td>
+        </tr>
+        <tr>
+            <td colspan="3"><canvas id="canvas"></canvas></td>
+        </tr>	
+    </table>
 
 
 
 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
@@ -102,7 +177,6 @@ table {
     <script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>  
     <script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>  
     
     
     
     
-
     <script language="JavaScript">
     <script language="JavaScript">
         var canvas = document.getElementById('canvas'),
         var canvas = document.getElementById('canvas'),
             ctx = canvas.getContext('2d'),
             ctx = canvas.getContext('2d'),
@@ -110,7 +184,9 @@ table {
             domainname = getDomainname();   
             domainname = getDomainname();   
             isActReference = false;
             isActReference = false;
             param;
             param;
-            
+            new_image = false;
+
+       
         function doReboot() {
         function doReboot() {
             if (confirm("Are you sure you want to reboot? Did you save the config?")) {
             if (confirm("Are you sure you want to reboot? Did you save the config?")) {
                     var stringota = getDomainname() + "/reboot";
                     var stringota = getDomainname() + "/reboot";
@@ -121,6 +197,7 @@ table {
             }
             }
         }
         }
 
 
+
         function doTake(){ 
         function doTake(){ 
             var xhttp = new XMLHttpRequest();
             var xhttp = new XMLHttpRequest();
             if (param["TakeImage"]["Brightness"].found && param["TakeImage"]["Brightness"].enabled)
             if (param["TakeImage"]["Brightness"].found && param["TakeImage"]["Brightness"].enabled)
@@ -145,14 +222,22 @@ table {
             xhttp.send();
             xhttp.send();
 
 
 
 
-            loadRawImage();
+            loadRawImage(true);
         }
         }
-            
-        function loadRawImage(){
-            url = getDomainname() + "/img_tmp/raw.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);
+        
+
+        function loadRawImage(new_image) {
+            if (new_image) {
+                url = getDomainname() + "/img_tmp/raw.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);
+                document.getElementById("updatereferenceimage").disabled = false;
+            }
+            else {
+                document.getElementById("updatereferenceimage").disabled = true;
+            }
+
             document.getElementById("finerotate").disabled = false;
             document.getElementById("finerotate").disabled = false;
             document.getElementById("prerotateangle").disabled = false;  
             document.getElementById("prerotateangle").disabled = false;  
-            document.getElementById("updatereferenceimage").disabled = false;
+            document.getElementById("startreference").disabled = true;
             document.getElementById("take").disabled = false;
             document.getElementById("take").disabled = false;
             if (param["Alignment"]["InitialMirror"].found)
             if (param["Alignment"]["InitialMirror"].found)
                 document.getElementById("mirror").disabled = false;
                 document.getElementById("mirror").disabled = false;
@@ -190,12 +275,21 @@ table {
             isActReference = false;
             isActReference = false;
             loadCanvas(url);  
             loadCanvas(url);  
             drawRotated();          
             drawRotated();          
-        }    
+        }
+        
 
 
         function showReference(_param){
         function showReference(_param){
-            url = getDomainname() + "/fileserver/config/reference.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);;
-            document.getElementById("finerotate").value = 0;
-            document.getElementById("prerotateangle").value = _param["Alignment"]["InitialRotate"].value1;
+            url = getDomainname() + "/fileserver/config/reference.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);
+
+            if (_param["Alignment"]["InitialRotate"].value1 < 0) {
+                document.getElementById("prerotateangle").value = Math.ceil(_param["Alignment"]["InitialRotate"].value1);
+            }
+            else {
+                document.getElementById("prerotateangle").value = Math.floor(_param["Alignment"]["InitialRotate"].value1);
+            }
+
+            document.getElementById("finerotate").value = (Number(_param["Alignment"]["InitialRotate"].value1) - 
+                                                            Number(document.getElementById("prerotateangle").value)).toFixed(1);
 
 
             if (_param["Alignment"]["InitialMirror"].found && (_param["Alignment"]["InitialMirror"].value1 == "true"))
             if (_param["Alignment"]["InitialMirror"].found && (_param["Alignment"]["InitialMirror"].value1 == "true"))
                 document.getElementById("mirror").checked = true;
                 document.getElementById("mirror").checked = true;
@@ -206,6 +300,7 @@ table {
             document.getElementById("finerotate").disabled = true;
             document.getElementById("finerotate").disabled = true;
             document.getElementById("prerotateangle").disabled = true; 
             document.getElementById("prerotateangle").disabled = true; 
             document.getElementById("updatereferenceimage").disabled = true;
             document.getElementById("updatereferenceimage").disabled = true;
+            document.getElementById("startreference").disabled = false;
             document.getElementById("take").disabled = true;
             document.getElementById("take").disabled = true;
             document.getElementById("TakeImage_Brightness_value1").disabled = true;
             document.getElementById("TakeImage_Brightness_value1").disabled = true;
             document.getElementById("TakeImage_Saturation_value1").disabled = true;
             document.getElementById("TakeImage_Saturation_value1").disabled = true;
@@ -227,7 +322,8 @@ table {
             loadCanvas(url);
             loadCanvas(url);
             drawRotated(false, true);
             drawRotated(false, true);
         }
         }
-            
+        
+        
         function dataURLtoBlob(dataurl) {
         function dataURLtoBlob(dataurl) {
             var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
             var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
                 bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
                 bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
@@ -236,10 +332,12 @@ table {
             }
             }
             return new Blob([u8arr], {type:mime});
             return new Blob([u8arr], {type:mime});
         }			
         }			
-                
+        
+        
         function SaveReference(){
         function SaveReference(){
-            if (confirm("Are you sure you want to update the Reference Image?")) {
-                param["Alignment"]["InitialRotate"].value1 = document.getElementById("prerotateangle").value;
+            if (confirm("Are you sure you want to save the new reference image configuration?")) {
+                param["Alignment"]["InitialRotate"].value1 = (Number(document.getElementById("prerotateangle").value) + 
+                                                                Number(document.getElementById("finerotate").value)).toFixed(1);
 
 
                 if ((param["Alignment"]["InitialMirror"].found == true) && (document.getElementById("mirror").checked))
                 if ((param["Alignment"]["InitialMirror"].found == true) && (document.getElementById("mirror").checked))
                 {
                 {
@@ -268,14 +366,16 @@ table {
 
 
                 WriteConfigININew();
                 WriteConfigININew();
                 SaveConfigToServer(getDomainname());    
                 SaveConfigToServer(getDomainname());    
+                document.getElementById("updatereferenceimage").disabled = true;
 
 
                 SaveCanvasToImage(canvas, "/config/reference.jpg", true, getDomainname());
                 SaveCanvasToImage(canvas, "/config/reference.jpg", true, getDomainname());
                 showReference(param);
                 showReference(param);
                 UpdatePage();
                 UpdatePage();
-                firework.launch('Reference got saved. It will get applied after the next reboot!', 'success', 5000);
+                firework.launch('Reference image configuration saved. It will get applied after next reboot', 'success', 5000);  
             }
             }
         }
         }
 
 
+
         function loadCanvas(dataURL) {
         function loadCanvas(dataURL) {
                 var canvas = document.getElementById('canvas');
                 var canvas = document.getElementById('canvas');
                 var context = canvas.getContext('2d');
                 var context = canvas.getContext('2d');
@@ -303,7 +403,19 @@ table {
             return { top: Math.round(top), left: Math.round(left) };
             return { top: Math.round(top), left: Math.round(left) };
         }
         }
 
 
+        
+        /* hash #description open the details part of the page */
+        function openDescription() {
+        if(window.location.hash) {
+            var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
+            if(hash == 'description')
+                document.getElementById("desc_details").open = true;
+            }
+        }
+    
+
         function init() {
         function init() {
+            openDescription();
             canvas.addEventListener('mousemove', mouseMove, false);    
             canvas.addEventListener('mousemove', mouseMove, false);    
             loadConfig(getDomainname()); 
             loadConfig(getDomainname()); 
             ParseConfig();
             ParseConfig();
@@ -339,10 +451,11 @@ table {
             showReference(param); 
             showReference(param); 
         }
         }
 
 
+
         function UpdateInput() {
         function UpdateInput() {
-            WriteParameter(param, category, "TakeImage", "Brightness", false);		
-            WriteParameter(param, category, "TakeImage", "Contrast", false);		
-            WriteParameter(param, category, "TakeImage", "Saturation", false);		
+            WriteParameter(param, category, "TakeImage", "Brightness", false, true);		
+            WriteParameter(param, category, "TakeImage", "Contrast", false, true);		
+            WriteParameter(param, category, "TakeImage", "Saturation", false, true);		
             WriteParameter(param, category, "TakeImage", "LEDIntensity", false);		
             WriteParameter(param, category, "TakeImage", "LEDIntensity", false);		
         }
         }
 
 
@@ -365,7 +478,7 @@ table {
         }
         }
         
         
 
 
-        function WriteParameter(_param, _category, _cat, _name, _optional, _select = false, _anzpara = 1){
+        function WriteParameter(_param, _category, _cat, _name, _optional, outval = false, _select = false, _anzpara = 1){
             if (_param[_cat][_name]["found"]){
             if (_param[_cat][_name]["found"]){
                 if (_optional) {
                 if (_optional) {
                     document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"];
                     document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"];
@@ -389,7 +502,8 @@ table {
                         document.getElementById(_cat+"_"+_name+"_value"+j).value = _param[_cat][_name]["value"+j];
                         document.getElementById(_cat+"_"+_name+"_value"+j).value = _param[_cat][_name]["value"+j];
                     }
                     }
                 }
                 }
-
+                if (outval)
+                    document.getElementById(_cat+"_"+_name+"_value1_output").value = document.getElementById(_cat+"_"+_name+"_value1").value;
             }
             }
             else {
             else {
                 if (_optional) {
                 if (_optional) {
@@ -461,6 +575,7 @@ table {
 
 
         }
         }
 
 
+
         function drawGrid(){
         function drawGrid(){
             var canvas = document.getElementById('canvas');
             var canvas = document.getElementById('canvas');
             var ctx = canvas.getContext('2d');
             var ctx = canvas.getContext('2d');
@@ -489,6 +604,7 @@ table {
             ctx.restore();
             ctx.restore();
         }
         }
 
 
+
         function mouseMove(e) {
         function mouseMove(e) {
             drawRotated();
             drawRotated();
             var canvas = document.getElementById('canvas');
             var canvas = document.getElementById('canvas');
@@ -508,8 +624,8 @@ table {
             context.stroke();            
             context.stroke();            
         }
         }
 
 
-
         init();
         init();
+    
     </script>
     </script>
 
 
 </body>
 </body>

+ 16 - 17
sd-card/html/explain_1.html

@@ -1,34 +1,33 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
+
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
-
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h3 {font-size: 1.2em;}
 h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
-
-
-
 </style>
 </style>
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<h4>Step 1: Define a Reference Image</h4>
-The reference image is the base to define the digits, counters and references positions.
-<p>
-    Firstly you see the default image. Use the Button "Create New Reference" to start to create your own reference image.<br>
-    Most important feature is a straight alignment of the image. Use the Pre-rotate angle and the fine alignment to adjust the rotation of the image.
-</p>
-<p>
-    Don't forget to save your changes with the <b>"Save"</b> button!
-</p>
+    <h4>Step 1 / 7: Adjust Focus And Verify Flashlight</h4>
+        Firstly you have find a proper mounting position and potentially have to adjust the focus of the camera lens to get a sharp and crisp image. 
+        This <b>live stream with flashlight on</b> could be helpful for this task. More details about adjusting the camera lens can be found here:
+        <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/#focus target=_blank>Focus Adjustment</a><br>
+        Additionally it should be verfied that the flashlight is not creating any distrubing reflection in the processing relevant areas. 
+        Beside using the built-in internal flash LED it's also possible to attach additional external LEDs to the device to have more possiblities 
+        to get proper light condition. Please read the documentation if you'd like to use extenal LEDs:
+        <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/External-LED/ target=_blank>Installation Of External LEDs</a>
+    <p>
+        NOTE: The flashlight indensity is set to default (50%) for initial verfication in this step and can be modified in next step. After modification
+        you can come back to this step if you'd like to test with adjusted light intensity.<br>
+        The live stream can also be called at any time also after setup mode is completed on regular web interface.
+    </p>
 
 
 </body>
 </body>
 </html>
 </html>

+ 4 - 17
sd-card/html/explain_2.html

@@ -1,34 +1,21 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
+
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h3 {font-size: 1.2em;}
 h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
-
-
-
 </style>
 </style>
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<h4>Step 2: Define two Alignment Marks</h4>
-Two opposite alignment marks are needed to identify unique fix points on the image.
-<p>
-    Mark the reference by drag and dop with the mouse or with the coordinates and push <b>"Update Reference"</b>.
-    <br> 
-    You can switch between the two reference with <b>"Select Reference"</b>.
-</p>
-<p>
-    Don't forget to save your changes with the <b>"Save"</b> button!
-</p>
+    <h4>Step 2 / 7: Create A Reference Image</h4>
 
 
 </body>
 </body>
 </html>
 </html>

+ 4 - 19
sd-card/html/explain_3.html

@@ -1,36 +1,21 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
+
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
-
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h3 {font-size: 1.2em;}
 h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
-
-
-
 </style>
 </style>
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<h4>Step 3: Define ROI's for your Digits</h4>
-Here you define your digits you want to read. If you have more than one number on the reading you can define several numbers with the <b>"Number"</b> selector. There you can also define new numbers.
-<p>
-    With the drop down menue <b>"ROI x"</b> you can change between the different digits. Mark them with the mouse or the coordinates.
-    <br>
-    To create new ROIs use <b>"New ROIs"</b>. The order of the ROIs defines the positon within the reading. <br>
-    You can change it with <b>"move Next" / "move Previous"</b>.
-</p>
-<p>
-    Don't forget to save your changes with the <b>"Save"</b> button!
-</p>
+    <h4>Step 3 / 7: Definement Of Alignment Marker</h4>
 
 
 </body>
 </body>
 </html>
 </html>

+ 4 - 18
sd-card/html/explain_4.html

@@ -1,35 +1,21 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
+
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h3 {font-size: 1.2em;}
 h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
-
-
-
 </style>
 </style>
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<h4>Step 4: Define ROI's for your Analog Counters</h4>
-Here you define your analog counters you want to read. If you have more than one number on the reading you can define several numbers with the <b>"Number"</b> selector. There you can also define new numbers. If you do not have analog counters delete all ROIs.
-<p>
-    With the drop down menue <b>"ROI x"</b> you can change between the different counters. Mark them with the mouse or the coordinates.
-    <br>
-    To create new ROIs use <b>"New ROIs"</b>. The order of the ROIs defines the positon within the reading. <br>
-    You can change it with <b>"move Next" / "move Previous"</b>.
-</p>
-<p>
-    Don't forget to save your changes with the <b>"Save"</b> button!
-</p>
+    <h4>Step 4 / 7: Configuration Of ROIs For Digit Numbers</h4>
 
 
 </body>
 </body>
 </html>
 </html>

+ 6 - 16
sd-card/html/explain_5.html

@@ -1,31 +1,21 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
+
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta charset="UTF-8" />
 
 
-<style>
+<style>  
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h3 {font-size: 1.2em;}
 h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
-
-
-
 </style>
 </style>
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<h4>Step 5: General Configuration Settings</h4>
-<p>Here you can define additional settings. The default settings should fit for a normal/initial setup.</p>
-<p>You will also be able to change them later, so don't worry if you do not understand the parameters yet!</p>
-</p>
-<p>
-    Don't forget to save your changes with the <b>"Save"</b> button!
-</p>
+    <h4>Step 5 / 7: Configuration Of ROIs For Analog Counters</h4>
 
 
 </body>
 </body>
-</html>
+</html>

+ 23 - 1
sd-card/html/explain_6.html

@@ -1 +1,23 @@
-<!-- This page is never shown -->
+<!DOCTYPE html>
+<html lang="en" xml:lang="en"> 
+
+<head>
+<title>AI on the edge</title>
+<meta charset="UTF-8" />
+
+<style>  
+h1 {font-size: 2em; margin-block-end: 0.3em;}
+h2 {font-size: 1.5em;margin-block-start: 0.3em;}
+h3 {font-size: 1.2em;}
+p {font-size: 1em;}
+</style>
+</head>
+
+<body style="font-family: arial">
+
+    <h4>Step 6 / 7: Configuration Page: List Of All Parameters</h4>
+    <p>
+        NOTE: All parameter can be edited later in the regular web interface. So don't worry if you do not understand the parameters yet!
+    </p>
+</body>
+</html>

+ 1 - 0
sd-card/html/explain_7.html

@@ -0,0 +1 @@
+<!-- This page is never shown -->

+ 154 - 123
sd-card/html/file_server.html

@@ -1,9 +1,15 @@
-<html>
+<!DOCTYPE html>
+<html lang="en" xml:lang="en"> 
     <head>
     <head>
         <link href="/firework.css?v=$COMMIT_HASH" rel="stylesheet">
         <link href="/firework.css?v=$COMMIT_HASH" rel="stylesheet">
         <script type="text/javascript" src="/jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
         <script type="text/javascript" src="/jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
         <script type="text/javascript" src="/firework.js?v=$COMMIT_HASH"></script>
         <script type="text/javascript" src="/firework.js?v=$COMMIT_HASH"></script>
         <style>
         <style>
+            h1 {font-size: 2em;}
+            h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+            h3 {font-size: 1.2em;}
+            p {font-size: 1em;}
+
             #files_table {
             #files_table {
                 font-family: Arial, Helvetica, sans-serif;
                 font-family: Arial, Helvetica, sans-serif;
                 border-collapse: collapse;
                 border-collapse: collapse;
@@ -27,147 +33,172 @@
                 padding-top: 12px;
                 padding-top: 12px;
                 padding-bottom: 12px;
                 padding-bottom: 12px;
                 text-align: left;
                 text-align: left;
-                background-color: #0011ff;
-                color: white;
+                background-color:lightgrey;
+                color: black;
+            }
+
+            input[type=file] {
+                padding: 5px 0px;
+                display: inline-block;
+                font-size: 16px; 
             }
             }
+
+            input[type=text] {
+                padding: 5px 10px;
+                display: inline-block;
+                border: 1px solid #ccc;
+                font-size: 16px; 
+            }
+
+            .button {
+                padding: 4px 10px;
+                width: 100px;
+                font-size: 16px;	
+		    }
         </style>
         </style>
     </head>
     </head>
-</body>
-<table class="fixed" border="0" width=100% style="font-family: arial">
-    <tr><td>
-        <h2>Content on SD-Card</h2>
-    </td>
-    <td rowspan="2" width="500px">
-        <table border="0">
+    
+    </body>
+        <table class="fixed" border="0" width=100% style="font-family: arial">
             <tr>
             <tr>
-                <td>
-                    <label for="newfile">Upload a file</label>
+                <td style="vertical-align: top;width: 300px;">
+                    <h2>Fileserver</h2>
                 </td>
                 </td>
-                <td colspan="2">
-                    <input id="newfile" type="file" onchange="setpath()" style="width:100%;">
+                <td rowspan="2">
+                    <table border="0" style="width:100%">
+                        <tr>
+                            <td style="width:80px">
+                                <label for="newfile">Source</label>
+                            </td>
+                            <td colspan="2">
+                                <input id="newfile" type="file" onchange="setpath()" style="width:100%;">
+                            </td>
+                        </tr>
+                        
+                        <tr>
+                            <td>
+                                <label for="filepath">Destination</label>
+                            </td>
+                            <td>
+                                <input id="filepath" type="text" style="width:94%;">
+                            </td>
+                            <td>
+                                <button id="upload" type="button" class="button" onclick="upload()">Upload</button>
+                            </td>
+                        </tr>
+                    </table>
                 </td>
                 </td>
             </tr>
             </tr>
+            <tr></tr>
             <tr>
             <tr>
-                <td>
-                    <label for="filepath">Set path on server</label>
-                </td>
-                <td>
-                    <input id="filepath" type="text" style="width:100%;">
-                </td>
-                <td>
-                    <button id="upload" type="button" onclick="upload()">Upload</button>
+                <td colspan="2">
+                    <button style="font-size:16px; padding: 5px 10px" id="dirup" type="button" onclick="dirup()" disabled>&#129145; Directory up</button>
+                    <span style="padding-left:15px" id="currentpath"></span>
                 </td>
                 </td>
             </tr>
             </tr>
         </table>
         </table>
-    </td></tr>
-    <tr>
-        <td>
-            <span id="currentpath"></span> &nbsp;&nbsp;&nbsp;&nbsp;<button id="dirup" type="button" onclick="dirup()" disabled>&#129041; Directory up</button>
-        </td>
-    </tr>
-</table>
-
-<script type="text/javascript" src="/common.js?v=$COMMIT_HASH"> 
-</script>            
-<script language="JavaScript">
-function setpath() {
-    var fileserverpraefix = "/fileserver";
-    var anz_zeichen_fileserver = fileserverpraefix.length;
-    var default_path = window.location.pathname.substring(anz_zeichen_fileserver) + document.getElementById("newfile").files[0].name;
-    document.getElementById("filepath").value = default_path;
-}
-
-function dirup() {
-    var str = window.location.href;
-    str = str.substring(0, str.length-1);
-	var zw = str.indexOf("/");
-	var found = zw;
-	while (zw >= 0)
-	{
-		zw = str.indexOf("/", found+1);  
-		if (zw >= 0)
-			found = zw;
-	}
-	var res = str.substring(0, found+1);
-
-	window.location.href = res;	
-}
-
-
-function upload() {
-    var filePath = document.getElementById("filepath").value;
-    var upload_path = "/upload/" + filePath;
-    var fileInput = document.getElementById("newfile").files;
-
-    /* Max size of an individual file. Make sure this
-     * value is same as that set in file_server.c */
-    var MAX_FILE_SIZE = 8000*1024;
-    var MAX_FILE_SIZE_STR = "8000KB";
-
-    if (fileInput.length == 0) {
-        firework.launch('No file selected!', 'danger', 30000);
-    } else if (filePath.length == 0) {
-        firework.launch('File path on server is not set!', 'danger', 30000);
-    } else if (filePath.length > 100) {
-        firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000);
-    } else if (filePath.indexOf(' ') >= 0) {
-        firework.launch('File path on server cannot have spaces!', 'danger', 30000);
-    } else if (filePath[filePath.length-1] == '/') {
-        firework.launch('File name not specified after path!', 'danger', 30000);
-    } else if (fileInput[0].size > MAX_FILE_SIZE) {
-        firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000);
-    } else {
-        document.getElementById("newfile").disabled = true;
-        document.getElementById("filepath").disabled = true;
-        document.getElementById("upload").disabled = true;
-
-        var file = fileInput[0];
-        var xhttp = new XMLHttpRequest();
-        xhttp.onreadystatechange = function() {
-            if (xhttp.readyState == 4) {
-                if (xhttp.status == 200) {
-                    document.open();
-                    document.write(xhttp.responseText);
-                    document.close();
-                } else if (xhttp.status == 0) {
-                    firework.launch('Server closed the connection abruptly!', 'danger', 30000);
-                    UpdatePage(false);
-                } else {
-                    firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
-                    UpdatePage(false);
-                }
-            }
-        };
-        xhttp.open("POST", upload_path, true);
-        xhttp.send(file);
-    }
-}
 
 
+        <script type="text/javascript" src="/common.js?v=$COMMIT_HASH"> 
+        </script>            
+        <script language="JavaScript">
+        function setpath() {
+            var fileserverpraefix = "/fileserver";
+            var anz_zeichen_fileserver = fileserverpraefix.length;
+            var default_path = window.location.pathname.substring(anz_zeichen_fileserver) + document.getElementById("newfile").files[0].name;
+            document.getElementById("filepath").value = default_path;
+        }
+
+        function dirup() {
+            var str = window.location.href;
+            str = str.substring(0, str.length-1);
+            var zw = str.indexOf("/");
+            var found = zw;
+            while (zw >= 0)
+            {
+                zw = str.indexOf("/", found+1);  
+                if (zw >= 0)
+                    found = zw;
+            }
+            var res = str.substring(0, found+1);
+
+            window.location.href = res;	
+        }
+
+
+        function upload() {
+            var filePath = document.getElementById("filepath").value;
+            var upload_path = "/upload/" + filePath;
+            var fileInput = document.getElementById("newfile").files;
+
+            /* Max size of an individual file. Make sure this
+            * value is same as that set in file_server.c */
+            var MAX_FILE_SIZE = 8000*1024;
+            var MAX_FILE_SIZE_STR = "8000KB";
+
+            if (fileInput.length == 0) {
+                firework.launch('No file selected!', 'danger', 30000);
+            } else if (filePath.length == 0) {
+                firework.launch('File path on server is not set!', 'danger', 30000);
+            } else if (filePath.length > 100) {
+                firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000);
+            } else if (filePath.indexOf(' ') >= 0) {
+                firework.launch('File path on server cannot have spaces!', 'danger', 30000);
+            } else if (filePath[filePath.length-1] == '/') {
+                firework.launch('File name not specified after path!', 'danger', 30000);
+            } else if (fileInput[0].size > MAX_FILE_SIZE) {
+                firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000);
+            } else {
+                document.getElementById("newfile").disabled = true;
+                document.getElementById("filepath").disabled = true;
+                document.getElementById("upload").disabled = true;
+
+                var file = fileInput[0];
+                var xhttp = new XMLHttpRequest();
+                xhttp.onreadystatechange = function() {
+                    if (xhttp.readyState == 4) {
+                        if (xhttp.status == 200) {
+                            document.open();
+                            document.write(xhttp.responseText);
+                            document.close();
+                            firework.launch('File upload completed', 'success', 5000);
+                        } else if (xhttp.status == 0) {
+                            firework.launch('Server closed the connection abruptly!', 'danger', 30000);
+                            UpdatePage(false);
+                        } else {
+                            firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
+                            UpdatePage(false);
+                        }
+                    }
+                };
+                xhttp.open("POST", upload_path, true);
+                xhttp.send(file);
+            }
+        }
 
 
-function checkAtRootLevel(res) {
-    if (getPath() == "/fileserver/") { // Already at root level
-        document.getElementById("dirup").disabled = true;
-        console.log("Already on sd-card root level!");
-        return true;
-    }
 
 
-    document.getElementById("dirup").disabled = false;
-    return false;
-}
+        function checkAtRootLevel(res) {
+            if (getPath() == "/fileserver/") { // Already at root level
+                document.getElementById("dirup").disabled = true;
+                console.log("Already on sd-card root level!");
+                return true;
+            }
 
 
+            document.getElementById("dirup").disabled = false;
+            return false;
+        }
 
 
-function getPath() {
-    return window.location.pathname.replace(/\/+$/, '') + "/"
-}
 
 
-checkAtRootLevel();
+        function getPath() {
+            return window.location.pathname.replace(/\/+$/, '') + "/"
+        }
 
 
-console.log("Current path: " + getPath().replace("/fileserver", ""));
-document.getElementById("currentpath").innerHTML = "Current path: <b>" + getPath().replace("/fileserver", "") + "</b>";
+        checkAtRootLevel();
 
 
-document.cookie = "page=" + getPath() + "; path=/";
+        console.log("Current path: " + getPath().replace("/fileserver", ""));
+        document.getElementById("currentpath").innerHTML = "Current path: <b>" + getPath().replace("/fileserver", "") + "</b>";
 
 
-</script>
+        document.cookie = "page=" + getPath() + "; path=/";
 
 
-</body>
+        </script>
+    </body>
 </html>
 </html>

+ 4 - 2
sd-card/html/firework.css

@@ -4,13 +4,15 @@
   border-color: #888;
   border-color: #888;
   border-radius: 6px;
   border-radius: 6px;
   color: #fff;
   color: #fff;
-  left: 200px;
+  left: 10%;
   padding: 5px;
   padding: 5px;
   position: fixed;
   position: fixed;
   opacity: 0;
   opacity: 0;
   text-align: center;
   text-align: center;
   top: 0px;
   top: 0px;
-  width: 600px;
+  width: 80%;
+  min-width:30%;
+  max-width:580px;
   z-index: 99;
   z-index: 99;
   font-size:120%;
   font-size:120%;
 }
 }

+ 1 - 1
sd-card/html/firework.js

@@ -29,7 +29,7 @@
         p += parseInt($(this).height()) + 30
         p += parseInt($(this).height()) + 30
       });
       });
 
 
-      $('<div id="'+ fid +'" class="'+ c +'">'+ m +'<a onclick="firework.remove(\'#'+ fid +'\')"><img src=close.png></a></div>')
+      $('<div id="'+ fid +'" class="'+ c +'">'+ m +'<a onclick="firework.remove(\'#'+ fid +'\')"><img style="height:28px;" src=close.png></a></div>')
         .appendTo('body')
         .appendTo('body')
         .animate({
         .animate({
           opacity: 1,
           opacity: 1,

+ 56 - 24
sd-card/html/graph.html

@@ -1,16 +1,40 @@
-<html>
-    <head>
+<!DOCTYPE html>
+<html lang="en" xml:lang="en"> 
+<head>
+    <title>Data Graph</title>
     <script type="text/javascript" src='plotly-basic-2.18.2.min.js?v=$COMMIT_HASH'></script>
     <script type="text/javascript" src='plotly-basic-2.18.2.min.js?v=$COMMIT_HASH'></script>
 
 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>  
     <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>  
-    <script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>  
+    <script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
+    
     <style>
     <style>
+        h1 {font-size: 2em;}
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
+        p {font-size: 1em;}
+
         body {
         body {
             font-family: Arial, Helvetica, sans-serif;
             font-family: Arial, Helvetica, sans-serif;
         }
         }
+
+        select {
+            padding: 3px 5px;
+            display: inline-block;
+            border: 1px solid #ccc;
+            font-size: 16px; 
+            margin-right: 10px;
+            min-width: 100px;
+            vertical-align: middle;
+        }
+
+        .button {
+            padding: 5px 10px;
+            width: 160px;
+            font-size: 16px;
+        }
     </style>
     </style>
-  
+
     <script>
     <script>
     function run() {
     function run() {
         datefile = document.getElementById("datafiles").value;
         datefile = document.getElementById("datafiles").value;
@@ -23,7 +47,7 @@
         .then(response => {
         .then(response => {
             // handle the response
             // handle the response
             if (response.status == 404) {
             if (response.status == 404) {
-                firework.launch("No log data available for " + dateString, 'warning', 10000);
+                firework.launch("No data available for " + dateString, 'warning', 10000);
             }
             }
             response.text()
             response.text()
             .then( result => {
             .then( result => {
@@ -132,17 +156,17 @@
                     },
                     },
 
 
                     margin: {
                     margin: {
-                        l: 50,
-                        r: 50,
+                        l: 70,
+                        r: 70,
                         b: 50,
                         b: 50,
-                        t: 50,
+                        t: 40,
                         pad: 4
                         pad: 4
                     },
                     },
 
 
                     legend: {
                     legend: {
-                        x: 0.2,
-                        y: 0.9,
-                        xanchor: 'right'
+                        x: 0.02,
+                        y: 0.97,
+                        xanchor: 'left'
                     }
                     }
                 };
                 };
 
 
@@ -158,19 +182,19 @@
     <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
     <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
     <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
     <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
     <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
     <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
-    </head>
-    <body>
-        <h3>Data Graph</h3>
-        <div id='chart'><p>Loading...<br></p></div>
-        <select id="datafiles" onchange="run();"></select>
-        <select id="numbers" onchange="run();"></select>
-        <input type="checkbox" id="showRrelativeValues" onclick = 'run();' unchecked ><label for="showRrelativeValues">Show relative values</label>
-        <button onclick="run();">Refresh</button>
-        &nbsp;&nbsp;|&nbsp;&nbsp;
-        <button onClick="window.location.href = 'data.html?v=$COMMIT_HASH'">Show data</button>
-        <button onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show data files</button>
-
-</div>
+</head>
+
+<body>
+    <h2>Data Graph</h2>
+    <div id='chart'><p>Loading...<br></p></div>
+    Number sequence:
+    <select id="numbers" onchange="run();"></select>
+    Day:
+    <select id="datafiles" onchange="run();"></select>
+    <input type="checkbox" id="showRrelativeValues" onclick = 'run();' unchecked ><label for="showRrelativeValues">Show relative values</label><br><br>
+    <button class="button" onclick="run();">Refresh</button>
+    <button class="button" onClick="window.location.href = 'data.html?v=$COMMIT_HASH'">Show Data Viewer</button>
+    <button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
 
 
 <script>
 <script>
     function WriteModelFiles()
     function WriteModelFiles()
@@ -214,7 +238,15 @@
     WriteModelFiles();
     WriteModelFiles();
     WriteNumbers();
     WriteNumbers();
 
 
+    function Refresh() {
+        setTimeout (function() {
+            run();
+            Refresh();
+        }, 300000);
+    }
+
     run();
     run();
+    Refresh();
 </script>
 </script>
 </body>
 </body>
 </html>
 </html>

+ 146 - 67
sd-card/html/index.html

@@ -1,65 +1,76 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en">
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<title>AI on the edge</title>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="stylesheet" href="style.css?v=$COMMIT_HASH" type="text/css" >
-<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
-
-<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
-<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
-<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
-
-<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
-<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
-<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
-
-<script>
-    async function loadPage(page) {
-        console.log("loadPage(" + page + ")");
-        document.cookie = "page="+page + "; path=/";
-        document.getElementById('maincontent').src = page;
-
-        [].forEach.call(document.querySelectorAll('.submenu'), function (el) {
-            el.style.visibility = 'hidden';
-        });
-    }
+    <link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
+    <title>AI on the edge</title>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="stylesheet" href="style.css?v=$COMMIT_HASH" type="text/css" >
+    <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
+
+    <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
+    <script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
+    <script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
+
+    <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
+    <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
+
+    <script>
+        var streamPopup;
+        var streamFlashlight = false;
+        var streamWindowFeatures =
+                'channelmode=no,directories=no,fullscreen=no,' +
+                'location=no,dependent=yes,menubar=no,resizable=no,scrollbars=no,' +
+                'status=no,toolbar=no,titlebar=no,' +
+                'left=10,top=250,width=640px,height=480px';
+
+        async function loadPage(page) {
+            if (streamPopup)   // Ensure that stream popup is closed because it's blocking web interface
+                streamPopup.close();
+
+            console.log("loadPage(" + page + ")");
+            document.cookie = "page="+page + "; path=/";
+            document.getElementById('maincontent').src = page;
+
+            [].forEach.call(document.querySelectorAll('.submenu'), function (el) {
+                el.style.visibility = 'hidden';
+            });
+        }
 
 
-    function resetMenu() {
-        [].forEach.call(document.querySelectorAll('.submenu'), function (el) {
-            el.style.visibility = 'visible';
-        });
-    }
-    
-    function getCookie(cname) {
-      let name = cname + "=";
-      let decodedCookie = decodeURIComponent(document.cookie);
-      let ca = decodedCookie.split(';');
-      for(let i = 0; i <ca.length; i++) {
-        let c = ca[i];
-        while (c.charAt(0) == ' ') {
-          c = c.substring(1);
+        function resetMenu() {
+            [].forEach.call(document.querySelectorAll('.submenu'), function (el) {
+                el.style.visibility = 'visible';
+            });
         }
         }
-        if (c.indexOf(name) == 0) {
-          return c.substring(name.length, c.length);
+        
+        function getCookie(cname) {
+        let name = cname + "=";
+        let decodedCookie = decodeURIComponent(document.cookie);
+        let ca = decodedCookie.split(';');
+        for(let i = 0; i <ca.length; i++) {
+            let c = ca[i];
+            while (c.charAt(0) == ' ') {
+            c = c.substring(1);
+            }
+            if (c.indexOf(name) == 0) {
+            return c.substring(name.length, c.length);
+            }
         }
         }
-      }
-      return "";
-    }        
-</script>
-
+        return "";
+        }        
+    </script>
 </head>
 </head>
 
 
 <body>
 <body>
 <div class="main">
 <div class="main">
 
 
-<table style="border: none">
-  <tr><td style="padding-right: 10px;"><img src="favicon.ico?v=$COMMIT_HASH"></td>
-    <td><h1 id="id_title"> Digitizer - AI on the edge</h1>
-        <h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
-    </td></tr>
+<table style="border: none; width:100%">
+    <tr>
+        <td style="padding-right: 10px;"><img style="width:64px; height:64px" src="favicon.ico?v=$COMMIT_HASH"></td>
+        <td><h1 id="id_title"> Digitizer - AI on the edge</h1>
+            <h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
+        </td>
+    </tr>
 </table>
 </table>
 
 
 <div class="menu" onmouseover="resetMenu()">
 <div class="menu" onmouseover="resetMenu()">
@@ -67,24 +78,24 @@
     <li><a href="#" onclick="loadPage('overview.html?v=$COMMIT_HASH');">Overview</a></li>
     <li><a href="#" onclick="loadPage('overview.html?v=$COMMIT_HASH');">Overview</a></li>
     <li><a>Settings <i class="arrow down"></i></a>
     <li><a>Settings <i class="arrow down"></i></a>
       <ul class="submenu">
       <ul class="submenu">
-        <li><a href="#" onclick="loadPage('prevalue_set.html?v=$COMMIT_HASH');">Set Previous Value</a></li>
+        <li><a href="#" onclick="loadPage('prevalue_set.html?v=$COMMIT_HASH');">Set "Previous Value"</a></li>
         <li><a href="#" onclick="loadPage('edit_config_param.html?v=$COMMIT_HASH');">Configuration</a></li>
         <li><a href="#" onclick="loadPage('edit_config_param.html?v=$COMMIT_HASH');">Configuration</a></li>
         <li><a>Alignment <i class="arrow right"></i></a>
         <li><a>Alignment <i class="arrow right"></i></a>
             <ul>
             <ul>
                 <li><a href="#" onclick="loadPage('edit_reference.html?v=$COMMIT_HASH');">Reference Image</a></li>
                 <li><a href="#" onclick="loadPage('edit_reference.html?v=$COMMIT_HASH');">Reference Image</a></li>
-                <li><a href="#" onclick="loadPage('edit_alignment.html?v=$COMMIT_HASH');">Alignment Marks</a></li>
+                <li><a href="#" onclick="loadPage('edit_alignment.html?v=$COMMIT_HASH');">Alignment Marker</a></li>
             </ul>
             </ul>
         </li>
         </li>
         <li><a><strong>R</strong>egions <strong>O</strong>f <strong>I</strong>nterest <i class="arrow right"></i></a>
         <li><a><strong>R</strong>egions <strong>O</strong>f <strong>I</strong>nterest <i class="arrow right"></i></a>
             <ul>
             <ul>
-                <li><a href="#" onclick="loadPage('edit_digits.html?v=$COMMIT_HASH');">Digital ROIs</a></li>
+                <li><a href="#" onclick="loadPage('edit_digits.html?v=$COMMIT_HASH');">Digit ROIs</a></li>
                 <li><a href="#" onclick="loadPage('edit_analog.html?v=$COMMIT_HASH');">Analog ROIs</a></li>
                 <li><a href="#" onclick="loadPage('edit_analog.html?v=$COMMIT_HASH');">Analog ROIs</a></li>
             </ul>
             </ul>
         </li>
         </li>
       </ul>
       </ul>
 
 
 
 
-    <li><a>Data <i class="arrow down"></i></a>
+    <li><a>Data<i class="arrow down"></i></a>
         <ul class="submenu">
         <ul class="submenu">
             <li><a href="#" onclick="loadPage(getDomainname() + '/value?full');">Recognition</a></li>
             <li><a href="#" onclick="loadPage(getDomainname() + '/value?full');">Recognition</a></li>
             <li><a href="#" onclick="loadPage('graph.html?v=$COMMIT_HASH');">Data Graph</a></li>
             <li><a href="#" onclick="loadPage('graph.html?v=$COMMIT_HASH');">Data Graph</a></li>
@@ -100,30 +111,98 @@
             <li><a href="#" onclick="loadPage('ota_page.html?v=$COMMIT_HASH');">OTA Update</a></li>
             <li><a href="#" onclick="loadPage('ota_page.html?v=$COMMIT_HASH');">OTA Update</a></li>
             <li><a href="#" onclick="loadPage('log.html?v=$COMMIT_HASH');">Log Viewer</a></li>
             <li><a href="#" onclick="loadPage('log.html?v=$COMMIT_HASH');">Log Viewer</a></li>
             <li><a href="#" onclick="loadPage(getDomainname() + '/fileserver/');">File Server</a></li>
             <li><a href="#" onclick="loadPage(getDomainname() + '/fileserver/');">File Server</a></li>
+            <li><a>Livestream <i class="arrow right"></i></a>
+                <ul>
+                    <li><a href="#" onclick="start_livestream(false);">Live Stream (Light off)</a></li>
+                    <li><a href="#" onclick="start_livestream(true);">Live Stream (Light on)</a></li>
+                </ul>
             <li><a href="#" onclick="loadPage('reboot_page.html?v=$COMMIT_HASH');">Reboot</a></li>
             <li><a href="#" onclick="loadPage('reboot_page.html?v=$COMMIT_HASH');">Reboot</a></li>
             <li><a href="#" onclick="loadPage('info.html?v=$COMMIT_HASH');">Info</a></li>
             <li><a href="#" onclick="loadPage('info.html?v=$COMMIT_HASH');">Info</a></li>
         </ul>
         </ul>
     </li>
     </li>
+    <li><a>Manual Control <i class="arrow down"></i></a>
+        <ul class="submenu">
+            <li><a href="#" onclick="flow_start()">Start Round</a></li>
+            <li id="HASendDiscovery" style="display:none;"><a href="#" onclick="HA_send_discovery()">Resend HA Discovery</a></li>
+        </ul>
+    </li>
   </ul>
   </ul>
 </div>
 </div>
 
 
-<iframe name="maincontent" class="iframe" id="maincontent"></iframe>
+<iframe title="maincontent" name="maincontent" class="iframe" id="maincontent"></iframe>
 
 
-<span id="Version" style="font-size: 10px; margin-top: -5px">Loading version...</span>
+<span id="Version" style="font-size: 10px; margin-top: -5px;padding-left: 10px;">Loading version...</span>
 
 
 <script type="text/javascript">
 <script type="text/javascript">
-  LoadHostname();
-  LoadFwVersion();
-  LoadWebUiVersion();
+    LoadHostname();
+    LoadFwVersion();
+    LoadWebUiVersion();
+    HA_send_discovery_visiblilty();
 
 
-  if (getCookie("page") == "" || getCookie("page") == "reboot_page.html?v=$COMMIT_HASH") {
+    if (getCookie("page") == "" || getCookie("page") == "reboot_page.html?v=$COMMIT_HASH") {
     document.cookie = "page=overview.html?v=$COMMIT_HASH" + "; path=/";
     document.cookie = "page=overview.html?v=$COMMIT_HASH" + "; path=/";
-  }
-  console.log("Loading page: " + getCookie("page"));
-  document.getElementById('maincontent').src = getCookie("page");
-</script>
+    }
+    console.log("Loading page: " + getCookie("page"));
+    document.getElementById('maincontent').src = getCookie("page");
 
 
-</div>
+    
+    function flow_start() {
+    var url = getDomainname() + '/flow_start'; 
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+				if (xhttp.responseText.substring(0,3) == "001") {
+					firework.launch('Flow start triggered', 'success', 5000);
+                    window.location.reload();
+				}
+				else if (xhttp.responseText.substring(0,3) == "002") {
+					firework.launch('Flow start scheduled. Start after round is completed', 'success', 5000);
+				}
+				else if (xhttp.responseText.substring(0,3) == "099") {
+					firework.launch('Flow start triggered, but start not possible (no flow task available)', 'danger', 5000);
+				}
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+    }
+
+
+    function HA_send_discovery_visiblilty()	{
+		loadConfig(domainname); 
+		ParseConfig();
+		category = getConfigCategory();
+        param = getConfigParameters();
+		if (category["MQTT"]["enabled"] && param["MQTT"]["HomeassistantDiscovery"]["value1"] == "true")
+            document.getElementById("HASendDiscovery").style.display="";
+	}
+
+
+    function HA_send_discovery() {
+    var url = getDomainname() + '/mqtt_publish_discovery'; 
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+				firework.launch('Sending HA discovery topics scheduled. The sending will be processed in state "Publish to MQTT"', 'success', 5000);
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+    }
+
+
+    function start_livestream(streamFlashlight) {
+        if (streamPopup) 
+            streamPopup.close();
+
+        if (streamFlashlight)
+            streamPopup = window.open(getDomainname() + '/stream?flashlight=true','LivestreamWithlight',streamWindowFeatures);
+        else
+            streamPopup = window.open(getDomainname() + '/stream','Livestream',streamWindowFeatures);
+
+        streamPopup.focus();
+    }
+</script>
 
 
 </body>
 </body>
 </html>
 </html>

+ 476 - 177
sd-card/html/info.html

@@ -1,9 +1,8 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>Info</title>
 <title>Info</title>
-<meta charset="utf-8">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
 h1 {font-size: 2em;}
 h1 {font-size: 2em;}
@@ -11,190 +10,490 @@ h2 {font-size: 1.5em;}
 h3 {font-size: 1.2em;}
 h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
 
 
-div {
-	width: 350px;
-    padding: 10px 5px;
-    border: 1px solid #ccc;
-	font-family: arial;
-    font-size: 16px;
-	max-height: 35px;
+th, td {
+  padding: 5px 5px 5px 5px;
+  border-width: 1px;
+  border-style: solid;
+  border-color: rgb(240, 240, 240);
 }
 }
 
 
+output {
+	padding-left:5px;
+}
+
+table {
+    width: 660px;
+	padding: 5px;
+	border-collapse:collapse;
+}
 </style>
 </style>
 
 
+<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
-<h3>Runtime Information</h3>
-<table style="font-family: arial">
-	<tr>
-		<td>
-			Last restart:
-		</td>
-		<td>
-			<div id="starttime">
-				<object data="/starttime"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			Uptime:
-		</td>
-		<td>
-			<div id="uptime">
-				<object data="/uptime"></object>
-			</div>
-		</td>
-	</tr>
-</table>
-
-<h3>Build Info</h3>
-<table style="font-family: arial">
-  <tr>
-	<td>
-		Firmware Version:
-	</td>
-	<td>
-		<div id="firmware" style="width: 700px">
-		    <object data="/info?type=FirmwareVersion" style="width: 700px"></object>
-		</div>
-	</td>
-  </tr>
-  <tr>
-	<td>
-		Firmware Build Time:
-	</td>
-	<td>
-		<div id="build-time">
-			<object data="/info?type=BuildTime"></object>
-		</div>
-	</td>
-  </tr>
-
-	<tr>
-	<td>
-		Web Interface Version:
-	</td>
-	<td>
-		    <div id="web-ui" style="width: 700px">
-			<object data="/info?type=HTMLVersion" style="width: 700px"></object>
-		</div>
-	</td>
-  </tr>
-</table>
-
-
-<h3>Host Info</h3>
-<table style="font-family: arial">
-	<tr>
-		<td>
-			Hostname:
-		</td>
-		<td>
-			<div id="Hostname">
-				<object data="/info?type=Hostname"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			IP-Address:
-		</td>	
-		<td>
-			<div id="IP">
-				<object data="/info?type=IP"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			WLan-SSID:
-		</td>	
-		<td>
-			<div id="SSID">
-				<object data="/info?type=SSID"></object>
-			</div>
-		</td>
-	</tr>
-</table>
-
-<h3>SD Card Info</h3>
-<table style="font-family: arial">
-	<tr>
-		<td>
-			SD Card Manufacturer:
-		</td>
-		<td>
-			<div id="SDCardManufacturer">
-				<object data="/info?type=SDCardManufacturer"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			SD Card Name:
-		</td>
-		<td>
-			<div id="SDCardName">
-				<object data="/info?type=SDCardName"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			SD Card Size [MB]:
-		</td>
-		<td>
-			<div id="SDCardCapacity">
-				<object data="/info?type=SDCardCapacity"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			SD Card Sector Size [byte]:
-		</td>
-		<td>
-			<div id="SDCardSectorSize">
-				<object data="/info?type=SDCardSectorSize"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			Partition Size [MB]:
-		</td>
-		<td>
-			<div id="SDPartitionSize">
-				<object data="/info?type=SDCardPartitionSize"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			Partition Free Space [MB]:
-		</td>	
-		<td>
-			<div id="SDFreePartitionSpace">
-				<object data="/info?type=SDCardFreePartitionSpace"></object>
-			</div>
-		</td>
-	</tr>
-	<tr>
-		<td>
-			Partition Allocation Size [byte]:
-		</td>	
-		<td>
-			<div id="SDCardPartitionAllocationSize">
-				<object data="/info?type=SDCardPartitionAllocationSize"></object>
-			</div>
-		</td>
-	</tr>
-</table>
+	<table>
+		<colgroup>
+			<col span="1" style="width: 35%;">
+			<col span="1" style="width: 65%;">
+		</colgroup>
+		<tr>
+			<h3>Runtime Information</h3>
+		</tr>
+		<tr>
+			<td>Start time:</td>
+			<td><output id="starttime"></output></td>
+		</tr>
+		<tr>
+			<td>Uptime:</td>
+			<td><output id="uptime"></output></td>
+		</tr>
+	</table>
+
+	<table>
+		<colgroup>
+			<col span="1" style="width: 35%;">
+			<col span="1" style="width: 65%;">
+		</colgroup>
+		<tr>
+			<h3>Build Info</h3>
+		</tr>
+		<tr>
+			<td>Firmware version:</td>
+			<td>
+				<output id="firmware"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Firmware build time:</td>
+			<td>
+				<output id="build-time"></output>
+			</td>
+		</tr>
+
+		<tr>
+			<td>Web interface version:</td>
+			<td>
+				<output id="web-ui"></output>
+			</td>
+		</tr>
+	</table>
+
+
+	<table>
+		<colgroup>
+			<col span="1" style="width: 35%;">
+			<col span="1" style="width: 65%;">
+		</colgroup>
+		<tr>			
+			<h3>Host Info</h3>
+		</tr>
+		<tr>
+			<td>Hostname:</td>
+			<td>
+				<output id="hostname"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>IP Address:</td>	
+			<td>
+				<output id="IP-address"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>WLAN SSID:</td>	
+			<td>
+				<output id="wlan-ssid"></output>
+			</td>
+		</tr>
+	</table>
+
+	<table>
+		<colgroup>
+			<col span="1" style="width: 35%;">
+			<col span="1" style="width: 65%;">
+		</colgroup>
+		<tr>			
+			<h3>SD Card Info</h3>
+		</tr>
+		<tr>
+			<td>SD card manufacturer:</td>
+			<td>
+				<output id="SDCardManufacturer"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>SD card name:</td>
+			<td>
+				<output id="SDCardName"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>SD card size:</td>
+			<td>
+				<output id="SDCardCapacity"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>SD card sector size:</td>
+			<td>
+				<output id="SDCardSectorSize"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Partition size:</td>
+			<td>
+				<output id="SDCardPartitionSize"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Partition free space:</td>	
+			<td>
+				<output id="SDCardFreePartitionSpace"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Partition allocation size:</td>	
+			<td>
+				<output id="SDCardPartitionAllocationSize"></output>
+			</td>
+		</tr>
+	</table>
+
+	<table>
+		<colgroup>
+			<col span="1" style="width: 35%;">
+			<col span="1" style="width: 65%;">
+		</colgroup>
+		<tr>			
+			<h3>Memory Info</h3>
+		</tr>
+		<tr>
+			<td>Total Free (Int + Ext):</td>	
+			<td>
+				<output id="RAMTotalFree"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Ext. RAM - Free:</td>	
+			<td>
+				<output id="ExtRAMFree"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Ext. RAM - Largest Free Block:</td>	
+			<td>
+				<output id="ExtRAMLargestFree"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Ext. RAM - Min Free:</td>	
+			<td>
+				<output id="ExtRAMMinFree"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Int. RAM - Free:</td>	
+			<td>
+				<output id="IntRAMFree"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Int. RAM - Largest Free Block:</td>	
+			<td>
+				<output id="IntRAMLargestFree"></output>
+			</td>
+		</tr>
+		<tr>
+			<td>Int. RAM - Min Free:</td>	
+			<td>
+				<output id="IntRAMMinFree"></output>
+			</td>
+		</tr>
+	</table>
+
 
 
 <h3>Copyright</h3>
 <h3>Copyright</h3>
 Copyright &copy; 2020 - 2023 by <a href="https://github.com/jomjol/AI-on-the-edge-device" target=_blank>Jomjol</a> and others.
 Copyright &copy; 2020 - 2023 by <a href="https://github.com/jomjol/AI-on-the-edge-device" target=_blank>Jomjol</a> and others.
 
 
 </body>
 </body>
 </html>
 </html>
+
+<script type="text/javascript">
+
+	function loadLastRestart() 
+	{
+		url = getDomainname() + '/starttime';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+				//Input format: 19700101-010019
+				var timestamp = xhttp.response.substr(6,2) + "." +
+						   xhttp.response.substr(4,2) + "." +
+						   xhttp.response.substr(0,4) + " " +
+						   xhttp.response.substr(9,2) + ":" +
+						   xhttp.response.substr(11,2) + ":" +
+						   xhttp.response.substr(13,2);
+ 				document.getElementById("starttime").value = timestamp;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadUptime() 
+	{
+		url = getDomainname() + '/uptime';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("uptime").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadFWVersion() 
+	{
+		url = getDomainname() + '/info?type=FirmwareVersion';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("firmware").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadFWBuildTime() 
+	{
+		url = getDomainname() + '/info?type=BuildTime';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+				// Input format: 2023-04-02 10:56
+				var timestamp = xhttp.response.substr(8,2) + "." +
+								xhttp.response.substr(5,2) + "." +
+								xhttp.response.substr(0,4) + " " +
+								xhttp.response.substr(11,2) + ":" +
+								xhttp.response.substr(14,2);
+ 				document.getElementById("build-time").value = timestamp;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadHTMLVersion() 
+	{
+		url = getDomainname() + '/info?type=HTMLVersion';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("web-ui").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadHostname() 
+	{
+		url = getDomainname() + '/info?type=Hostname';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("hostname").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadIPAddress() 
+	{
+		url = getDomainname() + '/info?type=IP';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("IP-address").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadWLANSSID() 
+	{
+		url = getDomainname() + '/info?type=SSID';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("WLAN-SSID").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadWLANSSID() 
+	{
+		url = getDomainname() + '/info?type=SSID';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("wlan-ssid").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadWLANSSID() 
+	{
+		url = getDomainname() + '/info?type=SSID';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("wlan-ssid").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardManufacturer() 
+	{
+		url = getDomainname() + '/info?type=SDCardManufacturer';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardManufacturer").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardName() 
+	{
+		url = getDomainname() + '/info?type=SDCardName';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardName").value = xhttp.response;
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardCapacity() 
+	{
+		url = getDomainname() + '/info?type=SDCardCapacity';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardCapacity").value = xhttp.response + " MB";
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardSectorSize() 
+	{
+		url = getDomainname() + '/info?type=SDCardSectorSize';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardSectorSize").value = xhttp.response + " byte";
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardPartitionSize() 
+	{
+		url = getDomainname() + '/info?type=SDCardPartitionSize';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardPartitionSize").value = xhttp.response + " MB";
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardFreePartitionSpace() 
+	{
+		url = getDomainname() + '/info?type=SDCardFreePartitionSpace';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardFreePartitionSpace").value = xhttp.response + " MB";
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadSDCardPartitionAllocationSize() 
+	{
+		url = getDomainname() + '/info?type=SDCardPartitionAllocationSize';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+ 				document.getElementById("SDCardPartitionAllocationSize").value = xhttp.response + " byte";
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function loadMemoryInfo() 
+	{
+		url = getDomainname() + '/heap';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+				data = xhttp.response.split("|");
+ 				document.getElementById("RAMTotalFree").value = data[0].split("l: ")[1] + " byte";
+				document.getElementById("IntRAMFree").value = data[4].split(":")[1] + " byte";
+				document.getElementById("IntRAMLargestFree").value = data[5].split(":")[1] + " byte";
+				document.getElementById("IntRAMMinFree").value = data[6].split(":")[1] + " byte";
+				document.getElementById("ExtRAMFree").value = data[1].split(":")[1] + " byte";
+				document.getElementById("ExtRAMLargestFree").value = data[2].split(":")[1] + " byte";
+				document.getElementById("ExtRAMMinFree").value = data[3].split(":")[1] + " byte";
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();
+	}
+
+	function init()
+	{
+		loadMemoryInfo();
+		loadLastRestart();
+		loadUptime();
+		loadFWVersion();
+		loadFWBuildTime();
+		loadHTMLVersion();
+		loadHostname();
+		loadIPAddress();
+		loadWLANSSID();
+		loadSDCardManufacturer();
+		loadSDCardName();
+		loadSDCardCapacity();
+		loadSDCardSectorSize();
+		loadSDCardPartitionSize();
+		loadSDCardFreePartitionSpace();
+		loadSDCardPartitionAllocationSize();
+	}
+
+	init();
+</script>

+ 19 - 10
sd-card/html/log.html

@@ -1,16 +1,19 @@
-<html>
+<!DOCTYPE html>
+<html lang="en" xml:lang="en"> 
     <head>
     <head>
+        <title>Log Viewer</title>
+        
         <style>
         <style>
             html,
             html,
             body {
             body {
                 height: 100%;
                 height: 100%;
-                margin: 2px;
+                margin: 1px;
             }
             }
 
 
             .box {
             .box {
                 display: flex;
                 display: flex;
                 flex-flow: column;
                 flex-flow: column;
-                height: 100%;
+                height: 99.75%;
             }
             }
 
 
             .box .row.header {
             .box .row.header {
@@ -29,21 +32,27 @@
                 font-family: 'Courier New', Courier, monospace;
                 font-family: 'Courier New', Courier, monospace;
                 font-size: small;
                 font-size: small;
             }
             }
+
+            .button {
+                padding: 5px 10px;
+                width: 190px;
+                font-size: 16px;
+            }
         </style>
         </style>
         <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
         <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
     </head>
     </head>
     <body>
     <body>
         <div class="box">
         <div class="box">
             <div class="row header">
             <div class="row header">
-                <button onClick="reload();">Reload</button>
-                <button onClick="window.open(getDomainname() + '/logfileact');">Show full log</button>
-                <button onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show older log files</button>
+                <button class="button" onClick="reload();">Reload</button>
+                <button class="button" onClick="window.open(getDomainname() + '/logfileact');">Show Full Log</button>
+                <button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show Older Log Files</button>
             </div>
             </div>
-            <div class="row content" id="log"><br><br><br><b>Loading Logfile, please wait...</b></div>
+            <div class="row content" id="log"><br><br><br><b>Loading logfile, please wait...</b></div>
             <div class="row footer">
             <div class="row footer">
-                <button onClick="reload();">Reload</button>
-                <button onClick="window.open(getDomainname() + '/logfileact');">Show full log</button>
-                <button onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show older log files</button>
+                <button class="button" onClick="reload();">Reload</button>
+                <button class="button" onClick="window.open(getDomainname() + '/logfileact');">Show Full Log</button>
+                <button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show Older Log Files</button>
             </div>
             </div>
           </div>
           </div>
     </body>
     </body>

+ 14 - 16
sd-card/html/ota_page.html

@@ -1,27 +1,25 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en">
 <head>
 <head>
-    <link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
     <title>OTA Update</title>
     <title>OTA Update</title>
-    <meta charset="utf-8">
+    <meta charset="UTF-8" />
 
 
     <style>
     <style>
         h1 {font-size: 2em;}
         h1 {font-size: 2em;}
-        h2 {font-size: 1.5em;}
-        h3 {font-size: 1.2em;} 
+        h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+        h3 {font-size: 1.2em;}
         p {font-size: 1em;}
         p {font-size: 1em;}
         
         
-        input[type=number] {
-            width: 138px;
-            padding: 10px 5px;
+        input[type=file] {
+            width: 660px;
+            padding: 5px 0px;
             display: inline-block;
             display: inline-block;
-            border: 1px solid #ccc;
             font-size: 16px; 
             font-size: 16px; 
-        }
+        }    
         
         
         .button {
         .button {
-            padding: 10px 20px;
-            width: 211px;
+            padding: 5px 10px;
+            width: 205px;
             font-size: 16px;
             font-size: 16px;
         }
         }
     </style>
     </style>
@@ -51,11 +49,11 @@
     <form id="upload_form" enctype="multipart/form-data" method="post">
     <form id="upload_form" enctype="multipart/form-data" method="post">
         <input type="file" accept=".bin,.zip,.tfl,.tflite" name="file_selector" id="file_selector" onchange="validate_file()"><br><br>
         <input type="file" accept=".bin,.zip,.tfl,.tflite" name="file_selector" id="file_selector" onchange="validate_file()"><br><br>
 
 
-        <button class="button" style="width:300px" id="start_OTA_button" type="button" onclick="start_OTA()" disabled>Upload and install</button>
+        <button class="button" id="start_OTA_button" type="button" onclick="start_OTA()" disabled>Upload And Install</button>
         <br><br>
         <br><br>
         <progress id="progressBar" value="0" max="100" style="width:600px;"></progress>
         <progress id="progressBar" value="0" max="100" style="width:600px;"></progress>
+        <h3><span id="status">Status: Idle</span></h3>
         <p id="loaded_n_total"></p>
         <p id="loaded_n_total"></p>
-        <h3><span id="status">Status: idle</span></h3>
     </form>
     </form>
     
     
 
 
@@ -262,10 +260,10 @@
 
 
         function progressHandler(event) {
         function progressHandler(event) {
             _("loaded_n_total").innerHTML = "Uploaded " + (event.loaded / 1024 / 1024).toFixed(2) + 
             _("loaded_n_total").innerHTML = "Uploaded " + (event.loaded / 1024 / 1024).toFixed(2) + 
-                    " MBytes of " + (event.total / 1024/ 1024).toFixed(2) + " MBytes.";
+                    " MB of " + (event.total / 1024/ 1024).toFixed(2) + " MB";
             var percent = (event.loaded / event.total) * 100;
             var percent = (event.loaded / event.total) * 100;
             _("progressBar").value = Math.round(percent);
             _("progressBar").value = Math.round(percent);
-            _("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded... please wait";
+            _("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded. Please wait...";
         }
         }
 
 
 
 

+ 110 - 71
sd-card/html/overview.html

@@ -1,77 +1,89 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>Overview</title>
 <title>Overview</title>
-<meta charset="utf-8">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
-.tg  {border-collapse:collapse;border-spacing:0;width:100%;color: darkslategray;border: inset;height:585px;}
-.tg td{font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
-.tg th{height: 50px;font-size:24px;font-weight:bold;text-align:left;padding:0px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;background-color:#f0f0f0}
-.tg .tg-1{width:700px;font-size:20px;font-family:Arial, Helvetica, sans-serif !important;border: inset;}
-.tg .tg-2{font-size:20px;font-family:Arial, Helvetica, sans-serif !important;border: inset;}
-.tg .tg-3{height: 15px;font-size:14px;font-family:Arial, Helvetica, sans-serif !important;border: inset;}		
+.tg  {border-collapse:collapse;border-spacing:0;width:100%;min-width:600px;height:100%;color:darkslategray;}
+.tg th{min-width:325px;width:325px;height:20px;font-size:18px;text-align:left;font-weight:bold;padding:5px 10px 5px 10px;;overflow:hidden;word-break:normal;background-color:lightgrey;}
+.tg td{font-size:15px;padding:5px 10px 5px 10px;overflow:hidden;word-break:normal;}
+.tg .tg-1{font-size:15px;vertical-align: top; font-family:Arial, Helvetica, sans-serif !important;}
+.tg .tg-2{height:52px;font-size:15px;padding:3px 0px 3px 10px;vertical-align:middle;font-family:Arial, Helvetica, sans-serif !important;}
+.tg .tg-3{height:45px;font-size:15px;padding:3px 10px 3px 10px;vertical-align:middle;font-family:Arial, Helvetica, sans-serif !important;}
+.tg .tg-4{height:fit-content;font-size:15px;padding:5px 10px 5px 10px;vertical-align:text-top;font-family:Arial, Helvetica, sans-serif !important;}
 </style>
 </style>
 
 
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<table class="tg">
-  <tr>
-    <td class="tg-1" rowspan="9" style="vertical-align: top"><div id="img"></div></td>
-    <th class="th">Value:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="value"></div>
-	</td>	
-  </tr>
-  <tr>
-    <th class="th">Previous Value:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="prevalue"></div>
-	</td>	
-  </tr>
-
-  <tr>
-    <th class="th">Raw Value:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="raw"></div>
-	</td>	
-  </tr>
-  <tr>
-    <th class="th">Status:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="error"></div>
-	</td>	
-  </tr> 
-  <tr>	
-    <td class="tg-3">
-	<div id="statusflow" ></div>	
-	<div id="timestamp" ></div>	
-	<div id="cputemp" ></div>	
-	<div id="rssi" ></div>
-	<div>
-		<span id="uptime" ></span>
-		<span id="round" ></span>
-	</div>	
-	</td>	
-  </tr>    
-</table>
-
-
-<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
-<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
-<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script> 
-<script type="text/javascript">
+	<table class="tg">
+		<tr>
+			<th class="th">Value</th>
+			<td class="tg-1" rowspan="13">
+				<img style="padding-left: 5px; padding-top: 0px; max-width:100%; width:100%; height:auto;" id="img" src="">
+			</td>
+		</tr>	 
+		<tr>	
+			<td class="tg-2">
+				<div id="value"></div>
+			</td>	
+		</tr>
+		<tr>
+			<th class="th">Previous Value</th>
+		</tr>	
+		<tr>	
+			<td class="tg-2">
+				<div id="prevalue"></div>
+			</td>	
+		</tr>
+		<tr>
+			<th class="th">Raw Value</th>
+		</tr>	
+		<tr>	
+			<td class="tg-2">
+				<div id="raw"></div>
+			</td>	
+		</tr>
+		<tr>
+			<th class="th">Value Status</th>
+		</tr>	
+		<tr>	
+			<td class="tg-2">
+				<div id="error"></div>
+			</td>	
+		</tr>
+		<tr>
+			<th class="th">Process State</th>
+		</tr>	
+		<tr>	
+			<td class="tg-3">
+				<div id="statusflow" ></div>
+			</td>
+		</tr>  
+		<tr>
+			<th class="th">System Info</th>
+		</tr>	
+		<tr>	
+			<td class="tg-4">
+				<div id="timestamp" ></div>	
+				<div id="cputemp" ></div>	
+				<div id="rssi" ></div>
+				<div>
+					<span id="uptime" ></span>
+					<span id="round" ></span>
+				</div>
+			</td>
+		</tr>
+	</table>
+
+
+	<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
+	<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
+	<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
+	<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
+	<script type="text/javascript">
 
 
 	function addZero(i) {
 	function addZero(i) {
 	  if (i < 10) {
 	  if (i < 10) {
@@ -88,10 +100,10 @@
 
 
 
 
 	function LoadData(){
 	function LoadData(){
-		loadValue("value", "value");
-		loadValue("raw", "raw");
-		loadValue("prevalue", "prevalue");
-		loadValue("error", "error", "font-size:8px");
+		loadValue("value", "value", "border-collapse: collapse; width: 100%");
+		loadValue("raw", "raw", "border-collapse: collapse; width: 100%");
+		loadValue("prevalue", "prevalue", "border-collapse: collapse; width: 100%");
+		loadValue("error", "error", "border-collapse: collapse; width: 100%");
 		loadStatus();
 		loadStatus();
 		loadCPUTemp();
 		loadCPUTemp();
 		loadRSSI();
 		loadRSSI();
@@ -106,7 +118,7 @@
 		var h = addZero(d.getHours());
 		var h = addZero(d.getHours());
 		var m = addZero(d.getMinutes());
 		var m = addZero(d.getMinutes());
 		var s = addZero(d.getSeconds());
 		var s = addZero(d.getSeconds());
-		$('#img').html('<img src=' + getDomainname() + '/img_tmp/alg_roi.jpg?timestamp='+ timestamp +'" max-height:555px; display:block; margin-left:auto;  margin-right:auto;"></img>');
+		document.getElementById("img").src = getDomainname() + '/img_tmp/alg_roi.jpg?timestamp=' + timestamp;
 		$('#timestamp').html("Last Page Refresh:" + (h + ":" + m + ":" + s));
 		$('#timestamp').html("Last Page Refresh:" + (h + ":" + m + ":" + s));
 	}
 	}
 
 
@@ -126,7 +138,7 @@
 		xhttp.onreadystatechange = function() {
 		xhttp.onreadystatechange = function() {
 			if (this.readyState == 4 && this.status == 200) {
 			if (this.readyState == 4 && this.status == 200) {
 				var _rsp = xhttp.responseText;
 				var _rsp = xhttp.responseText;
-				$('#statusflow').html("State: " + _rsp);
+				$('#statusflow').html(_rsp);
 			}
 			}
 		}
 		}
 		xhttp.open("GET", url, true);
 		xhttp.open("GET", url, true);
@@ -231,9 +243,11 @@
 				{
 				{
 					var _zer = ZerlegeZeile(_split[j], "\t")
 					var _zer = ZerlegeZeile(_split[j], "\t")
 					if (_zer.length == 1)
 					if (_zer.length == 1)
-						out = out + "<tr><td>" + _zer[0] + "</td><td> </td></tr>"; 
+						out = out + "<tr><td style=\"width: 22%; padding: 3px 5px; text-align: left; vertical-align:middle; border: 1px solid lightgrey\">" + 
+							_zer[0] + "</td><td style=\"padding: 3px 5px; text-align: left; vertical-align:middle; border: 1px solid lightgrey\"> </td></tr>"; 
 					else
 					else
-						out = out + "<tr><td>" + _zer[0] + "</td><td>" + _zer[1] + "</td></tr>"; 
+						out = out + "<tr><td style=\"width: 22%; padding: 3px 5px; text-align: left; vertical-align:middle; border: 1px solid lightgrey\">" + 
+							_zer[0] + "</td><td style=\"padding: 3px 5px; text-align: left; vertical-align:middle; border: 1px solid lightgrey\" >" + _zer[1] + "</td></tr>"; 
 				}
 				}
 				out = out + "</table>"
 				out = out + "</table>"
 
 
@@ -246,8 +260,33 @@
 	}
 	}
 
 
 
 
+	function setImageMaxWidth()
+	{
+		loadConfig(domainname); 
+		ParseConfig();
+		param = getConfigParameters();
+		if(param["TakeImage"]["ImageSize"]["value1"] == "QVGA") {
+			if (param["Alignment"]["FlipImageSize"]["value1"] == "false") {
+				document.getElementById("img").style.maxWidth = "320px";
+			}
+			else {
+				document.getElementById("img").style.maxWidth = "240px";
+			}
+		}
+		else {
+			if (param["Alignment"]["FlipImageSize"]["value1"] == "false") { 
+				document.getElementById("img").style.maxWidth = "640px";
+			}
+			else {
+				document.getElementById("img").style.maxWidth = "480px";
+			}
+		}
+	}
+
+
 	function init(){
 	function init(){
 		domainname = getDomainname();
 		domainname = getDomainname();
+		setImageMaxWidth();
 		Refresh();
 		Refresh();
 	}
 	}
 
 

+ 129 - 77
sd-card/html/prevalue_set.html

@@ -1,84 +1,136 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en">
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<title>Set PreValue</title>
-<meta charset="utf-8">
-	
-<style>
-h1 {font-size: 2em;}
-h2 {font-size: 1.5em;}
-h3 {font-size: 1.2em;}
-p {font-size: 1em;}
-
-div {
-	width: 200px;
-    padding: 10px 5px;
-    display: inline-block;
-    border: 1px solid #ccc;
-    font-size: 16px;
-	max-height: 35px;	
-}
+    <title>Set PreValue</title>
+    <meta charset="UTF-8" />
+
+    <style>
+    h1 {font-size: 2em;}
+    h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
+    h3 {font-size: 1.2em;}
+    p {font-size: 1em;}
+
+    div {
+        padding: 3px 5px;
+        display: inline-block;
+        border: 1px solid #ccc;
+        font-size: 16px;
+        height: 20px;
+        width: 120px;
+        vertical-align: middle;
+    }
 
 
-input[type=number] {
-	width: 125px;
-	padding: 10px 5px;
-	display: inline-block;
-	border: 1px solid #ccc;
-	font-size: 16px; 
-}
+    input[type=number] {
+        width: 120px;
+        margin-right: 10px;
+        padding: 3px 5px;
+        display: inline-block;
+        border: 1px solid #ccc;
+        font-size: 16px; 
+    }
+
+    .invalid-input {
+		background-color: #FFAA00;
+	}
+
+    th, td {
+    padding: 5px 5px 5px 0px;
+    }
+
+    select {
+        padding: 3px 5px;
+        display: inline-block;
+        border: 1px solid #ccc;
+        font-size: 16px; 
+        margin-right: 10px;
+        min-width: 100px;
+        vertical-align: middle;
+    }
+
+    .button {
+        padding: 5px 10px;
+        width: 205px;
+        font-size: 16px;	
+    }
+
+    table {
+        width: 660px;
+        padding: 5px;
+    }
+    </style>
 
 
-.button {
-	padding: 10px 20px;
-    width: 211px;
-	font-size: 16px;	
-}
-</style>	
-	
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
-<h3>Set the previous value for consistency check and substitution for NaN</h3>
-
-<class id="Numbers_text" style="font-size: 120%; color:black;"><b>Choose Number: </b>
-<select id="Numbers_value1" onchange="numberChanged()">
-</select>
-</class>
-
-
-<table style="width:100%">
-  <tr>
-    <td>
-      <h3>Current "Previous Value":</h3>
-    </td>
-    <td>
-      <div id="prevalue"></div>
-    </td>
-  </tr>
-  <tr>
-    <td>
-      <h3>New "Previous Value":<br>(Format = 123.456)</h3><p>&nbsp;</p>
-    </td>
-    <td>
-      <input type="number" id="myInput" name="myInput"
-              pattern="[0-9]+([\.,][0-9]+)?" step="0.001"
-                title="This should be a number with up to 4 decimal places.">
-      <button class="button" type="button" onclick="setprevalue()">Set Previous Value</button>
-      <p>(The current "Raw Value" got entered as the suggested new "Previous Value")</p>
-    </td>
-  </tr>	
-  <tr>
-    <td>
-      <h3>Result:</h3>
-    </td>
-    <td>
-	    <div id="result" readonly></div>
-    </td>
-  </tr>	 
-
-</table>
-
-</body></html>
+    <h2>Set "Previous Value"</h2>
+    <details id="desc_details">
+        <summary><b>CLICK HERE</b> for usage description. More infos in documentation: 
+            <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/FAQs/#pre-value target=_blank>"Previous Value"</a>
+        </summary>
+        <p>
+            Set the "previous value" for consistency checks and substitution for NaN
+        </p>
+        <p>
+            Previous value is a bit missleading, because normally it is the last valid value but not always the value of the previous round. 
+            The result of the the new round, as long it's a vaild result, will be promoted to the new "previous value". If the result is not usable the 
+            "previous value" will not be updated.
+            If activated in configuration, the "previous value" will be used in the following round to check negtive rates, high rates
+            (MaxRateValue / MaxRateType) and for the option "Check Digit Increase Consistency" (configuration paramter, only for dig-class11 models). 
+        </p>
+        <p>
+            The field to enter new "previous value" is prefilled with actual "raw value" because it's the most likely use case. Nevertheless every other
+            positive value can be set as new "previous value".
+        </p>
+    </details>
+    <hr />
+
+    <table>
+        <colgroup>
+            <col span="1" style="width: 35.0%;">
+            <col span="1" style="width: 65.0%;">
+        </colgroup>
+        <tr>
+            <td style="height: 40px;">
+                <class id="Numbers_text" style="color:black;">Number sequence:</class>
+            </td>
+            <td>
+                <select id="Numbers_value1" onchange="numberChanged()"></select>
+            </td>
+        </tr>
+    </table>
+
+    <hr />
+
+    <table>
+        <colgroup>
+            <col span="1" style="width: 35%;">
+            <col span="1" style="width: 65%;">
+        </colgroup>
+        <tr>
+            <td>Current "previous value":</td>
+            <td>
+                <div style="padding-left:5px" id="prevalue"></div>
+            </td>
+        </tr>
+        <tr>
+            <td style="vertical-align: text-top; padding-top: 12px;">Enter new "previous value":</td>
+            <td>
+                <input required type="number" id="myInput" name="myInput" min="0" oninput="(!validity.rangeUnderflow||(value=0));">
+                <button class="button" type="button" onclick="setprevalue()">Update Value</button>
+                <p style="padding-left: 5px;">NOTE: The current "raw value" is prefilled as 
+                    <br>the suggested new "previous value"</p>
+            </td>
+        </tr>	
+        <tr>
+            <td id="result_text">"Previous value" updated to:</td>
+            <td>
+                <div id="result" style="padding-left:5px;"></div>
+            </td>
+        </tr>	 
+    </table>
+
+</body>
+</html>
 
 
 <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
 <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
 <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
 <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
@@ -104,6 +156,7 @@ function setprevalue() {
           xhttp.send();
           xhttp.send();
           response = xhttp.responseText;
           response = xhttp.responseText;
           document.getElementById("result").innerHTML=response;
           document.getElementById("result").innerHTML=response;
+          firework.launch('New \"previous value\" set', 'success', 5000);
      }
      }
     catch (error)
     catch (error)
     {
     {
@@ -145,11 +198,10 @@ function loadPrevalue(_domainname) {
     lines.forEach(function(line) {
     lines.forEach(function(line) {
       arr = line.split("\t");
       arr = line.split("\t");
       if (_number == arr[0]) {
       if (_number == arr[0]) {
-        document.getElementById("myInput").value=arr[1];
+        document.getElementById("myInput").value = Number(arr[1]);
         return;
         return;
       }
       }
     });
     });
-
   }
   }
   catch (error)
   catch (error)
   {
   {
@@ -190,7 +242,7 @@ function UpdateNUMBERS(_sel){
 
 
 
 
 function init(){
 function init(){
-	domainname = getDomainname();
+  domainname = getDomainname();
   loadConfig(domainname); 
   loadConfig(domainname); 
   ParseConfig();
   ParseConfig();
   UpdateNUMBERS();
   UpdateNUMBERS();

+ 13 - 9
sd-card/html/readconfigcommon.js

@@ -85,6 +85,7 @@ function ZerlegeZeile(input, delimiter = " =\t\r")
      
      
      }    
      }    
 
 
+
 function findDelimiterPos(input, delimiter)
 function findDelimiterPos(input, delimiter)
      {
      {
           var pos = -1;
           var pos = -1;
@@ -131,7 +132,8 @@ function getConfig()
 }
 }
 
 
      
      
-function loadConfig(_domainname) {
+function loadConfig(_domainname)
+{
      var xhttp = new XMLHttpRequest();
      var xhttp = new XMLHttpRequest();
      try {
      try {
           url = _domainname + '/fileserver/config/config.ini';     
           url = _domainname + '/fileserver/config/config.ini';     
@@ -148,17 +150,17 @@ function loadConfig(_domainname) {
 }
 }
 
 
      
      
-
-
-function dataURLtoBlob(dataurl) {
+function dataURLtoBlob(dataurl)
+{
      var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
      var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
           bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
           bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
      while(n--){
      while(n--){
           u8arr[n] = bstr.charCodeAt(n);
           u8arr[n] = bstr.charCodeAt(n);
      }
      }
      return new Blob([u8arr], {type:mime});
      return new Blob([u8arr], {type:mime});
-     }	
-     
+}	
+ 
+
 function FileCopyOnServer(_source, _target, _domainname = ""){
 function FileCopyOnServer(_source, _target, _domainname = ""){
      url = _domainname + "/editflow?task=copy&in=" + _source + "&out=" + _target;
      url = _domainname + "/editflow?task=copy&in=" + _source + "&out=" + _target;
      var xhttp = new XMLHttpRequest();  
      var xhttp = new XMLHttpRequest();  
@@ -171,6 +173,7 @@ function FileCopyOnServer(_source, _target, _domainname = ""){
      }
      }
 }
 }
 
 
+
 function FileDeleteOnServer(_filename, _domainname = ""){
 function FileDeleteOnServer(_filename, _domainname = ""){
      var xhttp = new XMLHttpRequest();
      var xhttp = new XMLHttpRequest();
      var okay = false;
      var okay = false;
@@ -201,6 +204,7 @@ function FileDeleteOnServer(_filename, _domainname = ""){
      return okay;
      return okay;
 }
 }
 
 
+
 function FileSendContent(_content, _filename, _domainname = ""){
 function FileSendContent(_content, _filename, _domainname = ""){
      var xhttp = new XMLHttpRequest();  
      var xhttp = new XMLHttpRequest();  
      var okay = false;
      var okay = false;
@@ -242,6 +246,7 @@ function SaveCanvasToImage(_canvas, _filename, _delete = true, _domainname = "")
      FileSendContent(rtn, _filename, _domainname);
      FileSendContent(rtn, _filename, _domainname);
 }
 }
 
 
+
 function MakeContrastImageZW(zw, _enhance, _domainname){
 function MakeContrastImageZW(zw, _enhance, _domainname){
      _filename = zw["name"].replace("/config/", "/img_tmp/");
      _filename = zw["name"].replace("/config/", "/img_tmp/");
      url = _domainname + "/editflow?task=cutref&in=/config/reference.jpg&out=" + _filename + "&x=" + zw["x"] + "&y="  + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"];
      url = _domainname + "/editflow?task=cutref&in=/config/reference.jpg&out=" + _filename + "&x=" + zw["x"] + "&y="  + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"];
@@ -260,7 +265,7 @@ function MakeContrastImageZW(zw, _enhance, _domainname){
      }
      }
 
 
      if (xhttp.responseText == "CutImage Done") {
      if (xhttp.responseText == "CutImage Done") {
-          firework.launch('Reference Image Contrast got enhanced.', 'success', 5000);
+          firework.launch('Image Contrast got enhanced', 'success', 5000);
           return true;
           return true;
      }
      }
      else {
      else {
@@ -270,7 +275,6 @@ function MakeContrastImageZW(zw, _enhance, _domainname){
 }
 }
 
 
 
 
-
 function MakeRefZW(zw, _domainname){
 function MakeRefZW(zw, _domainname){
      _filetarget = zw["name"].replace("/config/", "/img_tmp/");
      _filetarget = zw["name"].replace("/config/", "/img_tmp/");
      _filetarget = _filetarget.replace(".jpg", "_org.jpg");
      _filetarget = _filetarget.replace(".jpg", "_org.jpg");
@@ -289,7 +293,7 @@ function MakeRefZW(zw, _domainname){
           _filetarget2 = zw["name"].replace("/config/", "/img_tmp/");
           _filetarget2 = zw["name"].replace("/config/", "/img_tmp/");
      //     _filetarget2 = _filetarget2.replace(".jpg", "_org.jpg");
      //     _filetarget2 = _filetarget2.replace(".jpg", "_org.jpg");
           FileCopyOnServer(_filetarget, _filetarget2, _domainname);
           FileCopyOnServer(_filetarget, _filetarget2, _domainname);
-          firework.launch('Reference Image got updated.', 'success', 5000);
+          firework.launch('Marker got updated', 'success', 5000);
           return true;
           return true;
      }
      }
      else {
      else {

+ 28 - 19
sd-card/html/readconfigparam.js

@@ -710,9 +710,10 @@ function getNUMBERInfo(){
 }
 }
 
 
 function RenameNUMBER(_alt, _neu){
 function RenameNUMBER(_alt, _neu){
-     if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0))
+     if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || 
+         (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0))
      {
      {
-          return "Name must not contain ',', '.', ' ' or '\"' - please change name";
+          return "Number sequence name must not contain , . \" or a space";
      }
      }
 
 
      index = -1;
      index = -1;
@@ -725,21 +726,21 @@ function RenameNUMBER(_alt, _neu){
      }
      }
 
 
      if (found)
      if (found)
-          return "Name is already existing - please use another name";
+          return "Number sequence name is already existing, please choose another name";
 
 
      NUMBERS[index]["name"] = _neu;
      NUMBERS[index]["name"] = _neu;
      
      
      return "";
      return "";
 }
 }
 
 
-function DeleteNUMBER(_delte){
+function DeleteNUMBER(_delete){
      if (NUMBERS.length == 1)
      if (NUMBERS.length == 1)
-          return "The last number cannot be deleted."
+          return "One number sequence is mandatory. Therefore this cannot be deleted"
      
      
 
 
      index = -1;
      index = -1;
      for (i = 0; i < NUMBERS.length; ++i) {
      for (i = 0; i < NUMBERS.length; ++i) {
-          if (NUMBERS[i]["name"] == _delte)
+          if (NUMBERS[i]["name"] == _delete)
                index = i;
                index = i;
      }
      }
 
 
@@ -758,7 +759,7 @@ function CreateNUMBER(_numbernew){
      }
      }
 
 
      if (found)
      if (found)
-          return "Name does already exist, please choose another one!";
+          return "Number sequence name is already existing, please choose another name";
 
 
      _ret = new Object();
      _ret = new Object();
      _ret["name"] = _numbernew;
      _ret["name"] = _numbernew;
@@ -796,24 +797,26 @@ function CreateNUMBER(_numbernew){
 
 
 
 
 function getROIInfo(_typeROI, _number){
 function getROIInfo(_typeROI, _number){
-     index = 0;
+     index = -1;
      for (var i = 0; i < NUMBERS.length; ++i)
      for (var i = 0; i < NUMBERS.length; ++i)
           if (NUMBERS[i]["name"] == _number)
           if (NUMBERS[i]["name"] == _number)
                index = i;
                index = i;
 
 
-     return NUMBERS[index][_typeROI];         
+     if (index != -1)
+          return NUMBERS[index][_typeROI];
+     else
+          return "";     
 }
 }
 
 
 
 
 function RenameROI(_number, _type, _alt, _neu){
 function RenameROI(_number, _type, _alt, _neu){
      if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) ||
      if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) ||
          (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || 
          (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || 
-         (_neu.includes("\""))) {
-          return "Name must not contain any of the following characters: . : , ; = \" ' '";
+         (_neu.includes("\""))) 
+     {
+          return "ROI name must not contain . : , ; = \" or space";
      }
      }
 
 
-
-
      index = -1;
      index = -1;
      found = false;
      found = false;
      _indexnumber = -1;
      _indexnumber = -1;
@@ -821,6 +824,9 @@ function RenameROI(_number, _type, _alt, _neu){
           if (NUMBERS[j]["name"] == _number)
           if (NUMBERS[j]["name"] == _number)
                _indexnumber = j;
                _indexnumber = j;
 
 
+     if (_indexnumber == -1)
+          return "Number sequence not existing. ROI cannot be renamed"  
+
      for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) {
      for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) {
           if (NUMBERS[_indexnumber][_type][i]["name"] == _alt)
           if (NUMBERS[_indexnumber][_type][i]["name"] == _alt)
                index = i;
                index = i;
@@ -829,18 +835,18 @@ function RenameROI(_number, _type, _alt, _neu){
      }
      }
 
 
      if (found)
      if (found)
-          return "Name is already existing - please use another name";
+          return "ROI name is already existing, please choose another name";
 
 
      NUMBERS[_indexnumber][_type][index]["name"] = _neu;
      NUMBERS[_indexnumber][_type][index]["name"] = _neu;
      
      
      return "";
      return "";
 }
 }
 
 
+
 function DeleteNUMBER(_delte){
 function DeleteNUMBER(_delte){
      if (NUMBERS.length == 1)
      if (NUMBERS.length == 1)
-          return "The last number cannot be deleted."
+          return "The last number cannot be deleted"
      
      
-
      index = -1;
      index = -1;
      for (i = 0; i < NUMBERS.length; ++i) {
      for (i = 0; i < NUMBERS.length; ++i) {
           if (NUMBERS[i]["name"] == _delte)
           if (NUMBERS[i]["name"] == _delte)
@@ -854,21 +860,24 @@ function DeleteNUMBER(_delte){
      return "";
      return "";
 }
 }
 
 
+
 function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){
 function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){
      _indexnumber = -1;
      _indexnumber = -1;
      for (j = 0; j < NUMBERS.length; ++j)
      for (j = 0; j < NUMBERS.length; ++j)
           if (NUMBERS[j]["name"] == _number)
           if (NUMBERS[j]["name"] == _number)
                _indexnumber = j;
                _indexnumber = j;
 
 
+     if (_indexnumber == -1)
+          return "Number sequence not existing. ROI cannot be created"
 
 
      found = false;
      found = false;
-     for (i = 0; i < NUMBERS.length; ++i) {
-          if (NUMBERS[_indexnumber][_type]["name"] == _roinew)
+     for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) {
+          if (NUMBERS[_indexnumber][_type][i]["name"] == _roinew)
                found = true;
                found = true;
      }
      }
 
 
      if (found)
      if (found)
-          return "ROI does already exist, please choose another name!";
+          return "ROI name is already existing, please choose another name";
 
 
      _ret = new Object();
      _ret = new Object();
      _ret["name"] = _roinew;
      _ret["name"] = _roinew;

+ 7 - 8
sd-card/html/reboot_page.html

@@ -1,9 +1,8 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>Reboot</title>
 <title>Reboot</title>
-<meta charset="utf-8">
+<meta charset="UTF-8" />
 
 
 <style>
 <style>
 h1 {font-size: 2em;}
 h1 {font-size: 2em;}
@@ -12,8 +11,8 @@ h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
 
 
 .button {
 .button {
-	padding: 10px 20px;
-    width: 211px;
+	padding: 5px 10px;
+    width: 205px;
 	font-size: 16px;	
 	font-size: 16px;	
 }
 }
 </style>
 </style>
@@ -22,13 +21,13 @@ p {font-size: 1em;}
 </head>
 </head>
 
 
 <body style="font-family: arial; padding: 0px 10px;">
 <body style="font-family: arial; padding: 0px 10px;">
-
-<h3>Do you really want to reboot your ESP32 now?</h3>
+	
+<h3>Do you really want to reboot now?</h3>
 
 
 <table class="fixed" border="0">
 <table class="fixed" border="0">
 	<tr>
 	<tr>
 		<td>
 		<td>
-			<button class="button" id="reboot" type="button" onclick="doReboot()">Yes, please reboot</button>
+			<button class="button" id="reboot" type="button" onclick="doReboot()">Reboot</button>
 		</td>
 		</td>
 	</tr>
 	</tr>
 </table>
 </table>

+ 304 - 110
sd-card/html/setup.html

@@ -1,17 +1,25 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html style="width: fit-content">
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
 <title>AI on the edge</title>
 <title>AI on the edge</title>
-<meta charset="utf-8">
+<meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
 
+
 <style>
 <style>
-.h_iframe iframe {width:995px;height:760px;}
-.h_iframe {width:995px;height:605px;}
+.h_iframe_explain iframe {
+    width:995px;
+    height:155px;
+    padding:5px;
+    padding-top:0px;
+    padding-bottom:0px;
+}
 
 
-.h_iframe_explain iframe {width:995px;height:200px;}
-.h_iframe_explain {width:995px;height:200px;}
+.h_iframe iframe {
+    width:995px;
+    height:800px;
+    padding:5px;
+}
 
 
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h1 {font-size: 2em; margin-block-end: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
 h2 {font-size: 1.5em;margin-block-start: 0.3em;}
@@ -19,132 +27,318 @@ h3 {font-size: 1.2em;}
 p {font-size: 1em;}
 p {font-size: 1em;}
 
 
 .button {
 .button {
-	padding: 5px 20px;
-    width: 211px;
-	font-size: 16px;	
+	padding: 5px 10px;
+    width: 125px;
+	font-size: 16px;
+}
+
+table {
+    width: 1015px;
+	padding: 0px;
+}
+
+.main {
+    display: flex; 
+    width: 100%; 
+    height: 100%; 
+    flex-direction: column; 
+    overflow: hidden;
 }
 }
+
+body, html {
+    width: 100%; 
+    height: 100%; 
+    min-height: 800px;
+    margin: 0px 0px 0px 2px; 
+    padding: 0; 
+    font-family: arial;
+    width: -moz-fit-content;
+    width: fit-content;
+}
+
 </style>
 </style>
+<script type="text/javascript">
+    function resizeIframe(obj) {
+        obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 20 + 'px';
+    }
+</script>
 </head>
 </head>
 
 
 <body style="font-family: arial">
 <body style="font-family: arial">
 
 
-<table style="border: none">
-  <tr><td style="padding-right: 10px;"><img src="favicon.ico?v=$COMMIT_HASH"></td>
-    <td><h1 id="id_title"> Digitizer - Initial Setup</h1>
-        <h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
-    </td></tr>
-</table>
-
-<table>
-   <tr>
-      <td>
-         <button class="button" id="previous" name="previous" onclick="clickPrevious()">Previous</button>
-         <button class="button" id="next" name="next" onclick="clickNext()">Next</button>
-         If you need support, have a look to the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs target=_blank>documentation</a> or the <a href=https://github.com/jomjol/AI-on-the-edge-device/discussions target=_blank>discussion</a> pages.
-      </td>
-   </tr>
-</table>
-
+    <table style="border: none">
+        <tr>
+            <td style="padding-right: 10px;"><img src="favicon.ico?v=$COMMIT_HASH"></td>
+            <td>
+                <h1> Digitizer - AI on the edge - Initial setup</h1>
+                <h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
+            </td>
+        </tr>
+    </table>
 
 
-<div class="h_iframe_explain" id="h_iframe_explain">
-   <iframe name="explaincontent" id ="explaincontent" src="" allowfullscreen></iframe> 
-</div>
+    <table>
+        <colgroup>
+            <col span="1" style="width: 45.0%;">
+            <col span="1" style="width: 15.0%;">
+            <col span="1" style="width: 25.0%;">
+        </colgroup>
+        <tr>
+            <td>
+                <button class="button" id="restart" name="restart" onclick="clickStart()">Restart Setup</button>
+                <button class="button" id="previous" name="previous" onclick="clickPrevious()">Previous Step</button>
+                <button class="button" id="next" name="next" onclick="clickNext()">Next Step</button>
+                <button class="button" id="skip" name="skip" onclick="clickAbort()">Abort Setup</button>
+            </td>
+            <td style="padding-left:10px;">Setup Progress:<br><progress id="progressBar" value="0" max="7" style="width:120px;"></progress></td>
+            <td style="padding-left:10px; padding-top: 10px; padding-right: 5px; float:right;">
+                <output id="rssi" name="rssi"></output>
+            </td>
+        </tr>
+    </table>
 
 
-<div class="h_iframe">
-	 <iframe name="maincontent" id ="maincontent" src="" allowfullscreen></iframe> 
-</div>
 
 
+    <div class="h_iframe_explain" id="h_iframe_explain">
+        <iframe name="explaincontent" id ="explaincontent" src="" allowfullscreen></iframe>
+    </div>
 
 
+    <div class="h_iframe" id="h_iframe">
+        <iframe name="maincontent" id ="maincontent" src="" onload="resizeIframe(this)" allowfullscreen></iframe>
+        <iframe name="stream" id ="stream" src="" display="none" allowfullscreen></iframe>
+    </div>
 
 
- 
 
 
 <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 <script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
 <script type="text/javascript">
 <script type="text/javascript">
-	var canvas = document.getElementById('canvas'),
-		domainname = getDomainname(); 
-		aktstatu = 0;
-
-function clickNext() {
-   aktstatu++;
-   if (aktstatu > 6) {
-      aktstatu = 6;
-   }
-   LoadStep();
-}
+    var aktstep = 0;
+    var setupCompleted = false;
+    document.getElementById('stream').style.display = "none";   // Make sure that stream iframe is always hidden
+    document.getElementById("progressBar").value = 0;
+
+    function clickStart() {
+        aktstep = 0;
+        setupCompleted = false;
+        document.getElementById('stream').src = "";     
+        document.getElementById('stream').style.display = "none";   // Make sure that stream iframe is always hidden
+        LoadStep();
+    }
 
 
-function clickPrevious() {
-   aktstatu--;
-   if (aktstatu < 0) {
-      aktstatu = 0;
+    function clickAbort() {
+        setupCompleted = false;
+        aktstep = 7;
+        document.getElementById('stream').src = "";     
+        document.getElementById('stream').style.display = "none";   // Make sure that stream iframe is always hidden
+        LoadStep();
+    }
+
+   function clickNext() {
+        aktstep++;
+        if (aktstep > 7) {
+            aktstep = 7;
+        }
+        document.getElementById('stream').src = "";     
+        document.getElementById('stream').style.display = "none";   // Make sure that stream iframe is always hidden
+        LoadStep();
+    }
+
+   function clickPrevious() {
+        aktstep--;
+        if (aktstep < 0) {
+            aktstep = 0;
+        }
+        document.getElementById('stream').src = "";     
+        document.getElementById('stream').style.display = "none";   // Make sure that stream iframe is always hidden
+        LoadStep();
    }
    }
-   LoadStep();
-}
 
 
-function LoadStep(){
-   switch (aktstatu) {
-      case 0:
-         document.getElementById('maincontent').src = 'edit_explain_0.html?v=$COMMIT_HASH';
-         document.getElementById('h_iframe_explain').style.display = "none";  
-         document.getElementById("previous").disabled = true;
-         document.getElementById("next").disabled = false;
-         break;
-      case 1:
-         document.getElementById('maincontent').src = 'edit_reference.html?v=$COMMIT_HASH';
-         document.getElementById('explaincontent').src = 'explain_1.html?v=$COMMIT_HASH';
-         document.getElementById('h_iframe_explain').style.display = "";  
-         document.getElementById("previous").disabled = false;
-         document.getElementById("next").disabled = false;
-         break;
-      case 2:
-         document.getElementById('maincontent').src = 'edit_alignment.html?v=$COMMIT_HASH';
-         document.getElementById('explaincontent').src = 'explain_2.html?v=$COMMIT_HASH';
-         document.getElementById('h_iframe_explain').style.display = "";           
-         document.getElementById("previous").disabled = false;
-         document.getElementById("next").disabled = false;
-
-         break;
-      case 3:
-         document.getElementById('maincontent').src = 'edit_digits.html?v=$COMMIT_HASH';
-         document.getElementById('explaincontent').src = 'explain_3.html?v=$COMMIT_HASH';         
-         document.getElementById('h_iframe_explain').style.display = "";           
-         document.getElementById("previous").disabled = false;
-         document.getElementById("next").disabled = false;
-
-         break;
-      case 4:
-         document.getElementById('maincontent').src = 'edit_analog.html?v=$COMMIT_HASH';
-         document.getElementById('explaincontent').src = 'explain_4.html?v=$COMMIT_HASH';   
-         document.getElementById('h_iframe_explain').style.display = "";           
-         document.getElementById("previous").disabled = false;
-         document.getElementById("next").disabled = false;
-
-         break;
-      case 5:
-         document.getElementById('maincontent').src = 'edit_config_param.html?v=$COMMIT_HASH?InitialSetup=true';
-         document.getElementById('explaincontent').src = 'explain_5.html?v=$COMMIT_HASH';            
-         document.getElementById('h_iframe_explain').style.display = "";           
-         document.getElementById("previous").disabled = false;
-         document.getElementById("next").disabled = false;
-
-         break; 
-      case 6:
-         document.getElementById('maincontent').src = 'edit_explain_6.html?v=$COMMIT_HASH';
-         document.getElementById('explaincontent').src = 'explain_6.html?v=$COMMIT_HASH';  // Note: The page never gets shown!    
-         document.getElementById('h_iframe_explain').style.display = "none";  
-         document.getElementById("previous").disabled = false;
-         document.getElementById("next").disabled = true;
-
-         break;   
-      }
+   function LoadStep(){
+      loadRSSI();
+      switch (aktstep) {
+        case 0: // Start page
+            document.getElementById('maincontent').src = 'edit_explain_0.html?v=$COMMIT_HASH';
+            document.getElementById('maincontent').style.display = "";
 
 
+            document.getElementById('h_iframe_explain').style.display = "none";
 
 
-}
+            document.getElementById("restart").disabled = true;
+            document.getElementById("previous").disabled = true;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById("progressBar").value = 0;
+            setupCompleted = false;
+            break;
+
+        case 1: // Live stream
+            document.getElementById('maincontent').style.display = "none";
+
+            document.getElementById('h_iframe_explain').style.display = "";
+            document.getElementById('h_iframe_explain').style="height:155px;"
+            document.getElementById('explaincontent').style="height:155px;"
+            document.getElementById('explaincontent').scrolling="yes"
+            document.getElementById('explaincontent').src = 'explain_1.html?v=$COMMIT_HASH';
+            
+            document.getElementById("restart").disabled = false;
+            document.getElementById("previous").disabled = false;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById('h_iframe').style="height:480px;"
+            document.getElementById('stream').style="height:480px;"
+
+            document.getElementById("progressBar").value = 1;
+            setupCompleted = false;
 
 
-LoadStep();
+            setTimeout(function() {
+                document.getElementById('stream').src = getDomainname() + '/stream?flashlight=true';   // needs to be the last statement because it's kind of blocking
+                document.getElementById('stream').style.display = "";
+            }, 500);
+            break;
 
 
+        case 2: // Reference image
+            document.getElementById('maincontent').src = 'edit_reference.html?v=$COMMIT_HASH#description';
+            document.getElementById('maincontent').style.display = "";
+
+            document.getElementById('h_iframe_explain').style.display = "";
+            document.getElementById('h_iframe_explain').style="height:45px;"
+            document.getElementById('explaincontent').style="height:45px;"
+            document.getElementById('explaincontent').scrolling="no"
+            document.getElementById('explaincontent').src = 'explain_2.html?v=$COMMIT_HASH';
+
+            document.getElementById("restart").disabled = false;
+            document.getElementById("previous").disabled = false;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById("progressBar").value = 2;
+            setupCompleted = false;
+            break;
+
+        case 3: // Alignment marker
+            document.getElementById('maincontent').src = 'edit_alignment.html?v=$COMMIT_HASH#description';
+
+            document.getElementById('h_iframe_explain').style.display = "";
+            document.getElementById('h_iframe_explain').style="height:45px;"
+            document.getElementById('explaincontent').style="height:45px;"
+            document.getElementById('explaincontent').scrolling="no"
+            document.getElementById('explaincontent').src = 'explain_3.html?v=$COMMIT_HASH';
+
+            document.getElementById("restart").disabled = false;
+            document.getElementById("previous").disabled = false;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById("progressBar").value = 3;
+            setupCompleted = false;
+            break;
+
+        case 4: // Digit ROIs
+            document.getElementById('maincontent').src = 'edit_digits.html?v=$COMMIT_HASH#description';
+
+            document.getElementById('h_iframe_explain').style.display = "";
+            document.getElementById('h_iframe_explain').style="height:45px;"
+            document.getElementById('explaincontent').style="height:45px;"
+            document.getElementById('explaincontent').scrolling="no"
+            document.getElementById('explaincontent').src = 'explain_4.html?v=$COMMIT_HASH';
+
+            document.getElementById("restart").disabled = false;
+            document.getElementById("previous").disabled = false;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById("progressBar").value = 4;
+            setupCompleted = false;
+            break;
+
+        case 5: // Analog ROIs
+            document.getElementById('maincontent').src = 'edit_analog.html?v=$COMMIT_HASH#description';
+
+            document.getElementById('h_iframe_explain').style.display = "";
+            document.getElementById('h_iframe_explain').style="height:45px;"
+            document.getElementById('explaincontent').style="height:45px;"
+            document.getElementById('explaincontent').scrolling="no"
+            document.getElementById('explaincontent').src = 'explain_5.html?v=$COMMIT_HASH';
+
+            document.getElementById("restart").disabled = false;
+            document.getElementById("previous").disabled = false;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById("progressBar").value = 5;
+            setupCompleted = false;
+            break;
+
+        case 6: // Config page
+            document.getElementById('maincontent').src = 'edit_config_param.html?v=$COMMIT_HASH#description';
+
+            document.getElementById('h_iframe_explain').style.display = "";
+            document.getElementById('h_iframe_explain').style="height:100px;"
+            document.getElementById('explaincontent').style="height:100px;"
+            document.getElementById('explaincontent').scrolling="no"
+            document.getElementById('explaincontent').src = 'explain_6.html?v=$COMMIT_HASH';
+
+            document.getElementById("restart").disabled = false;
+            document.getElementById("previous").disabled = false;
+            document.getElementById("next").disabled = false;
+            document.getElementById("skip").disabled = false;
+
+            document.getElementById("progressBar").value = 6;
+            setupCompleted = true;
+            break; 
+
+        case 7: // Setup completed / aborted
+            document.getElementById('h_iframe').style="height:660px;"
+            document.getElementById('maincontent').style="height:660px;"
+            if (setupCompleted) {
+                document.getElementById('maincontent').src = 'edit_explain_7.html?v=$COMMIT_HASH';
+            }
+            else {
+                document.getElementById('maincontent').src = 'edit_explain_7_abort.html?v=$COMMIT_HASH';
+                document.getElementById("previous").disabled = true; 
+            }
+
+            document.getElementById('h_iframe_explain').style.display = "none";
+
+            document.getElementById("skip").disabled = true;
+            document.getElementById("restart").disabled = false;
+            document.getElementById("next").disabled = true;
+
+            document.getElementById("progressBar").value = 7;
+            break;
+        }
+   }
+
+   function loadRSSI() {
+		url = getDomainname() + '/rssi';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+				var _rsp = xhttp.responseText;
+				
+				if (_rsp >= -55) {
+					document.getElementById('rssi').value = ("WIFI Signal: Excellent (" + _rsp + "dBm)");
+				}
+				else if (_rsp < -55 && _rsp >= -67) {
+					document.getElementById('rssi').value = ("WIFI Signal: Good (" + _rsp + "dBm)");
+				}
+				else if (_rsp < -67 && _rsp >= -78) {
+					document.getElementById('rssi').value = ("WIFI Signal: Fair (" + _rsp + "dBm)");
+				}
+				else if (_rsp < -78 && _rsp >= -85) {
+					document.getElementById('rssi').value = ("WIFI Signal: Weak (" + _rsp + "dBm)");
+				}
+				else {
+					document.getElementById('rssi').value = ("WIFI Signal: Unreliable (" + _rsp + "dBm)");
+				}
+			}
+		}
+		xhttp.open("GET", url, true);
+		xhttp.send();		
+	}
+
+
+   LoadStep();
 
 
 </script>
 </script>
- 
 
 
 </body>
 </body>
 </html>
 </html>

+ 24 - 26
sd-card/html/style.css

@@ -1,26 +1,39 @@
 body, html {
 body, html {
-    width: 100%; 
-    height: 100%; 
-    min-height: 800px;
+    max-width: 1022px;
+    min-width: 688px;
+    height: 100vh;
+    min-height: 100vh;
+    margin: 0px 0px 0px 2px; 
+    padding: 0; 
+    font-family: arial;
+}
+
+@media screen and (max-width:687px) {
+  body, html {
+    max-width: 687px;
+    height: 150vh;
+    min-height: 100vh;
     margin: 0px 0px 0px 2px; 
     margin: 0px 0px 0px 2px; 
     padding: 0; 
     padding: 0; 
     font-family: arial;
     font-family: arial;
-    width: fit-content;
+  }
 }
 }
 
 
 .main {
 .main {
     display: flex; 
     display: flex; 
     width: 100%; 
     width: 100%; 
     height: 100%; 
     height: 100%; 
-    flex-direction: column; 
+    flex-direction: column;
     overflow: hidden;
     overflow: hidden;
+    font-family: arial;
 }
 }
 
 
 .iframe {
 .iframe {
-    flex-grow: 1;
-    margin: 5px 0px 4px 0px; 
+    flex: 1 1 auto;
+    margin: 5px 0px 8px 0px; 
     padding: 0; 
     padding: 0; 
-    border: 2px solid #333; /* black */
+    border: 0px solid #333; /* black */
+    font-family: arial;
 }
 }
 
 
 h1 {
 h1 {
@@ -41,20 +54,13 @@ p {
     font-size: 1em;
     font-size: 1em;
 }
 }
 
 
-
-
-
-
-
-
-
 .menu {
 .menu {
   margin: 0px;
   margin: 0px;
   padding: 0px;
   padding: 0px;
   font-family: "Arial";
   font-family: "Arial";
   font-size: 18px;
   font-size: 18px;
   font-weight: bold;
   font-weight: bold;
-  width: 1008px;
+  width: 100%;
   background: #333; /* black */
   background: #333; /* black */
 }
 }
 
 
@@ -171,13 +177,6 @@ p {
   color: white;
   color: white;
 }
 }
 
 
-
-
-
-
-
-
-
 .arrow {
 .arrow {
   border: solid #333; /* black */
   border: solid #333; /* black */
   border-width: 0 3px 3px 0;
   border-width: 0 3px 3px 0;
@@ -187,9 +186,8 @@ p {
 }
 }
 
 
 .right {
 .right {
-  transform: rotate(-45deg);
   -webkit-transform: rotate(-45deg);
   -webkit-transform: rotate(-45deg);
-  
+  transform: rotate(-45deg);
   position: absolute;
   position: absolute;
   right: 10px;
   right: 10px;
   top: 20px;     
   top: 20px;     
@@ -198,8 +196,8 @@ p {
 }
 }
 
 
 .down {
 .down {
-  transform: rotate(45deg);
   -webkit-transform: rotate(45deg);
   -webkit-transform: rotate(45deg);
+  transform: rotate(45deg);
   border-bottom: solid white;
   border-bottom: solid white;
   border-right: solid white;
   border-right: solid white;
   margin: 0px 0px 2px 5px;
   margin: 0px 0px 2px 5px;

+ 0 - 33
sd-card/html/test.html

@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
-<meta charset="utf-8">
-</head>
-
-<body style="font-family: arial">
-	testschrift
-  <div id="value"></div>
-</html>
-
-<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script> 
-
-<script type="text/javascript">
-	var domainname = getDomainname(); 
-	function testinit(){
-		domainname = getDomainname();
-		url = domainname + '/value?all=true';     
-		var xhttp = new XMLHttpRequest();
-		xhttp.onreadystatechange = function() {
-			if (this.readyState == 4 && this.status == 200) {
-			// Typical action to be performed when the document is ready:
-			document.getElementById("value").innerHTML = xhttp.responseText;
-			}
-		};
-		xhttp.open("GET", url, true);
-		xhttp.send();		
-	}
-
-	testinit();
-</script>
-</body>

+ 0 - 1
sd-card/html/testcnn.html

@@ -1 +0,0 @@
-<!DOCTYPE html><html><head><meta http-equiv="refresh" content="2"></head><body><tr><td><img src = "/original.jpg"></td></tr><tr><td><img src = "/roi.jpg"></td></tr><tr><td><img src = "/resize.bmp"></td></tr><tr><td><h2>Not-a-Number</h2></td></tr></body></html>

+ 1 - 1
sd-card/html/timezones.html

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<html>
+<html lang="en" xml:lang="en"> 
 <head>
 <head>
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <style>
 <style>

+ 6 - 6
sd-card/html/wlan_config.html

@@ -1,5 +1,5 @@
-<html>
-    <head>
+<html lang="en" xml:lang="en"> 
+    <head> 
         <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
         <link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
         <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
         <script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>  
         <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
         <script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
@@ -13,15 +13,15 @@
 <tr><td>gateway</td><td><input type="text" name="gateway" id="gateway"></td><td>Leave emtpy if set by router</td></tr>
 <tr><td>gateway</td><td><input type="text" name="gateway" id="gateway"></td><td>Leave emtpy if set by router</td></tr>
 <tr><td>netmask</td><td><input type="text" name="netmask" id="netmask"></td><td>Leave emtpy if set by router</td>
 <tr><td>netmask</td><td><input type="text" name="netmask" id="netmask"></td><td>Leave emtpy if set by router</td>
 </tr><tr><td>DNS</td><td><input type="text" name="dns" id="dns"></td><td>Leave emtpy if set by router</td></tr>
 </tr><tr><td>DNS</td><td><input type="text" name="dns" id="dns"></td><td>Leave emtpy if set by router</td></tr>
-<tr><td>RSSI Threshold</td><td><input type="number" name="name" id="threshold" min="-100"  max="0" step="1" value = "0"></td><td>WLAN Mesh Parameter: Threashold for RSSI value to check for start switching access point in a mesh system.Possible values: -100 to 0, 0 = disabled - Value will be transfered to wlan.ini at next startup)</td></tr>
+<tr><td>RSSI Threshold</td><td><input type="number" name="name" id="threshold" min="-100"  max="0" step="1" value = "0"></td><td>WLAN Mesh Parameter: Threshold for RSSI value to check for start switching access point in a mesh system.Possible values: -100 to 0, 0 = disabled - Value will be transfered to wlan.ini at next startup)</td></tr>
 </table>
 </table>
-<button class="button" type="button" onclick="wr()">Write wlan.ini</button>
+<button class="button" type="button" onclick="wr();">Write wlan.ini</button>
 <input id="newfile" type="file">
 <input id="newfile" type="file">
 <button class="button" style="width:300px" id="doUpdate" type="button" onclick="upload()">Upload Files</button>
 <button class="button" style="width:300px" id="doUpdate" type="button" onclick="upload()">Upload Files</button>
 
 
 
 
 <script language="JavaScript">function wr(){
 <script language="JavaScript">function wr(){
-        api = "/config?"+"ssid"+document.getElementById("ssid").value+"&pwd="+document.getElementById("password").value;+"&hn="+document.getElementById("hostname").value;+"&ip="+document.getElementById("ip").value;+"&gw="+document.getElementById("gateway").value;+"&nm="+document.getElementById("netmask").value;+"&dns="+document.getElementById("dns").value;+"&rssi="+document.getElementById("threashold").value;
+        api = "/config?"+"ssid"+document.getElementById("ssid").value+"&pwd="+document.getElementById("password").value;+"&hn="+document.getElementById("hostname").value;+"&ip="+document.getElementById("ip").value;+"&gw="+document.getElementById("gateway").value;+"&nm="+document.getElementById("netmask").value;+"&dns="+document.getElementById("dns").value;+"&rssi="+document.getElementById("threshold").value;
         fetch(api);}
         fetch(api);}
 
 
 
 
@@ -110,5 +110,5 @@ if (!file.name.includes("remote-setup")){
 
 
     
     
     </script>
     </script>
-</html>
 </body>
 </body>
+</html>

Некоторые файлы не были показаны из-за большого количества измененных файлов