Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59

This commit is contained in:
Dano van den Bosch
2024-02-15 16:29:40 +01:00
21 changed files with 455 additions and 16 deletions

View File

@@ -1,3 +1,6 @@
// Dano Bosch
// 14/2/2024
#include <SPI.h> #include <SPI.h>
#include <Wire.h> #include <Wire.h>
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>

View File

@@ -1,5 +1,5 @@
// Sietse Jonker // Sietse Jonker & Dano Bosch
// 09/02/2024 // 13/02/2024
#include <Wire.h> #include <Wire.h>
#include <Adafruit_SH110X.h> #include <Adafruit_SH110X.h>
@@ -21,15 +21,16 @@ DHT dht(DHTPIN, DHTTYPE);
Adafruit_SGP30 sgp; Adafruit_SGP30 sgp;
uint16_t TVOC_base, eCO2_base; uint16_t TVOC_base, eCO2_base;
int counter = 0; uint16_t counter = 0;
float temperature = 0; float temperature = 0;
float humidity = 0; float humidity = 0;
int eCO2 = 0; uint16_t eCO2 = 0;
int TVOC = 0; uint16_t TVOC = 0;
bool noise = false; bool noise = false;
void resetValues() { void resetValues() {
TVOC_base, eCO2_base; TVOC_base;
eCO2_base;
counter = 0; counter = 0;
temperature = 0; temperature = 0;
humidity = 0; humidity = 0;

View File

@@ -1,9 +1,9 @@
## The First Designs ## The First Designs(led By Bram)
The first designs are made using a pencil and paper, because we want a clear view of the direction we want to go in. The Design of the nodes that are being put around school, wil have a compact and simple look. The first designs are made using a pencil and paper, because we want a clear view of the direction we want to go in. The design of the nodes that are being put around school, wil have a compact and simple look.
![The First Node Sketch](../assets/ImagesSp1/sp1NodeSketch.jpg) ![The First Node Sketch(Bram)](../assets/ImagesSp1/sp1NodeSketch.jpg)
On the top of this, page the front of the node is visable. On the top of this, page the front of the node is visable.
This front shows a screen , a bar with led's ( wich is used to show how much sound is picked up on the node.), and a hexagon grid where the sensors are located behind. This front shows a screen , a bar with led's ( wich is used to show how much sound is picked up on the node.), and a hexagon grid where the sensors are located behind.
This way we can have enough airflow and more senso pickups. This way we can have enough airflow and more sensor pickups.
On top of the node there are two lights. These indicate if the air is too warm for comfort, so the cleaners are aware of the the current studying climate. On top of the node there are two lights. These indicate if the air is too warm for comfort, so the cleaners are aware of the the current studying climate.
@@ -13,7 +13,7 @@ The nodes will be powerd by batteries and wil be mounted on walls around eye hei
Next up is the central node that has a questionaire built into it. Next up is the central node that has a questionaire built into it.
![The First Questionaire Node Sketch](../assets/ImagesSp1/Sp1questionBoxNode.jpg) ![The First Questionaire Node Sketch(Bram)](../assets/ImagesSp1/Sp1questionBoxNode.jpg)
On the top Of the page The front of the node is drawn. The node has two screens to show both the statistics and the questionaire. On the node, three Buttons are show wich the user can press in order to take the questionaire. On the top Of the page The front of the node is drawn. The node has two screens to show both the statistics and the questionaire. On the node, three Buttons are show wich the user can press in order to take the questionaire.
@@ -22,4 +22,20 @@ This node still has all the sensors like all of the others, except this one has
The locations for the nodes are still unsure but what is certain is that the questionaire node will be placed besides the water fountain and cofemachines. The locations for the nodes are still unsure but what is certain is that the questionaire node will be placed besides the water fountain and cofemachines.
This location is frequently visited and is a wel known spot. This location is frequently visited and is a wel known spot.
The people going for a cup of coffee often have to wait for it to be finished, so we can take advantage of that time by giving them a short questionaire that they can comforably fil in while their cofee is being made. The people going for a cup of coffee often have to wait for it to be finished, so we can take advantage of that time by giving them a short questionaire that they can comforably fil in while their cofee is being made.
### Feedback
As for feedback, we got a lot of positives, but also a few critic points.
`the LED's could be seen as distracting.
That is why we decided to remove them intirely. THis wat the lights can't be distracting and the focus can remain on the statistics.
`The whole ventilation look is a bit too crowded and messy.
That is why we will shrink down the size of the hexagons and make them less obvious.
We also redesignd the shell shape. it now curves inward in order to lock the statistics screen in place.
Here is an updated version ready to be printed.
![3D design by Sietse](../assets/ImagesSp1/Sp13DDesignUpdated.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,36 @@
# Feedback
### Studieomgeving(Led by Sam)
* "Betere zitplekken"
* "Mensen minder praten"
* "Geluidsgehalte lager in studieomgeving"
* "Zachtere lachten"
* "Minder domme mensen"
### What are we going to do to improve the study area?
We are going to build multiple sensor nodes and hang them around study areas to measure the sound level. These nodes are going to send the data to a server, which is going to process the data and send it to the main node that is located at the coffee machine. This node is going to show the data so the student can quickly find a quiet spot to work.
### Feedback about physical node design(Led By Sam)
* "Cool"
* "Goed"
* "Prima"
* "Is wel Nice"
* "Vet idee"
* "Duidelijker maken wat lampjes rechts doen"
* "Beetje te druk"
* "Display in midden"
* "Ventilatie niet in het midden focus niet op scherm"
* "Lampjes mischien afleidend"
### Conclusion(led by Bram and Sam)
We got a lot of positive feedback like "Cool" and "Vet idee". But we also got some feedback about the design of the node.
We Wil use this Feedback and see what we can do to change the design in a way that is more accepted by our target audience.
The design will be updated to include:
`smaller holes for less distraction.
`ventilation at the bottom for better airflow.
`Remove the lamps on top of the node for less distraction.

View File

@@ -1,5 +1,11 @@
# Questions # Questions
How clean are the toilets (clean, normal, disgusting) ## Criteria
How clean is the study area (clean, normal, disgusting) Questions shouldnt be able to measure using sensors. 3 possible answers.
What do you think of the temparature in the study area (hot, perfect, cold)
## Questions
How clean are the toilets? (clean, normal, disgusting).
How clean is the study area? (clean, normal, disgusting).
What do you think of the temperature in the study area? (hot, perfect, cold).
How crowded would you say the study area is?(not at all, its fine, really crowded).
Is there enough help available? (no, decently, yes).

View File

@@ -0,0 +1,64 @@
# Node Design
## Design Process (led by sietse)
### Thoughts
Before making the design i was thinking about the following things:
- The node should be compact and simple
- The node should have a screen
- The node should have a bar with led's to show how much sound is picked up on the node
- The node should have a hexagon grid where the sensors are located behind
- The node should have two lights on top
- The nodes should be powered by batteries
I also thought about the following things on how to make the design. I have decided to make the design using fusion360, because i have some experience with it and i think it is a good tool to make the design. I wanted it to be really easy to assemble so i split the design in two parts. The top and the bottom. The top part will be the part with the screen and the sensors, and the bottom part will be the part with the whole circuitboard.
### Bottom design
I made the final design of sprint 1 using fusion360. I used the original drawing from Bram and modified it using the feedback we've got from the usertest. I begun making the bottom side of the node, because this could serve me as a template to make the rest. The bottom side was pretty easy to make because i only had to sketch and measure a few things. It eventually looked like this:
![The Bottom Side of the Node](../assets/ImagesSp1/Sp1NodeBottomSide.png)
### Top design
When i went to work on the upper side it took some more time than the bottom one. since i had to make cutouts for the screen and led bar and the hexagon grid. The hexagon grid was the hardest because i used the geometric pattern fucntion on my hexagon object and i had to make sure that there would still be room between the hexagons. I made it so the screens have like a indent on the top part. Otherwise the battery, sensors and esp32 wouldnt be able to fit underneath the grid. The final product looks like this:
![The Upper Side of the Node](../assets/ImagesSp1/Sp1NodeUpperSide.png)
### Assembly
#### First assembly
The part was finished on 15/2 at 11am. I first screwed the pcb in the bottom part which was really easy to do. When trying to put the top part on the bottom part i noticed that the holes were not aligned, and the batteryholder was fatter than i thought. I tried to cut some material away from the top part but it was still not fitting.
It looked like this from the top:
![The Assembly of the Node Topview](../assets/ImagesSp1/assemblyOfNodeTopview.jpg)
You can see that the oled screen cutouts and the led bar cutouts are not aligned with the components on the pcb.
---
And like this from the side view:
![The Assembly of the Node Sideview](../assets/ImagesSp1/assemblyOfNodeSideview.jpg)
Here you can see that the wifi antenna of the esp32 is not fitting in the top part, because the fillet is too small.
#### Second assembly
In fusion360 i made the cutouts for the screen and the led bar lower on the part. I also made the fillet on the top part a bit bigger, and adjusted the fillet on top too. We also decided we'd take this oppurtunitty to make vent holes in the bottom aswell. This is because hot air rises and with this there would be a little bit of air coming through the node for more accurate readings. I then printed the new design and it took around 7 hours. The new design looks like this:
![The New Upper Side of the Node](../assets/ImagesSp1/Sp1NodeUpperSideNew.png)
The new design fits perfectly and looks like this:
...
### Conclusion
```mermaid
graph LR
A[Design Sketch] -->|Usertest| B(Fusion360 design)
B -->|Not fitting| C[New fusion360 design]
C -->|assembly| D[Finished product]
```

View File

@@ -0,0 +1,46 @@
### Reverse proxy
#### Introduction
A reverse proxy is for example used to host 2 services on the same port. This is useful for us because we can use the same port for the websockets and the webserver.
#### How to use a reverse proxy
We are going to use `Apache2` as our reverse proxy. This is because it is easy to use and has a lot of documentation. It also hosts our webserver so it is easy to configure and we don't have to install another program.
#### Additional modules
We need to enable the `proxy` and `proxy_wstunnel` modules. These are used to proxy the websockets.
You can install them with these commands on a Raspberry Pi. For other linux distributions its may be different.
```bash
$ sudo a2enmod proxy
$ sudo a2enmod proxy_wstunnel
```
#### Script
The enabled apache2 config scripts are found in `/etc/apache2/conf-enabled/`. You can create a new file with the name of your service. For example `studyarea.conf`.
```apache
<VirtualHost *:80>
DocumentRoot /home/pi/www/html/
# Enable proxying WebSockets
ProxyPass /ws ws://localhost:8001/
# Enable proxying HTTP
ProxyPass /ws http://localhost:8080/
</VirtualHost>
```
Because VirtualHost is listening on port 80, we can use the same port for the webserver and the websockets. The `ProxyPass` is used to proxy the websocket. The `/ws` is the path where the websockets are hosted. Its hosted on `localhost/ws` so it kinda creates a new subdomain for the websocket. The `localhost:8001` is the address of the websockets and the `localhost:8080` is the address of the webserver.
`DocumentRoot` is the path where the files are for the website.
### Sources:
* https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html
* https://www.serverlab.ca/tutorials/linux/web-servers-linux/how-to-reverse-proxy-websockets-with-apache-2-4/
* https://gist.github.com/mortenege/91ec6fe02dca6f736303a00f8cea2731
* https://www.jscape.com/blog/forward-proxy-vs-reverse-proxy#:~:text=While%20a%20forward%20proxy%20proxies,is%20providing%20file%20transfer%20services.
* https://webmasters.stackexchange.com/questions/143106/functional-difference-between-proxypass-and-proxypassreverse-in-apache

View File

@@ -7,8 +7,14 @@ With websockets you can establish a connection between the client and the server
### How to use websockets ### How to use websockets
There are different languages to serve websockets with, but we are going to use Python with the library `websockets`. This library is easy to use and has a lot of documentation. There are different languages to serve websockets with, but we are going to use Python with the library `websockets`. This library is easy to use and has a lot of documentation.
## Issues
### Ports
We can only use certain ports like 113, 80, 443. These are common ports and are not blocked by firewalls. Something in the network is blocking all other ports which makes it hard to use websockets.
#### Sources: #### Sources:
* https://websockets.readthedocs.io/en/stable/index.html * https://websockets.readthedocs.io/en/stable/index.html
**Written by Sam**

70
web/index.html Normal file
View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://cdn.plot.ly/plotly-latest.min.js" charset="utf-8"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Climate-Measuring-Box</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<!-- Make a new header with a navigation bar -->
<header>
<nav class="navbar">
<ul>
<li><a href="climate-monitor.html">Monitoring</a></li>
<li><a href="Map.html">Map</a></li>
<li><a onclick="serialConnect()" class="navRight">Connect to port</a></li>
<li><a onclick="disconnect()" class="navRight">Disconnect from port</a></li>
</li>
</ul>
</nav>
</header>
<!-- Make a new flex container for the live data -->
<div class="flex-LiveData">
<div>
<div>Temperatuur: <p id="temperature">Not connected</p>
</div>
<div class="statusElement">
<p class="statusText" id="tempStatus">Not connected</p>
</div>
</div>
<div>
<div>Luchtvochtigheid: <p id="humidity">Not connected</p>
</div>
<div class="statusElement">
<p class="statusText" id="humidStatus">Not connected</p>
</div>
</div>
<div>
<div>Lichtintensiteit: <p id="lightIntensity">Not connected</p>
</div>
<div class="statusElement">
<p class="statusText" id="lightIntensityStatus">Not connected</p>
</div>
</div>
</div>
<!-- Make a new flexcontainer for the graphs and API request time -->
<div class="flex-graph">
<div>
<p>Live graph:</p>
<div id="liveGraph"></div>
</div>
<div>
<div>Time until POST request to API:<p id="cnt">Connect to port</p></div>
</div>
<div>
<p>API data:</p>
<div id="apiGraph"></div>
</div>
</div>
<!-- Include the js file -->
<script src="main.js"></script>
</body>
<html>

63
web/main.js Normal file
View File

@@ -0,0 +1,63 @@
// Make lines in the graph of the live data
Plotly.plot("liveGraph", [
{
x: timeArray, // Use timeArray as x values
y: newArrayTemp,
mode: "lines",
line: { color: "#80CAF6" },
name: "Temperature",
},
{
x: timeArray, // Use timeArray as x values
y: newArrayHumid,
mode: "lines",
line: { color: "#FFA500" },
name: "Humidity",
},
{
x: timeArray, // Use timeArray as x values
y: newArrayLight,
mode: "lines",
line: { color: "#00FF00" },
name: "Light / 100",
},
]);
let cnt = 0;
// Update the graph every 1 ms
let interval = setInterval(function () {
var time = new Date();
var update = {
x: [[time]],
y: [[newArrayTemp], [newArrayHumid], [newArrayLight]],
};
var olderTime = time.setMinutes(time.getMinutes() - 1);
var futureTime = time.setMinutes(time.getMinutes() + 1);
var minuteView = {
xaxis: {
type: "date",
range: [olderTime, futureTime],
},
};
Plotly.relayout("liveGraph", minuteView);
apiGraph = document.getElementById("apiGraph");
Plotly.newPlot(
apiGraph,
[
{
x: dateArray,
y: valueArray,
},
],
{
margin: { t: 0 },
}
);
if (cnt === 100) clearInterval(interval);
}, 1);

128
web/styles.css Normal file
View File

@@ -0,0 +1,128 @@
body {
background-color: white;
align-content: center;
text-align: center;
font-family: "inter", sans-serif;
margin: 0;
}
h1 {
opacity: 0.8;
color: black;
margin: auto;
width: 50%;
}
h2 {
text-align: center;
color: black;
opacity: 0.8;
}
p1 {
color: solid white;
}
.liveGraph{
width: 90%;
height: 100%;
}
.divCnt{
text-align: begin;
}
.apiGraph{
height: 100%;
width: 90%;
}
.statusElement{
display:inline-block;
border: solid #1f82d3 2px;
border-radius: 10px;
width: 90%;
}
.statusText{
font-size: 20px;
}
.flex-LiveData {
display: flex;
align-content: begin;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-evenly;
gap: 5px;
padding: 10px;
}
.flex-LiveData > div {
border: solid #1f82d3 2px;
padding: 15px 0;
font-size: 30px;
border-radius: 10px;
height: fit-content;
width: 30%;
}
.flex-graph {
display: flex;
align-content: begin;
flex-wrap: wrap;
justify-content: space-evenly;
gap: 5px;
padding: 10px;
}
.flex-graph > div {
position: relative;
border: solid #1f82d3 2px;
padding: 15px 0;
font-size: 30px;
border-radius: 10px;
flex-basis: 95%;
}
@media screen and (max-width: 850px) {
.flex-LiveData>div {
width: 100%;
}
}
ul {
margin: 0;
padding: 20px 0;
}
.navbar {
text-align: center;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
a{
padding: 10px;
color: black;
text-decoration: none;
font-weight: bold;
}
li{
display: inline-block;
padding: 10px;
margin: 0 5px;
border-radius: 5px;
transition: 0.3s;
}
.navbar a:hover {
background-color: #196bad;
}
img {
max-width: 100%;
height: auto;
}