From 15e40abe272367ac94afe25b6c0676546a40fcd4 Mon Sep 17 00:00:00 2001 From: Mario Mariete <11509521+melkati@users.noreply.github.com> Date: Fri, 7 Jun 2024 23:41:58 +0200 Subject: [PATCH] CO2 Gadget Beta v0.14.004 Improve calibration wizard --- data/combined.js.gz | Bin 3548 -> 3548 bytes data/index.html.gz | Bin 991 -> 991 bytes data/main.js.gz | Bin 578 -> 578 bytes data/ota.html.gz | Bin 789 -> 789 bytes data/preferences.html.gz | Bin 5112 -> 5147 bytes data/preferences.js.gz | Bin 3822 -> 3810 bytes data/preferences.min.js | 2 +- data/status.html.gz | Bin 1915 -> 1915 bytes data/status.js.gz | Bin 2213 -> 2213 bytes data/style.css.gz | Bin 2554 -> 2648 bytes platformio.ini | 6 +- webserver/preferences.html | 8 +- webserver/preferences.js | 200 ++++++++++++++++++++----------------- webserver/style.css | 62 +++++++++--- 14 files changed, 164 insertions(+), 114 deletions(-) diff --git a/data/combined.js.gz b/data/combined.js.gz index 27f1791d31fb8c485c99d31ff8bfc3c40e19cae4..9be5aedbb2a52331c52984247b02850d2f7745be 100644 GIT binary patch delta 15 Wcmca3eMg#2zMF&Nc;!a6YrFt0Mg@rg delta 15 Wcmca3eMg#2zMF%i(rhE!HC_NJBLw&W diff --git a/data/index.html.gz b/data/index.html.gz index d063e3f95a0fedc85eecebba1421db885dd1b492..ee991bfc87306d53caf00d247397b483b6b2a39f 100644 GIT binary patch delta 15 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 diff --git a/data/preferences.js.gz b/data/preferences.js.gz index 1a1414768ad76c0f0284c51282e67098bc2cf721..0036d686640e49f2cca841929333352925fffec7 100644 GIT binary patch literal 3810 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 kU+!-CBza>0qresponse.json()).then(versionInfo=>{if(preferencesDebug)console.log("Version information:",versionInfo);const versionElement=document.getElementById("co2GadgetVersion");const versionText=`CO2 Gadget: v${versionInfo.firmVerMajor}.${versionInfo.firmVerMinor}.${versionInfo.firmRevision}-${versionInfo.firmBranch} (Flavour: ${versionInfo.firmFlavour})`;versionElement.innerText=versionText}).catch(error=>console.error("Error fetching version information:",error))}function populateFormWithPreferences(preferences){if(preferences.relaxedSecurity!==undefined){if(preferencesDebug)console.log(`Setting relaxedSecurity to:`,preferences.relaxedSecurity);relaxedSecurity=preferences.relaxedSecurity}handlePasswordFields();const setFormValue=(elementId,value)=>{const element=document.getElementById(elementId);if(element)element.value=value;if(preferencesDebug)console.log(`Setting ${elementId} to:`,value)};const setFormCheckbox=(elementId,isChecked)=>{const element=document.getElementById(elementId);if(element)element.checked=isChecked;if(preferencesDebug)console.log(`Setting ${elementId} to:`,isChecked)};setFormCheckbox("activeWIFI",preferences.activeWIFI);setFormValue("wifiSSID",preferences.wifiSSID);if(relaxedSecurity)setFormValue("wifiPass",preferences.wifiPass);setFormValue("hostName",preferences.hostName);setFormCheckbox("useStaticIP",preferences.useStaticIP);setFormValue("staticIP",preferences.staticIP);setFormValue("gateway",preferences.gateway);setFormValue("subnet",preferences.subnet);setFormValue("dns1",preferences.dns1);setFormValue("dns2",preferences.dns2);setFormValue("selCO2Sensor",preferences.selCO2Sensor);setFormCheckbox("autoSelfCalibration",preferences.autoSelfCal);setFormValue("customCalValue",preferences.customCalValue);setFormValue("co2OrangeRange",preferences.co2OrangeRange);setFormValue("co2RedRange",preferences.co2RedRange);setFormValue("tempOffset",preferences.tempOffset);setFormCheckbox("showFahrenheit",preferences.showFahrenheit);setFormValue("altitudeMeters",preferences.altitudeMeters);setFormValue("measurementInterval",preferences.measurementInterval);setFormCheckbox("outModeRelay",preferences.outModeRelay);setFormValue("channelESPNow",preferences.channelESPNow);setFormValue("boardIdESPNow",preferences.boardIdESPNow);setFormValue("peerESPNowAddress",preferences.peerESPNowAddress);setFormValue("neopixBright",preferences.neopixBright);setFormValue("selNeopxType",preferences.selNeopxType);setFormCheckbox("activeBLE",preferences.activeBLE);setFormCheckbox("activeMQTT",preferences.activeMQTT);setFormCheckbox("activeESPNOW",preferences.activeESPNOW);setFormValue("mqttClientId",preferences.mqttClientId);setFormCheckbox("mqttShowInCon",preferences.mqttShowInCon);setFormValue("rootTopic",preferences.rootTopic);setFormValue("mqttBroker",preferences.mqttBroker);setFormValue("mqttUser",preferences.mqttUser);if(relaxedSecurity)setFormValue("mqttPass",preferences.mqttPass);setFormValue("batDischgd",preferences.batDischgd);setFormValue("batChargd",preferences.batChargd);setFormValue("vRef",preferences.vRef);setFormValue("tToDispOff",preferences.tToDispOff);setFormValue("tToPubMQTT",preferences.tToPubMQTT);setFormValue("tToPubESPNow",preferences.tToPubESPNow);setFormValue("tKeepAlMQTT",preferences.tKeepAlMQTT);setFormValue("tKeepAlESPNow",preferences.tKeepAlESPNow);setFormCheckbox("showTemp",preferences.showTemp);setFormCheckbox("showHumidity",preferences.showHumidity);setFormCheckbox("showBattery",preferences.showBattery);setFormCheckbox("showCO2",preferences.showCO2);setFormCheckbox("dispOffOnExP",preferences.dispOffOnExP);setFormCheckbox("displayReverse",preferences.displayReverse);setFormValue("DisplayBright",preferences.DisplayBright);setFormCheckbox("debugSensors",preferences.debugSensors);setFormValue("toneBzrBeep",preferences.toneBzrBeep);setFormValue("durBzrBeep",preferences.durBzrBeep);setFormValue("timeBtwnBzr",preferences.timeBtwnBzr);if(preferences.cpNoTimeout!==undefined){setFormCheckbox("cpNoTimeout",preferences.cpNoTimeout)}if(preferences.cpRelaxedSec!==undefined){setFormCheckbox("cpRelaxedSec",preferences.cpRelaxedSec)}if(preferences.cpDebug!==undefined){setFormCheckbox("cpDebug",preferences.cpDebug)}if(preferences.cpWaitTime!==undefined){setFormValue("cpWaitTime",preferences.cpWaitTime)}toggleVisibility("activeWIFI","wifiNetworks",isChecked=>{document.getElementById("mqttConfig").style.display=isChecked?"block":"none"});toggleVisibility("activeMQTT","mqttConfig");toggleVisibility("activeESPNOW","espNowConfig");toggleVisibility("useStaticIP","staticIPSettings");handleWiFiMQTTDependency()}function loadPreferencesFromServer(){fetch("/getActualSettingsAsJson"+(relaxedSecurity?"?relaxedSecurity=true":"")).then(response=>response.json()).then(preferences=>{if(preferencesDebug)console.log("Get preferences from server response:",preferences);populateFormWithPreferences(preferences)}).catch(error=>console.error("Error retrieving preferences:",error))}function collectPreferencesData(){const preferencesData={customCalValue:document.getElementById("customCalValue").value,tempOffset:document.getElementById("tempOffset").value,altitudeMeters:document.getElementById("altitudeMeters").value,autoSelfCalibration:document.getElementById("autoSelfCalibration").checked,co2OrangeRange:document.getElementById("co2OrangeRange").value,co2RedRange:document.getElementById("co2RedRange").value,DisplayBright:document.getElementById("DisplayBright").value,neopixBright:document.getElementById("neopixBright").value,selNeopxType:document.getElementById("selNeopxType").value,activeBLE:document.getElementById("activeBLE").checked,activeWIFI:document.getElementById("activeWIFI").checked,activeMQTT:document.getElementById("activeMQTT").checked,activeESPNOW:document.getElementById("activeESPNOW").checked,rootTopic:document.getElementById("rootTopic").value,batDischgd:document.getElementById("batDischgd").value,batChargd:document.getElementById("batChargd").value,vRef:document.getElementById("vRef").value,tToDispOff:document.getElementById("tToDispOff").value,tToPubMQTT:document.getElementById("tToPubMQTT").value,tToPubESPNow:document.getElementById("tToPubESPNow").value,tKeepAlMQTT:document.getElementById("tKeepAlMQTT").value,tKeepAlESPNow:document.getElementById("tKeepAlESPNow").value,dispOffOnExP:document.getElementById("dispOffOnExP").checked,wifiSSID:document.getElementById("wifiSSID").value,hostName:document.getElementById("hostName").value,useStaticIP:document.getElementById("useStaticIP").checked,staticIP:document.getElementById("staticIP").value,gateway:document.getElementById("gateway").value,subnet:document.getElementById("subnet").value,dns1:document.getElementById("dns1").value,dns2:document.getElementById("dns2").value,selCO2Sensor:document.getElementById("selCO2Sensor").value,debugSensors:document.getElementById("debugSensors").checked,displayReverse:document.getElementById("displayReverse").checked,showFahrenheit:document.getElementById("showFahrenheit").checked,measurementInterval:document.getElementById("measurementInterval").value,outModeRelay:document.getElementById("outModeRelay").checked,channelESPNow:document.getElementById("channelESPNow").value,boardIdESPNow:document.getElementById("boardIdESPNow").value,peerESPNowAddress:document.getElementById("peerESPNowAddress").value,showTemp:document.getElementById("showTemp").checked,showHumidity:document.getElementById("showHumidity").checked,showBattery:document.getElementById("showBattery").checked,showCO2:document.getElementById("showCO2").checked,mqttClientId:document.getElementById("mqttClientId").value,mqttShowInCon:document.getElementById("mqttShowInCon").checked,mqttBroker:document.getElementById("mqttBroker").value,mqttUser:document.getElementById("mqttUser").value,toneBzrBeep:document.getElementById("toneBzrBeep").value,durBzrBeep:document.getElementById("durBzrBeep").value,timeBtwnBzr:document.getElementById("timeBtwnBzr").value};if(relaxedSecurity){preferencesData.wifiPass=document.getElementById("wifiPass").value;preferencesData.mqttPass=document.getElementById("mqttPass").value}const cpNoTimeout=document.getElementById("cpNoTimeout");if(cpNoTimeout){preferencesData.cpNoTimeout=cpNoTimeout.checked}const cpRelaxedSec=document.getElementById("cpRelaxedSec");if(cpRelaxedSec){preferencesData.cpRelaxedSec=cpRelaxedSec.checked}const cpDebug=document.getElementById("cpDebug");if(cpDebug){preferencesData.cpDebug=cpDebug.checked}const cpWaitTime=document.getElementById("cpWaitTime");if(cpWaitTime){preferencesData.cpWaitTime=cpWaitTime.value}console.log("Collected preferences data:",preferencesData);return preferencesData}function showSavingPopup(){const popup=document.getElementById("popup");popup.style.display="block";console.log("Show popup");setTimeout(()=>{popup.style.display="none";console.log("Hide popup")},2e3)}function savePreferences(){showSavingPopup();const preferencesData=collectPreferencesData();if(preferencesDebug)console.log("Sending preferences to server:",preferencesData);fetch("/savePreferences",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(preferencesData)}).then(response=>{if(response.ok){console.log("Preferences updated successfully!")}else{alert("Error updating preferences. Please try again.")}}).catch(error=>console.error("Error saving preferences:",error))}function restartESP32(){const isConfirmed=confirm("Are you sure you want to restart the ESP32?");if(isConfirmed){if(preferencesDebug)console.log("Restarting ESP32...");fetch("/restart",{method:"GET",headers:{"Content-Type":"text/plain"}}).then(response=>{if(response.ok){console.log("ESP32 restart initiated")}else{throw new Error(`HTTP error! Status: ${response.status}`)}}).catch(error=>console.error("Error restarting ESP32:",error))}}function backupPreferences(){const preferencesData=collectPreferencesData();const jsonData=JSON.stringify(preferencesData);const blob=new Blob([jsonData],{type:"application/json"});const a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download="preferences_backup.json";document.body.appendChild(a);a.click();document.body.removeChild(a);alert("Preferences backup completed successfully!")}function restorePreferencesFromData(preferencesData){const preferences=JSON.parse(preferencesData);populateFormWithPreferences(preferences)}function chooseFileAndRestore(){document.getElementById("fileInput").click()}function handleFileSelection(event){const file=event.target.files[0];if(file){const reader=new FileReader;reader.readAsText(file,"UTF-8");reader.onload=evt=>{const preferencesData=evt.target.result;restorePreferencesFromData(preferencesData)};reader.onerror=evt=>{console.error("Error reading file:",evt.target.error);alert("Error reading file. Please try again.")}}}function toggleVisibility(checkboxId,elementId,callback){const checkbox=document.getElementById(checkboxId);const element=document.getElementById(elementId);if(!checkbox||!element){console.error(`Checkbox or element not found: ${checkboxId}, ${elementId}`);return}const toggleElement=()=>{element.style.display=checkbox.checked?"block":"none";if(callback)callback(checkbox.checked)};toggleElement();checkbox.addEventListener("change",toggleElement)}function handleWiFiMQTTDependency(){const wifiCheckbox=document.getElementById("activeWIFI");const mqttCheckbox=document.getElementById("activeMQTT");if(!wifiCheckbox||!mqttCheckbox){console.error("Checkboxes not found: activeWIFI, activeMQTT");return}const updateMQTTState=()=>{if(!wifiCheckbox.checked){mqttCheckbox.checked=false;mqttCheckbox.disabled=true;document.getElementById("mqttConfig").style.display="none"}else{mqttCheckbox.disabled=false}};const updateWiFiState=()=>{if(mqttCheckbox.checked){wifiCheckbox.checked=true}toggleVisibility("activeMQTT","mqttConfig")};wifiCheckbox.addEventListener("change",updateMQTTState);mqttCheckbox.addEventListener("change",updateWiFiState);updateMQTTState();updateWiFiState()}function updateVoltage(){fetch("/readBatteryVoltage").then(response=>response.text()).then(voltage=>{document.getElementById("currentVoltage").textContent=voltage+" Volts"}).catch(error=>console.error("Error fetching battery voltage:",error))}function updateVRef(){const vRefValue=document.getElementById("vRef").value;fetch(`/settings?SetVRef=${vRefValue}`).then(response=>{if(!response.ok)throw new Error("Error updating VRef");console.log("VRef updated successfully")}).catch(error=>console.error("Error updating VRef:",error))}setInterval(updateVoltage,1e3);document.getElementById("vRef").addEventListener("input",()=>{setTimeout(updateVRef,100)});function handlePasswordFields(){const inputField=document.getElementById("wifiSSID");const passwordFields=document.querySelectorAll("input[type=password]");passwordFields.forEach(field=>{if(relaxedSecurity){field.removeAttribute("disabled")}else{field.disabled=true;field.value="";field.placeholder="Password (disabled)"}});if(relaxedSecurity){inputField.removeAttribute("readonly")}else{inputField.setAttribute("readonly","readonly")}}function calibrateSensor(calibrationValue){if(calibrationValue>400&&calibrationValue<2e3){console.log("Calibration process started...");console.log("Calibration value:",calibrationValue);fetch(`/settings?CalibrateCO2=${calibrationValue}`).then(response=>{if(!response.ok)throw new Error("Error calibrating CO2 sensor");console.log("CO2 sensor calibrated successfully")}).catch(error=>console.error("Error calibrating CO2 sensor:",error))}else{console.error("Invalid calibration value, please enter a value between 400 and 2000 ppm");console.log("Calibration value:",calibrationValue)}}function handleCalibrationWizard(){const calibrateButton=document.getElementById("calibrateButton");const calibrationModal=document.getElementById("calibrationModal");const countdownModal=document.getElementById("countdownModal");const closeSpan=document.querySelector(".close");const acknowledgeCheckbox=document.getElementById("acknowledgeCheckbox");const acknowledgeLabel=document.getElementById("acknowledgeLabel");const calibrateNowButton=document.getElementById("calibrateNowButton");const countdownSpan=document.getElementById("countdown");const currentCO2ValueSpan=document.getElementById("currentCO2Value");function getCurrentCO2Value(){fetch("/readCO2").then(response=>response.text()).then(data=>{let co2Value=parseFloat(data);document.getElementById("currentCO2Value").textContent=co2Value.toFixed(0)}).catch(error=>{console.error("Error fetching CO2 data",error)})}function changeTextColor(){acknowledgeLabel.style.color="var(--unchecked-font-color)"}calibrateButton.addEventListener("click",()=>{calibrationModal.style.display="block";document.getElementById("customCalibrationValue").textContent=document.getElementById("customCalValue").value+" ppm";getCurrentCO2Value();updateCO2Interval=setInterval(getCurrentCO2Value,5e3)});closeSpan.addEventListener("click",()=>{calibrationModal.style.display="none";clearInterval(updateCO2Interval)});acknowledgeCheckbox.addEventListener("change",()=>{if(acknowledgeCheckbox.checked){acknowledgeLabel.style.color=""}});calibrateNowButton.addEventListener("click",()=>{if(!acknowledgeCheckbox.checked){changeTextColor();return}calibrationModal.style.display="none";countdownModal.style.display="block";calibrateSensor(document.getElementById("customCalValue").value);let countdown=15;countdownSpan.textContent=countdown;const interval=setInterval(()=>{countdown-=1;countdownSpan.textContent=countdown;if(countdown<=0){clearInterval(interval);countdownModal.style.display="none"}},1e3)});window.addEventListener("click",event=>{if(event.target==calibrationModal){calibrationModal.style.display="none";clearInterval(updateCO2Interval)}})}document.addEventListener("DOMContentLoaded",()=>{var currentURL=window.location.href;if(currentURL.includes("preferences.html")){highlightCurrentPage();relaxedSecurity=currentURL.includes("relaxedSecurity");forceCaptivePortalActive=currentURL.includes("forceCaptivePortalActive");handlePasswordFields();loadPreferencesFromServer();fetchVersion();toggleVisibility("activeWIFI","wifiNetworks",isChecked=>{document.getElementById("mqttConfig").style.display=isChecked?"block":"none"});toggleVisibility("activeMQTT","mqttConfig");toggleVisibility("activeESPNOW","espNowConfig");toggleVisibility("useStaticIP","staticIPSettings");handleWiFiMQTTDependency();handleCalibrationWizard()}}); \ No newline at end of file +var relaxedSecurity=false;var forceCaptivePortalActive=false;var preferencesDebug=false;function fetchVersion(){fetch("/getVersion").then(response=>response.json()).then(versionInfo=>{if(preferencesDebug)console.log("Version information:",versionInfo);const versionElement=document.getElementById("co2GadgetVersion");const versionText=`CO2 Gadget: v${versionInfo.firmVerMajor}.${versionInfo.firmVerMinor}.${versionInfo.firmRevision}-${versionInfo.firmBranch} (Flavour: ${versionInfo.firmFlavour})`;versionElement.innerText=versionText}).catch(error=>console.error("Error fetching version information:",error))}function populateFormWithPreferences(preferences){if(preferences.relaxedSecurity!==undefined){if(preferencesDebug)console.log(`Setting relaxedSecurity to:`,preferences.relaxedSecurity);relaxedSecurity=preferences.relaxedSecurity}handlePasswordFields();const setFormValue=(elementId,value)=>{const element=document.getElementById(elementId);if(element)element.value=value;if(preferencesDebug)console.log(`Setting ${elementId} to:`,value)};const setFormCheckbox=(elementId,isChecked)=>{const element=document.getElementById(elementId);if(element)element.checked=isChecked;if(preferencesDebug)console.log(`Setting ${elementId} to:`,isChecked)};setFormCheckbox("activeWIFI",preferences.activeWIFI);setFormValue("wifiSSID",preferences.wifiSSID);if(relaxedSecurity)setFormValue("wifiPass",preferences.wifiPass);setFormValue("hostName",preferences.hostName);setFormCheckbox("useStaticIP",preferences.useStaticIP);setFormValue("staticIP",preferences.staticIP);setFormValue("gateway",preferences.gateway);setFormValue("subnet",preferences.subnet);setFormValue("dns1",preferences.dns1);setFormValue("dns2",preferences.dns2);setFormValue("selCO2Sensor",preferences.selCO2Sensor);setFormCheckbox("autoSelfCalibration",preferences.autoSelfCal);setFormValue("customCalValue",preferences.customCalValue);setFormValue("co2OrangeRange",preferences.co2OrangeRange);setFormValue("co2RedRange",preferences.co2RedRange);setFormValue("tempOffset",preferences.tempOffset);setFormCheckbox("showFahrenheit",preferences.showFahrenheit);setFormValue("altitudeMeters",preferences.altitudeMeters);setFormValue("measurementInterval",preferences.measurementInterval);setFormCheckbox("outModeRelay",preferences.outModeRelay);setFormValue("channelESPNow",preferences.channelESPNow);setFormValue("boardIdESPNow",preferences.boardIdESPNow);setFormValue("peerESPNowAddress",preferences.peerESPNowAddress);setFormValue("neopixBright",preferences.neopixBright);setFormValue("selNeopxType",preferences.selNeopxType);setFormCheckbox("activeBLE",preferences.activeBLE);setFormCheckbox("activeMQTT",preferences.activeMQTT);setFormCheckbox("activeESPNOW",preferences.activeESPNOW);setFormValue("mqttClientId",preferences.mqttClientId);setFormCheckbox("mqttShowInCon",preferences.mqttShowInCon);setFormValue("rootTopic",preferences.rootTopic);setFormValue("mqttBroker",preferences.mqttBroker);setFormValue("mqttUser",preferences.mqttUser);if(relaxedSecurity)setFormValue("mqttPass",preferences.mqttPass);setFormValue("batDischgd",preferences.batDischgd);setFormValue("batChargd",preferences.batChargd);setFormValue("vRef",preferences.vRef);setFormValue("tToDispOff",preferences.tToDispOff);setFormValue("tToPubMQTT",preferences.tToPubMQTT);setFormValue("tToPubESPNow",preferences.tToPubESPNow);setFormValue("tKeepAlMQTT",preferences.tKeepAlMQTT);setFormValue("tKeepAlESPNow",preferences.tKeepAlESPNow);setFormCheckbox("showTemp",preferences.showTemp);setFormCheckbox("showHumidity",preferences.showHumidity);setFormCheckbox("showBattery",preferences.showBattery);setFormCheckbox("showCO2",preferences.showCO2);setFormCheckbox("dispOffOnExP",preferences.dispOffOnExP);setFormCheckbox("displayReverse",preferences.displayReverse);setFormValue("DisplayBright",preferences.DisplayBright);setFormCheckbox("debugSensors",preferences.debugSensors);setFormValue("toneBzrBeep",preferences.toneBzrBeep);setFormValue("durBzrBeep",preferences.durBzrBeep);setFormValue("timeBtwnBzr",preferences.timeBtwnBzr);if(preferences.cpNoTimeout!==undefined){setFormCheckbox("cpNoTimeout",preferences.cpNoTimeout)}if(preferences.cpRelaxedSec!==undefined){setFormCheckbox("cpRelaxedSec",preferences.cpRelaxedSec)}if(preferences.cpDebug!==undefined){setFormCheckbox("cpDebug",preferences.cpDebug)}if(preferences.cpWaitTime!==undefined){setFormValue("cpWaitTime",preferences.cpWaitTime)}toggleVisibility("activeWIFI","wifiNetworks",isChecked=>{document.getElementById("mqttConfig").style.display=isChecked?"block":"none"});toggleVisibility("activeMQTT","mqttConfig");toggleVisibility("activeESPNOW","espNowConfig");toggleVisibility("useStaticIP","staticIPSettings");handleWiFiMQTTDependency()}function loadPreferencesFromServer(){fetch("/getActualSettingsAsJson"+(relaxedSecurity?"?relaxedSecurity=true":"")).then(response=>response.json()).then(preferences=>{if(preferencesDebug)console.log("Get preferences from server response:",preferences);populateFormWithPreferences(preferences)}).catch(error=>console.error("Error retrieving preferences:",error))}function collectPreferencesData(){const preferencesData={customCalValue:document.getElementById("customCalValue").value,tempOffset:document.getElementById("tempOffset").value,altitudeMeters:document.getElementById("altitudeMeters").value,autoSelfCalibration:document.getElementById("autoSelfCalibration").checked,co2OrangeRange:document.getElementById("co2OrangeRange").value,co2RedRange:document.getElementById("co2RedRange").value,DisplayBright:document.getElementById("DisplayBright").value,neopixBright:document.getElementById("neopixBright").value,selNeopxType:document.getElementById("selNeopxType").value,activeBLE:document.getElementById("activeBLE").checked,activeWIFI:document.getElementById("activeWIFI").checked,activeMQTT:document.getElementById("activeMQTT").checked,activeESPNOW:document.getElementById("activeESPNOW").checked,rootTopic:document.getElementById("rootTopic").value,batDischgd:document.getElementById("batDischgd").value,batChargd:document.getElementById("batChargd").value,vRef:document.getElementById("vRef").value,tToDispOff:document.getElementById("tToDispOff").value,tToPubMQTT:document.getElementById("tToPubMQTT").value,tToPubESPNow:document.getElementById("tToPubESPNow").value,tKeepAlMQTT:document.getElementById("tKeepAlMQTT").value,tKeepAlESPNow:document.getElementById("tKeepAlESPNow").value,dispOffOnExP:document.getElementById("dispOffOnExP").checked,wifiSSID:document.getElementById("wifiSSID").value,hostName:document.getElementById("hostName").value,useStaticIP:document.getElementById("useStaticIP").checked,staticIP:document.getElementById("staticIP").value,gateway:document.getElementById("gateway").value,subnet:document.getElementById("subnet").value,dns1:document.getElementById("dns1").value,dns2:document.getElementById("dns2").value,selCO2Sensor:document.getElementById("selCO2Sensor").value,debugSensors:document.getElementById("debugSensors").checked,displayReverse:document.getElementById("displayReverse").checked,showFahrenheit:document.getElementById("showFahrenheit").checked,measurementInterval:document.getElementById("measurementInterval").value,outModeRelay:document.getElementById("outModeRelay").checked,channelESPNow:document.getElementById("channelESPNow").value,boardIdESPNow:document.getElementById("boardIdESPNow").value,peerESPNowAddress:document.getElementById("peerESPNowAddress").value,showTemp:document.getElementById("showTemp").checked,showHumidity:document.getElementById("showHumidity").checked,showBattery:document.getElementById("showBattery").checked,showCO2:document.getElementById("showCO2").checked,mqttClientId:document.getElementById("mqttClientId").value,mqttShowInCon:document.getElementById("mqttShowInCon").checked,mqttBroker:document.getElementById("mqttBroker").value,mqttUser:document.getElementById("mqttUser").value,toneBzrBeep:document.getElementById("toneBzrBeep").value,durBzrBeep:document.getElementById("durBzrBeep").value,timeBtwnBzr:document.getElementById("timeBtwnBzr").value};if(relaxedSecurity){preferencesData.wifiPass=document.getElementById("wifiPass").value;preferencesData.mqttPass=document.getElementById("mqttPass").value}const cpNoTimeout=document.getElementById("cpNoTimeout");if(cpNoTimeout){preferencesData.cpNoTimeout=cpNoTimeout.checked}const cpRelaxedSec=document.getElementById("cpRelaxedSec");if(cpRelaxedSec){preferencesData.cpRelaxedSec=cpRelaxedSec.checked}const cpDebug=document.getElementById("cpDebug");if(cpDebug){preferencesData.cpDebug=cpDebug.checked}const cpWaitTime=document.getElementById("cpWaitTime");if(cpWaitTime){preferencesData.cpWaitTime=cpWaitTime.value}console.log("Collected preferences data:",preferencesData);return preferencesData}function showSavingPopup(){const popup=document.getElementById("popup");popup.style.display="block";console.log("Show popup");setTimeout(()=>{popup.style.display="none";console.log("Hide popup")},2e3)}function savePreferences(){showSavingPopup();const preferencesData=collectPreferencesData();if(preferencesDebug)console.log("Sending preferences to server:",preferencesData);fetch("/savePreferences",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(preferencesData)}).then(response=>{if(response.ok){console.log("Preferences updated successfully!")}else{alert("Error updating preferences. Please try again.")}}).catch(error=>console.error("Error saving preferences:",error))}function restartESP32(){const isConfirmed=confirm("Are you sure you want to restart the ESP32?");if(isConfirmed){if(preferencesDebug)console.log("Restarting ESP32...");fetch("/restart",{method:"GET",headers:{"Content-Type":"text/plain"}}).then(response=>{if(response.ok){console.log("ESP32 restart initiated")}else{throw new Error(`HTTP error! Status: ${response.status}`)}}).catch(error=>console.error("Error restarting ESP32:",error))}}function backupPreferences(){const preferencesData=collectPreferencesData();const jsonData=JSON.stringify(preferencesData);const blob=new Blob([jsonData],{type:"application/json"});const a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download="preferences_backup.json";document.body.appendChild(a);a.click();document.body.removeChild(a);alert("Preferences backup completed successfully!")}function restorePreferencesFromData(preferencesData){const preferences=JSON.parse(preferencesData);populateFormWithPreferences(preferences)}function chooseFileAndRestore(){document.getElementById("fileInput").click()}function handleFileSelection(event){const file=event.target.files[0];if(file){const reader=new FileReader;reader.readAsText(file,"UTF-8");reader.onload=evt=>{const preferencesData=evt.target.result;restorePreferencesFromData(preferencesData)};reader.onerror=evt=>{console.error("Error reading file:",evt.target.error);alert("Error reading file. Please try again.")}}}function toggleVisibility(checkboxId,elementId,callback){const checkbox=document.getElementById(checkboxId);const element=document.getElementById(elementId);if(!checkbox||!element){console.error(`Checkbox or element not found: ${checkboxId}, ${elementId}`);return}const toggleElement=()=>{element.style.display=checkbox.checked?"block":"none";if(callback)callback(checkbox.checked)};toggleElement();checkbox.addEventListener("change",toggleElement)}function handleWiFiMQTTDependency(){const wifiCheckbox=document.getElementById("activeWIFI");const mqttCheckbox=document.getElementById("activeMQTT");if(!wifiCheckbox||!mqttCheckbox){console.error("Checkboxes not found: activeWIFI, activeMQTT");return}const updateMQTTState=()=>{if(!wifiCheckbox.checked){mqttCheckbox.checked=false;mqttCheckbox.disabled=true;document.getElementById("mqttConfig").style.display="none"}else{mqttCheckbox.disabled=false}};const updateWiFiState=()=>{if(mqttCheckbox.checked){wifiCheckbox.checked=true}toggleVisibility("activeMQTT","mqttConfig")};wifiCheckbox.addEventListener("change",updateMQTTState);mqttCheckbox.addEventListener("change",updateWiFiState);updateMQTTState();updateWiFiState()}function updateVoltage(){fetch("/readBatteryVoltage").then(response=>response.text()).then(voltage=>{document.getElementById("currentVoltage").textContent=voltage+" Volts"}).catch(error=>console.error("Error fetching battery voltage:",error))}function updateVRef(){const vRefValue=document.getElementById("vRef").value;fetch(`/settings?SetVRef=${vRefValue}`).then(response=>{if(!response.ok)throw new Error("Error updating VRef");console.log("VRef updated successfully")}).catch(error=>console.error("Error updating VRef:",error))}setInterval(updateVoltage,1e3);document.getElementById("vRef").addEventListener("input",()=>{setTimeout(updateVRef,100)});function handlePasswordFields(){const inputField=document.getElementById("wifiSSID");const passwordFields=document.querySelectorAll("input[type=password]");passwordFields.forEach(field=>{if(relaxedSecurity){field.removeAttribute("disabled")}else{field.disabled=true;field.value="";field.placeholder="Password (disabled)"}});if(relaxedSecurity){inputField.removeAttribute("readonly")}else{inputField.setAttribute("readonly","readonly")}}function calibrateSensor(calibrationValue){if(calibrationValue>400&&calibrationValue<2e3){console.log("Calibration process started...");console.log("Calibration value:",calibrationValue)}else{console.error("Invalid calibration value, please enter a value between 400 and 2000 ppm");console.log("Calibration value:",calibrationValue)}}function handleCalibrationWizard(){const calibrateButton=document.getElementById("calibrateButton");const calibrationModal=document.getElementById("calibrationModal");const countdownModal=document.getElementById("countdownModal");const closeSpan=document.querySelector(".close");const acknowledgeCheckbox=document.getElementById("acknowledgeCheckbox");const acknowledgeLabel=document.getElementById("acknowledgeLabel");const calibrateNowButton=document.getElementById("calibrateNowButton");const countdownSpan=document.getElementById("countdown");const currentCO2ValueSpan=document.getElementById("currentCO2Value");function getCurrentCO2Value(){fetch("/readCO2").then(response=>response.text()).then(data=>{let co2Value=parseFloat(data);document.getElementById("currentCO2Value").textContent=co2Value.toFixed(0)}).catch(error=>{console.error("Error fetching CO2 data",error)})}function changeTextColor(){acknowledgeLabel.style.color="var(--unchecked-font-color)"}calibrateButton.addEventListener("click",()=>{calibrationModal.style.display="block";const customCalibrationValueInput=document.getElementById("modalCustomCalibrationValueInput");customCalibrationValueInput.value=document.getElementById("customCalValue").value;getCurrentCO2Value();updateCO2Interval=setInterval(getCurrentCO2Value,5e3)});closeSpan.addEventListener("click",()=>{calibrationModal.style.display="none";clearInterval(updateCO2Interval)});acknowledgeCheckbox.addEventListener("change",()=>{if(acknowledgeCheckbox.checked){acknowledgeLabel.style.color=""}});calibrateNowButton.addEventListener("click",()=>{if(!acknowledgeCheckbox.checked){changeTextColor();return}calibrationModal.style.display="none";countdownModal.style.display="block";const customCalValue=parseInt(document.getElementById("modalCustomCalibrationValueInput").value,10);calibrateSensor(customCalValue);let countdown=15;countdownSpan.textContent=countdown;const interval=setInterval(()=>{countdown-=1;countdownSpan.textContent=countdown;if(countdown<=0){clearInterval(interval);countdownModal.style.display="none"}},1e3)});window.addEventListener("click",event=>{if(event.target==calibrationModal){calibrationModal.style.display="none";clearInterval(updateCO2Interval)}})}document.addEventListener("DOMContentLoaded",()=>{var currentURL=window.location.href;if(currentURL.includes("preferences.html")){highlightCurrentPage();relaxedSecurity=currentURL.includes("relaxedSecurity");forceCaptivePortalActive=currentURL.includes("forceCaptivePortalActive");handlePasswordFields();loadPreferencesFromServer();fetchVersion();toggleVisibility("activeWIFI","wifiNetworks",isChecked=>{document.getElementById("mqttConfig").style.display=isChecked?"block":"none"});toggleVisibility("activeMQTT","mqttConfig");toggleVisibility("activeESPNOW","espNowConfig");toggleVisibility("useStaticIP","staticIPSettings");handleWiFiMQTTDependency();handleCalibrationWizard()}}); \ No newline at end of file diff --git a/data/status.html.gz b/data/status.html.gz index ef888b6f20abc0b3e40e9e45b7ce0c9aa9d15e2d..f6060da10094e56d56026bafa49ab5ea8c52ec01 100644 GIT binary patch delta 15 Wcmey(_nVJRzMF&Nc;!a6Qg#3?kOf8n delta 15 Wcmey(_nVJRzMF%i(rhDJDLViwZ3MLd diff --git a/data/status.js.gz b/data/status.js.gz index 40f945f1c089e6549449f23aed6e95bdeb18cf19..398a8dcfdac86e5a105d59a08110a4fea2c285fd 100644 GIT binary patch delta 15 WcmZ1~xKxl$zMF&Nc;!a6`5XWx%LK~+ delta 15 WcmZ1~xKxl$zMF%i(rhE!d=3C2s02Cy diff --git a/data/style.css.gz b/data/style.css.gz index 0aa4eac975958bd0246ddaa8207d920033fbd0d8..cd4b09d077a0d147637fa4a1300c1e93f58b286c 100644 GIT binary patch literal 2648 zcmV-e3a9lSiwFqEd1Gb-0CRMCY-KKOX>KlKb8`UIS#7VAFckhPs4;PIEHK7&EGE81 zV`8Gw#4pAV1j zAx00pCI4CZ3!pq=1RDrFsMGri^MEu>neb)ZHpWbnB*TmncC5;{ZJMf_nBF8P3%!9t zh&)9XB5$)}MnMNRMdX`it#uM$zDHfvZOtZ>IQ^(nvNCT~6-}gLd?(BX^`3wQ=1wn8?!NoGCx^A4uV@zwjHC) zV4$CyIm5=9lKcwXf_Q^MG>14P;hz!bZ;|&nv=OJ+=&>~qMO*C(U-out%3e2vzF@c9 zdQ0DbG>1L4y@4_nI5$acMCgg^RV5N_LElMcFY zXr(xTrjJWs zEbexotenZ^;_o0IWqe9?6?yrMx&_XfrS?wp!_iQot)$Le016RE;QK{BVP3~F=t~IL zZyCjSo{298_7Kg*SEN*7A31y;IR@9@o))SoLQtBwl*bnh zBg}(v#U6$h_rMS6>QzHMCAU)%`$=r{;Po_)L#t95R+gFi5byb^m?c{knAuHyVZA8v{E7VrCh)4t4qG- z?yE=mB#UWiLO@tQ!Iiy$8%M|CbcaJbWmDiae2_JZ~X#i_IN?mLL}Qub$(H^2mI{(w(o(&TU{ za!Dc7QIQ-D7oOPGJlk~LJ>FF7+2wAn@SEj7Akj8e9fg1>mVWqyx^(d;mPH=8FtKER zW~(87kaj7s<|eP#6Zfakygzsow};SZGbj*dP?NtY-vRR00);@vfY{v=&9=7y-WL@p z3jUMJ++EKFt%!RGueV%oQdunwfmrsSg!+d;=&j{7&FOyJF}o?LPw}WHG`LDxows`s z8D69GfSXU4P*A}*klt8Y|G7D5C9Z$I_t{FfmE5glW0yDgFGdNgRZOA~)Vsi!?>Wum zyvUoMy@jM19s@UXf{GpHJlO6sPl#bCWNTC(@T;(gVhZu5!OD$q@nKCVeF^?>R(Af# z;w^6$UyA{XiJoEZ|2}g{5f?lbCg88~XBpV|vqA*R)YBTC>sc=(e?v>~+G@2*x&S{= zZzTNH#ZHwI)=9dhyL)`-1=u6GFbLo#C`-v?8`&@ec zR=J(K=60*$1Ay=kC8+srU@!;&sxcz8KY}dwU~bezJk4mFtU&;)X(G22{<@SeS(UVO z{uEBzpEcRQ9ft%6gQ#Z3C?p%wphEk!a`|(kToF&=f96BY!YYMzINwkr%(u3UGD`Iv z=L~HorS2a5$L_3Bq@MrO>eYR-@2s1=8L{~f{pcGRbLjVjG~C)7y2|3&tkCDZ)F|O^ zJX<&_=V0~#qp2^HKELxQ`Z{;=6Q?L4qDz{zY6d@5;`$SP5AXhTzK-h6LF+O5QQ<1^sBI$w;0s`noil(e3Sv@m}*zWeYo z9b`Lvnhsp%2kwQPJ2bLuJ@OIK;pLVZ94a~8bH+u$5D4MB*5jK>8wnv@tFx%N$Duf; zRT>(apz!d=G^UcM-72-qHBkmhlX|+4yD6qbB)Kiib@%wnp$;-GBHd~Vt-k?j1y;tI GCIA4uv?p`` literal 2554 zcmVKlKb8`UIS=)}&FcAHf079^$sd8z`HWd;# zfsl|uAn}5Da1*CBq)B8a6sYp=jO`?L?4%Ul&}w&6dt%QV&zTudV_KH=*>$tBsNJN@ zOB&x>uh(1G-R=9&S(d@)n$$V&hc;`BF@jN&l*RBK=07l)5Sl1ikc6=UecvJK?oje= zPs^rAht+ShO@@?2jeiW9gkh*A4&`@D`x(!R);n!-SJG6?;>Y|)&9VbZ%Tw$*tLlfd zhF`khp@-f={4D(&kUU@n3rHN)?)`+hL7JxA_@ZiRVqA6-bnGT z*(-SgsUJp*z*{eZhy(lhrWfl#Qm4liO!AW9&eVPpoEj6OW9Ozy5muwRVXioO<)}NH z-G*v*+MSvrIpE|QPW8hsDJu53{ahdL5kGmrH+t~J-~~=HFY{pq6Ksc_M zAAOY2rMj`3?Jr<*ihpp;ylqu7B9x{$M>YA5g@v$GQRAW>oB6e2HOYSVlQFAM0`80J z6UN0Bj zFLZ_o0cRO92P1~nHnAYs$O-Lee52%-DB*aV`%-GN0k8V@{1lKsJe&<3eBUjRTP6U2J4Pr29e4D}KM;#)2;p6BMv0r9?kW1BRTf!bVSbrQh} zWDl52iDzTo4k3YMR?=h45|rbIK2%<&WQUC{8i6Q8?=f*epULns&5JHe_cCIolT>s^p4EX>?rvM+< za2LJHuIQ$ZhX)M}_tgbtbVEhu0eTLmqNXnY2kTl{kj?PQu5!n<(CGltT|3cn5Q;r} zdm~os+N=kE;0}2q_Nau{X)j~>MH}oodwoi{ZCCFh31#KNvq|U=5`r%49Uwa^ObDp$)Pf5Dve_W^lV5G*bEEZYp zXVigTp)-f`FKnJJKW9njO;jP%yE$@jV$*&~i((eF4F~Ao7?W-Aqg!yJDey=05uazU z{d<)IpPS2iGa_+}GBEYr``le_$6bT`wqLjHvag1XLmqB94oA6N4sKiFsS82|w=U@8 zogC@ZGaNvIXp=|8Krdb~8~~jT_%OV0m+;#wE+NqN3#lH~EmmOV5_V#$Wd2IHt*en)xJ0b*ad^{c$P!fWom ze2kA>@eFMN2;)bRra9bTnu65-zG^tRY9AxZBL6uTD8mg8lw;ZqOz9le;S+ym!xhP; zBUb06VetJRL!^9E`|=HkJB+L4N;7!~XBBQOKNSHwl{-$^b%nKw7L5vfzy(gPjZ-KloN&pJ} z)AQWj&IMHDJw()3t~k=T3#7b?5l43*DIAi7e;9;r7pWLwB1EZlbyX6d(os)fftD~N zEO5jS8D67wkLypEGJs$lNUtoV|J-`B64gK7^K8&71}vr)2Y6_PCc^segp zJ7Hu;a#H{7PpCVFThM0CP`SdK2islS2{Q~p)<(4fzlwWk#~|L+Sh?{vKCFS#m)wtL zZ5NL`-a@=U`K1`3l;{-}{_k_AlySl1VFLatf9?XCcvg(ync7Bp5uG(=2H+c3Z=qXK z9`mC6kd;Zp=64aY{a%xO&M}i9dZ3EeaDV}=QLc6P&wuVGE8$7n%zR&PV^xqk3$Dnl z^BrKL`cSR8xof`}%iDYKAG@=lbU0t^h{_SQcNYdt-Hed-hqmpNiaG52ULKsFMn_Wl zY!zd%(Lt-Cwm% zawx3CAq+*U+R&9+>$;8SMK-ge8Xq1DCO^?cw}X%BVxVXWd Q diff --git a/platformio.ini b/platformio.ini index 8ca1eadb..e73517fb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ extra_configs = platformio_extra_configs.ini [version] build_flags = -D CO2_GADGET_VERSION="\"0.14."\" - -D CO2_GADGET_REV="\"003-development"\" + -D CO2_GADGET_REV="\"004-development"\" ;**************************************************************************************** ;*** You can disable features by commenting the line with a semicolon at the beginning @@ -337,8 +337,8 @@ board_build.flash_mode = dio board_upload.flash_size = 16MB upload_speed = 921600 monitor_speed = 115200 -monitor_port = COM13 -upload_port = COM13 +monitor_port = COM8 +upload_port = COM8 lib_deps = bodmer/TFT_eSPI @ ^2.5.43 ${common_env_data.lib_deps} diff --git a/webserver/preferences.html b/webserver/preferences.html index 257d8690..2fcc6eec 100644 --- a/webserver/preferences.html +++ b/webserver/preferences.html @@ -434,7 +434,8 @@

