From 36277a7e5debc0dc24e49950e044a663bb2483f8 Mon Sep 17 00:00:00 2001 From: Sietse Jonker Date: Wed, 6 Mar 2024 20:56:19 +0100 Subject: [PATCH 01/22] Update file index.html --- web/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/web/index.html b/web/index.html index 36d76b3..29a1abc 100644 --- a/web/index.html +++ b/web/index.html @@ -29,6 +29,5 @@ - \ No newline at end of file From bd66f210825fdeca3b59f99dc5ccff7bff260211 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Wed, 6 Mar 2024 21:16:30 +0100 Subject: [PATCH 02/22] Update interval delay and refactor liveGraph creation --- web/main.js | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/web/main.js b/web/main.js index db1c2e3..3aeb144 100644 --- a/web/main.js +++ b/web/main.js @@ -1,13 +1,13 @@ const sensorData = {}; -let intervalDelay = 1000; +let intervalDelay = 5000; // Create WebSocket connection. const socket = new WebSocket("ws://145.92.8.114/ws"); +let liveGraphs = []; function openConnection() { // Open connection socket.addEventListener("open", (event) => { console.log("Connected to the WebSocket server"); - socket.send("Hello Server!"); }); // Error handling @@ -35,14 +35,11 @@ function openConnection() { // Attempt to reconnect setTimeout(openConnection, 1000); // Retry after 1 second }); - console.log("Connected to the WebSocket server!!!!!!!!"); + console.log("Connected to the WebSocket server"); } -// Open the connection openConnection(); - - function handleIncomingData(data) { nodeNumber = data.node; temperature = data.Temp; @@ -80,16 +77,7 @@ function processNodeData(nodeNumber, temperature, humidity, CO2, TVOC) { } } - - -function pushArray(array) { - for (let i = 0; i < 10; i++) { - array.push(Math.random() * 10); - } -} - //function for making the html elements for the following html code - function nodeData(data, node) { let nodeData = document.createElement("div"); nodeData.innerHTML = data; @@ -198,9 +186,9 @@ function updateNodeData(node, temperature, humidity, eCO2, TVOC) { document.getElementById("CO2Status").textContent = "Connected"; document.getElementById("TVOCStatus").textContent = "Connected"; - // Update the graph` - graphNode1.updateData(temperature, humidity, eCO2, TVOC); - graphNode1.updateGraph(); + // Update the graph + liveGraphs[node - 1].updateData(); + liveGraphs[node - 1].updateGraph(); } // Call the function to create the HTML structure @@ -210,11 +198,11 @@ createNodeData(3); createNodeData(4); // Create a new liveGraph object -let graphNode1 = new liveGraph(1); +liveGraphs.push(new liveGraph(1)); -graphNode1.makeGraph(); +// make the graphs +liveGraphs.forEach((graph) => { + graph.makeGraph(); +} +); -let graphNode2 = new liveGraph(2); - -graphNode2.makeGraph(); -// openConnection(); From 656cd83aeec1b18baa98584d668594454fe97290 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Wed, 6 Mar 2024 21:27:19 +0100 Subject: [PATCH 03/22] Refactor CSS styles and remove unnecessary code --- web/styles.css | 53 +++++++++++++------------------------------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/web/styles.css b/web/styles.css index 42e9256..2f8370a 100644 --- a/web/styles.css +++ b/web/styles.css @@ -33,11 +33,6 @@ p1 { text-align: begin; } -.apiGraph{ - height: 100%; - width: 90%; -} - .statusElement{ display:inline-block; border: solid #1f82d3 2px; @@ -50,35 +45,6 @@ p1 { font-size: 20px; } -/* body{ - display: flex; - flex-direction: row; - justify-content: space-evenly; - align-content: center; -} */ - -#randomShit{ - display: flex; - flex-direction: row; - justify-content: space-evenly; - align-content: center; - border: 2px solid purple; - -} - -#nodeDataLocation{ - display: flex; - flex-direction: column; - align-items: center; - /* justify-content: center; */ - /* align-content: center; */ - border: 4px solid blue; - /* padding-bottom: 50%; */ - -} - - - .flex-NodeData { display: flex; margin-left: 1%; @@ -87,21 +53,32 @@ p1 { /* height: 40%; */ flex-direction: column; border: 3px solid #1f82d3; - /* border-radius: 20px; */ + border-radius: 20px; + /* width: 90%; */ /* border: 2px solid red; */ /* margin-right: 90%; */ - /* width: 150vh; */ /* padding-right: 40%; */ /* padding-left: 40%; */ } +#nodeDataLocation{ + display: flex; + flex-direction: column; + align-items: center; + align-content: center; + border: 4px solid rgb(0, 0, 255); + /* padding-bottom: 50%; */ + +} + + + .nodeData { display: flex; justify-content: left; flex-direction: row; margin-bottom: 2%; margin-top: 1%; - /* border: 2px solid red; */ } @@ -113,8 +90,6 @@ justify-content: left; justify-content: space-evenly; gap: 5px; padding: 10px; - - } From 6070ba7480f040a3527746f30c745315597df806 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 11:22:25 +0100 Subject: [PATCH 04/22] edits css --- web/styles.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/styles.css b/web/styles.css index 2f8370a..06cb22f 100644 --- a/web/styles.css +++ b/web/styles.css @@ -63,7 +63,8 @@ p1 { #nodeDataLocation{ display: flex; - flex-direction: column; + flex-direction: row; + flex-wrap: wrap; align-items: center; align-content: center; border: 4px solid rgb(0, 0, 255); From 2e394f3d4510f691aa9c3efc92da2da5fd36ce20 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 12:57:54 +0100 Subject: [PATCH 05/22] Update liveGraphs to include temperature, humidity, eCO2, and TVOC data --- web/main.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/main.js b/web/main.js index 3aeb144..7c39a74 100644 --- a/web/main.js +++ b/web/main.js @@ -187,7 +187,7 @@ function updateNodeData(node, temperature, humidity, eCO2, TVOC) { document.getElementById("TVOCStatus").textContent = "Connected"; // Update the graph - liveGraphs[node - 1].updateData(); + liveGraphs[node - 1].updateData(temperature, humidity, eCO2, TVOC); liveGraphs[node - 1].updateGraph(); } @@ -203,6 +203,5 @@ liveGraphs.push(new liveGraph(1)); // make the graphs liveGraphs.forEach((graph) => { graph.makeGraph(); -} -); +}); From bc8cc500cb5caa2dcf2e8720ccee3fd3b420402b Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 13:00:22 +0100 Subject: [PATCH 06/22] Refactor code to dynamically create node data and live graphs --- web/main.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/web/main.js b/web/main.js index 7c39a74..dad1607 100644 --- a/web/main.js +++ b/web/main.js @@ -192,13 +192,10 @@ function updateNodeData(node, temperature, humidity, eCO2, TVOC) { } // Call the function to create the HTML structure -createNodeData(1); -createNodeData(2); -createNodeData(3); -createNodeData(4); - -// Create a new liveGraph object -liveGraphs.push(new liveGraph(1)); +for (let i = 1; i <= 4; i++) { + createNodeData(i); + liveGraphs.push(new liveGraph(i)); +} // make the graphs liveGraphs.forEach((graph) => { From 0b8ae0ef349c7e56e5fe50d397fbf938873e19a7 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 13:03:28 +0100 Subject: [PATCH 07/22] Refactor main.js: Add descriptions, declare variables, and update loop condition --- web/main.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/web/main.js b/web/main.js index dad1607..ff372a0 100644 --- a/web/main.js +++ b/web/main.js @@ -1,9 +1,13 @@ +// Description: Main JavaScript file for the web application. +// arrays and stuff const sensorData = {}; -let intervalDelay = 5000; -// Create WebSocket connection. -const socket = new WebSocket("ws://145.92.8.114/ws"); let liveGraphs = []; +// variables +let intervalDelay = 5000; +let amountOfNodes = 4; + +const socket = new WebSocket("ws://145.92.8.114/ws"); function openConnection() { // Open connection socket.addEventListener("open", (event) => { @@ -192,7 +196,7 @@ function updateNodeData(node, temperature, humidity, eCO2, TVOC) { } // Call the function to create the HTML structure -for (let i = 1; i <= 4; i++) { +for (let i = 1; i <= amountOfNodes; i++) { createNodeData(i); liveGraphs.push(new liveGraph(i)); } From 1472c17125aa2210b0303f8a1efcf1ea94e7fc6a Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 13:09:28 +0100 Subject: [PATCH 08/22] Fix variable name and update amount of nodes --- web/main.js | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/web/main.js b/web/main.js index ff372a0..0cd4aad 100644 --- a/web/main.js +++ b/web/main.js @@ -3,9 +3,9 @@ const sensorData = {}; let liveGraphs = []; -// variables +// letiables let intervalDelay = 5000; -let amountOfNodes = 4; +let amountOfNodes = 3; const socket = new WebSocket("ws://145.92.8.114/ws"); function openConnection() { @@ -92,46 +92,46 @@ function nodeData(data, node) { function createNodeData(node) { // Create main div - var nodeData = document.createElement("div"); + let nodeData = document.createElement("div"); nodeData.className = "nodeData"; // Create flex-NodeData div - var flexNodeData = document.createElement("div"); + let flexNodeData = document.createElement("div"); flexNodeData.className = "flex-NodeData"; // Create p element - var pNode = document.createElement("p"); + let pNode = document.createElement("p"); pNode.textContent = "Node " + node; // Append p to flex-NodeData flexNodeData.appendChild(pNode); // Create flex-LiveData div - var flexLiveData = document.createElement("div"); + let flexLiveData = document.createElement("div"); flexLiveData.className = "flex-LiveData"; // Create data divs (Temperature, Humidity, Light Intensity) - var dataTypes = ["Temperatuur", "Luchtvochtigheid", "CO2", "TVOC"]; - var ids = ["temperature", "humidity", "CO2", "TVOC"]; - var statusIds = ["tempStatus", "humidStatus", "CO2Status", "TVOCStatus"]; + let dataTypes = ["Temperatuur", "Luchtvochtigheid", "CO2", "TVOC"]; + let ids = ["temperature", "humidity", "CO2", "TVOC"]; + let statusIds = ["tempStatus", "humidStatus", "CO2Status", "TVOCStatus"]; - for (var i = 0; i < dataTypes.length; i++) { - var dataDiv = document.createElement("div"); + for (let i = 0; i < dataTypes.length; i++) { + let dataDiv = document.createElement("div"); - var dataTypeDiv = document.createElement("div"); + let dataTypeDiv = document.createElement("div"); dataTypeDiv.textContent = dataTypes[i] + ": "; - var pElement = document.createElement("p"); + let pElement = document.createElement("p"); pElement.id = ids[i] + node; pElement.textContent = "Not connected"; dataTypeDiv.appendChild(pElement); dataDiv.appendChild(dataTypeDiv); - var statusElement = document.createElement("div"); + let statusElement = document.createElement("div"); statusElement.className = "statusElement"; - var statusText = document.createElement("p"); + let statusText = document.createElement("p"); statusText.className = "statusText"; statusText.id = statusIds[i]; statusText.textContent = "Not connected"; @@ -146,15 +146,15 @@ function createNodeData(node) { flexNodeData.appendChild(flexLiveData); // Create flex-graph div - var flexGraph = document.createElement("div"); + let flexGraph = document.createElement("div"); flexGraph.className = "flex-graph"; - var graphDiv = document.createElement("div"); + let graphDiv = document.createElement("div"); - var graphP = document.createElement("p"); + let graphP = document.createElement("p"); graphP.textContent = "Live graph:"; - var liveGraph = document.createElement("div"); + let liveGraph = document.createElement("div"); liveGraph.id = "liveGraph" + node; graphDiv.appendChild(graphP); @@ -168,7 +168,7 @@ function createNodeData(node) { nodeData.appendChild(flexNodeData); // Check if nodeDataLocation element exists - var nodeDataLocation = document.getElementById("nodeDataLocation"); + let nodeDataLocation = document.getElementById("nodeDataLocation"); if (nodeDataLocation) { // Append main div to nodeDataLocation nodeDataLocation.appendChild(nodeData); @@ -204,5 +204,4 @@ for (let i = 1; i <= amountOfNodes; i++) { // make the graphs liveGraphs.forEach((graph) => { graph.makeGraph(); -}); - +}); \ No newline at end of file From 878fb9f49174b29810561c56af6ad59414b9e9ee Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Thu, 7 Mar 2024 13:11:01 +0100 Subject: [PATCH 09/22] Refactor JSON parsing and data handling functions --- docs/brainstorm/SoftwareDocumentatie/Dev_page.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/brainstorm/SoftwareDocumentatie/Dev_page.md b/docs/brainstorm/SoftwareDocumentatie/Dev_page.md index 138990e..6d75aca 100644 --- a/docs/brainstorm/SoftwareDocumentatie/Dev_page.md +++ b/docs/brainstorm/SoftwareDocumentatie/Dev_page.md @@ -2,15 +2,17 @@ ### parsing JSON +The data that is send by the nodes is send in json data. We chose this becouse we can easily use the data within javascript, this is called parsing. We use the parced data and send that in to the next function to make the data more acceseble to use in further instences. + ```js const jsonData = JSON.parse(event.data); // Use the parsed JSON data as needed handleIncomingData(jsonData); ``` -### Pro - +Here is the function that receves the parced JSON data and set it into variables. +```js function handleIncomingData(data) { nodeNumber = data.node; temperature = data.Temp; @@ -20,7 +22,7 @@ function handleIncomingData(data) { processNodeData(nodeNumber, temperature, humidity, CO2, TVOC); } - +``` function processNodeData(nodeNumber, temperature, humidity, CO2, TVOC) { // Initialize the array for this node if it doesn't exist yet if (!sensorData[nodeNumber]) { From 598dd545217e967aabee310f2828b4769354f318 Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 13:18:12 +0100 Subject: [PATCH 10/22] Add new lines for temperature, humidity, eCO2, and TVOC in liveGraph class --- web/classes.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/classes.js b/web/classes.js index bea7d93..2067bfc 100644 --- a/web/classes.js +++ b/web/classes.js @@ -9,9 +9,9 @@ class liveGraph { this.cnt = 0; this.nodeId = "liveGraph" + id; } - // Fuction to create a graph makeGraph() { + // Create a new line for temperature Plotly.plot(this.nodeId, [ { x: this.timeArray, // Use timeArray as x values @@ -21,6 +21,7 @@ class liveGraph { name: "Temperature", }, ]); + // Create a new line for humidity Plotly.plot(this.nodeId, [ { x: this.timeArray, // Use timeArray as x values @@ -30,6 +31,7 @@ class liveGraph { name: "Humidity", }, ]); + // Create a new line for eCO2 Plotly.plot(this.nodeId, [ { x: this.timeArray, // Use timeArray as x values @@ -39,6 +41,7 @@ class liveGraph { name: "eCO2 / 10", }, ]); + // Create a new line for TVOC Plotly.plot(this.nodeId, [ { x: this.timeArray, // Use timeArray as x values @@ -50,7 +53,7 @@ class liveGraph { ]); } - // Function to update the graph with new values + // Function to update the graph with new values got from updateData function updateGraph() { let time = new Date(); this.timeArray.push(new Date()); @@ -71,7 +74,7 @@ class liveGraph { Plotly.relayout(this.nodeId, minuteView); 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); From 185a972f1ba68ce4a510b03374bda7958e1133b7 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Thu, 7 Mar 2024 14:01:20 +0100 Subject: [PATCH 11/22] dev page documentation --- .../SoftwareDocumentatie/Dev_page.md | 111 +++--------------- 1 file changed, 17 insertions(+), 94 deletions(-) diff --git a/docs/brainstorm/SoftwareDocumentatie/Dev_page.md b/docs/brainstorm/SoftwareDocumentatie/Dev_page.md index 6d75aca..d88ec4f 100644 --- a/docs/brainstorm/SoftwareDocumentatie/Dev_page.md +++ b/docs/brainstorm/SoftwareDocumentatie/Dev_page.md @@ -10,7 +10,7 @@ The data that is send by the nodes is send in json data. We chose this becouse w handleIncomingData(jsonData); ``` -Here is the function that receves the parced JSON data and set it into variables. +Here is the function that receves the parced JSON data and set it into variables. So that it can be more easlily used in the next function with is the processNodeData, witch is setting the data in to the right array. ```js function handleIncomingData(data) { @@ -23,12 +23,19 @@ function handleIncomingData(data) { processNodeData(nodeNumber, temperature, humidity, CO2, TVOC); } ``` -function processNodeData(nodeNumber, temperature, humidity, CO2, TVOC) { + +In the function processNodeData we first check if there is a array for the node that is sending the data, this is done becouse if we want to seperate the data in to show witch node is sending what data. So if the nodeNumber plus sensorData (the name of the array) not already there the array is made. + +```js // Initialize the array for this node if it doesn't exist yet if (!sensorData[nodeNumber]) { sensorData[nodeNumber] = []; } +``` +For the actual data put in to array function is there a simple array.push for the data that is send allong from when the function is called. + +```js // Push the new data onto the array for this node sensorData[nodeNumber].push({ 'node': nodeNumber, @@ -37,106 +44,22 @@ function processNodeData(nodeNumber, temperature, humidity, CO2, TVOC) { 'CO2': CO2, 'TVOC': TVOC, }); +``` - // updateNodeData(node, temperature, humidity, lightIntensity) - updateNodeData(nodeNumber, temperature, humidity, CO2, TVOC); - - // Log the array for this node - console.log(sensorData[nodeNumber]); +We want only use the last 10 readings from the nodes so there is a check for if the array is longer than 10 the first (or the oldest reading), if that is so there is a .shift executed. This is done to be later used in the graph function. Than there is a call for the next function, that is the updateNodeData and that will acctually find the right html id coresponding with the right reading to update that. +```js // If the array for this node has more than 10 elements, remove the oldest one if (sensorData[nodeNumber].length >= 10) { sensorData[nodeNumber].shift(); } -} -function createNodeData(node) { - // Create main div - var nodeData = document.createElement("div"); - nodeData.className = "nodeData"; + updateNodeData(nodeNumber, temperature, humidity, CO2, TVOC); +``` - // Create flex-NodeData div - var flexNodeData = document.createElement("div"); - flexNodeData.clsName = "flex-NodeData"; - - // Create p element - var pNode = document.createElement("p"); - pNode.textContent = "Node " + node; - - // Append p to flex-NodeData - flexNodeData.appendChild(pNode); - - // Create flex-LiveData div - var flexLiveData = document.createElement("div"); - flexLiveData.className = "flex-LiveData"; - - // Create data divs (Temperature, Humidity, Light Intensity) - var dataTypes = ["Temperatuur", "Luchtvochtigheid", "CO2", "TVOC"]; - var ids = ["temperature", "humidity", "CO2", "TVOC"]; - var statusIds = ["tempStatus", "humidStatus", "CO2Status", "TVOCStatus"]; - - for (var i = 0; i < dataTypes.length; i++) { - var dataDiv = document.createElement("div"); - - var dataTypeDiv = document.createElement("div"); - dataTypeDiv.textContent = dataTypes[i] + ": "; - - var pElement = document.createElement("p"); - pElement.id = ids[i] + node; - pElement.textContent = "Not connected"; - - dataTypeDiv.appendChild(pElement); - dataDiv.appendChild(dataTypeDiv); - - var statusElement = document.createElement("div"); - statusElement.className = "statusElement"; - - var statusText = document.createElement("p"); - statusText.className = "statusText"; - statusText.id = statusIds[i]; - statusText.textContent = "Not connected"; - - statusElement.appendChild(statusText); - dataDiv.appendChild(statusElement); - - flexLiveData.appendChild(dataDiv); - } - - // Append flex-LiveData to flex-NodeData - flexNodeData.appendChild(flexLiveData); - - // Create flex-graph div - var flexGraph = document.createElement("div"); - flexGraph.className = "flex-graph"; - - var graphDiv = document.createElement("div"); - - var graphP = document.createElement("p"); - graphP.textContent = "Live graph:"; - - var liveGraph = document.createElement("div"); - liveGraph.id = "liveGraph"; - - graphDiv.appendChild(graphP); - graphDiv.appendChild(liveGraph); - flexGraph.appendChild(graphDiv); - - // Append flex-graph to flex-NodeData - flexNodeData.appendChild(flexGraph); - - // Append flex-NodeData to main div - nodeData.appendChild(flexNodeData); - - // Check if nodeDataLocation element exists - var nodeDataLocation = document.getElementById("nodeDataLocation"); - if (nodeDataLocation) { - // Append main div to nodeDataLocation - nodeDataLocation.appendChild(nodeData); - } else { - console.error("Element with ID 'nodeDataLocation' does not exist."); - } -} +In the last function there are 2 updates the first is to actually update the text to the right value that we are getting from the node, and the connection checker. +```js function updateNodeData(node, temperature, humidity, eCO2, TVOC) { // Update the temperature, humidity and light intensity values document.getElementById("temperature" + node).textContent = temperature; @@ -150,4 +73,4 @@ function updateNodeData(node, temperature, humidity, eCO2, TVOC) { document.getElementById("CO2Status").textContent = "Connected"; document.getElementById("TVOCStatus").textContent = "Connected"; } - +``` \ No newline at end of file From 866af9253ee0de162ac691a655d402d8d5adaafd Mon Sep 17 00:00:00 2001 From: sietse jonker Date: Thu, 7 Mar 2024 14:20:21 +0100 Subject: [PATCH 12/22] Add graph documentation --- .../SoftwareDocumentatie/graph_classes.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/brainstorm/SoftwareDocumentatie/graph_classes.md diff --git a/docs/brainstorm/SoftwareDocumentatie/graph_classes.md b/docs/brainstorm/SoftwareDocumentatie/graph_classes.md new file mode 100644 index 0000000..5df185e --- /dev/null +++ b/docs/brainstorm/SoftwareDocumentatie/graph_classes.md @@ -0,0 +1,56 @@ +# Graphs + +## Introduction + +The graphs are used to display the data from the sensors. The data is collected by the raspberry pi and then displayed on the graphs. The graphs are made using the [plotly library](https://plotly.com/javascript/) . + +## Requirements + +### Live graphs +- Every node has to have a live graph +- The graphs has to be updated every 5 seconds +- All the data from one node has to fit in one graph + + +## Class diagrams + +### Live graphs + +```mermaid +classDiagram + class liveGraph { + +nodeId + +cnt + +timeArray + +tempArray + +humiArray + +eco2Array + +tvocArray + makeGraph() + updateGraph() + updateData() + } +``` + +## Order of operations + +### Live graphs + +```mermaid +sequenceDiagram + participant Node + participant Raspberry pi + participant Website + + Node->>Raspberry pi: sensordata via websocket every 5 seconds + Raspberry pi->>Website: Node data via websocket if new data is received from the node + Website->>Website: updateGraph() + Website->>Website: updateData() +``` + +1. Every node sends its data to the raspberry pi via websocket every 5 seconds +2. The raspberry pi sends the data to the website via websocket if new data is received from the node +3. The website updates the data coming from the raspberry pi on its own variables and arrays +4. The website updates the live graphs every time new data is received from the websocket + + From 54f52bce48698cf9afceee6ebe459ebd6378b745 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Thu, 7 Mar 2024 14:22:30 +0100 Subject: [PATCH 13/22] path updated for page --- docs/.pages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/.pages b/docs/.pages index 3ae2722..a58ded2 100644 --- a/docs/.pages +++ b/docs/.pages @@ -24,5 +24,5 @@ nav: - Taskflow: brainstorm/Taskflow - Design: Sp1SchetsProject/FirstDesign - 🖨️ Software: - - Dev page: brainstrom/SotwareDocumentatie/Dev_page + - Dev page: brainstorm/SotwareDocumentatie/Dev_page \ No newline at end of file From aa6c35044ef07adcbb229d27f164094ab2268017 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Mar 2024 19:54:31 +0100 Subject: [PATCH 14/22] Added a function to attempt to diplay the words in full --- .../Screen-code-full/displayText.cpp | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/arduino/Screen code/Screen-code-full/displayText.cpp b/arduino/Screen code/Screen-code-full/displayText.cpp index 99d6db6..9044558 100644 --- a/arduino/Screen code/Screen-code-full/displayText.cpp +++ b/arduino/Screen code/Screen-code-full/displayText.cpp @@ -4,6 +4,7 @@ //constructor DisplayText::DisplayText(Adafruit_ST7796S_kbv& tftDisplay) : tft(tftDisplay) { tft.setCursor(0,0); + tft.fillScreen(ST7796S_BLACK); } void DisplayText::writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom) { @@ -15,12 +16,12 @@ void DisplayText::writeText(char* text, int size, int posX, int posY, int screen } tft.setCursor(posX, posY); tft.setTextSize(size); - tft.println(text); + printWordsFull(text); delay(screenTime); } int DisplayText::centerText(char* text) { - int16_t x1, y1; + int16_t x1, y1; uint16_t w, h; tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h); int x = (tft.width() - w) / 2; @@ -33,4 +34,39 @@ int DisplayText::bottomText(char* text) { tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h); int y = (tft.height() - h); return y; +} + +void DisplayText::printWordsFull(char* text) { + + char* textArray[100]; + int i = 0; + + char* textCopy = strdup(text); + + char* word = strtok(text, " "); + while (word != NULL) { + textArray[i] = word; + word = strtok(NULL, " "); + i++; + } + + int lineWidth = 0; + int maxLineWidth = 320; // replace with the width of your TFT display + int charWidth = 11; // replace with the width of your characters + + for (int j = 0; j < i; j++) { + int wordLength = strlen(textArray[j]); + + // If the word won't fit on the current line, move to the next line + if (lineWidth + wordLength * charWidth > maxLineWidth) { + tft.println(); + lineWidth = 0; + } + + tft.print(textArray[j]); + tft.print(" "); + lineWidth += (wordLength + 1) * charWidth; // +1 for the space + } + free(textCopy); + } \ No newline at end of file From 2351c515f3982348577d36e1f962e68fa4aca1fd Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Mar 2024 19:54:41 +0100 Subject: [PATCH 15/22] Added function to header --- arduino/Screen code/Screen-code-full/displayText.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arduino/Screen code/Screen-code-full/displayText.h b/arduino/Screen code/Screen-code-full/displayText.h index b7637d5..7103044 100644 --- a/arduino/Screen code/Screen-code-full/displayText.h +++ b/arduino/Screen code/Screen-code-full/displayText.h @@ -9,6 +9,7 @@ class DisplayText { Adafruit_ST7796S_kbv& tft; int centerText(char* text); int bottomText(char* text); + void printWordsFull(char* text); public: DisplayText(Adafruit_ST7796S_kbv& tftDisplay); From 3b375266ee14fcd21b8065ae44e1d9e037b6dcc5 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Mar 2024 19:54:48 +0100 Subject: [PATCH 16/22] Moved libraries over --- arduino/Screen code/Screen-code-full/headerFile.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arduino/Screen code/Screen-code-full/headerFile.h b/arduino/Screen code/Screen-code-full/headerFile.h index f74f963..e4c5fcb 100644 --- a/arduino/Screen code/Screen-code-full/headerFile.h +++ b/arduino/Screen code/Screen-code-full/headerFile.h @@ -1,3 +1,10 @@ +#include +#include "Adafruit_GFX.h" +#include "Adafruit_ST7796S_kbv.h" +#include "displayText.h" + + + #define TFT_CS 14 #define TFT_DC 13 #define TFT_RST 12 From 56abd5cbdeaa68a51ac627cd36f5c73b5e165078 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Mar 2024 19:55:02 +0100 Subject: [PATCH 17/22] removed libraryies and made delay longer --- arduino/Screen code/Screen-code-full/Screen-code-full.ino | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arduino/Screen code/Screen-code-full/Screen-code-full.ino b/arduino/Screen code/Screen-code-full/Screen-code-full.ino index 6987434..bce5d52 100644 --- a/arduino/Screen code/Screen-code-full/Screen-code-full.ino +++ b/arduino/Screen code/Screen-code-full/Screen-code-full.ino @@ -1,8 +1,5 @@ -#include -#include "Adafruit_GFX.h" -#include "Adafruit_ST7796S_kbv.h" #include "headerFile.h" -#include "displayText.h" + int i = 0; char* Question[] = { @@ -29,7 +26,6 @@ DisplayText displayText(tft); void setup() { tft.begin(); // Initialize the display tft.setRotation(3); // Set the rotation to horizontal - tft.fillScreen(ST7796S_BLACK); } void loop() { @@ -43,7 +39,7 @@ void loop() { // writeText(Answer[0], 2, 50, 300, 4000); displayText.writeText(Question[i], 3, 0, 0, 0, true, false); displayText.writeText(Answer[i], 3, 0, 200, 0, true, true); - delay(10000); + delay(20000); } From 5df0bfa0dc7c0334fa2553d5e36f94bdf3cf55e3 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Fri, 8 Mar 2024 11:46:46 +0100 Subject: [PATCH 18/22] brodcast added --- server/Websocket.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/server/Websocket.py b/server/Websocket.py index 407038c..1d77e3f 100644 --- a/server/Websocket.py +++ b/server/Websocket.py @@ -1,21 +1,34 @@ -import websockets; -import asyncio; +import websockets +import asyncio +connected = set() async def handler(websocket): - while True: - #Save the incoming message in variable message. - message = await websocket.recv() - print(message) + # Register. + connected.add(websocket) + try: + while True: + message = await websocket.recv() + print(message) + await broadcast(message) + except websockets.ConnectionClosedOK: + print("Client disconnected") + finally: + connected.remove(websocket) +async def broadcast(message): + if connected: # asyncio.wait doesn't accept an empty list + await asyncio.wait([ws.send(message) for ws in connected]) + +async def sendClientId(): + if connected: # asyncio.wait doesn't accept an empty list + await asyncio.wait([ws.send(message) for ws in connected]) async def main(): - async with websockets.serve(handler, "145.92.8.114" , 8001): + async with websockets.serve(handler, "0.0.0.0", 8001): await asyncio.Future() # run forever - if __name__ == "__main__": - asyncio.run(main()) - + asyncio.run(main()) #https://websockets.readthedocs.io/en/stable/reference/sync/server.html#websockets.sync.server.serve \ No newline at end of file From 3a8998c00a42f0df1a4b4eca75b2f898136db49b Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Fri, 8 Mar 2024 12:52:39 +0100 Subject: [PATCH 19/22] Fix typo in software documentation path --- docs/.pages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/.pages b/docs/.pages index a58ded2..ad124e6 100644 --- a/docs/.pages +++ b/docs/.pages @@ -24,5 +24,5 @@ nav: - Taskflow: brainstorm/Taskflow - Design: Sp1SchetsProject/FirstDesign - 🖨️ Software: - - Dev page: brainstorm/SotwareDocumentatie/Dev_page + - Dev page: brainstorm/SoftwareDocumentatie/Dev_page \ No newline at end of file From 77636f2a608f00a9eb4a290856feeb6fcc360bfd Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 8 Mar 2024 14:24:53 +0100 Subject: [PATCH 20/22] Documentation --- docs/.pages | 1 + docs/arduino-documentation/classes.md | 73 +++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 docs/arduino-documentation/classes.md diff --git a/docs/.pages b/docs/.pages index ad124e6..9803d55 100644 --- a/docs/.pages +++ b/docs/.pages @@ -9,6 +9,7 @@ nav: - 🎮 Arduino documentation: - I2C: arduino-documentation/i2c-ESP32 - TFT screen : node-documentation/TFT-screen + - Classes : arduino-documentation/classes - 🍓 RPi Documentation: - Raspberry pi: Sp1SchetsProject/InfrastructuurDocumentatie/raspberryPi - MariaDB: rpi-documentation/mariadb-installation diff --git a/docs/arduino-documentation/classes.md b/docs/arduino-documentation/classes.md new file mode 100644 index 0000000..72e691a --- /dev/null +++ b/docs/arduino-documentation/classes.md @@ -0,0 +1,73 @@ +# Arduino classes + + +## How do I make a class? + +First you need to start out with a header file. This file will contain the class definition. And which functions of the class are public and which are private. + +```cpp +#ifndef DISPLAYTEXT_H +#define DISPLAYTEXT_H + +#include "Adafruit_GFX.h" +#include "Adafruit_ST7796S_kbv.h" + +class DisplayText { + private: + Adafruit_ST7796S_kbv& tft; + int centerText(char* text); + int bottomText(char* text); + void printWordsFull(char* text); + + public: + DisplayText(Adafruit_ST7796S_kbv& tftDisplay); + void writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom); +}; + +#endif +``` +```#ifndef``` DISPLAYTEXT_H is a preprocessor directive that checks if DISPLAYTEXT_H is defined. If it is not defined, the code between #ifndef and #endif will be included in the compilation. If it is defined, the code will be excluded from the compilation. This is to prevent the same code from being included multiple times in the same file. + + +To start out with a class you need a constructor. This is a function that is called when the class is created. This function is used to initialize the class. +```cpp +DisplayText::DisplayText(Adafruit_ST7796S_kbv& tftDisplay) : tft(tftDisplay) { + tft.fillScreen(0x0000); +} +``` +The library gets passed to tftdisplay. And the tft gets initialized with the tftdisplay. + + + +## How do I create a function in a class? +```cpp +void DisplayText::centerText() { + //insert code here +} +``` +This is a example of a function in a class. The function is called centerText and it is a private function. This means that it can only be called from within the class. + + +When creating a class you also need to reference it in the header file like this + +```cpp +#include "DisplayText.h" + +class DisplayText { + private: + int centerText(); + //other functions + + public: + //other functions + +}; + +``` + + +# Sources +* https://www.circuitbasics.com/programming-with-classes-and-objects-on-the-arduino/ + + + From 60d86bc0d52eed8a32edc5bc9ffbb57023cd36eb Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 8 Mar 2024 14:25:24 +0100 Subject: [PATCH 21/22] Added comments and cleanup --- .../Screen-code-full/Screen-code-full.ino | 22 ------------------- .../Screen-code-full/displayText.cpp | 19 +++++++++------- .../Screen code/Screen-code-full/headerFile.h | 2 -- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/arduino/Screen code/Screen-code-full/Screen-code-full.ino b/arduino/Screen code/Screen-code-full/Screen-code-full.ino index bce5d52..60c88df 100644 --- a/arduino/Screen code/Screen-code-full/Screen-code-full.ino +++ b/arduino/Screen code/Screen-code-full/Screen-code-full.ino @@ -41,25 +41,3 @@ void loop() { displayText.writeText(Answer[i], 3, 0, 200, 0, true, true); delay(20000); } - - -// void writeText(char* text, int size, int posX, int posY, int screenTime, bool center){ -// //if true overwrites x -// if (center){ -// posX = centerText(text); -// } -// tft.setCursor(posX, posY); // Set the cursor to the top left corner -// tft.setTextSize(size); // Set textsize -// tft.println(text); -// delay(screenTime); -// } - -// int centerText(char* text) { -// int16_t x1, y1; -// uint16_t w, h; - -// tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h); // Calculate the width of the text -// int x = (tft.width() - w) / 2; // Calculate the x-coordinate for the centered text - -// return x; -// } \ No newline at end of file diff --git a/arduino/Screen code/Screen-code-full/displayText.cpp b/arduino/Screen code/Screen-code-full/displayText.cpp index 9044558..1971152 100644 --- a/arduino/Screen code/Screen-code-full/displayText.cpp +++ b/arduino/Screen code/Screen-code-full/displayText.cpp @@ -6,7 +6,7 @@ DisplayText::DisplayText(Adafruit_ST7796S_kbv& tftDisplay) : tft(tftDisplay) { tft.setCursor(0,0); tft.fillScreen(ST7796S_BLACK); } - +//display text public function void DisplayText::writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom) { if (center) { posX = centerText(text); @@ -19,7 +19,7 @@ void DisplayText::writeText(char* text, int size, int posX, int posY, int screen printWordsFull(text); delay(screenTime); } - +//to center the text when enabled in the public function int DisplayText::centerText(char* text) { int16_t x1, y1; uint16_t w, h; @@ -27,7 +27,7 @@ int DisplayText::centerText(char* text) { int x = (tft.width() - w) / 2; return x; } - +//to dijsplay the text at the bottom when enabled in the public function int DisplayText::bottomText(char* text) { int16_t x1, y1; uint16_t w, h; @@ -36,13 +36,14 @@ int DisplayText::bottomText(char* text) { return y; } +//attempt to write the text out in full (wip) void DisplayText::printWordsFull(char* text) { char* textArray[100]; int i = 0; - + //copy the text into a variable so the string can be re-used later char* textCopy = strdup(text); - + //split the text into words and put them into a array char* word = strtok(text, " "); while (word != NULL) { textArray[i] = word; @@ -53,20 +54,22 @@ void DisplayText::printWordsFull(char* text) { int lineWidth = 0; int maxLineWidth = 320; // replace with the width of your TFT display int charWidth = 11; // replace with the width of your characters - for (int j = 0; j < i; j++) { + //count the amount of letters in the word int wordLength = strlen(textArray[j]); - // If the word won't fit on the current line, move to the next line + // If the word won't fit on the current line, move to the next line if (lineWidth + wordLength * charWidth > maxLineWidth) { tft.println(); + //reset lineWidth lineWidth = 0; } - + //print the text tft.print(textArray[j]); tft.print(" "); lineWidth += (wordLength + 1) * charWidth; // +1 for the space } + //removes textCopy out of the memory free(textCopy); } \ No newline at end of file diff --git a/arduino/Screen code/Screen-code-full/headerFile.h b/arduino/Screen code/Screen-code-full/headerFile.h index e4c5fcb..83372dd 100644 --- a/arduino/Screen code/Screen-code-full/headerFile.h +++ b/arduino/Screen code/Screen-code-full/headerFile.h @@ -3,8 +3,6 @@ #include "Adafruit_ST7796S_kbv.h" #include "displayText.h" - - #define TFT_CS 14 #define TFT_DC 13 #define TFT_RST 12 From 649ea5e1a66d07fe8567c08c39996d0e827a7235 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 8 Mar 2024 14:25:33 +0100 Subject: [PATCH 22/22] Edited database --- server/DatabasewithMAC.sql | 120 +++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 server/DatabasewithMAC.sql diff --git a/server/DatabasewithMAC.sql b/server/DatabasewithMAC.sql new file mode 100644 index 0000000..32c3c8a --- /dev/null +++ b/server/DatabasewithMAC.sql @@ -0,0 +1,120 @@ +-- MySQL Script generated by MySQL Workbench +-- Fri Mar 8 12:25:17 2024 +-- Model: New Model Version: 1.0 +-- MySQL Workbench Forward Engineering + +SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; +SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; +SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; + +-- ----------------------------------------------------- +-- Schema NodeData +-- ----------------------------------------------------- + +-- ----------------------------------------------------- +-- Schema NodeData +-- ----------------------------------------------------- +CREATE SCHEMA IF NOT EXISTS `NodeData` DEFAULT CHARACTER SET utf8 ; +USE `NodeData` ; + +-- ----------------------------------------------------- +-- Table `NodeData`.`Question` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `NodeData`.`Question` ( + `QuestionID` INT NOT NULL, + `Question` VARCHAR(45) NULL, + PRIMARY KEY (`QuestionID`)) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `NodeData`.`Node` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `NodeData`.`Node` ( + `NodeID` INT NOT NULL, + `Name` VARCHAR(45) NULL, + `Location` VARCHAR(45) NULL, + `MAC` VARCHAR(45) NULL, + PRIMARY KEY (`NodeID`)) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `NodeData`.`Measurement` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `NodeData`.`Measurement` ( + `NodeID` INT NOT NULL, + `Type` VARCHAR(45) NULL, + `Value` FLOAT NULL, + `TimeStamp` DATETIME NULL DEFAULT CURRENT_TIMESTAMP, + `Node_NodeID` INT NOT NULL, + PRIMARY KEY (`NodeID`, `Node_NodeID`), + INDEX `fk_Measurement_Node1_idx` (`Node_NodeID` ASC) VISIBLE, + CONSTRAINT `fk_Measurement_Node1` + FOREIGN KEY (`Node_NodeID`) + REFERENCES `NodeData`.`Node` (`NodeID`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `NodeData`.`Enquete` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `NodeData`.`Enquete` ( + `EnqueteID` INT NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`EnqueteID`)) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `NodeData`.`enqueteQuestion` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `NodeData`.`enqueteQuestion` ( + `Enquete_EnqueteID` INT NOT NULL, + `Question_QuestionID` INT NOT NULL, + PRIMARY KEY (`Enquete_EnqueteID`, `Question_QuestionID`), + INDEX `fk_Enquete_has_Question_Question1_idx` (`Question_QuestionID` ASC) VISIBLE, + INDEX `fk_Enquete_has_Question_Enquete1_idx` (`Enquete_EnqueteID` ASC) VISIBLE, + CONSTRAINT `fk_Enquete_has_Question_Enquete1` + FOREIGN KEY (`Enquete_EnqueteID`) + REFERENCES `NodeData`.`Enquete` (`EnqueteID`) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + CONSTRAINT `fk_Enquete_has_Question_Question1` + FOREIGN KEY (`Question_QuestionID`) + REFERENCES `NodeData`.`Question` (`QuestionID`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +-- ----------------------------------------------------- +-- Table `NodeData`.`Reply` +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `NodeData`.`Reply` ( + `Node_NodeID` INT NOT NULL, + `enqueteQuestion_Enquete_EnqueteID` INT NOT NULL, + `enqueteQuestion_Question_QuestionID` INT NOT NULL, + `Result` INT NULL, + `Time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, + `AnswerID` INT NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`AnswerID`, `Node_NodeID`, `enqueteQuestion_Enquete_EnqueteID`, `enqueteQuestion_Question_QuestionID`), + INDEX `fk_Node_has_enqueteQuestion_enqueteQuestion1_idx` (`enqueteQuestion_Enquete_EnqueteID` ASC, `enqueteQuestion_Question_QuestionID` ASC) VISIBLE, + INDEX `fk_Node_has_enqueteQuestion_Node1_idx` (`Node_NodeID` ASC) VISIBLE, + CONSTRAINT `fk_Node_has_enqueteQuestion_Node1` + FOREIGN KEY (`Node_NodeID`) + REFERENCES `NodeData`.`Node` (`NodeID`) + ON DELETE NO ACTION + ON UPDATE NO ACTION, + CONSTRAINT `fk_Node_has_enqueteQuestion_enqueteQuestion1` + FOREIGN KEY (`enqueteQuestion_Enquete_EnqueteID` , `enqueteQuestion_Question_QuestionID`) + REFERENCES `NodeData`.`enqueteQuestion` (`Enquete_EnqueteID` , `Question_QuestionID`) + ON DELETE NO ACTION + ON UPDATE NO ACTION) +ENGINE = InnoDB; + + +SET SQL_MODE=@OLD_SQL_MODE; +SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; +SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;