From b79c3ce37dc161f2209d152af5facf28d40e88a4 Mon Sep 17 00:00:00 2001 From: Bram Barbieri Date: Fri, 29 Mar 2024 14:50:18 +0100 Subject: [PATCH 01/62] docs new node redesign --- docs/node-documentation/node-design.md | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/node-documentation/node-design.md b/docs/node-documentation/node-design.md index 01fba8e..2f2cd56 100644 --- a/docs/node-documentation/node-design.md +++ b/docs/node-documentation/node-design.md @@ -61,4 +61,29 @@ graph LR A[Design Sketch] -->|Usertest| B(Fusion360 design) B -->|Not fitting| C[New fusion360 design] C -->|assembly| D[Finished product] -``` \ No newline at end of file +``` + +## The evolved design of the nodes. +During the last sprint we had a lot of feeback about the node and mostly about tis design. hence why we had decided to remake it in several different ways. + +We had made a prototype for a wooden version, but that never made it past an first sketch, seeing as almost all fedback came back telling About how the plastic design looked better and was less distreacting. +The user-test document is here:( https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/blob/main/docs/brainstorm/Feedback.md?ref_type=heads#design-questions-led-by-bram ) + +After the results came back, we decided to make progress with further designing the cover of the node. +The main body shape was certain, because all of the components needed to fit inside of the node and needed some space. +Aswell as the simple shape to save on printing costs and keep the design simple to look at. + +The only thing that was able to change was the cover. +The cover was originally made of solid plastic and was molded to fit the shape of the board and the sensors/ screen inside. + +From here we decided to brainstorm on an easyer way of covering the circurty. + +That is when it hit us, We could use acrylic as a cover! + +Acrylic can come in many different colors, is easyer to cut out ( takes less time) and gives a bit of an isight into the wiring. + +This this in mind we made a node with this new design and remade one with the old design, this again could be further used for user-tests. + +For the time being we are able to show off both of the designs and are able to read data from both, the only difference being the outer shell. + +The images: \ No newline at end of file From c4fa9fbfa5ad0b12c6e4f101d150e149039984ed Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Fri, 29 Mar 2024 14:59:23 +0100 Subject: [PATCH 02/62] removed junk --- web/newWebsite/main.js | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/web/newWebsite/main.js b/web/newWebsite/main.js index 25fbf2f..a62e059 100644 --- a/web/newWebsite/main.js +++ b/web/newWebsite/main.js @@ -4,7 +4,7 @@ const sensorData = {}; let liveGraphs = []; let nodeArray = []; let nodeDict = {}; - +let graphArray = []; // letiables let intervalDelay = 5000; let amountOfNodes = 3; @@ -101,29 +101,6 @@ async function nodeAdressHandler(node, dataTypes) { } } -function createGauge(node, dataType) { - // Create a new gauge here - let gauge = new GaugeGroup(node, dataType); // Assuming Gauge is the name of the class - sensorData[node][dataType] = gauge; // Store the gauge in the sensorData object for later use -} - - -//function for making the html elements for the following html code -function nodeData(data) { - let nodeData = document.createElement("div"); - nodeData.innerHTML = data; - // nodeData.setAttribute("id", "node" + node); - document.body.appendChild(nodeData); - // console.log("Hello World"); -} - - -function updateGauge(nodeNumber, dataType, value) { - // Update the gauge here - let gauge = sensorData[nodeNumber][dataType]; // Get the gauge from the sensorData object - gauge.update(value); // Assuming the Gauge class has an update method - } - function getNodeInfo(node){ return fetch("http://145.92.8.114/getNodeInfo?macAdress=" + node) .then(response => { @@ -142,4 +119,5 @@ function getNodeInfo(node){ }; }) -} \ No newline at end of file +} + From 7f48f0f3b3437a3625360605ca0286f012f18760 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Fri, 29 Mar 2024 14:59:30 +0100 Subject: [PATCH 03/62] added graph div --- web/newWebsite/GaugGroup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/newWebsite/GaugGroup.js b/web/newWebsite/GaugGroup.js index fc214fc..31da446 100644 --- a/web/newWebsite/GaugGroup.js +++ b/web/newWebsite/GaugGroup.js @@ -24,6 +24,7 @@ class GaugeGroup { `).join('')} +
Graphs + @@ -25,9 +26,10 @@ - - +
+ + \ No newline at end of file diff --git a/web/newWebsite/index.html b/web/newWebsite/index.html index 2519ffb..3402076 100644 --- a/web/newWebsite/index.html +++ b/web/newWebsite/index.html @@ -6,6 +6,7 @@ Gauges + @@ -29,5 +30,6 @@ + \ No newline at end of file From 5bf5a193b9d4f5e1a450698afe8eef5c2844d652 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Fri, 29 Mar 2024 15:18:36 +0100 Subject: [PATCH 05/62] Add getQuestionData route --- server/Flask/main.py | 21 ++++++++++++++++++--- server/Flask/queries.py | 7 +++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/server/Flask/main.py b/server/Flask/main.py index c185937..7232c81 100644 --- a/server/Flask/main.py +++ b/server/Flask/main.py @@ -22,9 +22,13 @@ def getNodeInfoIndex(): macAdress = request.args.get('macAdress', None) return getNodeInfo(macAdress) +@app.route('/getQuestionData') +def getQuestionDataIndex(): + return getQuestionData() + def updateData(node, name, location): mydb = loginDB() - query = update_query(node, name, location) + query = update_query(node, name, location, False, False) cursor = mydb.cursor(dictionary=True) # Enable dictionary output cursor.execute(query) mydb.commit() @@ -45,7 +49,7 @@ def loginDB(): def getData(node, dataType, MAC): mydb = loginDB() - query = get_query(node, dataType, MAC) + query = get_query(node, dataType, MAC, False, False) cursor = mydb.cursor(dictionary=True) # Enable dictionary output cursor.execute(query) result = cursor.fetchall() # Fetch the results @@ -56,7 +60,18 @@ def getData(node, dataType, MAC): def getNodeInfo(macAdress): mydb = loginDB() - query = get_query(False, False, macAdress) + query = get_query(False, False, macAdress, False, False) + cursor = mydb.cursor(dictionary=True) # Enable dictionary output + cursor.execute(query) + result = cursor.fetchall() # Fetch the results + cursor.close() + mydb.close() + + return result + +def getQuestionData(): + mydb = loginDB() + query = get_query(False, False, False, True, False) cursor = mydb.cursor(dictionary=True) # Enable dictionary output cursor.execute(query) result = cursor.fetchall() # Fetch the results diff --git a/server/Flask/queries.py b/server/Flask/queries.py index e2da308..dda5ff9 100644 --- a/server/Flask/queries.py +++ b/server/Flask/queries.py @@ -1,4 +1,4 @@ -def get_query(node, dataType, MAC): +def get_query(node, dataType, MAC, questionID, replies): if node and dataType: query = f"SELECT * FROM Measurement WHERE NodeID = {node} AND Type = '{dataType}'" elif node: @@ -7,12 +7,15 @@ def get_query(node, dataType, MAC): query = f"SELECT * FROM Measurement WHERE Type = '{dataType}'" elif MAC: query = f"SELECT * FROM Node WHERE MAC = '{MAC}'" + elif questionID: + query = f"SELECT * FROM Question" + elif replies: + query = f"SELECT * FROM Reply WHERE QuestionID = '{questionID}'" else: query = "SELECT * FROM `Measurement`" return query - def update_query(node, name, location): if node and name and location: query = f""" From 0db496fb726ee454f3fe96cc6ce515a94bfaec80 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Fri, 29 Mar 2024 15:39:48 +0100 Subject: [PATCH 06/62] Refactor queries.py to improve query selection logic --- server/Flask/queries.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/Flask/queries.py b/server/Flask/queries.py index dda5ff9..cd85146 100644 --- a/server/Flask/queries.py +++ b/server/Flask/queries.py @@ -7,10 +7,10 @@ def get_query(node, dataType, MAC, questionID, replies): query = f"SELECT * FROM Measurement WHERE Type = '{dataType}'" elif MAC: query = f"SELECT * FROM Node WHERE MAC = '{MAC}'" + elif replies and questionID: + query = f"SELECT * FROM Reply WHERE QuestionID = '{questionID}'" elif questionID: query = f"SELECT * FROM Question" - elif replies: - query = f"SELECT * FROM Reply WHERE QuestionID = '{questionID}'" else: query = "SELECT * FROM `Measurement`" return query From 26b35036ec737e740af805963a0a789242b3bb74 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Fri, 29 Mar 2024 16:16:08 +0100 Subject: [PATCH 07/62] Added graph --- web/newWebsite/GaugGroup.js | 4 +++- web/newWebsite/index.html | 1 + web/newWebsite/main.js | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/web/newWebsite/GaugGroup.js b/web/newWebsite/GaugGroup.js index 31da446..8b9e427 100644 --- a/web/newWebsite/GaugGroup.js +++ b/web/newWebsite/GaugGroup.js @@ -24,8 +24,10 @@ class GaugeGroup {
`).join('')} -
+
+
`; // Append the new div to the body diff --git a/web/newWebsite/index.html b/web/newWebsite/index.html index 52122e5..05f02b7 100644 --- a/web/newWebsite/index.html +++ b/web/newWebsite/index.html @@ -27,6 +27,7 @@ + diff --git a/web/newWebsite/main.js b/web/newWebsite/main.js index a62e059..a97fd96 100644 --- a/web/newWebsite/main.js +++ b/web/newWebsite/main.js @@ -98,9 +98,17 @@ async function nodeAdressHandler(node, dataTypes) { let gaugeGroup = new GaugeGroup(nodeName, nodeLocation, dataTypes.length, maxGaugeValues, dataTypes); sensorData[node] = gaugeGroup; + gaugeGroup.graph = new liveGraph(nodeName); + sensorData[node] = gaugeGroup; + gaugeGroup.graph.makeGraph(); + sensorData[node] = gaugeGroup; + + } } + + function getNodeInfo(node){ return fetch("http://145.92.8.114/getNodeInfo?macAdress=" + node) .then(response => { From 49dc40a2c29a373a807542fdd667506268868ea3 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Fri, 29 Mar 2024 16:25:54 +0100 Subject: [PATCH 08/62] Add data filtering functionality and input elements for user input --- web/newWebsite/graph-main.js | 97 +++++++++++++++++++++++++- web/newWebsite/styles/graph-styles.css | 27 ++++++- 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/web/newWebsite/graph-main.js b/web/newWebsite/graph-main.js index 139597f..3eb71ae 100644 --- a/web/newWebsite/graph-main.js +++ b/web/newWebsite/graph-main.js @@ -1,2 +1,95 @@ - - +// Sample data - you can replace this with your actual dataset +const data = [ + { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 25, humidity: 50, eco2: 400, tvoc: 1 }, + { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 26, humidity: 45, eco2: 450, tvoc: 2 }, + { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 24, humidity: 55, eco2: 500, tvoc: 3 }, + { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 27, humidity: 40, eco2: 550, tvoc: 4 }, + { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 23, humidity: 60, eco2: 600, tvoc: 5 }, + { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 25, humidity: 50, eco2: 650, tvoc: 6 } + ]; + + // Function to filter data based on user input + function filterData(data, startDate, endDate, nodes, selectedFields) { + const filteredData = data.filter(item => { + const timestamp = new Date(item.timestamp); + return timestamp >= startDate && timestamp <= endDate && nodes.includes(item.node); + }).map(item => { + const filteredItem = { node: item.node, timestamp: item.timestamp }; + selectedFields.forEach(field => { + filteredItem[field] = item[field]; + }); + return filteredItem; + }); + return filteredData; + } + + // Create HTML input elements for user input + // Include checkboxes for each data field + const temperatureCheckbox = createCheckBox('temperature', 'Temperature'); + const humidityCheckbox = createCheckBox('humidity', 'Humidity'); + const eco2Checkbox = createCheckBox('eco2', 'eCO2'); + const tvocCheckbox = createCheckBox('tvoc', 'TVOC'); + + // Create a checkbox element with label + function createCheckBox(id, label) { + const checkbox = document.createElement('input'); + checkbox.setAttribute('type', 'checkbox'); + checkbox.setAttribute('id', id); + checkbox.setAttribute('class', 'checkbox'); + + const checkboxLabel = document.createElement('label'); + checkboxLabel.setAttribute('for', id); + checkboxLabel.textContent = label; + + return { checkbox, checkboxLabel }; + } + + const startDateInput = document.createElement('input'); + startDateInput.setAttribute('type', 'datetime-local'); + startDateInput.setAttribute('id', 'start-date'); + startDateInput.setAttribute('class', 'input-field'); + + const endDateInput = document.createElement('input'); + endDateInput.setAttribute('type', 'datetime-local'); + endDateInput.setAttribute('id', 'end-date'); + endDateInput.setAttribute('class', 'input-field'); + + const nodeInput = document.createElement('input'); + nodeInput.setAttribute('type', 'text'); + nodeInput.setAttribute('placeholder', 'Enter node (A, B, etc.)'); + nodeInput.setAttribute('id', 'node-input'); + nodeInput.setAttribute('class', 'input-field'); + + const filterButton = document.createElement('button'); + filterButton.textContent = 'Filter Data'; + filterButton.setAttribute('class', 'filter-button'); + filterButton.addEventListener('click', () => { + const startDate = new Date(document.getElementById('start-date').value); + const endDate = new Date(document.getElementById('end-date').value); + const selectedNodes = document.getElementById('node-input').value.split(',').map(node => node.trim()); + + const selectedFields = []; + const checkboxes = [temperatureCheckbox, humidityCheckbox, eco2Checkbox, tvocCheckbox]; + checkboxes.forEach(checkbox => { + if (checkbox.checkbox.checked) { + selectedFields.push(checkbox.checkbox.id); + } + }); + + const filteredData = filterData(data, startDate, endDate, selectedNodes, selectedFields); + console.log(filteredData); + }); + + // Append input elements to the document body + document.body.appendChild(startDateInput); + document.body.appendChild(endDateInput); + document.body.appendChild(nodeInput); + document.body.appendChild(temperatureCheckbox.checkbox); + document.body.appendChild(temperatureCheckbox.checkboxLabel); + document.body.appendChild(humidityCheckbox.checkbox); + document.body.appendChild(humidityCheckbox.checkboxLabel); + document.body.appendChild(eco2Checkbox.checkbox); + document.body.appendChild(eco2Checkbox.checkboxLabel); + document.body.appendChild(tvocCheckbox.checkbox); + document.body.appendChild(tvocCheckbox.checkboxLabel); + document.body.appendChild(filterButton); \ No newline at end of file diff --git a/web/newWebsite/styles/graph-styles.css b/web/newWebsite/styles/graph-styles.css index 8ad355d..ec79d48 100644 --- a/web/newWebsite/styles/graph-styles.css +++ b/web/newWebsite/styles/graph-styles.css @@ -165,4 +165,29 @@ body { color: #fff; text-decoration: none; font-size: 18px; -} \ No newline at end of file +} + +.input-field { + margin: 10px; + padding: 5px; + border: 1px solid #ccc; + border-radius: 5px; + } + + .checkbox { + margin-right: 5px; + } + + .filter-button { + margin: 10px; + padding: 5px 10px; + background-color: #007bff; + color: #fff; + border: none; + border-radius: 5px; + cursor: pointer; + } + + .filter-button:hover { + background-color: #0056b3; + } \ No newline at end of file From 09e3d7020ef8398af8adfeaadc759d75c5c57ea7 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Fri, 29 Mar 2024 19:36:07 +0100 Subject: [PATCH 09/62] moved navbar into body --- web/newWebsite/index.html | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/web/newWebsite/index.html b/web/newWebsite/index.html index 05f02b7..854fcd6 100644 --- a/web/newWebsite/index.html +++ b/web/newWebsite/index.html @@ -11,22 +11,23 @@ - + + From 0666b21bc57b2799a7d9cad5a19a3c616d952ef3 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Fri, 29 Mar 2024 19:36:12 +0100 Subject: [PATCH 10/62] styling --- web/newWebsite/styles/dashboard-styles.css | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/web/newWebsite/styles/dashboard-styles.css b/web/newWebsite/styles/dashboard-styles.css index 2985720..190586e 100644 --- a/web/newWebsite/styles/dashboard-styles.css +++ b/web/newWebsite/styles/dashboard-styles.css @@ -6,21 +6,20 @@ } body { - padding-top: 5vw; display: flex; justify-content: center; - align-items: center; - height: 100vh; margin: 0; + margin-top: 8vh; background-color: #f0f0f0; flex-direction: column; background-color: #afafaf; + align-items: center; } .gaugeGroup { width: 98vw; - height: 20vh; + height: auto; display: flex; flex-direction: column; /* Keep as column */ justify-content: flex-start; @@ -32,8 +31,8 @@ body { clear: both; margin-bottom: 10px; position: relative; - float: top; } + .groupTitle { width: 100%; text-align: center; @@ -76,7 +75,9 @@ body { height: 80%; /* Increase the height from 70% to 80% */ position: relative; overflow: visible; - + height: 5vh; + margin-bottom: 1vh; + } .gaugeImage { @@ -89,7 +90,6 @@ body { left: 0; z-index: 1; /* Make the image display below the needle */ bottom: 0; - margin-bottom: 10px; } .gaugeValue, .gaugeText { @@ -179,4 +179,15 @@ body { color: #fff; text-decoration: none; font-size: 18px; +} + +.plotly-container { + + float: bottom; + margin: auto; + padding: 1vw; + align-items: center; + justify-content: center; + display: flex; + width: 20vw; } \ No newline at end of file From 9ac39ff74f77e98c534c59f989b7e5ae58bae484 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Sat, 30 Mar 2024 12:38:13 +0100 Subject: [PATCH 11/62] removed junk --- web/newWebsite/liveGraph.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/web/newWebsite/liveGraph.js b/web/newWebsite/liveGraph.js index e2aac1d..6668620 100644 --- a/web/newWebsite/liveGraph.js +++ b/web/newWebsite/liveGraph.js @@ -54,15 +54,16 @@ class liveGraph { } // Function to update the graph with new values got from updateData function - updateGraph() { + updateGraph(temperature, humidity, eCO2, TVOC) { + // Update the graph + this.tempArray.push(temperature); + this.humiArray.push(humidity); + this.eco2Array.push(eCO2 / 10); + this.tvocArray.push(TVOC / 10); + let time = new Date(); this.timeArray.push(new Date()); - let update = { - x: [[this.timeArray]], - y: [[this.tempArray], [this.humiArray], [this.eco2Array], [this.tvocArray]] - }; - let olderTime = time.setMinutes(time.getMinutes() - 1); let futureTime = time.setMinutes(time.getMinutes() + 1); let minuteView = { @@ -75,11 +76,4 @@ class liveGraph { if (this.cnt === 10) clearInterval(interval); } // function to get the new data for graph - updateData(temperature, humidity, eCO2, TVOC) { - // Update the graph - this.tempArray.push(temperature); - this.humiArray.push(humidity); - this.eco2Array.push(eCO2 / 10); - this.tvocArray.push(TVOC / 10); - } } \ No newline at end of file From 92b27ab9b7749d9989536ec41534d7c8ce005483 Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Sat, 30 Mar 2024 12:38:20 +0100 Subject: [PATCH 12/62] graph works now --- web/newWebsite/main.js | 2 +- web/newWebsite/styles/dashboard-styles.css | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/web/newWebsite/main.js b/web/newWebsite/main.js index a97fd96..d55fb12 100644 --- a/web/newWebsite/main.js +++ b/web/newWebsite/main.js @@ -66,6 +66,7 @@ async function handleIncomingData(data) { sensorData[data.node].updateGauge(2, humidity); sensorData[data.node].updateGauge(3, CO2); sensorData[data.node].updateGauge(4, TVOC); + sensorData[data.node].graph.updateGraph(temperature, humidity, CO2, TVOC); } else { console.error('No sensor data for node:', nodeName); } @@ -102,7 +103,6 @@ async function nodeAdressHandler(node, dataTypes) { sensorData[node] = gaugeGroup; gaugeGroup.graph.makeGraph(); sensorData[node] = gaugeGroup; - } } diff --git a/web/newWebsite/styles/dashboard-styles.css b/web/newWebsite/styles/dashboard-styles.css index 190586e..0758c94 100644 --- a/web/newWebsite/styles/dashboard-styles.css +++ b/web/newWebsite/styles/dashboard-styles.css @@ -190,4 +190,6 @@ body { justify-content: center; display: flex; width: 20vw; + z-index: -0; + height: -; } \ No newline at end of file From 3e7a89bf8b8e98665a5b39ea32d5d5995b9e403c Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Sat, 30 Mar 2024 17:22:55 +0100 Subject: [PATCH 13/62] Added togglegraph function --- web/newWebsite/main.js | 15 ++++++++++++++- web/newWebsite/styles/dashboard-styles.css | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/web/newWebsite/main.js b/web/newWebsite/main.js index d55fb12..c5e1486 100644 --- a/web/newWebsite/main.js +++ b/web/newWebsite/main.js @@ -103,7 +103,6 @@ async function nodeAdressHandler(node, dataTypes) { sensorData[node] = gaugeGroup; gaugeGroup.graph.makeGraph(); sensorData[node] = gaugeGroup; - } } @@ -129,3 +128,17 @@ function getNodeInfo(node){ } +// create a function to enable and disable the graph using .disabled using the id of the graph +function toggleGraph(nodeId) { + let graph = document.querySelector('#liveGraph' + nodeId); + + if (graph) { + if (graph.classList.contains('disabled')) { + graph.classList.remove('disabled'); + } else { + graph.classList.add('disabled'); + } + } else { + console.error('No element found with id: liveGraph' + nodeId); + } +} \ No newline at end of file diff --git a/web/newWebsite/styles/dashboard-styles.css b/web/newWebsite/styles/dashboard-styles.css index 0758c94..d550f41 100644 --- a/web/newWebsite/styles/dashboard-styles.css +++ b/web/newWebsite/styles/dashboard-styles.css @@ -191,5 +191,10 @@ body { display: flex; width: 20vw; z-index: -0; - height: -; + +} +* +.disabled { + opacity: 0; + height: 0; } \ No newline at end of file From 02b32c33ea7a958f18eec8b344836529f6abeaae Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Sat, 30 Mar 2024 17:31:41 +0100 Subject: [PATCH 14/62] made dropdown graph --- web/newWebsite/GaugGroup.js | 3 ++- web/newWebsite/styles/dashboard-styles.css | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/web/newWebsite/GaugGroup.js b/web/newWebsite/GaugGroup.js index 8b9e427..cf3c1f4 100644 --- a/web/newWebsite/GaugGroup.js +++ b/web/newWebsite/GaugGroup.js @@ -13,6 +13,7 @@ class GaugeGroup { this.element.innerHTML = `