CO2 Gadget Preferences

×

Calibration Instructions

Please place the sensor outside for a few minutes to stabilize.

-

Calibration Value: ppm

+

Calibration Value: ppm

Current CO2 Value: ppm

@@ -442,12 +443,13 @@

Calibration Instructions

- + + diff --git a/webserver/preferences.js b/webserver/preferences.js index 86a0327a..a9a195e6 100644 --- a/webserver/preferences.js +++ b/webserver/preferences.js @@ -464,109 +464,123 @@ function handlePasswordFields() { } function calibrateSensor(calibrationValue) { - // Implement the calibration logic here - if (calibrationValue > 400 && calibrationValue < 2000) { - console.log("Calibration process started..."); - console.log("Calibration value:", calibrationValue); - // Call the calibration endpoint with the calibration value settings?CalibrateCO2=400 - fetch(`/settings?CalibrateCO2=${calibrationValue}`) - .then(response => { - if (!response.ok) throw new Error('Error calibrating CO2 sensor'); - console.log('CO2 sensor calibrated successfully'); - }) - .catch(error => console.error('Error calibrating CO2 sensor:', error)); - } else { - console.error("Invalid calibration value, please enter a value between 400 and 2000 ppm"); - console.log("Calibration value:", calibrationValue); - } + // Implement the calibration logic here + if (calibrationValue > 400 && calibrationValue < 2000) { + console.log("Calibration process started..."); + console.log("Calibration value:", calibrationValue); + Call the calibration endpoint with the calibration value settings?CalibrateCO2=400 + fetch(`/settings?CalibrateCO2=${calibrationValue}`) + .then(response => { + if (!response.ok) throw new Error('Error calibrating CO2 sensor'); + console.log('CO2 sensor calibrated successfully'); + }) + .catch(error => console.error('Error calibrating CO2 sensor:', error)); + } else { + console.error( + "Invalid calibration value, please enter a value between 400 and 2000 ppm" + ); + console.log("Calibration value:", calibrationValue); + } } /** * Handles the calibration wizard functionality. */ function handleCalibrationWizard() { - const calibrateButton = document.getElementById("calibrateButton"); - const calibrationModal = document.getElementById("calibrationModal"); - const countdownModal = document.getElementById("countdownModal"); - const closeSpan = document.querySelector(".close"); - const acknowledgeCheckbox = document.getElementById("acknowledgeCheckbox"); - const acknowledgeLabel = document.getElementById("acknowledgeLabel"); - const calibrateNowButton = document.getElementById("calibrateNowButton"); - const countdownSpan = document.getElementById("countdown"); - const currentCO2ValueSpan = document.getElementById("currentCO2Value"); - - // Function to fetch current CO2 value from /readCO2 endpoint as text - function getCurrentCO2Value() { - fetch('/readCO2') - .then(response => response.text()) - .then(data => { - let co2Value = parseFloat(data); - document.getElementById("currentCO2Value").textContent = co2Value.toFixed(0); - }) - .catch((error) => { - console.error('Error fetching CO2 data', error); - }); + const calibrateButton = document.getElementById("calibrateButton"); + const calibrationModal = document.getElementById("calibrationModal"); + const countdownModal = document.getElementById("countdownModal"); + const closeSpan = document.querySelector(".close"); + const acknowledgeCheckbox = document.getElementById("acknowledgeCheckbox"); + const acknowledgeLabel = document.getElementById("acknowledgeLabel"); + const calibrateNowButton = document.getElementById("calibrateNowButton"); + const countdownSpan = document.getElementById("countdown"); + const currentCO2ValueSpan = document.getElementById("currentCO2Value"); + + // Function to fetch current CO2 value from /readCO2 endpoint as text + function getCurrentCO2Value() { + fetch("/readCO2") + .then((response) => response.text()) + .then((data) => { + let co2Value = parseFloat(data); + document.getElementById("currentCO2Value").textContent = + co2Value.toFixed(0); + }) + .catch((error) => { + console.error("Error fetching CO2 data", error); + }); + } + + // Function to change text color when "Calibrate Now" button is clicked without acknowledging + function changeTextColor() { + acknowledgeLabel.style.color = "var(--unchecked-font-color)"; + } + + calibrateButton.addEventListener("click", () => { + // Uncheck the acknowledge checkbox when modal is opened + acknowledgeCheckbox.checked = false; + calibrationModal.style.display = "block"; + // Set the custom calibration value input to the current custom calibration value + const customCalibrationValueInput = document.getElementById( + "modalCustomCalibrationValueInput" + ); + customCalibrationValueInput.value = + document.getElementById("customCalValue").value; + // Fetch current CO2 value when modal is opened + getCurrentCO2Value(); + // Start interval to update CO2 value every 5 seconds + updateCO2Interval = setInterval(getCurrentCO2Value, 5000); + }); + + closeSpan.addEventListener("click", () => { + calibrationModal.style.display = "none"; + // Clear interval when modal is closed + clearInterval(updateCO2Interval); + }); + + acknowledgeCheckbox.addEventListener("change", () => { + // Reset text color when checkbox is checked + if (acknowledgeCheckbox.checked) { + acknowledgeLabel.style.color = ""; // Reset to default color } + }); - // Function to change text color when "Calibrate Now" button is clicked without acknowledging - function changeTextColor() { - acknowledgeLabel.style.color = "var(--unchecked-font-color)"; + calibrateNowButton.addEventListener("click", () => { + if (!acknowledgeCheckbox.checked) { + changeTextColor(); // Call the function to change text color + return; // Exit function if checkbox is not acknowledged } - calibrateButton.addEventListener("click", () => { - calibrationModal.style.display = "block"; - document.getElementById("customCalibrationValue").textContent = document.getElementById("customCalValue").value + " ppm"; - // Fetch current CO2 value when modal is opened - getCurrentCO2Value(); - // Start interval to update CO2 value every 5 seconds - updateCO2Interval = setInterval(getCurrentCO2Value, 5000); - }); - - closeSpan.addEventListener("click", () => { - calibrationModal.style.display = "none"; - // Clear interval when modal is closed - clearInterval(updateCO2Interval); - }); - - acknowledgeCheckbox.addEventListener("change", () => { - // Reset text color when checkbox is checked - if (acknowledgeCheckbox.checked) { - acknowledgeLabel.style.color = ""; // Reset to default color - } - }); - - calibrateNowButton.addEventListener("click", () => { - if (!acknowledgeCheckbox.checked) { - changeTextColor(); // Call the function to change text color - return; // Exit function if checkbox is not acknowledged - } - - calibrationModal.style.display = "none"; - countdownModal.style.display = "block"; - - calibrateSensor(document.getElementById("customCalValue").value); - - let countdown = 15; - countdownSpan.textContent = countdown; - - const interval = setInterval(() => { - countdown -= 1; - countdownSpan.textContent = countdown; - - if (countdown <= 0) { - clearInterval(interval); - countdownModal.style.display = "none"; - } - }, 1000); - }); - - window.addEventListener("click", (event) => { - if (event.target == calibrationModal) { - calibrationModal.style.display = "none"; - // Clear interval when modal is closed - clearInterval(updateCO2Interval); - } - }); + calibrationModal.style.display = "none"; + countdownModal.style.display = "block"; + + const customCalValue = parseInt( + document.getElementById("modalCustomCalibrationValueInput").value, + 10 + ); + calibrateSensor(customCalValue); + + let countdown = 15; + countdownSpan.textContent = countdown; + + const interval = setInterval(() => { + countdown -= 1; + countdownSpan.textContent = countdown; + + if (countdown <= 0) { + clearInterval(interval); + countdownModal.style.display = "none"; + } + }, 1000); + }); + + window.addEventListener("click", (event) => { + if (event.target == calibrationModal) { + calibrationModal.style.display = "none"; + // Clear interval when modal is closed + clearInterval(updateCO2Interval); + } + }); } document.addEventListener("DOMContentLoaded", () => { diff --git a/webserver/style.css b/webserver/style.css index 86cab2d7..574be43d 100644 --- a/webserver/style.css +++ b/webserver/style.css @@ -26,10 +26,12 @@ --close-button-hover-color: darkred; --status-bar-bg-color: #fbef83; --status-bar-text-color: #333; + --modal-bg-color: #f1f1f1; + --modal-overlay-bg-color: rgba(0, 0, 0, 0.4); --unchecked-font-color: orange; } -[theme='dark'] { +[theme="dark"] { --font-color: #ecf0f1; --bg-color: #2c3e50; --title-color: #1abc9c; @@ -57,17 +59,31 @@ --close-button-hover-color: #c0392b; --status-bar-bg-color: #34495e; --status-bar-text-color: #ecf0f1; + --modal-bg-color: #3b4a5a; + --modal-overlay-bg-color: rgba(0, 0, 0, 0.8); --unchecked-font-color: yellow; } +/* For small screens */ +@media screen and (max-width: 600px) { + .content { + max-width: 100%; + padding: 0 10px; + } +} + body { - font-family: 'Arial', sans-serif; + font-family: "Arial", sans-serif; background-color: var(--bg-color); color: var(--font-color); margin: 0; + overflow-x: hidden; } -h1, h2, h3, h4 { +h1, +h2, +h3, +h4 { color: var(--header-font-color); margin: 20px 0 10px; border-bottom: 2px solid var(--header-border-color); @@ -166,7 +182,7 @@ h4 { transition: background-color 0.3s, color 0.3s; } -[theme='dark'] .tag { +[theme="dark"] .tag { color: var(--title-color); background-color: var(--tag-dark-bg-color); } @@ -251,12 +267,14 @@ button:hover { flex-wrap: nowrap; } -.buttonsBackupRestore, .buttonsRestartSave { +.buttonsBackupRestore, +.buttonsRestartSave { display: flex; gap: 10px; } -#backupButton, #restoreButton { +#backupButton, +#restoreButton { margin-right: 10px; } @@ -271,14 +289,16 @@ button:hover { gap: 20px; } - .buttonsBackupRestore, .buttonsRestartSave { + .buttonsBackupRestore, + .buttonsRestartSave { flex-direction: column; width: auto; margin-bottom: 0; align-items: center; } - .buttonsBackupRestore button, .buttonsRestartSave button { + .buttonsBackupRestore button, + .buttonsRestartSave button { width: 100%; margin-bottom: 10px; } @@ -306,6 +326,7 @@ button:hover { .content { max-width: 600px; margin: 0 auto; + overflow-x: auto; } .flex-wrapper { @@ -354,7 +375,7 @@ button:hover { } .circular-chart.temp .circle { - stroke: #4CC790; + stroke: #4cc790; } .circular-chart.humi .circle { @@ -457,7 +478,7 @@ button:hover { animation: fadeInOut 2s ease-in-out; } -.tooltip-icon:hover+.tooltip-text { +.tooltip-icon:hover + .tooltip-text { visibility: visible; } @@ -471,23 +492,35 @@ button:hover { width: 100%; height: 100%; overflow: auto; - background-color: rgba(0, 0, 0, 0.4); + background-color: var(--modal-overlay-bg-color); } .modal-content { - background-color: var(--popup-bg-color); + background-color: var(--modal-bg-color); margin: auto; padding: 20px; border: 1px solid var(--input-border-color); width: 80%; - color: var(--popup-text-color); + color: var(--modal-text-color); +} + +#modalCalibrationValueContainer { + display: inline-block; /* Ensure the elements are on the same line */ +} + +#modalCustomCalibrationValueInput { + width: 80px; /* Increase width for better visibility */ + padding: 8px; /* Add padding for better visual appeal */ + border: 1px solid #ccc; /* Add border for visual distinction */ + border-radius: 4px; /* Add border-radius for a softer look */ + font-size: 16px; /* Increase font size for better readability */ + box-sizing: border-box; /* Include padding and border in the width */ } .unchecked-text { color: var(--unchecked-font-color); } - .close { color: var(--close-button-color); float: right; @@ -501,6 +534,7 @@ button:hover { text-decoration: none; cursor: pointer; } + #captive-portal-status-bar { width: 100%; background-color: var(--status-bar-bg-color);