### Setup Navigation and State Management Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/setup.html Manages the setup progress, including starting, aborting, navigating between steps, and loading step-specific content. It also controls the visibility and source of stream and main content iframes. ```javascript 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 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(); } 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; 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').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;" ``` -------------------------------- ### JavaScript Function to Complete Setup and Reboot Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_explain_7.html This function prompts the user for confirmation before completing the setup mode and rebooting the device. It loads configuration, updates setup mode parameters, and then redirects the user to the regular web interface. ```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 = getCamConfig(); param["System"]["SetupMode"]["enabled"] = true; param["System"]["SetupMode"]["value1"] = "false"; WriteConfigININew(); SaveConfigToServer(domainname); var stringota = getDomainname() + "/reboot"; parent.location = stringota; parent.location.href = stringota; parent.location.assign(stringota); parent.location.replace(stringota); } } ``` -------------------------------- ### Clone Repository and Initialize Submodules Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/code/README.md Initial setup steps to clone the project repository and update its submodules. ```bash git clone https://github.com/jomjol/AI-on-the-edge-device.git cd AI-on-the-edge-device git checkout main git submodule update --init ``` -------------------------------- ### Update UI for Setup Step 7 (Completion/Abort) Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/setup.html This snippet handles the UI for the final setup step, displaying either a completion or an abort message based on the 'setupCompleted' flag. It adjusts iframe heights, sets content sources, and updates button states and progress. ```javascript 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; ``` -------------------------------- ### Load Start Time Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/info.html Fetches and displays the system start time. Expects the response in 'YYYYMMDD-HHMMSS' format. ```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(); } ``` -------------------------------- ### Update UI for Setup Step 5 (Analog ROIs) Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/setup.html This snippet prepares the UI for the Analog ROIs setup step. It sets the main content source, adjusts iframe and content heights, and updates navigation controls and progress. ```javascript 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; ``` -------------------------------- ### Start Flow Process Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/index.html Initiates a 'flow start' process by sending a GET request to the server. Provides feedback via a firework notification based on the server's response. ```javascript function flow_start() { var url = getDomainname() + '/flow_start'; var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { firework.launch(xhttp.responseText, 'success', 5000); /*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(); } ``` -------------------------------- ### Start Backup Process Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/backup.html Initiates the backup process by fetching the hostname, listing configuration files, and then zipping them for download. It uses XMLHttpRequest to communicate with the device's API. ```javascript function startBackup() { document.getElementById("progress").innerHTML = "Creating backup...
\n"; // Get hostname try { var xhttp = new XMLHttpRequest(); xhttp.open("GET", getDomainname() + "/info?type=Hostname", false); xhttp.send(); hostname = xhttp.responseText; } catch(err) { setStatus("Failed to fetch hostname: " + err.message + "!"); return; } // get date/time var dateTime = new Date().toJSON().slice(0,10) + "_" + new Date().toJSON().slice(11,19).replaceAll(":", "-"); zipFilename = hostname + "_" + dateTime + ".zip"; console.log(zipFilename); // Get files list setStatus("Fetching File List..."); try { var xhttp = new XMLHttpRequest(); xhttp.open("GET", getDomainname() + "/fileserver/config/", false); xhttp.send(); var parser = new DOMParser(); var content = parser.parseFromString(xhttp.responseText, 'text/html'); } catch(err) { setStatus("Failed to fetch files list: " + err.message); return; } const list = content.querySelectorAll("a"); var urls = []; for (a of list) { url = a.getAttribute("href"); urls.push(getDomainname() + url); } // Pack as zip and download try { backup(urls, zipFilename); } catch(err) { setStatus("Failed to zip files: " + err.message + "!"); return; } } ``` -------------------------------- ### JavaScript Function to Abort Setup Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_explain_7_abort.html This JavaScript function prompts the user to confirm aborting the setup mode. If confirmed, it attempts to load configuration, update setup mode parameters, save the configuration, and then reboots the device to the regular web interface. ```javascript function reboot() { if (confirm("Do you want to abort 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() + "/reboot"; parent.location = stringota; parent.location.href = stringota; parent.location.assign(stringota); parent.location.replace(stringota); } } ``` -------------------------------- ### Initial Data Loading and Refresh Setup Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/graph.html Initializes the data display by calling WriteModelFiles and WriteNumbers, then sets up a recurring refresh mechanism using setTimeout. ```javascript WriteModelFiles(); WriteNumbers(); function Refresh() { setTimeout (function() { run(); Refresh(); }, 300000); } run(); Refresh(); ``` -------------------------------- ### Backup Utility Function Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/backup.html A wrapper function that initiates the backup process by calling fetchFiles. It handles the initial setup and logging before starting the file fetching sequence. ```javascript const backup = (urls, zipFilename) => { if(!urls) return; /* Testing */ /*len = urls.length; for (i = 0; i < len - 3; i++) { urls.pop(); }*/ console.log(urls); urlIndex = 0; setStatus("Fetching files..."); fetchFiles(urls, [], 0, 0, zipFilename); }; ``` -------------------------------- ### Update UI for Setup Step 3 (Digit ROIs) Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/setup.html This snippet updates the UI elements to display information and controls for the Digit ROIs setup step. It sets iframe sources, element styles, and button states. ```javascript 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; ``` -------------------------------- ### JavaScript: Initialize Device Configuration and Refresh Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/overview.html Initializes the device by getting the domain name and refreshing the display. It includes commented-out code for setting image max width, which is no longer used. ```javascript function init(){ domainname = getDomainname(); // setImageMaxWidth(); // CamFrameSize was replaced by zoom - CamFrameSize is no longer needed/used for zoom Refresh(); } ``` -------------------------------- ### Helper Function to Start Zip Export Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/data_export.html A wrapper function to initiate the zip export process by calling fetchFiles. It handles cases where the URLs might be null. ```javascript const startExportZip = (urls, zipFilename) => { if(!urls) { return; } console.log(urls); urlIndex = 0; setStatus("Fetching files..."); fetchFiles(urls, [], 0, 0, zipFilename); }; ``` -------------------------------- ### Update UI for Setup Step 6 (Config Page) Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/setup.html This snippet configures the UI for the configuration page. It sets the main content source, adjusts iframe and content heights (specifically for the explanation iframe), and updates progress and navigation controls. ```javascript document.getElementById('maincontent').src = 'edit_config.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; ``` -------------------------------- ### Initiate OTA Update Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/ota_page.html Initiates the OTA update process by sending a GET request to the server. It constructs the URL with the file path and task parameters. This function is called when the user selects a file and is ready to proceed. ```javascript function update() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { if (this.responseText == "OK") { firework.launch('Update completed!', 'success', 5000); document.getElementById("file_selector").disabled = false; document.getElementById("status").innerText = "Status: Update completed"; clearInterval(updateTimer); } else if (this.responseText == "FAIL") { firework.launch('Update failed, please try again!', 'danger', 30000); clearInterval(updateTimer); } else if (this.responseText == "BUSY") { firework.launch('Device is busy, please try again later!', 'danger', 30000); clearInterval(updateTimer); } } else if (this.readyState == 4) { if (this.status == 404) { firework.launch('File not found! Please check the file name.', 'danger', 30000); } else { firework.launch('An error occured: ' + this.statusText, 'danger', 30000); } clearInterval(updateTimer); document.getElementById("status").innerText = "Status: Idle"; document.getElementById("file_selector").disabled = false; } }; var file_name = document.getElementById("file_selector").value; filePath = file_name.split(/[/\\]/).pop(); var url = domainname + "/ota?task=update&file=" + filePath; xhttp.open("GET", url, true); xhttp.send(); } ``` -------------------------------- ### JavaScript Initialization Function Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/prevalue_set.html This function initializes the application by getting the domain name, loading configuration, parsing it, updating the number selection, and loading the initial prevalue. Call this function on page load. ```javascript function init(){ domainname = getDomainname(); loadConfig(domainname); ParseConfig(); UpdateNUMBERS(); loadPrevalue(domainname); } init(); ``` -------------------------------- ### Initiate Data Export Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/data_export.html Starts the process of exporting data by zipping the contents of the data folder and initiating a download. It fetches the hostname and current date/time to create a unique filename for the zip archive. ```javascript function startExportData() { document.getElementById("progress").innerHTML = "Creating Export Data...
\n"; // Get hostname try { var xhttp = new XMLHttpRequest(); xhttp.open("GET", getDomainname() + "/info?type=Hostname", false); xhttp.send(); hostname = xhttp.responseText; } catch(err) { setStatus("Failed to fetch hostname: " + err.message + "!"); return; } // get date/time var dateTime = new Date().toJSON().slice(0,10) + "_" + new Date().toJSON().slice(11,19).replaceAll(":", "-"); zipFilename = hostname + "_" + dateTime + "_csv" + ".zip"; console.log(zipFilename); // Get files list setStatus("Fetching File List..."); try { var xhttp = new XMLHttpRequest(); xhttp.open("GET", getDomainname() + "/fileserver/log/data/", false); xhttp.send(); var parser = new DOMParser(); var content = parser.parseFromString(xhttp.responseText, 'text/html'); } catch(err) { setStatus("Failed to fetch files list: " + err.message); return; } const list = content.querySelectorAll("a"); var urls = []; for (a of list) { url = a.getAttribute("href"); urls.push(getDomainname() + url); } // Pack as zip and download try { startExportZip(urls, zipFilename); } catch(err) { setStatus("Failed to zip files: " + err.message + "!"); return; } } ``` -------------------------------- ### Update UI for Setup Step 4 (Digit ROIs) Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/setup.html This snippet configures the UI for the Digit ROIs editing step. It loads the relevant HTML, adjusts iframe heights, and updates progress indicators and button states. ```javascript 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; ``` -------------------------------- ### Read and Write Configuration Parameters Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_config_template.html Demonstrates how to read and write configuration parameters using JavaScript functions. These functions are used to interact with various settings like post-processing options, database fields, and MQTT configurations. ```javascript ReadParameter(param, "PostProcessing", "MaxRateType", true, NUNBERSAkt); ReadParameter(param, "PostProcessing", "ExtendedResolution", false, NUNBERSAkt); ReadParameter(param, "PostProcessing", "IgnoreLeadingNaN", false, NUNBERSAkt); // ReadParameter(param, "PostProcessing", "IgnoreAllNaN", false, NUNBERSAkt); ReadParameter(param, "PostProcessing", "AllowNegativeRates", false, NUNBERSAkt); ReadParameter(param, "PostProcessing", "CheckDigitIncreaseConsistency", false, NUNBERSAkt); ReadParameter(param, "InfluxDB", "Field", true, NUNBERSAkt); ReadParameter(param, "InfluxDBv2", "Field", true, NUNBERSAkt); ReadParameter(param, "InfluxDB", "Measurement", true, NUNBERSAkt); ReadParameter(param, "InfluxDBv2", "Measurement", true, NUNBERSAkt); ReadParameter(param, "MQTT", "DomoticzIDX", true, NUNBERSAkt); // var sel = document.getElementById("Numbers_value1"); NUNBERSAkt = sel.selectedIndex; // WriteParameter(param, category, "PostProcessing", "PreValueUse", false, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "DecimalShift", true, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "AnalogToDigitTransitionStart", true, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "ChangeRateThreshold", true, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "MaxRateValue", true, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "MaxRateType", true, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "ExtendedResolution", false, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "IgnoreLeadingNaN", false, NUNBERSAkt); // WriteParameter(param, category, "PostProcessing", "IgnoreAllNaN", false, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "AllowNegativeRates", false, NUNBERSAkt); WriteParameter(param, category, "PostProcessing", "CheckDigitIncreaseConsistency", false, NUNBERSAkt); WriteParameter(param, category, "InfluxDB", "Field", true, NUNBERSAkt); WriteParameter(param, category, "InfluxDBv2", "Field", true, NUNBERSAkt); WriteParameter(param, category, "InfluxDB", "Measurement", true, NUNBERSAkt); WriteParameter(param, category, "InfluxDBv2", "Measurement", true, NUNBERSAkt); WriteParameter(param, category, "MQTT", "DomoticzIDX", true, NUNBERSAkt); ``` -------------------------------- ### JavaScript Get Element Coordinates Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_alignment.html Calculates the cross-browser absolute position of an element relative to the document. ```javascript function getCoords(elem) { // crossbrowser version var box = elem.getBoundingClientRect(); var body = document.body; var docEl = document.documentElement; var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop; var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft; var clientTop = docEl.clientTop || body.clientTop || 0; var clientLeft = docEl.clientLeft || body.clientLeft || 0; var top = box.top + scrollTop - clientTop; var left = box.left + scrollLeft - clientLeft; return { top: Math.round(top), left: Math.round(left) }; } ``` -------------------------------- ### Reading Configuration Parameters Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_config_template.html This snippet demonstrates reading various configuration parameters for different services like MQTT, InfluxDB, Webhook, GPIO, and System settings. It also includes backward compatibility settings for older versions. ```javascript ReadParameter(param, "MQTT", "ClientKey", true); ReadParameter(param, "MQTT", "ValidateServerCert", true); ReadParameter(param, "MQTT", "DomoticzTopicIn", true); ReadParameter(param, "InfluxDB", "Uri", true); ReadParameter(param, "InfluxDB", "Database", true); ReadParameter(param, "InfluxDB", "Measurement", true); ReadParameter(param, "InfluxDB", "user", true); ReadParameter(param, "InfluxDB", "password", true); ReadParameter(param, "InfluxDBv2", "Uri", true); ReadParameter(param, "InfluxDBv2", "Bucket", true); ReadParameter(param, "InfluxDBv2", "Measurement", true); ReadParameter(param, "InfluxDBv2", "Org", true); ReadParameter(param, "InfluxDBv2", "Token", true); // ReadParameter(param, "InfluxDB", "Field", true); ReadParameter(param, "Webhook", "Uri", true); ReadParameter(param, "Webhook", "ApiKey", true); ReadParameter(param, "Webhook", "UploadImg", false); ReadParameter(param, "GPIO", "IO0", true); ReadParameter(param, "GPIO", "IO1", true); ReadParameter(param, "GPIO", "IO3", true); ReadParameter(param, "GPIO", "IO4", true); ReadParameter(param, "GPIO", "IO12", true); ReadParameter(param, "GPIO", "IO13", true); ReadParameter(param, "GPIO", "LEDType", false); ReadParameter(param, "GPIO", "LEDNumbers", false); ReadParameter(param, "GPIO", "LEDColor", false); // Folgende Zeilen sind für Abwärtskompatibität < v9.0.0 notwendig (manchmal parameter auskommentiert) param["GPIO"]["LEDType"]["enabled"] = true; param["GPIO"]["LEDNumbers"]["enabled"] = true; param["GPIO"]["LEDColor"]["enabled"] = true; param["GPIO"]["LEDType"]["found"] = true; param["GPIO"]["LEDNumbers"]["found"] = true; param["GPIO"]["LEDColor"]["found"] = true; //ReadParameter(param, "AutoTimer", "AutoStart", false); ReadParameter(param, "AutoTimer", "Interval", false); ReadParameter(param, "DataLogging", "DataLogActive", false); ReadParameter(param, "DataLogging", "DataFilesRetention", false); ReadParameter(param, "Debug", "LogLevel", false); ReadParameter(param, "Debug", "LogfilesRetention", false); ReadParameter(param, "System", "Tooltip", false); ReadParameter(param, "System", "TimeZone", true); ReadParameter(param, "System", "Hostname", true); ReadParameter(param, "System", "TimeServer", true); ReadParameter(param, "System", "RSSIThreshold", true); ReadParameter(param, "System", "CPUFrequency", true); ``` -------------------------------- ### Load Configuration and Initialize Parameters Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_config_template.html Loads the system configuration and initializes individual camera parameters. It updates UI elements and enables/disables camera zoom and sharpness controls based on the loaded configuration. ```javascript function LoadConfigNeu() { if (!loadConfig(domainname)) { firework.launch('Configuration could not be loaded! Please reload the page!', 'danger', 30000); return; } param = getCamConfig(); category = getConfigCategory(); InitIndivParameter(); UpdateInput(); var sel = document.getElementById("Numbers_value1"); UpdateInputIndividual(sel); UpdateExpertModus(); UpdateTooltipModus(); document.getElementById("divall").style.display = ''; if(!document.getElementById("TakeImage_CamZoom_value1").selectedIndex) { // EnDisableItem(_status, _param, _category, _cat, _name, _optional, _number = -1) EnDisableItem(true, param, category, "TakeImage", "CamZoomOffsetX", false); EnDisableItem(true, param, category, "TakeImage", "CamZoomOffsetY", false); EnDisableItem(true, param, category, "TakeImage", "CamZoomSize", false); } else { EnDisableItem(false, param, category, "TakeImage", "CamZoomOffsetX", false); EnDisableItem(false, param, category, "TakeImage", "CamZoomOffsetY", false); EnDisableItem(false, param, category, "TakeImage", "CamZoomSize", false); } if(document.getElementById("TakeImage_CamAutoSharpness_value1").selectedIndex) { EnDisableItem(true, param, category, "TakeImage", "CamSharpness", false); } else { EnDisableItem(false, param, category, "TakeImage", "CamSharpness", false); } } ``` -------------------------------- ### Mouse Down Event Handler Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_alignment.html Handles the mousedown event on the canvas to record the starting coordinates for drawing a rectangle. ```javascript function mouseDown(e) { var zw = getCoords(this) rect.startX = e.pageX - zw.left; rect.startY = e.pageY - zw.top; document.getElementById("refx").value = rect.startX; document.getElementById("refy").value = rect.startY; drag = true; } ``` -------------------------------- ### Get Element Coordinates Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_reference.html Calculates the bounding box and scroll offsets for an element to determine its position on the page. ```javascript function getCoords(elem) { // crossbrowser version var box = elem.getBoundingClientRect(); var body = document.body; var docEl = document.documentElement; var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop; var scrollLeft = window.pageXOffset || docEl.scrollLeft || ``` -------------------------------- ### Initialize Web UI and Load Versions Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/index.html Loads hostname, firmware version, and web UI version. Sets the default page cookie if none exists and loads the main content frame. ```javascript LoadHostname(); LoadFwVersion(); LoadWebUiVersion(); HA_send_discovery_visibility(); if (getCookie("page") == "" || getCookie("page") == "reboot_page.html?v=$COMMIT_HASH") { document.cookie = "page=overview.html?v=$COMMIT_HASH" + "; path=/"; } console.log("Loading page: " + getCookie("page")); document.getElementById('maincontent').src = getCookie("page"); ``` -------------------------------- ### Handle Mouse Down Event for Region Selection Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_analog.html Initiates the drawing or resizing of a region when the mouse button is pressed. Records the starting coordinates and sets the drag flag. ```javascript function mouseDown(e) { zw = getCoords(this) rect.startX = e.pageX - zw.left; rect.startY = e.pageY - zw.top; if (drawFromCenter) { rect.centerX = rect.startX; rect.centerY = rect.startY; } document.getElementById("refx").value = rect.startX; document.getElementById("refy").value = rect.startY; drag = true; } ``` -------------------------------- ### Initialize Application and Event Listeners Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_digits.html Initializes the application by opening the description, loading configuration, parsing parameters, and attaching mouse event listeners to the canvas. It also performs checks on ROI equidistance and synchronicity. ```javascript function init() { openDescription(); domainname = getDomainname(); if (!loadConfig(domainname)) { firework.launch('Configuration could not be loaded! Please reload the page!', 'danger', 30000); return; } ParseConfig(); param = getConfigParameters(); cofcat = getConfigCategory(); canvas.addEventListener('mousedown', mouseDown, false); canvas.addEventListener('mouseup', mouseUp, false); canvas.addEventListener('mousemove', mouseMove, false); loadCanvas(domainname + "/fileserver/config/reference.jpg"); UpdateNUMBERS(); /* Check if the ROIs are equidistant. Only if not, untick the checkbox */ if (ROIInfo.length > 1) { var distanceROI0_to_ROI1 = parseInt(ROIInfo[1].x) - (parseInt(ROIInfo[0].x) + parseInt(ROIInfo[0].dx)); // Distance between 1st and 2nd ROI //console.log("0->1: " + distanceROI0_to_ROI1); for (var i = 1; i < (ROIInfo.length - 1); ++i) { // 2nd .. 2nd-last ROI //console.log(i + "->" + i+1 + ": " + (parseInt(ROIInfo[i+1].x) - (parseInt(ROIInfo[i].x) + parseInt(ROIInfo[i].dx)))); if (distanceROI0_to_ROI1 != (parseInt(ROIInfo[i+1].x) - (parseInt(ROIInfo[i].x) + parseInt(ROIInfo[i].dx)))) { console.log("Not equidistant, unticking the checkbox!"); lockSpaceEquidistant = false; document.getElementById("lockSpaceEquidistant").checked = lockSpaceEquidistant; if (!lockSpaceEquidistant) { document.getElementById("space").disabled = true; } else { document.getElementById("space").disabled = false; } break; } } } /* Check if the ROIs have same y, dy and dx. If so, tick the sync checkbox */ var all_y_dx_dy_Identical = true; if (ROIInfo.length > 1) { for (var i = 1; i < (ROIInfo.length); ++i) { // 2nd .. } ``` -------------------------------- ### Load and Initialize Reference Image Settings Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_reference.html Loads a reference image from a URL and initializes various camera parameters and UI elements. It sets initial rotation values, enables/disables specific input fields, and updates the UI state based on reference image settings. ```javascript function showReference(){ url = domainname + "/fileserver/config/reference.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1); loadCanvas(url, false); isActReference = true; var _rotate_temp = param["Alignment"]["InitialRotate"].value1; if (_rotate_temp < 0) { document.getElementById("PreRotateAngle_value1").value = Math.ceil(_rotate_temp); } else { document.getElementById("PreRotateAngle_value1").value = Math.floor(_rotate_temp); } document.getElementById("FineRotate_value1").value = (Number(_rotate_temp) - Number(document.getElementById("PreRotateAngle_value1").value)).toFixed(1); WriteParameter(param, category, "TakeImage", "CamBrightness", false, true); WriteParameter(param, category, "TakeImage", "CamContrast", false, true); WriteParameter(param, category, "TakeImage", "CamSaturation", false, true); WriteParameter(param, category, "TakeImage", "CamSharpness", false, true); WriteParameter(param, category, "TakeImage", "CamAutoSharpness", false); WriteParameter(param, category, "TakeImage", "CamZoom", false); WriteParameter(param, category, "TakeImage", "CamZoomOffsetX", false); WriteParameter(param, category, "TakeImage", "CamZoomOffsetY", false); WriteParameter(param, category, "TakeImage", "CamZoomSize", false); WriteParameter(param, category, "TakeImage", "CamAec", false); WriteParameter(param, category, "TakeImage", "CamAec2", false); WriteParameter(param, category, "TakeImage", "CamAeLevel", false, true); WriteParameter(param, category, "TakeImage", "CamHmirror", false); WriteParameter(param, category, "TakeImage", "CamVflip", false); WriteParameter(param, category, "TakeImage", "CamSpecialEffect", false); WriteParameter(param, category, "TakeImage", "LEDIntensity", false); EnDisableItem(false, param, category, "TakeImage", "CamBrightness", false); EnDisableItem(false, param, category, "TakeImage", "CamSaturation", false); EnDisableItem(false, param, category, "TakeImage", "CamContrast", false); EnDisableItem(false, param, category, "TakeImage", "CamSharpness", false); EnDisableItem(false, param, category, "TakeImage", "CamAutoSharpness", false); EnDisableItem(false, param, category, "TakeImage", "CamZoom", false); EnDisableItem(false, param, category, "TakeImage", "CamZoomOffsetX", false); EnDisableItem(false, param, category, "TakeImage", "CamZoomOffsetY", false); EnDisableItem(false, param, category, "TakeImage", "CamZoomSize", false); EnDisableItem(false, param, category, "TakeImage", "CamAec", false); EnDisableItem(false, param, category, "TakeImage", "CamAec2", false); EnDisableItem(false, param, category, "TakeImage", "CamAeLevel", false); EnDisableItem(false, param, category, "TakeImage", "CamHmirror", false); EnDisableItem(false, param, category, "TakeImage", "CamVflip", false); EnDisableItem(false, param, category, "TakeImage", "CamSpecialEffect", false); EnDisableItem(false, param, category, "TakeImage", "LEDIntensity", false); document.getElementById("ExpertModus_enabled").disabled = true; document.getElementById("FineRotate_value1").disabled = true; document.getElementById("FineRotate_text").style.color = "rgb(122, 122, 122)"; document.getElementById("PreRotateAngle_value1").disabled = true; document.getElementById("PreRotateAngle_text").style.color = "rgb(122, 122, 122)"; document.getElementById("savereferenceimage").disabled = true; document.getElementById("updatereferenceimage").disabled = true; document.getElementById("showcurrentreference").disabled = true; document.getElementById("startreference").disabled = false; } ``` -------------------------------- ### Get URL Parameter by Name Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_config_template.html Extracts a URL parameter's value from a given URL. Handles URL encoding and special characters in parameter names. ```javascript function getParameterByName(name, url = window.location.href) { name = name.replace(/[\[\]]/g, '\$&'); var regex = new RegExp('[\]' + name + '(=([^&#]*)|\]|#|$)'), results = regex.exec(url); if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, ' ')); } ``` -------------------------------- ### Handling Mouse Down Event for ROI Selection Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_digits.html Captures the starting coordinates of a mouse drag operation to initiate ROI selection or modification. Updates input fields with initial values. ```javascript function mouseDown(e) { zw = getCoords(this) rect.startX = e.pageX - zw.left; rect.startY = e.pageY - zw.top; document.getElementById("refx").value = rect.startX; document.getElementById("refy").value = rect.startY; drag = true; } ``` -------------------------------- ### Handling Mouse Up Event to Finalize ROI Dimensions Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_digits.html Finalizes the ROI dimensions after a drag operation, ensuring width and height are positive. Updates input fields with the final dimensions and starting coordinates. ```javascript function mouseUp() { drag = false; if (rect.w < 0) { rect.w = -rect.w rect.startX-=rect.w } if (rect.h < 0) { rect.h = -rect.h rect.startY-=rect.h } document.getElementById("refdx").value = rect.w; document.getElementById("refdy").value = rect.h; document.getElementById("refx").value = rect.startX; document.getElementById("refy").value = rect.startY; } ``` -------------------------------- ### Compile Firmware Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/code/README.md Command to compile the project for the esp32cam environment using PlatformIO. ```bash cd code platformio run --environment esp32cam ``` -------------------------------- ### Load Firmware Build Time Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/info.html Fetches and displays the firmware build time. Expects the response in 'YYYY-MM-DD HH:MM' format and reformats it to 'DD.MM.YYYY HH:MM'. ```javascript 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(); } ``` -------------------------------- ### Page Initialization Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/sd-card/html/edit_analog.html Initializes the page by opening the description, loading configuration, parsing parameters, and setting up canvas event listeners. It also checks if all ROIs have identical dimensions and updates the UI accordingly. ```javascript function init() { openDescription(); domainname = getDomainname(); if (!loadConfig(domainname)) { firework.launch('Configuration could not be loaded! Please reload the page!', 'danger', 30000); return; } ParseConfig(); param = getConfigParameters(); cofcat = getConfigCategory(); canvas.addEventListener('mousedown', mouseDown, false); canvas.addEventListener('mouseup', mouseUp, false); canvas.addEventListener('mousemove', mouseMove, false); loadCanvas(domainname + "/fileserver/config/reference.jpg"); UpdateNUMBERS(); /* Check if the ROIs have same dy and dx. If so, tick the sync checkbox */ var all_dx_dy_Identical = true; if (ROIInfo.length > 1) { for (var i = 1; i < (ROIInfo.length); ++i) { // 2nd .. last ROI if (parseInt(ROIInfo[i].dx) != parseInt(ROIInfo[0].dx) || parseInt(ROIInfo[i].dy) != parseInt(ROIInfo[0].dy)) { all_dx_dy_Identical = false; break; } } } if (all_dx_dy_Identical) { lockSizes = true; console.log("All ROI have the same dX and dY, ticking the sync checkbox!"); document.getElementById("lockSizes").checked = lockSizes; } else { console.log("Not all ROI have the same dX and dY, unticking the sync checkbox!"); } document.getElementById("saveroi").disabled = true; drawImage(); draw(); } ``` -------------------------------- ### Adding Extra Component Directories in CMake Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/code/components/jomjol_controlcamera/CMakeLists.txt This command appends a specific directory path, likely containing common protocol examples, to the EXTRA_COMPONENT_DIRS list. This is useful for including shared components in the build. ```cmake list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) ``` -------------------------------- ### Get Git Revision and Build Time Source: https://github.com/jomjol/ai-on-the-edge-device/blob/main/code/main/CMakeLists.txt Executes git commands to retrieve the commit revision, diff status, tag, and branch. Also captures the build timestamp. This information is used for versioning the build. ```cmake execute_process(COMMAND git log --pretty=format:'%h' -n 1 OUTPUT_VARIABLE GIT_REV ERROR_QUIET) string(TIMESTAMP BUILD_TIME "%Y-%m-%d %H:%M") ```