${this.nodeId} - ${this.location}

+ ${Array(this.gaugesCount).fill().map((_, i) => `
@@ -26,7 +27,7 @@ class GaugeGroup { `).join('')}
-
+
`; diff --git a/web/newWebsite/styles/dashboard-styles.css b/web/newWebsite/styles/dashboard-styles.css index d550f41..e4e367a 100644 --- a/web/newWebsite/styles/dashboard-styles.css +++ b/web/newWebsite/styles/dashboard-styles.css @@ -190,11 +190,11 @@ body { justify-content: center; display: flex; width: 20vw; - z-index: -0; } * .disabled { opacity: 0; height: 0; + } \ No newline at end of file From 79c3c956fe729207c15c9b8667c25337d6843428 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 20:43:51 +0100 Subject: [PATCH 15/62] Update graph styles and input field margins --- web/newWebsite/graph-main.js | 188 +++++++++++++------------ web/newWebsite/styles/graph-styles.css | 24 +++- 2 files changed, 118 insertions(+), 94 deletions(-) diff --git a/web/newWebsite/graph-main.js b/web/newWebsite/graph-main.js index 3eb71ae..eadfb77 100644 --- a/web/newWebsite/graph-main.js +++ b/web/newWebsite/graph-main.js @@ -1,95 +1,99 @@ // Sample data - you can replace this with your actual dataset const data = [ - { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 25, humidity: 50, eco2: 400, tvoc: 1 }, - { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 26, humidity: 45, eco2: 450, tvoc: 2 }, - { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 24, humidity: 55, eco2: 500, tvoc: 3 }, - { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 27, humidity: 40, eco2: 550, tvoc: 4 }, - { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 23, humidity: 60, eco2: 600, tvoc: 5 }, - { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 25, humidity: 50, eco2: 650, tvoc: 6 } - ]; - - // Function to filter data based on user input - function filterData(data, startDate, endDate, nodes, selectedFields) { - const filteredData = data.filter(item => { - const timestamp = new Date(item.timestamp); - return timestamp >= startDate && timestamp <= endDate && nodes.includes(item.node); - }).map(item => { - const filteredItem = { node: item.node, timestamp: item.timestamp }; - selectedFields.forEach(field => { - filteredItem[field] = item[field]; - }); - return filteredItem; - }); - return filteredData; - } - - // Create HTML input elements for user input - // Include checkboxes for each data field - const temperatureCheckbox = createCheckBox('temperature', 'Temperature'); - const humidityCheckbox = createCheckBox('humidity', 'Humidity'); - const eco2Checkbox = createCheckBox('eco2', 'eCO2'); - const tvocCheckbox = createCheckBox('tvoc', 'TVOC'); - - // Create a checkbox element with label - function createCheckBox(id, label) { - const checkbox = document.createElement('input'); - checkbox.setAttribute('type', 'checkbox'); - checkbox.setAttribute('id', id); - checkbox.setAttribute('class', 'checkbox'); - - const checkboxLabel = document.createElement('label'); - checkboxLabel.setAttribute('for', id); - checkboxLabel.textContent = label; - - return { checkbox, checkboxLabel }; - } - - const startDateInput = document.createElement('input'); - startDateInput.setAttribute('type', 'datetime-local'); - startDateInput.setAttribute('id', 'start-date'); - startDateInput.setAttribute('class', 'input-field'); - - const endDateInput = document.createElement('input'); - endDateInput.setAttribute('type', 'datetime-local'); - endDateInput.setAttribute('id', 'end-date'); - endDateInput.setAttribute('class', 'input-field'); - - const nodeInput = document.createElement('input'); - nodeInput.setAttribute('type', 'text'); - nodeInput.setAttribute('placeholder', 'Enter node (A, B, etc.)'); - nodeInput.setAttribute('id', 'node-input'); - nodeInput.setAttribute('class', 'input-field'); - - const filterButton = document.createElement('button'); - filterButton.textContent = 'Filter Data'; - filterButton.setAttribute('class', 'filter-button'); - filterButton.addEventListener('click', () => { - const startDate = new Date(document.getElementById('start-date').value); - const endDate = new Date(document.getElementById('end-date').value); - const selectedNodes = document.getElementById('node-input').value.split(',').map(node => node.trim()); - - const selectedFields = []; - const checkboxes = [temperatureCheckbox, humidityCheckbox, eco2Checkbox, tvocCheckbox]; - checkboxes.forEach(checkbox => { - if (checkbox.checkbox.checked) { - selectedFields.push(checkbox.checkbox.id); - } - }); - - const filteredData = filterData(data, startDate, endDate, selectedNodes, selectedFields); - console.log(filteredData); + { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 25, humidity: 50, eco2: 400, tvoc: 1 }, + { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 26, humidity: 45, eco2: 450, tvoc: 2 }, + { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 24, humidity: 55, eco2: 500, tvoc: 3 }, + { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 27, humidity: 40, eco2: 550, tvoc: 4 }, + { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 23, humidity: 60, eco2: 600, tvoc: 5 }, + { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 25, humidity: 50, eco2: 650, tvoc: 6 } +]; + +// Function to create checkbox with label +function createCheckBox(id, label) { + const checkbox = document.createElement('input'); + checkbox.setAttribute('type', 'checkbox'); + checkbox.setAttribute('id', id); + checkbox.setAttribute('class', 'checkbox'); + + const checkboxLabel = document.createElement('label'); + checkboxLabel.setAttribute('for', id); + checkboxLabel.textContent = label; + + return { checkbox, checkboxLabel }; +} + +// Create HTML input elements for user input +const container = document.createElement('div'); +container.setAttribute('class', 'container'); + +const dataTypesContainer = document.createElement('div'); +dataTypesContainer.setAttribute('class', 'data-types'); + +const temperatureCheckbox = createCheckBox('temperature', 'Temperature'); +const humidityCheckbox = createCheckBox('humidity', 'Humidity'); +const eco2Checkbox = createCheckBox('eco2', 'eCO2'); +const tvocCheckbox = createCheckBox('tvoc', 'TVOC'); + +dataTypesContainer.appendChild(temperatureCheckbox.checkbox); +dataTypesContainer.appendChild(temperatureCheckbox.checkboxLabel); +dataTypesContainer.appendChild(humidityCheckbox.checkbox); +dataTypesContainer.appendChild(humidityCheckbox.checkboxLabel); +dataTypesContainer.appendChild(eco2Checkbox.checkbox); +dataTypesContainer.appendChild(eco2Checkbox.checkboxLabel); +dataTypesContainer.appendChild(tvocCheckbox.checkbox); +dataTypesContainer.appendChild(tvocCheckbox.checkboxLabel); + +const filterButton = document.createElement('button'); +filterButton.textContent = 'Filter Data'; +filterButton.setAttribute('class', 'filter-button'); +filterButton.addEventListener('click', () => { + const startDate = new Date(document.getElementById('start-date').value); + const endDate = new Date(document.getElementById('end-date').value); + const selectedNodes = document.getElementById('node-input').value.split(',').map(node => node.trim()); + + const selectedFields = []; + const checkboxes = [temperatureCheckbox, humidityCheckbox, eco2Checkbox, tvocCheckbox]; + checkboxes.forEach(checkbox => { + if (checkbox.checkbox.checked) { + selectedFields.push(checkbox.checkbox.id); + } }); - - // Append input elements to the document body - document.body.appendChild(startDateInput); - document.body.appendChild(endDateInput); - document.body.appendChild(nodeInput); - document.body.appendChild(temperatureCheckbox.checkbox); - document.body.appendChild(temperatureCheckbox.checkboxLabel); - document.body.appendChild(humidityCheckbox.checkbox); - document.body.appendChild(humidityCheckbox.checkboxLabel); - document.body.appendChild(eco2Checkbox.checkbox); - document.body.appendChild(eco2Checkbox.checkboxLabel); - document.body.appendChild(tvocCheckbox.checkbox); - document.body.appendChild(tvocCheckbox.checkboxLabel); - document.body.appendChild(filterButton); \ No newline at end of file + + const filteredData = filterData(data, startDate, endDate, selectedNodes, selectedFields); + console.log(filteredData); +}); + +container.appendChild(dataTypesContainer); + +const dateFilter = document.createElement('div'); +dateFilter.setAttribute('class', 'date-filter'); + +const startDateInput = document.createElement('input'); +startDateInput.setAttribute('type', 'datetime-local'); +startDateInput.setAttribute('id', 'start-date'); +startDateInput.setAttribute('class', 'input-field'); + +const endDateInput = document.createElement('input'); +endDateInput.setAttribute('type', 'datetime-local'); +endDateInput.setAttribute('id', 'end-date'); +endDateInput.setAttribute('class', 'input-field'); + +dateFilter.appendChild(startDateInput); +dateFilter.appendChild(endDateInput); +container.appendChild(dateFilter); + +const nodeFilter = document.createElement('div'); +nodeFilter.setAttribute('class', 'node-filter'); + +const nodeInput = document.createElement('input'); +nodeInput.setAttribute('type', 'text'); +nodeInput.setAttribute('placeholder', 'Enter node (A, B, etc.)'); +nodeInput.setAttribute('id', 'node-input'); +nodeInput.setAttribute('class', 'input-field'); + +nodeFilter.appendChild(nodeInput); +container.appendChild(nodeFilter); + +container.appendChild(filterButton); + +document.body.appendChild(container); \ No newline at end of file diff --git a/web/newWebsite/styles/graph-styles.css b/web/newWebsite/styles/graph-styles.css index ec79d48..eaf79e0 100644 --- a/web/newWebsite/styles/graph-styles.css +++ b/web/newWebsite/styles/graph-styles.css @@ -167,8 +167,28 @@ body { font-size: 18px; } -.input-field { - margin: 10px; +.container { + display: flex; + justify-content: space-around; + align-items: center; + border: 2px solid #ccc; + border-radius: 10px; + padding: 10px; + margin: 20px; + } + + .data-types { + display: flex; + flex-direction: column; + } + + .date-filter, + .node-filter { + margin-left: 10px; + } + + .input-field { + margin: 5px; padding: 5px; border: 1px solid #ccc; border-radius: 5px; From 726d411321335ce588e443a0d14230d29b3c3791 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 21:25:20 +0100 Subject: [PATCH 16/62] Add dataTypesContainer to container and update styles --- web/newWebsite/graph-main.js | 3 +- web/newWebsite/graphs.html | 3 +- web/newWebsite/styles/graph-styles.css | 60 +++++++++++++------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/web/newWebsite/graph-main.js b/web/newWebsite/graph-main.js index eadfb77..024aad6 100644 --- a/web/newWebsite/graph-main.js +++ b/web/newWebsite/graph-main.js @@ -42,6 +42,7 @@ dataTypesContainer.appendChild(eco2Checkbox.checkbox); dataTypesContainer.appendChild(eco2Checkbox.checkboxLabel); dataTypesContainer.appendChild(tvocCheckbox.checkbox); dataTypesContainer.appendChild(tvocCheckbox.checkboxLabel); +container.appendChild(dataTypesContainer); const filterButton = document.createElement('button'); filterButton.textContent = 'Filter Data'; @@ -63,8 +64,6 @@ filterButton.addEventListener('click', () => { console.log(filteredData); }); -container.appendChild(dataTypesContainer); - const dateFilter = document.createElement('div'); dateFilter.setAttribute('class', 'date-filter'); diff --git a/web/newWebsite/graphs.html b/web/newWebsite/graphs.html index 0629172..ad48fd4 100644 --- a/web/newWebsite/graphs.html +++ b/web/newWebsite/graphs.html @@ -28,7 +28,8 @@
- + +
diff --git a/web/newWebsite/styles/graph-styles.css b/web/newWebsite/styles/graph-styles.css index eaf79e0..ce423d9 100644 --- a/web/newWebsite/styles/graph-styles.css +++ b/web/newWebsite/styles/graph-styles.css @@ -168,46 +168,46 @@ body { } .container { + box-sizing: border-box; display: flex; - justify-content: space-around; + flex-wrap: wrap; + flex-direction: row; + justify-content: center; align-items: center; - border: 2px solid #ccc; + border: 2px solid #000000; border-radius: 10px; - padding: 10px; - margin: 20px; + padding: 20px; } .data-types { - display: flex; flex-direction: column; + align-self: self-center; + justify-content: space-between; + padding: 20px; + width: 30%; /* Adjust width as needed */ + background-color: #f1f1f1; } - .date-filter, - .node-filter { - margin-left: 10px; + .date-filter{ + align-content: center; + flex-direction: column; + justify-content: space-between; + /* width: 30%; /* Adjust width as needed */ + background-color: #f1f1f1; } - - .input-field { - margin: 5px; - padding: 5px; - border: 1px solid #ccc; - border-radius: 5px; - } - - .checkbox { - margin-right: 5px; - } - - .filter-button { - margin: 10px; - padding: 5px 10px; - background-color: #007bff; - color: #fff; + + .node-filter{ + align-self: center; + justify-content: space-between; + width: 10%; /* Adjust width as needed */ border: none; - border-radius: 5px; - cursor: pointer; + border-radius: 4px; + background-color: #f1f1f1; + } + + .filter-button { + width: 100%; + margin-top: 20px; } - .filter-button:hover { - background-color: #0056b3; - } \ No newline at end of file + /* Additional styling as needed */ \ No newline at end of file From 415a0c456e0e960945cc2de49ec64b76cbce8d68 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 21:46:32 +0100 Subject: [PATCH 17/62] Remove extra closing div tag in graphs.html --- web/newWebsite/graphs.html | 3 +- web/newWebsite/styles/graph-styles.css | 320 +++++++++++++------------ 2 files changed, 163 insertions(+), 160 deletions(-) diff --git a/web/newWebsite/graphs.html b/web/newWebsite/graphs.html index ad48fd4..0629172 100644 --- a/web/newWebsite/graphs.html +++ b/web/newWebsite/graphs.html @@ -28,8 +28,7 @@
- -
+ diff --git a/web/newWebsite/styles/graph-styles.css b/web/newWebsite/styles/graph-styles.css index ce423d9..f60bf63 100644 --- a/web/newWebsite/styles/graph-styles.css +++ b/web/newWebsite/styles/graph-styles.css @@ -1,213 +1,217 @@ * { - box-sizing: border-box; - font-family: "Roboto", sans-serif; + box-sizing: border-box; + font-family: "Roboto", sans-serif; } body { - padding-top: 5vw; - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - margin: 0; - background-color: #f0f0f0; - flex-direction: column; - background-color: #afafaf; - + padding-top: 5vw; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; + background-color: #f0f0f0; + flex-direction: column; + background-color: #afafaf; } .gaugeGroup { - width: 98vw; - height: 20vh; - display: flex; - flex-direction: column; /* Keep as column */ - justify-content: flex-start; - background-color: #333; - color: #fff; - padding: 10px; - border-radius: 50px; - border: 2px solid #333; - clear: both; - margin-bottom: 10px; - position: relative; - float: top; + width: 98vw; + height: 20vh; + display: flex; + flex-direction: column; /* Keep as column */ + justify-content: flex-start; + background-color: #333; + color: #fff; + padding: 10px; + border-radius: 50px; + border: 2px solid #333; + clear: both; + margin-bottom: 10px; + position: relative; + float: top; } .groupTitle { - width: 100%; - text-align: center; - font-size: 24px; + width: 100%; + text-align: center; + font-size: 24px; } .Node { - display: flex; - justify-content: space-around; - align-items: center; - width: 100%; - height: 100%; + display: flex; + justify-content: space-around; + align-items: center; + width: 100%; + height: 100%; } .Sensorvalues { - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-around; - flex-wrap: wrap; - width: 15%; - height: 110%; - background-color: #ddd; - color: #333; - padding: 10px; - margin: 10px; - border-radius: 10px; - text-align: center; - position: relative; - padding-bottom: 6vh; /* Increase bottom padding */ - + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-around; + flex-wrap: wrap; + width: 15%; + height: 110%; + background-color: #ddd; + color: #333; + padding: 10px; + margin: 10px; + border-radius: 10px; + text-align: center; + position: relative; + padding-bottom: 6vh; /* Increase bottom padding */ } .gaugeContainer { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; - height: 80%; /* Increase the height from 70% to 80% */ - position: relative; - overflow: visible; - + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 80%; /* Increase the height from 70% to 80% */ + position: relative; + overflow: visible; } .gaugeImage { - width: 100%; - height: auto; - max-height: 200%; - object-fit: contain; - position: absolute; /* Make the image position absolute */ - top: 0; - left: 0; - z-index: 1; /* Make the image display below the needle */ - bottom: 0; - margin-bottom: 10px; + width: 100%; + height: auto; + max-height: 200%; + object-fit: contain; + position: absolute; /* Make the image position absolute */ + top: 0; + left: 0; + z-index: 1; /* Make the image display below the needle */ + bottom: 0; + margin-bottom: 10px; } -.gaugeValue, .gaugeText { - width: 100%; - text-align: center; - font-size: 24px; - z-index: 2; +.gaugeValue, +.gaugeText { + width: 100%; + text-align: center; + font-size: 24px; + z-index: 2; } .gaugeText { - width: 100%; - text-align: center; - font-size: 1.4vw; - z-index: 2; - position: absolute; - bottom: -3.2vw; /* Adjust this value to move the text further down */ - + width: 100%; + text-align: center; + font-size: 1.4vw; + z-index: 2; + position: absolute; + bottom: -3.2vw; /* Adjust this value to move the text further down */ } - .valueContainer { - display: flex; - justify-content: center; - margin-top: 10px; + display: flex; + justify-content: center; + margin-top: 10px; } #valueText { - font-size: 20px; + font-size: 20px; } .needle { - position: absolute; - bottom: -40%; /* Lower the needle to the bottom */ - left: 50%; - width: 2px; - height: 110%; - background-color: black; - transform-origin: bottom; - z-index: 3; /* Make the needle display above the image */ + position: absolute; + bottom: -40%; /* Lower the needle to the bottom */ + left: 50%; + width: 2px; + height: 110%; + background-color: black; + transform-origin: bottom; + z-index: 3; /* Make the needle display above the image */ } .contentContainer { - display: flex; - flex-direction: row; /* Layout children side by side */ - width: 100%; - height: 100%; + display: flex; + flex-direction: row; /* Layout children side by side */ + width: 100%; + height: 100%; } .navbar { - background-color: #333; - height: 60px; - display: flex; - align-items: center; - padding: 0 20px; - position: fixed; /* Fix the navbar at the top of the page */ - top: 0; /* Position it at the very top */ - width: 100%; /* Make it span the full width of the page */ - z-index: 1000; /* Make sure it's above all other elements */ + background-color: #333; + height: 60px; + display: flex; + align-items: center; + padding: 0 20px; + position: fixed; /* Fix the navbar at the top of the page */ + top: 0; /* Position it at the very top */ + width: 100%; /* Make it span the full width of the page */ + z-index: 1000; /* Make sure it's above all other elements */ } .navbar-nav { - list-style: none; - display: flex; - align-items: center; - justify-content: center; /* Center the links horizontally */ - height: 100%; - width: 100%; /* Make it span the full width of the navbar */ + list-style: none; + display: flex; + align-items: center; + justify-content: center; /* Center the links horizontally */ + height: 100%; + width: 100%; /* Make it span the full width of the navbar */ } .nav-item { - margin-right: 20px; + margin-right: 20px; } .nav-link { - color: #fff; - text-decoration: none; - font-size: 18px; + color: #fff; + text-decoration: none; + font-size: 18px; } .container { - box-sizing: border-box; - display: flex; - flex-wrap: wrap; - flex-direction: row; - justify-content: center; - align-items: center; - border: 2px solid #000000; - border-radius: 10px; - padding: 20px; - } - - .data-types { - flex-direction: column; - align-self: self-center; - justify-content: space-between; - padding: 20px; - width: 30%; /* Adjust width as needed */ - background-color: #f1f1f1; - } - - .date-filter{ - align-content: center; - flex-direction: column; - justify-content: space-between; - /* width: 30%; /* Adjust width as needed */ - background-color: #f1f1f1; - } + display: flex; + flex-direction: row; + align-items: center; + border: 2px solid #ccc; + border-radius: 10px; + padding: 20px; + width: 100%; + box-sizing: border-box; +} - .node-filter{ - align-self: center; - justify-content: space-between; - width: 10%; /* Adjust width as needed */ - border: none; - border-radius: 4px; - background-color: #f1f1f1; - } +.data-types { + display: flex; + flex-direction: column; /* Display data types in a column */ + align-items: flex-start; /* Align to the start of the container */ + text-align: right; /* Align text to the right */ + width: 20%; /* Set a fixed width for the data types */ +} - .filter-button { - width: 100%; - margin-top: 20px; - } - - /* Additional styling as needed */ \ No newline at end of file +.filter { + display: flex; + flex-direction: column; /* Display filters in a column */ + align-items: center center; /* Align to the center of the container */ + text-align: center center; + margin-left: 20px; /* Add some space between the data types and filters */ +} + +.date-filter { + flex-direction: column; + align-items: center center; + justify-content: center; + align-self: center; + width: 30%; +} + +.node-filter { + align-items: center; + text-align: center; + justify-content: center; + align-self: flex-end; + width: 20%; +} + +.filter-button { + text-align: center; + align-items: center; + justify-content: center; + width: 10%; + margin-top: auto; +} + +/* Additional styling as needed */ \ No newline at end of file From 0a25bbf84f432fc0650ae1496a3ad37e702d79e1 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 22:27:16 +0100 Subject: [PATCH 18/62] Refactor graph styles and filters --- web/newWebsite/styles/graph-styles.css | 187 ++++++------------------- 1 file changed, 40 insertions(+), 147 deletions(-) diff --git a/web/newWebsite/styles/graph-styles.css b/web/newWebsite/styles/graph-styles.css index f60bf63..68c7c86 100644 --- a/web/newWebsite/styles/graph-styles.css +++ b/web/newWebsite/styles/graph-styles.css @@ -6,130 +6,8 @@ body { padding-top: 5vw; display: flex; - justify-content: center; - align-items: center; - height: 100vh; - margin: 0; - background-color: #f0f0f0; - flex-direction: column; background-color: #afafaf; -} - -.gaugeGroup { - width: 98vw; - height: 20vh; - display: flex; - flex-direction: column; /* Keep as column */ - justify-content: flex-start; - background-color: #333; - color: #fff; - padding: 10px; - border-radius: 50px; - border: 2px solid #333; - clear: both; - margin-bottom: 10px; - position: relative; - float: top; -} -.groupTitle { - width: 100%; - text-align: center; - font-size: 24px; -} - -.Node { - display: flex; - justify-content: space-around; - align-items: center; - width: 100%; - height: 100%; -} - -.Sensorvalues { - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-around; - flex-wrap: wrap; - width: 15%; - height: 110%; - background-color: #ddd; - color: #333; - padding: 10px; - margin: 10px; - border-radius: 10px; - text-align: center; - position: relative; - padding-bottom: 6vh; /* Increase bottom padding */ -} - -.gaugeContainer { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; - height: 80%; /* Increase the height from 70% to 80% */ - position: relative; - overflow: visible; -} - -.gaugeImage { - width: 100%; - height: auto; - max-height: 200%; - object-fit: contain; - position: absolute; /* Make the image position absolute */ - top: 0; - left: 0; - z-index: 1; /* Make the image display below the needle */ - bottom: 0; - margin-bottom: 10px; -} - -.gaugeValue, -.gaugeText { - width: 100%; - text-align: center; - font-size: 24px; - z-index: 2; -} - -.gaugeText { - width: 100%; - text-align: center; - font-size: 1.4vw; - z-index: 2; - position: absolute; - bottom: -3.2vw; /* Adjust this value to move the text further down */ -} - -.valueContainer { - display: flex; - justify-content: center; - margin-top: 10px; -} - -#valueText { - font-size: 20px; -} - -.needle { - position: absolute; - bottom: -40%; /* Lower the needle to the bottom */ - left: 50%; - width: 2px; - height: 110%; - background-color: black; - transform-origin: bottom; - z-index: 3; /* Make the needle display above the image */ -} - -.contentContainer { - display: flex; - flex-direction: row; /* Layout children side by side */ - width: 100%; - height: 100%; + margin: 0; } .navbar { @@ -169,49 +47,64 @@ body { align-items: center; border: 2px solid #ccc; border-radius: 10px; + margin: 20px; padding: 20px; width: 100%; box-sizing: border-box; } .data-types { + flex: 1; display: flex; - flex-direction: column; /* Display data types in a column */ - align-items: flex-start; /* Align to the start of the container */ - text-align: right; /* Align text to the right */ - width: 20%; /* Set a fixed width for the data types */ + flex-direction: column; + align-items: flex-start; + margin-right: 60px; + margin-bottom: 10px; + font-size: 0.8em; + padding: 8px; + border-radius: 5px; + background-color: #f0f0f0; } -.filter { +.filters { display: flex; - flex-direction: column; /* Display filters in a column */ - align-items: center center; /* Align to the center of the container */ - text-align: center center; - margin-left: 20px; /* Add some space between the data types and filters */ + justify-content: space-between; + align-items: center; + width: 100%; + margin-bottom: 10px; } .date-filter { - flex-direction: column; - align-items: center center; - justify-content: center; - align-self: center; - width: 30%; + flex: 1; + text-align: center; + margin-right: 60px; + font-size: 1.2em; /* Increase font size for a bigger appearance */ + padding: 8px; + border-radius: 5px; /* Add border radius for a rounded look */ + background-color: #f0f0f0; /* Light background color for contrast */ } .node-filter { - align-items: center; + flex: 1; + margin: auto; text-align: center; - justify-content: center; - align-self: flex-end; - width: 20%; + margin-right: 60px; + align-content: center; + font-size: 1.2em; /* Increase font size for a bigger appearance */ + padding: 8px; + border-radius: 5px; /* Add border radius for a rounded look */ + background-color: #f0f0f0; /* Light background color for contrast */ } .filter-button { - text-align: center; - align-items: center; - justify-content: center; - width: 10%; - margin-top: auto; + flex: 1; + width: 20%; + background-color: #007bff; + color: white; + padding: 10px; + border: none; + border-radius: 5px; + cursor: pointer; } -/* Additional styling as needed */ \ No newline at end of file +/* Additional styling as needed */ From 97c21f9d3179e6c5362f5faf5023211cbed35702 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 22:33:42 +0100 Subject: [PATCH 19/62] Add query for retrieving replies --- server/Flask/queries.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/Flask/queries.py b/server/Flask/queries.py index cd85146..d2b4144 100644 --- a/server/Flask/queries.py +++ b/server/Flask/queries.py @@ -11,6 +11,8 @@ def get_query(node, dataType, MAC, questionID, replies): query = f"SELECT * FROM Reply WHERE QuestionID = '{questionID}'" elif questionID: query = f"SELECT * FROM Question" + elif replies: + query = f"SELECT * FROM Reply" else: query = "SELECT * FROM `Measurement`" return query From 8416254d6c6a12bb9ce6e1cb80b4c7af483bd94a Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 22:33:45 +0100 Subject: [PATCH 20/62] Refactor code to create filter container and fetch data from server --- web/newWebsite/graph-main.js | 174 ++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 72 deletions(-) diff --git a/web/newWebsite/graph-main.js b/web/newWebsite/graph-main.js index 024aad6..c1436ed 100644 --- a/web/newWebsite/graph-main.js +++ b/web/newWebsite/graph-main.js @@ -1,98 +1,128 @@ // Sample data - you can replace this with your actual dataset -const data = [ - { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 25, humidity: 50, eco2: 400, tvoc: 1 }, - { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 26, humidity: 45, eco2: 450, tvoc: 2 }, - { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 24, humidity: 55, eco2: 500, tvoc: 3 }, - { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 27, humidity: 40, eco2: 550, tvoc: 4 }, - { node: 'A', timestamp: '2022-01-01 08:00:00', temperature: 23, humidity: 60, eco2: 600, tvoc: 5 }, - { node: 'B', timestamp: '2022-01-01 09:00:00', temperature: 25, humidity: 50, eco2: 650, tvoc: 6 } -]; +const data = []; // Function to create checkbox with label function createCheckBox(id, label) { - const checkbox = document.createElement('input'); - checkbox.setAttribute('type', 'checkbox'); - checkbox.setAttribute('id', id); - checkbox.setAttribute('class', 'checkbox'); + const checkbox = document.createElement("input"); + checkbox.setAttribute("type", "checkbox"); + checkbox.setAttribute("id", id); + checkbox.setAttribute("class", "checkbox"); - const checkboxLabel = document.createElement('label'); - checkboxLabel.setAttribute('for', id); + const checkboxLabel = document.createElement("label"); + checkboxLabel.setAttribute("for", id); checkboxLabel.textContent = label; return { checkbox, checkboxLabel }; } -// Create HTML input elements for user input -const container = document.createElement('div'); -container.setAttribute('class', 'container'); +// Function to ceate filter container and all the input elements +function createFilterContainer() { + // Create HTML input elements for user input + const container = document.createElement("div"); + container.setAttribute("class", "container"); -const dataTypesContainer = document.createElement('div'); -dataTypesContainer.setAttribute('class', 'data-types'); + const dataTypesContainer = document.createElement("div"); + dataTypesContainer.setAttribute("class", "data-types"); -const temperatureCheckbox = createCheckBox('temperature', 'Temperature'); -const humidityCheckbox = createCheckBox('humidity', 'Humidity'); -const eco2Checkbox = createCheckBox('eco2', 'eCO2'); -const tvocCheckbox = createCheckBox('tvoc', 'TVOC'); + const temperatureCheckbox = createCheckBox("temperature", "Temperature"); + const humidityCheckbox = createCheckBox("humidity", "Humidity"); + const eco2Checkbox = createCheckBox("eco2", "eCO2"); + const tvocCheckbox = createCheckBox("tvoc", "TVOC"); -dataTypesContainer.appendChild(temperatureCheckbox.checkbox); -dataTypesContainer.appendChild(temperatureCheckbox.checkboxLabel); -dataTypesContainer.appendChild(humidityCheckbox.checkbox); -dataTypesContainer.appendChild(humidityCheckbox.checkboxLabel); -dataTypesContainer.appendChild(eco2Checkbox.checkbox); -dataTypesContainer.appendChild(eco2Checkbox.checkboxLabel); -dataTypesContainer.appendChild(tvocCheckbox.checkbox); -dataTypesContainer.appendChild(tvocCheckbox.checkboxLabel); -container.appendChild(dataTypesContainer); + dataTypesContainer.appendChild(temperatureCheckbox.checkbox); + dataTypesContainer.appendChild(temperatureCheckbox.checkboxLabel); + dataTypesContainer.appendChild(humidityCheckbox.checkbox); + dataTypesContainer.appendChild(humidityCheckbox.checkboxLabel); + dataTypesContainer.appendChild(eco2Checkbox.checkbox); + dataTypesContainer.appendChild(eco2Checkbox.checkboxLabel); + dataTypesContainer.appendChild(tvocCheckbox.checkbox); + dataTypesContainer.appendChild(tvocCheckbox.checkboxLabel); + container.appendChild(dataTypesContainer); -const filterButton = document.createElement('button'); -filterButton.textContent = 'Filter Data'; -filterButton.setAttribute('class', 'filter-button'); -filterButton.addEventListener('click', () => { - const startDate = new Date(document.getElementById('start-date').value); - const endDate = new Date(document.getElementById('end-date').value); - const selectedNodes = document.getElementById('node-input').value.split(',').map(node => node.trim()); + const filterButton = document.createElement("button"); + filterButton.textContent = "Filter Data"; + filterButton.setAttribute("class", "filter-button"); + filterButton.addEventListener("click", () => { + const startDate = new Date(document.getElementById("start-date").value); + const endDate = new Date(document.getElementById("end-date").value); + const selectedNodes = document + .getElementById("node-input") + .value.split(",") + .map((node) => node.trim()); - const selectedFields = []; - const checkboxes = [temperatureCheckbox, humidityCheckbox, eco2Checkbox, tvocCheckbox]; - checkboxes.forEach(checkbox => { - if (checkbox.checkbox.checked) { - selectedFields.push(checkbox.checkbox.id); - } + const selectedFields = []; + const checkboxes = [ + temperatureCheckbox, + humidityCheckbox, + eco2Checkbox, + tvocCheckbox, + ]; + checkboxes.forEach((checkbox) => { + if (checkbox.checkbox.checked) { + selectedFields.push(checkbox.checkbox.id); + } + }); + + const filteredData = filterData( + data, + startDate, + endDate, + selectedNodes, + selectedFields + ); + console.log(filteredData); }); - const filteredData = filterData(data, startDate, endDate, selectedNodes, selectedFields); - console.log(filteredData); -}); + const dateFilter = document.createElement("div"); + dateFilter.setAttribute("class", "date-filter"); -const dateFilter = document.createElement('div'); -dateFilter.setAttribute('class', 'date-filter'); + const startDateInput = document.createElement("input"); + startDateInput.setAttribute("type", "datetime-local"); + startDateInput.setAttribute("id", "start-date"); + startDateInput.setAttribute("class", "input-field"); -const startDateInput = document.createElement('input'); -startDateInput.setAttribute('type', 'datetime-local'); -startDateInput.setAttribute('id', 'start-date'); -startDateInput.setAttribute('class', 'input-field'); + const endDateInput = document.createElement("input"); + endDateInput.setAttribute("type", "datetime-local"); + endDateInput.setAttribute("id", "end-date"); + endDateInput.setAttribute("class", "input-field"); -const endDateInput = document.createElement('input'); -endDateInput.setAttribute('type', 'datetime-local'); -endDateInput.setAttribute('id', 'end-date'); -endDateInput.setAttribute('class', 'input-field'); + dateFilter.appendChild(startDateInput); + dateFilter.appendChild(endDateInput); + container.appendChild(dateFilter); -dateFilter.appendChild(startDateInput); -dateFilter.appendChild(endDateInput); -container.appendChild(dateFilter); + const nodeFilter = document.createElement("div"); + nodeFilter.setAttribute("class", "node-filter"); -const nodeFilter = document.createElement('div'); -nodeFilter.setAttribute('class', 'node-filter'); + const nodeInput = document.createElement("input"); + nodeInput.setAttribute("type", "text"); + nodeInput.setAttribute("placeholder", "Enter node (A, B, etc.)"); + nodeInput.setAttribute("id", "node-input"); + nodeInput.setAttribute("class", "input-field"); -const nodeInput = document.createElement('input'); -nodeInput.setAttribute('type', 'text'); -nodeInput.setAttribute('placeholder', 'Enter node (A, B, etc.)'); -nodeInput.setAttribute('id', 'node-input'); -nodeInput.setAttribute('class', 'input-field'); + nodeFilter.appendChild(nodeInput); + container.appendChild(nodeFilter); -nodeFilter.appendChild(nodeInput); -container.appendChild(nodeFilter); + container.appendChild(filterButton); -container.appendChild(filterButton); + document.body.appendChild(container); +} -document.body.appendChild(container); \ No newline at end of file +// Get request to fetch data from the server +function fetchData() { + fetch("http://145.92.8.114/getNodeInfo") + .then((response) => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then((data) => { + data.push(...data); + createFilterContainer(); + }) + .catch((error) => { + console.error("Error fetching data:", error); + }); +} + +fetchData(); \ No newline at end of file From 66793a12fc117dd9e5d791c5508a46738184abca Mon Sep 17 00:00:00 2001 From: Bram Barbieri Date: Sat, 30 Mar 2024 22:50:24 +0100 Subject: [PATCH 21/62] kleine pdates questiondata pulling. --- server/Flask/main.py | 6 +++--- server/Flask/queries.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/Flask/main.py b/server/Flask/main.py index 7232c81..6e7c9f4 100644 --- a/server/Flask/main.py +++ b/server/Flask/main.py @@ -69,12 +69,12 @@ def getNodeInfo(macAdress): return result -def getQuestionData(): +def getQuestionData(questionID, replies): mydb = loginDB() - query = get_query(False, False, False, True, False) + query = get_query(False, False, False, questionID, replies) cursor = mydb.cursor(dictionary=True) # Enable dictionary output cursor.execute(query) - result = cursor.fetchall() # Fetch the results + result = cursor.fetchall() # Fetch the results cursor.close() mydb.close() diff --git a/server/Flask/queries.py b/server/Flask/queries.py index d2b4144..143b691 100644 --- a/server/Flask/queries.py +++ b/server/Flask/queries.py @@ -8,7 +8,7 @@ def get_query(node, dataType, MAC, questionID, replies): elif MAC: query = f"SELECT * FROM Node WHERE MAC = '{MAC}'" elif replies and questionID: - query = f"SELECT * FROM Reply WHERE QuestionID = '{questionID}'" + query = f"SELECT * FROM Reply WHERE replies = '{replies}' AND QuestionID = '{questionID}'" elif questionID: query = f"SELECT * FROM Question" elif replies: From 034dd2b660ddd36b2f8905837f6d269f7538ba99 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Sat, 30 Mar 2024 22:57:40 +0100 Subject: [PATCH 22/62] Add Questions Dashboard page --- web/newWebsite/graphs.html | 2 + web/newWebsite/index.html | 2 + web/newWebsite/questions-dashboard.html | 34 +++++++++++++++ web/newWebsite/questions-main.js | 0 web/newWebsite/settings.html | 2 + .../styles/questions-dashboard-styles.css | 42 +++++++++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 web/newWebsite/questions-dashboard.html create mode 100644 web/newWebsite/questions-main.js create mode 100644 web/newWebsite/styles/questions-dashboard-styles.css diff --git a/web/newWebsite/graphs.html b/web/newWebsite/graphs.html index 0629172..e6c7ab4 100644 --- a/web/newWebsite/graphs.html +++ b/web/newWebsite/graphs.html @@ -23,6 +23,8 @@ + + +