Compare commits
545 Commits
Websockets
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
d40a93e747 | ||
|
79865e0852 | ||
|
958889306e | ||
|
fdebe8ddde | ||
|
2f230ebfb3 | ||
|
048d6ff8ea | ||
|
a0a5501726 | ||
|
2494536b79 | ||
|
3c62ee4bd2 | ||
|
910b555bc1 | ||
|
9844e2d4d4 | ||
|
1461053c36 | ||
|
233038f0a7 | ||
|
44b16c168d | ||
|
1d538bd3df | ||
|
2ae320d230 | ||
|
43242f2080 | ||
|
beb123c2b9 | ||
|
9ee589da29 | ||
|
9d6b950db5 | ||
|
e14b653534 | ||
|
605f425d9d | ||
|
5531485385 | ||
|
0db2e8ab52 | ||
|
72ebd92c99 | ||
|
eac2d891e8 | ||
|
b8c16a13c7 | ||
|
d19a71906a | ||
|
1410ff7989 | ||
|
060b2edc92 | ||
|
d4b44e33b3 | ||
|
fa7baccffd | ||
|
6feb27d769 | ||
|
e0d1a91645 | ||
|
3cd2d62e83 | ||
863b491021 | |||
f7253574d0 | |||
7efc4dddef | |||
|
a006932ff3 | ||
|
44857fdd65 | ||
|
74cebc0cef | ||
|
39657b24a3 | ||
|
e43be1c6b1 | ||
|
3a825744e7 | ||
|
c8ab03c0cd | ||
0af4bce035 | |||
654f797d9d | |||
3c87feec76 | |||
|
74b8fa5f1e | ||
|
2c39cc90ad | ||
|
a4600b25e6 | ||
|
a92b6b58d6 | ||
|
c7059086c2 | ||
|
8c9ccda61a | ||
|
6f5f9d4b47 | ||
|
f4bd73a77a | ||
|
c44c9c82b3 | ||
|
db29d0d4cf | ||
|
50dff89761 | ||
|
045fbb50d9 | ||
|
24ec686fa0 | ||
|
a2e77e6f3d | ||
|
e67764ee42 | ||
|
b85eb7faf7 | ||
|
50906649c2 | ||
|
355a2b4f75 | ||
|
5d8bec404b | ||
|
556f06026e | ||
|
5f426df0ed | ||
|
e949949f42 | ||
|
86193d3593 | ||
46f9ca1292 | |||
70c95e676e | |||
|
222abb3ec3 | ||
|
24aaf29bce | ||
|
c74a4e6400 | ||
|
b69b029628 | ||
|
c61cdaad1f | ||
|
badea73c4d | ||
|
adab457fd9 | ||
|
8085060490 | ||
|
b6c2bdb4a4 | ||
|
5316e2d647 | ||
|
8724691716 | ||
|
cf16a2cdc1 | ||
|
5761e0a028 | ||
|
4edbe2312a | ||
|
8bb1a1c69f | ||
|
62206a6ce3 | ||
ecac4e7966 | |||
276ec2ed12 | |||
|
94ee31f6ac | ||
|
93492db324 | ||
|
8503300aa0 | ||
|
b9455a56a8 | ||
|
c66bd305bb | ||
|
f044891ed8 | ||
|
6fb54d0b07 | ||
|
30d8543ff4 | ||
|
b5f0b7cc5a | ||
|
cac0977035 | ||
|
a1ceb2d2c1 | ||
4173a02200 | |||
7b8f98cb3c | |||
|
61d67fc1e2 | ||
|
267bb7db9c | ||
|
5aa494773e | ||
|
a53ecb1c96 | ||
|
44b1f6b33d | ||
|
c789aec373 | ||
|
4ab7709c82 | ||
|
650032fced | ||
|
6dd926d782 | ||
|
b0b1ed84c7 | ||
|
52c615eba3 | ||
|
fdd4b647ec | ||
|
f79abd05c2 | ||
|
96d10b32fd | ||
|
b2d7f7c434 | ||
|
c539bb2edf | ||
|
ab8249702e | ||
|
38722052f3 | ||
|
59377aa2b5 | ||
|
8ff9a4e9e4 | ||
|
9954d66af6 | ||
2808e2e55f | |||
47a228123e | |||
|
6f56b9d628 | ||
|
887e84c16c | ||
|
9ba6a237f3 | ||
|
5de768c3ab | ||
|
81b81683c9 | ||
|
ec756cd387 | ||
|
a4a73b84cc | ||
|
0d86c6bcbd | ||
|
69ef7013bb | ||
|
5e2daa445a | ||
|
76532c538b | ||
|
ae082b53a4 | ||
|
f803ab021c | ||
|
912ffc052b | ||
|
e94f12e13c | ||
|
28cc13484f | ||
|
f2050a54a4 | ||
|
3435bdaaab | ||
|
cf0a6c6565 | ||
|
64ba63e9ad | ||
|
074406aec5 | ||
|
eea0828b37 | ||
|
a381fa1ee1 | ||
|
034dd2b660 | ||
|
66793a12fc | ||
|
8416254d6c | ||
|
97c21f9d31 | ||
|
0a25bbf84f | ||
|
415a0c456e | ||
|
726d411321 | ||
|
642c4a24ad | ||
|
79c3c956fe | ||
02b32c33ea | |||
3e7a89bf8b | |||
92b27ab9b7 | |||
9ac39ff74f | |||
463b161855 | |||
0666b21bc5 | |||
09e3d7020e | |||
|
49dc40a2c2 | ||
26b35036ec | |||
|
0db496fb72 | ||
|
39dd5c62d8 | ||
|
5bf5a193b9 | ||
|
30a739d02b | ||
7a35c54322 | |||
7f48f0f3b3 | |||
c4fa9fbfa5 | |||
|
363eaeb922 | ||
|
b79c3ce37d | ||
|
1743b998eb | ||
|
207416013a | ||
8f5c547336 | |||
70a7b4651c | |||
|
002818f1b9 | ||
0b079798cd | |||
|
f4824731dc | ||
|
b467c1823e | ||
|
f02d2d61ce | ||
345acda615 | |||
71826ee76f | |||
9b130d009c | |||
a6da7a1654 | |||
85154d1beb | |||
ce996e622e | |||
|
61073577e3 | ||
14511c34fd | |||
|
dac363339a | ||
|
f08be2a4aa | ||
|
e2e00636bc | ||
|
c6a6ba72f0 | ||
|
c7912022b5 | ||
|
4ef167c590 | ||
d21bae4b19 | |||
899d2bb868 | |||
64f9ab24e0 | |||
1c13d20b49 | |||
c6f3c7c018 | |||
e7597d8d1f | |||
f788580ef4 | |||
e5348f0ffa | |||
ba96a81d3f | |||
778c47fa68 | |||
627af72f0f | |||
883460cdaa | |||
9ddcfe88f5 | |||
3ecb87a9e4 | |||
f3cd6bd011 | |||
cbf6cf1484 | |||
d54c020144 | |||
e920298df8 | |||
f5ebaa676e | |||
9463063917 | |||
28f5153cee | |||
|
461e3bdfeb | ||
|
77302d64a5 | ||
900a713468 | |||
a36b6746fd | |||
|
d09df80886 | ||
|
5c07478997 | ||
|
912344153e | ||
|
96a9e6ef63 | ||
|
68c68fa7a6 | ||
7f79b46c01 | |||
502ae3c614 | |||
|
570b8b7a67 | ||
|
5dee5d99ab | ||
|
cf86970605 | ||
|
b38730e9a1 | ||
|
b914be9534 | ||
|
6d548f7738 | ||
|
1ac6f01331 | ||
|
98e47d39fc | ||
|
5f31176a7e | ||
|
6fd674f4c9 | ||
|
9fc5c5b53b | ||
|
e5b44cd85a | ||
|
675cc23665 | ||
|
6735a498ca | ||
|
5ce77d54ef | ||
|
c0afae2688 | ||
|
75ff84ee70 | ||
|
a35bd6b88d | ||
|
fb9088e2b1 | ||
|
8aca330aad | ||
|
379a8b0f84 | ||
|
906b5e4304 | ||
|
d9a603886c | ||
|
17f6ba8376 | ||
|
970b7eaa41 | ||
|
44a2d1e5c6 | ||
|
f2a7f32d43 | ||
|
146e0c2eea | ||
|
f75eff03a4 | ||
|
891df42972 | ||
|
56d45b9fe9 | ||
|
91f24a6f42 | ||
|
93bf3aed37 | ||
|
c4c36de0f7 | ||
|
2ef003ef39 | ||
|
c19d77ce15 | ||
|
9f295d7bb3 | ||
|
466066d4c7 | ||
|
4eeb80cdb2 | ||
|
9598a64f0e | ||
|
f800f7fc33 | ||
|
62124ec402 | ||
|
8d2e2a6931 | ||
|
4290d5572b | ||
|
53b50b6851 | ||
|
940304c3b2 | ||
|
eb53fd5fcd | ||
|
12909d3650 | ||
|
5dc020a6ce | ||
|
36d46b8c4a | ||
|
3d091cec98 | ||
|
6c0baf626d | ||
|
1182e89c56 | ||
|
2221be88bf | ||
|
e5511d1925 | ||
|
e5d2f23d59 | ||
|
ca5d92bd86 | ||
|
8ae69a6fbe | ||
|
dcc99c1258 | ||
|
07cc13d573 | ||
|
7104331e4c | ||
|
11f9f53f6b | ||
|
4708c9c71e | ||
|
cb1dbe8b11 | ||
|
1982db8c50 | ||
|
61c8d09760 | ||
|
f2907117be | ||
|
0ecc2457e7 | ||
|
fde715d7ed | ||
|
e2ffcc4fa1 | ||
|
adce47db3a | ||
|
3d85220adc | ||
54a2eef7c5 | |||
09522218f3 | |||
|
f94c452a19 | ||
4cf78ddb0b | |||
6ce7ac8c97 | |||
|
cd56c45c47 | ||
|
ec336f914a | ||
|
5bf19a82ff | ||
|
38d34cce91 | ||
|
c0034acf65 | ||
|
d52eabbb61 | ||
|
11099a1af9 | ||
|
cf18d4ab4f | ||
|
a4b8ae0dca | ||
5b327942be | |||
89956bc4c8 | |||
15504eaea6 | |||
|
a8f6491736 | ||
|
a82acc526c | ||
|
5fa07f3a82 | ||
|
ac7d97c890 | ||
|
b28ae0e4a1 | ||
|
7d8f820100 | ||
|
19034fe7e1 | ||
|
54fc6f2306 | ||
|
a707c4f9bb | ||
|
b8fbf0dfaf | ||
|
b4dcdf7609 | ||
1c7fd2ab68 | |||
6ea17a63c7 | |||
|
a2ff97d7fb | ||
|
6c60a184b8 | ||
|
065cb42ef7 | ||
|
b3d80c1194 | ||
|
4fd8c3d958 | ||
|
94f118742e | ||
|
b13824afe5 | ||
|
28ff778ce8 | ||
|
d20e6db9fe | ||
ef8821fe48 | |||
|
072ff99624 | ||
035a7f4c72 | |||
23bfbdada5 | |||
47f1f393da | |||
|
10eee12189 | ||
|
c4880ce0e2 | ||
|
3801b074f6 | ||
|
25de52c54b | ||
7b6f8463cd | |||
b8f8f5ea7e | |||
6efac7b179 | |||
023a1b0781 | |||
|
6c3b523208 | ||
|
7f5db74732 | ||
|
ddb7df5679 | ||
|
d7a762f30c | ||
|
85a49151ac | ||
|
0ab0b433ab | ||
|
8b0be0d6bd | ||
|
5d2223e5d7 | ||
|
dd6b5caa33 | ||
8da5b9f215 | |||
4fd0badd3c | |||
15f897f4d9 | |||
d542da7db9 | |||
|
8aeca410fc | ||
|
57ee918b64 | ||
|
57a556ab6c | ||
1bafce0015 | |||
|
fd260d9c56 | ||
|
f8489bca01 | ||
|
cc92eff4f8 | ||
|
4d0bd8aa43 | ||
dec48091f4 | |||
|
3fe74603ca | ||
|
c90fda2977 | ||
|
b27f9f8ed6 | ||
|
d21776cfc4 | ||
|
3bdc81b320 | ||
|
856775c2a8 | ||
|
649ea5e1a6 | ||
|
60d86bc0d5 | ||
|
77636f2a60 | ||
|
9acd2b44a8 | ||
|
3886292110 | ||
|
3a8998c00a | ||
|
5df0bfa0dc | ||
|
08c9bedb44 | ||
|
28bfd3a300 | ||
|
56abd5cbde | ||
|
3b375266ee | ||
|
2351c515f3 | ||
|
aa6c35044e | ||
|
67aaaca588 | ||
|
54f52bce48 | ||
|
083858f9cf | ||
|
866af9253e | ||
|
185a972f1b | ||
|
fb304af3a4 | ||
|
c7ee23afd7 | ||
|
598dd54521 | ||
|
9566148fa6 | ||
|
878fb9f491 | ||
|
1472c17125 | ||
|
d1c962f71c | ||
|
f2964ebce8 | ||
|
0b8ae0ef34 | ||
|
bc8cc500cb | ||
|
2e394f3d45 | ||
|
6070ba7480 | ||
|
656cd83aee | ||
|
bd66f21082 | ||
|
36277a7e5d | ||
|
2c0b7df0a1 | ||
|
55f94387cc | ||
|
24164841a9 | ||
|
c14c18deb0 | ||
|
f4840775ed | ||
|
63be84e287 | ||
|
199283d3e0 | ||
|
27742cfa89 | ||
|
5a8e13c0d6 | ||
|
284071b4ee | ||
|
8ed556d856 | ||
|
951fc64e6d | ||
|
65783ac3b6 | ||
|
9b01523f0e | ||
|
b971fe0b54 | ||
|
a2219fa03a | ||
|
67d77d59d1 | ||
|
db9c984446 | ||
|
026bd92d65 | ||
|
698b3055a4 | ||
|
2b31f80655 | ||
|
d3952306b2 | ||
|
de1ae975a4 | ||
|
f99d7b5c3d | ||
|
21ef8604c2 | ||
|
e09651a90c | ||
|
0886352a1c | ||
|
307257eefc | ||
|
fba7ada367 | ||
|
1596f0c641 | ||
|
3ebe661de0 | ||
|
fed0adb299 | ||
|
7476f98590 | ||
|
db9380816c | ||
|
d127a6001d | ||
|
bcbb8080c2 | ||
|
072752cec8 | ||
|
9193a753ce | ||
|
902031cfd5 | ||
|
d24744823b | ||
|
5b26d6b844 | ||
|
ce24a782ed | ||
|
5d9d377010 | ||
|
a70575d8b8 | ||
|
4db11e3035 | ||
|
20a5446c8c | ||
|
5c59dc033c | ||
|
ff296eefb0 | ||
|
2389c068bf | ||
|
f533e1a9c1 | ||
|
7b48a4a04e | ||
|
d1714fabec | ||
|
eee106a402 | ||
|
5f88a8f495 | ||
|
0d1da4503e | ||
|
14b07da103 | ||
|
9238d9841e | ||
|
734dca30bc | ||
|
503ef68e67 | ||
|
1d76c5ff7a | ||
|
3afc7797ab | ||
|
ddb21adc52 | ||
|
b0731f739b | ||
|
982a275aa0 | ||
|
3e82990c97 | ||
|
1b594b503a | ||
|
dcb2f37694 | ||
|
5558289ba2 | ||
|
dc3566f5e5 | ||
|
63ad49675b | ||
|
984e5e748d | ||
|
17588c38b3 | ||
|
3f60a08695 | ||
|
53af1d5858 | ||
|
766d03282b | ||
|
540d80a545 | ||
|
a084960f0f | ||
|
9adbde7e5c | ||
|
79ec11a7a2 | ||
|
cf6aaa2f33 | ||
|
71981d193a | ||
|
9255b8ab97 | ||
|
44b1317e33 | ||
|
16105122dd | ||
|
a0f8378cc9 | ||
|
270cff0435 | ||
|
955dab9dd4 | ||
|
515792b03f | ||
|
6ddb09112e | ||
|
aa31eeaaef | ||
|
26f075ee78 | ||
|
22e30063c4 | ||
|
35117663b1 | ||
|
613a01924d | ||
|
ea8cbe7c88 | ||
|
e6b3e07a71 | ||
|
154b10b66c | ||
|
885d2978a2 | ||
|
b622902221 | ||
|
ccfa8c75d0 | ||
|
faa49c7a21 | ||
|
02c92a9a70 | ||
|
c0af3e3cd4 | ||
|
d3f810ecf7 | ||
|
ce88a119c6 | ||
|
23a2f623a6 | ||
|
1ba6b305bb | ||
|
8ee0774602 | ||
|
41b678bf9c | ||
|
55fbb73a89 | ||
|
816f25757f | ||
|
85fc96cb63 | ||
|
ceb52b70fa | ||
|
fc0b96ec0a | ||
|
5791b373e9 | ||
|
bfeb8169eb | ||
|
e8ab30fbb1 | ||
|
0d00f4a874 | ||
|
b276ef1199 | ||
|
183f49f8c6 | ||
|
762dbee696 | ||
|
39250f33d8 | ||
|
ef90e4000a | ||
|
8a664f39ae | ||
|
26d88ce281 | ||
|
d253fd8394 | ||
|
23a3bc2cb2 | ||
|
ccd94c260e |
40
arduino/Button code/simple-buttons.ino
Normal file
@@ -0,0 +1,40 @@
|
||||
//connect the 3v3 directly to the button and the other end of the button to a pin.
|
||||
//this script adds a digital resistor so you dont have to add one yourself
|
||||
|
||||
const int buttonPin = 21; // the number of the pushbutton pin
|
||||
const int buttonPin1 = 1; // the number of the pushbutton pin
|
||||
const int buttonPin2 = 37; // the number of the pushbutton pin
|
||||
|
||||
|
||||
// variables will change:
|
||||
int buttonState = 0; // variable for reading the pushbutton status
|
||||
int buttonState1 = 0; // variable for reading the pushbutton status
|
||||
int buttonState2 = 0; // variable for reading the pushbutton status
|
||||
|
||||
void setup() {
|
||||
// initialize the pushbutton pin as an input:
|
||||
pinMode(buttonPin, INPUT_PULLDOWN);
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// read the state of the pushbutton value:
|
||||
buttonState = digitalRead(buttonPin);
|
||||
buttonState1 = digitalRead(buttonPin1);
|
||||
buttonState2 = digitalRead(buttonPin2);
|
||||
|
||||
|
||||
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
|
||||
if (buttonState == HIGH) {
|
||||
Serial.println("ik ben high");
|
||||
}
|
||||
else if (buttonState1 == HIGH){
|
||||
Serial.println("ik ben higher");
|
||||
}
|
||||
else if (buttonState2 == HIGH){
|
||||
Serial.println("ik ben highest");
|
||||
}
|
||||
else {
|
||||
// turn LED off:
|
||||
}
|
||||
}
|
41
arduino/Mic/Mic.ino
Normal file
@@ -0,0 +1,41 @@
|
||||
const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz)
|
||||
int const AMP_PIN = 7; // Preamp output pin connected to A0
|
||||
unsigned int sample;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long startMillis = millis(); // Start of sample window
|
||||
unsigned int peakToPeak = 0; // peak-to-peak level
|
||||
|
||||
unsigned int signalMax = 0;
|
||||
unsigned int signalMin = 1024;
|
||||
|
||||
// collect data for 50 mS and then plot data
|
||||
while (millis() - startMillis < sampleWindow)
|
||||
{
|
||||
sample = analogRead(AMP_PIN);
|
||||
if (sample < 1024) // toss out spurious readings
|
||||
{
|
||||
if (sample > signalMax)
|
||||
{
|
||||
signalMax = sample; // save just the max levels
|
||||
}
|
||||
else if (sample < signalMin)
|
||||
{
|
||||
signalMin = sample; // save just the min levels
|
||||
}
|
||||
}
|
||||
}
|
||||
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude
|
||||
if (peakToPeak == 4294966272){
|
||||
peakToPeak = 0;
|
||||
}
|
||||
Serial.println(peakToPeak);
|
||||
//double volts = (peakToPeak * 5.0) / 1024; // convert to volts
|
||||
//Serial.println(volts);
|
||||
}
|
7
arduino/Screen code/Screen-code-final/.theia/launch.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
]
|
||||
}
|
115
arduino/Screen code/Screen-code-final/Screen-code-final.ino
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "headerFile.h"
|
||||
|
||||
int i = 0;
|
||||
int questionID = 1;
|
||||
char* Question[] = {
|
||||
"How clean are the toilets?",
|
||||
"How clean is the study area?",
|
||||
"What do you think of the temperature in the study area?",
|
||||
"How crowded would you say the study area is?",
|
||||
"Is there enough help available?"
|
||||
};
|
||||
|
||||
char* Answer[] = {
|
||||
"clean, normal, disgusting",
|
||||
"clean, normal, disgusting",
|
||||
"hot, perfect, cold",
|
||||
"not at all, its fine, really crowded",
|
||||
"no, decently, yes"
|
||||
};
|
||||
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
DisplayText displayText(tft);
|
||||
|
||||
void setup() {
|
||||
//buttonpins
|
||||
pinMode(16, INPUT_PULLDOWN);
|
||||
pinMode(17, INPUT_PULLDOWN);
|
||||
pinMode(18, INPUT_PULLDOWN);
|
||||
Serial.begin(9600);
|
||||
|
||||
tft.begin(); // Initialize the display
|
||||
tft.setRotation(3); // Set the rotation to horizontal
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
displayText.writeText("Loading...", 3, 0, 200, 0, true, true);
|
||||
websocketSetup();
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
screenButtonHandler();
|
||||
}
|
||||
|
||||
void websocketSetup(){
|
||||
WiFiMulti.addAP("iotroam", "BcgrFpX3kl");
|
||||
WiFiMulti.addAP("ObsidianAmstelveen", "drijversstraatmaastricht");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// server address, port and URL
|
||||
webSocket.begin("145.92.8.114", 80, "/ws");
|
||||
// try ever 500 again if connection has failed
|
||||
webSocket.setReconnectInterval(500);
|
||||
}
|
||||
|
||||
void screenButtonHandler(){
|
||||
|
||||
int redButton = digitalRead(16);
|
||||
int whiteButton = digitalRead(17);
|
||||
int greenButton = digitalRead(18);
|
||||
|
||||
if (initialized) {
|
||||
initialized = false;
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
displayText.writeText(Question[i], 3, 0, 0, 0, true, false);
|
||||
displayText.writeText(Answer[i], 3, 0, 200, 0, true, true);
|
||||
}
|
||||
// 0 is best 2 is worst
|
||||
if (redButton == HIGH){
|
||||
sendData(questionID, "0");
|
||||
}
|
||||
if (whiteButton == HIGH){
|
||||
sendData(questionID, "1");
|
||||
}
|
||||
if (greenButton == HIGH){
|
||||
sendData(questionID, "2");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (redButton || whiteButton || greenButton) {
|
||||
i++;
|
||||
questionID++;
|
||||
if (questionID == 6){
|
||||
questionID = 1;
|
||||
}
|
||||
if (i == 5) {
|
||||
i = 0;
|
||||
}
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
displayText.writeText(Question[i], 3, 0, 0, 0, true, false);
|
||||
displayText.writeText(Answer[i], 3, 0, 200, 0, true, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sendData(int question, String answer){
|
||||
webSocket.sendTXT("{\"node\": \"" + String(WiFi.macAddress()) + "\", \"Response\":\"" + String(answer) + "\",\"QuestionID\":\"" + String(question) + "\"}");
|
||||
}
|
||||
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
106
arduino/Screen code/Screen-code-final/displayText.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "displayText.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
//constructor
|
||||
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);
|
||||
}
|
||||
// if (bottom) {
|
||||
// posY = bottomText(text);
|
||||
// }
|
||||
tft.setCursor(posX, posY);
|
||||
tft.setTextSize(size);
|
||||
printWordsFull(text, bottom);
|
||||
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;
|
||||
tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
int x = (tft.width() - w) / 2;
|
||||
return x;
|
||||
}
|
||||
|
||||
// //to display the text at the bottom when enabled in the public function
|
||||
// int DisplayText::bottomText(char* text) {
|
||||
// int16_t x1, y1;
|
||||
// uint16_t w, h;
|
||||
// tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
// int y = (tft.height() - h);
|
||||
// return y;
|
||||
// }
|
||||
|
||||
//attempt to write the text out in full (wip)
|
||||
void DisplayText::printWordsFull(char* text, bool bottom) {
|
||||
const int screenWidth = 480; // replace with your TFT display width
|
||||
const int lineHeight = 30; // replace with your text line height
|
||||
//the double copy is needed so it doesnt alter the original text
|
||||
char* newtext1 = strdup(text); // Create a copy of the string for the first strtok_r
|
||||
char* newtext2 = strdup(text); // Create a second copy for the second strtok_r
|
||||
char* saveptr1, *saveptr2;
|
||||
char* word = strtok_r(newtext1, " ", &saveptr1);
|
||||
char line[100] = "";
|
||||
int lineCount = 0;
|
||||
int lineWidth = 0;
|
||||
|
||||
// Calculate total number of lines
|
||||
int totalLines = 0;
|
||||
char* tempWord = strtok_r(newtext2, " ", &saveptr2);
|
||||
while (tempWord != NULL) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft.getTextBounds(tempWord, 0, 0, &x1, &y1, &w, &h);
|
||||
if (lineWidth + w > screenWidth && strlen(line) > 0) {
|
||||
//if the line width is greater than the screen width, then we need to add a new line
|
||||
totalLines++;
|
||||
lineWidth = w;
|
||||
//otherwise we just add the width of the word to the line width
|
||||
} else {
|
||||
lineWidth += w;
|
||||
}
|
||||
tempWord = strtok_r(NULL, " ", &saveptr2);
|
||||
}
|
||||
totalLines++; // Add one for the last line
|
||||
|
||||
// Reset variables for actual printing
|
||||
strcpy(line, "");
|
||||
lineWidth = 0;
|
||||
|
||||
while (word != NULL) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft.getTextBounds(word, 0, 0, &x1, &y1, &w, &h);
|
||||
|
||||
if (lineWidth + w > screenWidth && strlen(line) > 0) {
|
||||
int y = bottom ? tft.height() - lineHeight * (totalLines - lineCount) : lineHeight * lineCount;
|
||||
tft.setCursor(0, y);
|
||||
tft.println(line);
|
||||
lineCount++;
|
||||
strcpy(line, word);
|
||||
strcat(line, " ");
|
||||
lineWidth = w;
|
||||
} else {
|
||||
strcat(line, word);
|
||||
strcat(line, " ");
|
||||
lineWidth += w;
|
||||
}
|
||||
|
||||
word = strtok_r(NULL, " ", &saveptr1);
|
||||
}
|
||||
|
||||
// print the last line
|
||||
int y = bottom ? tft.height() - lineHeight * (totalLines - lineCount) : lineHeight * lineCount;
|
||||
tft.setCursor(0, y);
|
||||
tft.println(line);
|
||||
|
||||
free(newtext1); // Free the memory allocated by strdup
|
||||
free(newtext2); // Free the memory allocated by strdup
|
||||
}
|
19
arduino/Screen code/Screen-code-final/displayText.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#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, bool bottom);
|
||||
|
||||
public:
|
||||
DisplayText(Adafruit_ST7796S_kbv& tftDisplay);
|
||||
void writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom);
|
||||
};
|
||||
|
||||
#endif
|
22
arduino/Screen code/Screen-code-final/headerFile.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//screen stuff
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ST7796S_kbv.h"
|
||||
#include "displayText.h"
|
||||
|
||||
#define TFT_CS 14
|
||||
#define TFT_DC 13
|
||||
#define TFT_RST 12
|
||||
#define MOSI 11
|
||||
#define SCK 10
|
||||
#define MISO 9
|
||||
|
||||
//websocket stuff
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFi.h>
|
||||
#include <WebSocketsClient.h>
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
bool initialized = true;
|
40
arduino/Screen code/Screen-example-simplified.ino
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ST7796S_kbv.h"
|
||||
|
||||
#define TFT_CS 14
|
||||
#define TFT_DC 13
|
||||
#define TFT_RST 12 // RST can be set to -1 if you tie it to Arduino's reset
|
||||
#define MOSI 11
|
||||
#define SCK 10
|
||||
#define MISO 9
|
||||
|
||||
//simplify the name of the library
|
||||
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
tft.begin(); // Initialize the display
|
||||
tft.setRotation(3); // Set the rotation
|
||||
tft.fillScreen(ST7796S_BLACK); // Fill the screen with black color
|
||||
tft.setTextColor(ST7796S_WHITE); // Set the text color to white
|
||||
tft.setTextSize(2); // Set the text size to 2
|
||||
}
|
||||
|
||||
void loop() {
|
||||
tft.setTextSize(5); // Set textsize
|
||||
tft.setCursor(0, 0); // Set the cursor to the top left corner
|
||||
//the cursor is where it types the text or shape on the screen, 0,0 is the topleft
|
||||
tft.println("Hello, world!"); // Print the text
|
||||
delay(2000); // Wait for 2 seconds
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK); // Clear the screen
|
||||
|
||||
tft.setCursor(0, 0); // Set the cursor to the top left corner
|
||||
tft.println("New text!"); // Print the new text
|
||||
delay(2000); // Wait for 2 seconds
|
||||
tft.fillScreen(ST7796S_BLACK); // Clear the screen
|
||||
|
||||
}
|
327
arduino/Screen code/Screen-example.ino
Normal file
@@ -0,0 +1,327 @@
|
||||
/***************************************************
|
||||
This is our library for the Adafruit HX8357D Breakout
|
||||
----> http://www.adafruit.com/products/2050
|
||||
|
||||
Check out the links above for our tutorials and wiring diagrams
|
||||
These displays use SPI to communicate, 4 or 5 pins are required to
|
||||
interface (RST is optional)
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
MIT license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ST7796S_kbv.h"
|
||||
|
||||
// These are 'flexible' lines that can be changed
|
||||
#define TFT_CS 14
|
||||
#define TFT_DC 13
|
||||
#define TFT_RST 12 // RST can be set to -1 if you tie it to Arduino's reset
|
||||
#define MOSI 11
|
||||
#define SCK 10
|
||||
#define MISO 9
|
||||
|
||||
// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
|
||||
//Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, TFT_RST);
|
||||
|
||||
// SoftSPI - note that on some processors this might be *faster* than hardware SPI!
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println("ST7796S_kbv Test!");
|
||||
|
||||
tft.begin();
|
||||
|
||||
// read diagnostics (optional but can help debug problems)
|
||||
uint8_t x = tft.readcommand8(ST7796S_RDMODE);
|
||||
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
|
||||
x = tft.readcommand8(ST7796S_RDMADCTL);
|
||||
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
|
||||
x = tft.readcommand8(ST7796S_RDPIXFMT);
|
||||
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
|
||||
x = tft.readcommand8(ST7796S_RDIMGFMT);
|
||||
Serial.print("Image Format: 0x"); Serial.println(x, HEX);
|
||||
x = tft.readcommand8(ST7796S_RDSELFDIAG);
|
||||
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
|
||||
|
||||
Serial.println(F("Benchmark Time (microseconds)"));
|
||||
|
||||
tft.setRotation(1);
|
||||
|
||||
Serial.print(F("Text "));
|
||||
Serial.println(testText());
|
||||
delay(500);
|
||||
|
||||
Serial.print(F("Lines "));
|
||||
Serial.println(testLines(ST7796S_CYAN));
|
||||
delay(500);
|
||||
|
||||
Serial.print(F("Rectangles (outline) "));
|
||||
Serial.println(testRects(ST7796S_GREEN));
|
||||
delay(500);
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
Serial.print(F("Circles (outline) "));
|
||||
Serial.println(testCircles(10, ST7796S_RED));
|
||||
delay(500);
|
||||
|
||||
|
||||
Serial.print(F("Triangles (outline) "));
|
||||
Serial.println(testTriangles());
|
||||
delay(500);
|
||||
|
||||
Serial.print(F("Triangles (filled) "));
|
||||
Serial.println(testFilledTriangles());
|
||||
delay(500);
|
||||
|
||||
|
||||
Serial.print(F("Rounded rects (outline) "));
|
||||
Serial.println(testRoundRects());
|
||||
delay(500);
|
||||
|
||||
Serial.print(F("Rounded rects (filled) "));
|
||||
Serial.println(testFilledRoundRects());
|
||||
delay(500);
|
||||
|
||||
Serial.println(F("Done!"));
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
for(uint8_t rotation=0; rotation<4; rotation++) {
|
||||
tft.setRotation(rotation);
|
||||
testText();
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long testFillScreen() {
|
||||
unsigned long start = micros();
|
||||
tft.fillScreen(ST7796S_RED);
|
||||
tft.fillScreen(ST7796S_GREEN);
|
||||
tft.fillScreen(ST7796S_BLUE);
|
||||
tft.fillScreen(ST7796S_WHITE);
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
|
||||
unsigned long testText() {
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
unsigned long start = micros();
|
||||
tft.setCursor(0, 0);
|
||||
tft.setTextColor(ST7796S_WHITE); tft.setTextSize(1);
|
||||
tft.println("Hello World!");
|
||||
tft.setTextColor(ST7796S_YELLOW); tft.setTextSize(2);
|
||||
tft.println(1234.56);
|
||||
tft.setTextColor(ST7796S_RED); tft.setTextSize(3);
|
||||
tft.println(0xDEADBEEF, HEX);
|
||||
tft.println();
|
||||
tft.setTextColor(ST7796S_GREEN);
|
||||
tft.setTextSize(5);
|
||||
tft.println("Groop");
|
||||
tft.setTextSize(2);
|
||||
tft.println("I implore thee,");
|
||||
tft.setTextSize(1);
|
||||
tft.println("my foonting turlingdromes.");
|
||||
tft.println("And hooptiously drangle me");
|
||||
tft.println("with crinkly bindlewurdles,");
|
||||
tft.println("Or I will rend thee");
|
||||
tft.println("in the gobberwarts");
|
||||
tft.println("with my blurglecruncheon,");
|
||||
tft.println("see if I don't!");
|
||||
|
||||
tft.setTextColor(ST7796S_WHITE);
|
||||
tft.println(F("Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice 'without pictures or conversations?'"));
|
||||
|
||||
tft.println(F("So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her."));
|
||||
|
||||
tft.println(F("There was nothing so very remarkable in that; nor did Alice think it so very much out of the way to hear the Rabbit say to itself, 'Oh dear! Oh dear! I shall be late!' (when she thought it over afterwards, it occurred to her that she ought to have wondered at this, but at the time it all seemed quite natural); but when the Rabbit actually took a watch out of its waistcoat-pocket, and looked at it, and then hurried on, Alice started to her feet, for it flashed across her mind that she had never before seen a rabbit with either a waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across the field after it, and fortunately was just in time to see it pop down a large rabbit-hole under the hedge."));
|
||||
|
||||
tft.println(F("In another moment down went Alice after it, never once considering how in the world she was to get out again."));
|
||||
|
||||
tft.println(F("The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly down, so suddenly that Alice had not a moment to think about stopping herself before she found herself falling down a very deep well."));
|
||||
|
||||
tft.println(F("Either the well was very deep, or she fell very slowly, for she had plenty of time as she went down to look about her and to wonder what was going to happen next. First, she tried to look down and make out what she was coming to, but it was too dark to see anything; then she looked at the sides of the well, and noticed that they were filled with cupboards and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a jar from one of the shelves as she passed; it was labelled 'ORANGE MARMALADE', but to her great disappointment it was empty: she did not like to drop the jar for fear of killing somebody, so managed to put it into one of the cupboards as she fell past it."));
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testLines(uint16_t color) {
|
||||
unsigned long start, t;
|
||||
int x1, y1, x2, y2,
|
||||
w = tft.width(),
|
||||
h = tft.height();
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
|
||||
x1 = y1 = 0;
|
||||
y2 = h - 1;
|
||||
start = micros();
|
||||
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
|
||||
x2 = w - 1;
|
||||
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
|
||||
t = micros() - start; // fillScreen doesn't count against timing
|
||||
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
|
||||
unsigned long start;
|
||||
int x, y, w = tft.width(), h = tft.height();
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
start = micros();
|
||||
for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
|
||||
for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testRects(uint16_t color) {
|
||||
unsigned long start;
|
||||
int n, i, i2,
|
||||
cx = tft.width() / 2,
|
||||
cy = tft.height() / 2;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
n = min(tft.width(), tft.height());
|
||||
start = micros();
|
||||
for(i=2; i<n; i+=6) {
|
||||
i2 = i / 2;
|
||||
tft.drawRect(cx-i2, cy-i2, i, i, color);
|
||||
}
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
|
||||
unsigned long start, t = 0;
|
||||
int n, i, i2,
|
||||
cx = tft.width() / 2 - 1,
|
||||
cy = tft.height() / 2 - 1;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
n = min(tft.width(), tft.height());
|
||||
for(i=n; i>0; i-=6) {
|
||||
i2 = i / 2;
|
||||
start = micros();
|
||||
tft.fillRect(cx-i2, cy-i2, i, i, color1);
|
||||
t += micros() - start;
|
||||
// Outlines are not included in timing results
|
||||
tft.drawRect(cx-i2, cy-i2, i, i, color2);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
|
||||
unsigned long start;
|
||||
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
start = micros();
|
||||
for(x=radius; x<w; x+=r2) {
|
||||
for(y=radius; y<h; y+=r2) {
|
||||
tft.fillCircle(x, y, radius, color);
|
||||
}
|
||||
}
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testCircles(uint8_t radius, uint16_t color) {
|
||||
unsigned long start;
|
||||
int x, y, r2 = radius * 2,
|
||||
w = tft.width() + radius,
|
||||
h = tft.height() + radius;
|
||||
|
||||
// Screen is not cleared for this one -- this is
|
||||
// intentional and does not affect the reported time.
|
||||
start = micros();
|
||||
for(x=0; x<w; x+=r2) {
|
||||
for(y=0; y<h; y+=r2) {
|
||||
tft.drawCircle(x, y, radius, color);
|
||||
}
|
||||
}
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testTriangles() {
|
||||
unsigned long start;
|
||||
int n, i, cx = tft.width() / 2 - 1,
|
||||
cy = tft.height() / 2 - 1;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
n = min(cx, cy);
|
||||
start = micros();
|
||||
for(i=0; i<n; i+=5) {
|
||||
tft.drawTriangle(
|
||||
cx , cy - i, // peak
|
||||
cx - i, cy + i, // bottom left
|
||||
cx + i, cy + i, // bottom right
|
||||
tft.color565(200, 20, i));
|
||||
}
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testFilledTriangles() {
|
||||
unsigned long start, t = 0;
|
||||
int i, cx = tft.width() / 2 - 1,
|
||||
cy = tft.height() / 2 - 1;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
start = micros();
|
||||
for(i=min(cx,cy); i>10; i-=5) {
|
||||
start = micros();
|
||||
tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
|
||||
tft.color565(0, i, i));
|
||||
t += micros() - start;
|
||||
tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
|
||||
tft.color565(i, i, 0));
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
unsigned long testRoundRects() {
|
||||
unsigned long start;
|
||||
int w, i, i2,
|
||||
cx = tft.width() / 2 ,
|
||||
cy = tft.height() / 2 ;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
w = min(tft.width(), tft.height());
|
||||
start = micros();
|
||||
for(i=0; i<w; i+=8) {
|
||||
i2 = i / 2 - 2;
|
||||
tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 100, 100));
|
||||
}
|
||||
|
||||
return micros() - start;
|
||||
}
|
||||
|
||||
unsigned long testFilledRoundRects() {
|
||||
unsigned long start;
|
||||
int i, i2,
|
||||
cx = tft.width() / 2 + 10,
|
||||
cy = tft.height() / 2 + 10;
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
start = micros();
|
||||
for(i=min(tft.width(), tft.height()) - 20; i>25; i-=6) {
|
||||
i2 = i / 2;
|
||||
tft.fillRoundRect(cx-i2, cy-i2, i-20, i-20, i/8, tft.color565(100, i/2, 100));
|
||||
}
|
||||
|
||||
return micros() - start;
|
||||
}
|
106
arduino/Screen code/screen-code-class/displayText.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "displayText.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
//constructor
|
||||
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);
|
||||
}
|
||||
// if (bottom) {
|
||||
// posY = bottomText(text);
|
||||
// }
|
||||
tft.setCursor(posX, posY);
|
||||
tft.setTextSize(size);
|
||||
printWordsFull(text, bottom);
|
||||
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;
|
||||
tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
int x = (tft.width() - w) / 2;
|
||||
return x;
|
||||
}
|
||||
|
||||
// //to display the text at the bottom when enabled in the public function
|
||||
// int DisplayText::bottomText(char* text) {
|
||||
// int16_t x1, y1;
|
||||
// uint16_t w, h;
|
||||
// tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
|
||||
// int y = (tft.height() - h);
|
||||
// return y;
|
||||
// }
|
||||
|
||||
//attempt to write the text out in full (wip)
|
||||
void DisplayText::printWordsFull(char* text, bool bottom) {
|
||||
const int screenWidth = 480; // replace with your TFT display width
|
||||
const int lineHeight = 30; // replace with your text line height
|
||||
//the double copy is needed so it doesnt alter the original text
|
||||
char* newtext1 = strdup(text); // Create a copy of the string for the first strtok_r
|
||||
char* newtext2 = strdup(text); // Create a second copy for the second strtok_r
|
||||
char* saveptr1, *saveptr2;
|
||||
char* word = strtok_r(newtext1, " ", &saveptr1);
|
||||
char line[100] = "";
|
||||
int lineCount = 0;
|
||||
int lineWidth = 0;
|
||||
|
||||
// Calculate total number of lines
|
||||
int totalLines = 0;
|
||||
char* tempWord = strtok_r(newtext2, " ", &saveptr2);
|
||||
while (tempWord != NULL) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft.getTextBounds(tempWord, 0, 0, &x1, &y1, &w, &h);
|
||||
if (lineWidth + w > screenWidth && strlen(line) > 0) {
|
||||
//if the line width is greater than the screen width, then we need to add a new line
|
||||
totalLines++;
|
||||
lineWidth = w;
|
||||
//otherwise we just add the width of the word to the line width
|
||||
} else {
|
||||
lineWidth += w;
|
||||
}
|
||||
tempWord = strtok_r(NULL, " ", &saveptr2);
|
||||
}
|
||||
totalLines++; // Add one for the last line
|
||||
|
||||
// Reset variables for actual printing
|
||||
strcpy(line, "");
|
||||
lineWidth = 0;
|
||||
|
||||
while (word != NULL) {
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
tft.getTextBounds(word, 0, 0, &x1, &y1, &w, &h);
|
||||
|
||||
if (lineWidth + w > screenWidth && strlen(line) > 0) {
|
||||
int y = bottom ? tft.height() - lineHeight * (totalLines - lineCount) : lineHeight * lineCount;
|
||||
tft.setCursor(0, y);
|
||||
tft.println(line);
|
||||
lineCount++;
|
||||
strcpy(line, word);
|
||||
strcat(line, " ");
|
||||
lineWidth = w;
|
||||
} else {
|
||||
strcat(line, word);
|
||||
strcat(line, " ");
|
||||
lineWidth += w;
|
||||
}
|
||||
|
||||
word = strtok_r(NULL, " ", &saveptr1);
|
||||
}
|
||||
|
||||
// print the last line
|
||||
int y = bottom ? tft.height() - lineHeight * (totalLines - lineCount) : lineHeight * lineCount;
|
||||
tft.setCursor(0, y);
|
||||
tft.println(line);
|
||||
|
||||
free(newtext1); // Free the memory allocated by strdup
|
||||
free(newtext2); // Free the memory allocated by strdup
|
||||
}
|
19
arduino/Screen code/screen-code-class/displayText.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#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, bool bottom);
|
||||
|
||||
public:
|
||||
DisplayText(Adafruit_ST7796S_kbv& tftDisplay);
|
||||
void writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom);
|
||||
};
|
||||
|
||||
#endif
|
43
arduino/Screen code/screen-code-class/example.ino
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "headerFile.h"
|
||||
|
||||
int i = 0;
|
||||
|
||||
char* Question[] = {
|
||||
"How clean are the toilets?",
|
||||
"How clean is the study area?",
|
||||
"What do you think of the temperature in the study area?",
|
||||
"How crowded would you say the study area is?",
|
||||
"Is there enough help available?"
|
||||
};
|
||||
|
||||
char* Answer[] = {
|
||||
"clean, normal, disgusting",
|
||||
"clean, normal, disgusting",
|
||||
"hot, perfect, cold",
|
||||
"not at all, its fine, really crowded",
|
||||
"no, decently, yes"
|
||||
};
|
||||
|
||||
//simplify the name of the library
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
DisplayText displayText(tft);
|
||||
|
||||
|
||||
void setup() {
|
||||
tft.begin(); // Initialize the display
|
||||
tft.setRotation(3); // Set the rotation to horizontal
|
||||
}
|
||||
|
||||
void loop() {
|
||||
i++;
|
||||
if (i == 5) {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK); // Fill the screen with black color
|
||||
// writeText(Question[0], 2, 50, 0, 0);
|
||||
// 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(2000);
|
||||
}
|
11
arduino/Screen code/screen-code-class/headerFile.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ST7796S_kbv.h"
|
||||
#include "displayText.h"
|
||||
|
||||
#define TFT_CS 14
|
||||
#define TFT_DC 13
|
||||
#define TFT_RST 12
|
||||
#define MOSI 11
|
||||
#define SCK 10
|
||||
#define MISO 9
|
53
arduino/Screen code/screen-with-questions-nostyling.ino
Normal file
@@ -0,0 +1,53 @@
|
||||
//styling still needs to be done.
|
||||
//this code is to display the questions on the screen.
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ST7796S_kbv.h"
|
||||
|
||||
#define TFT_CS 14
|
||||
#define TFT_DC 13
|
||||
#define TFT_RST 12
|
||||
#define MOSI 11
|
||||
#define SCK 10
|
||||
#define MISO 9
|
||||
|
||||
char* Question[] = {
|
||||
"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)"
|
||||
};
|
||||
|
||||
//simplify the name of the library
|
||||
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
tft.begin(); // Initialize the display
|
||||
tft.setRotation(3); // Set the rotation to horizontal
|
||||
tft.fillScreen(ST7796S_BLACK); // Fill the screen with black color
|
||||
tft.setTextColor(ST7796S_WHITE); // Set the text color to white
|
||||
tft.setTextSize(2); // Set the text size to 2
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
tft.setTextSize(2); // Set textsize
|
||||
tft.setCursor(0, 0); // Set the cursor to the top left corner
|
||||
//the cursor is where it types the text or shape on the screen, 0,0 is the topleft
|
||||
tft.println("Hello, world!"); // Print the text
|
||||
delay(2000); // Wait for 2 seconds
|
||||
|
||||
tft.fillScreen(ST7796S_BLACK); // Clear the screen
|
||||
|
||||
tft.setCursor(0, 0); // Set the cursor to the top left corner
|
||||
tft.println("New text!"); // Print the new text
|
||||
delay(2000); // Wait for 2 seconds
|
||||
tft.fillScreen(ST7796S_BLACK); // Clear the screen
|
||||
tft.setCursor(0, 0); // Set the cursor to the top left corner
|
||||
tft.println(Question[1]);
|
||||
delay(10000); //delay set a longer delay so the long text can write out
|
||||
}
|
40
arduino/Screen code/writetext function.ino
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_ST7796S_kbv.h"
|
||||
#include "headerFile.h"
|
||||
|
||||
char* Question[] = {
|
||||
"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)"
|
||||
};
|
||||
|
||||
//simplify the name of the library
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
tft.begin(); // Initialize the display
|
||||
tft.setRotation(3); // Set the rotation to horizontal
|
||||
tft.fillScreen(ST7796S_BLACK);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
writeText(Question[0], 2, 0, 0, 4000);
|
||||
writeText(Question[1], 2, 0, 0, 4000);
|
||||
writeText(Question[2], 2, 0, 0, 4000);
|
||||
}
|
||||
|
||||
|
||||
void writeText(char* text, int size, int posX, int posY, int screenTime){
|
||||
tft.fillScreen(ST7796S_BLACK); // Fill the screen with black color
|
||||
|
||||
tft.setCursor(posX, posY); // Set the cursor to the top left corner
|
||||
tft.setTextSize(size); // Set textsize
|
||||
tft.println(text);
|
||||
delay(screenTime);
|
||||
}
|
13
arduino/mac_adress.ino
Normal file
@@ -0,0 +1,13 @@
|
||||
// Complete Instructions to Get and Change ESP MAC Address: https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/
|
||||
#include <WiFi.h>
|
||||
|
||||
void setup(){
|
||||
Serial.begin(115200);
|
||||
Serial.println();
|
||||
Serial.print("ESP Board MAC Address: ");
|
||||
Serial.println(WiFi.macAddress());
|
||||
}
|
||||
|
||||
void loop(){
|
||||
|
||||
}
|
54
arduino/node-code/headerFile.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef headerFile_h
|
||||
#define headerFile_h
|
||||
|
||||
// include these libraries
|
||||
#include <Wire.h>
|
||||
// #include <Adafruit_SH110X.h>
|
||||
// #include <Adafruit_SGP30.h>
|
||||
// #include "DHT.h"
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFi.h>
|
||||
// #include <WebSocketsClient.h>
|
||||
// #include <nodeCodeHeader.h>
|
||||
// #include <websockets.h>
|
||||
|
||||
// define pins on esp32
|
||||
#define MICPIN 6
|
||||
#define DHTPIN 7
|
||||
#define SCL 9
|
||||
#define SDA 8
|
||||
#define DHTTYPE DHT11
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define i2c_adress 0x3c
|
||||
#define OLED_RESET -1 // QT-PY / XIAO
|
||||
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
// make new objects
|
||||
// Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
// Adafruit_SH110X display = Adafruit_SH110X(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
// Adafruit_SH110X display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
// Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
// DHT dht(DHTPIN, DHTTYPE);
|
||||
|
||||
// WiFiMulti WiFiMulti;
|
||||
|
||||
// Adafruit_SGP30 sgp;
|
||||
// WebSocketsClient webSocket;
|
||||
|
||||
// define variables
|
||||
uint16_t TVOC_base, eCO2_base;
|
||||
uint16_t counter = 0;
|
||||
uint16_t eCO2 = 0;
|
||||
uint16_t TVOC = 0;
|
||||
uint16_t interval = 5000;
|
||||
float temperature = 0;
|
||||
float humidity = 0;
|
||||
unsigned long currentMillis;
|
||||
unsigned long lastMillis;
|
||||
bool errorSGP30 = false;
|
||||
bool errorDHT11 = false;
|
||||
bool noise = false;
|
||||
#endif
|
@@ -1,3 +1,6 @@
|
||||
// Dano Bosch
|
||||
// 14/2/2024
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
|
177
arduino/node-code/node-code-final.ino
Normal file
@@ -0,0 +1,177 @@
|
||||
// include header file into code
|
||||
#include <headerFile.h>
|
||||
|
||||
// setup function
|
||||
void setup() {
|
||||
// make serial connection at 115200 baud
|
||||
Serial.begin(115200);
|
||||
|
||||
// tell display what settings to use
|
||||
display.begin(i2c_adress, true);
|
||||
display.clearDisplay();
|
||||
|
||||
// tell sensors to start reading
|
||||
dht.begin();
|
||||
sgp.begin();
|
||||
|
||||
pinMode(MICPIN, INPUT);
|
||||
pinMode(DHTPIN, INPUT);
|
||||
|
||||
websocketSetup();
|
||||
resetValues();
|
||||
}
|
||||
|
||||
// loop function
|
||||
void loop() {
|
||||
// loop the websocket connection so it stays alive
|
||||
webSocket.loop();
|
||||
|
||||
// update when interval is met
|
||||
if (currentMillis - lastMillis >= interval){
|
||||
lastMillis = millis();
|
||||
update();
|
||||
}
|
||||
|
||||
// update the counter
|
||||
currentMillis = millis();
|
||||
}
|
||||
|
||||
// hexdump function for websockets binary handler
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
||||
// handler for websocket events
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("{\"message\": \"Connected\"}");
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
// USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
// USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// special function to setup websocket
|
||||
void websocketSetup(){
|
||||
WiFiMulti.addAP("iotroam", "vbK9gbDBIB");
|
||||
WiFiMulti.addAP("LansanKPN-boven", "19sander71vlieland14");
|
||||
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// server address, port and URL
|
||||
webSocket.begin("145.92.8.114", 80, "/ws");
|
||||
|
||||
// event handler
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
// try ever 500 again if connection has failed
|
||||
webSocket.setReconnectInterval(500);
|
||||
}
|
||||
|
||||
// function to reset the values if needed
|
||||
void resetValues() {
|
||||
TVOC_base;
|
||||
eCO2_base;
|
||||
counter = 0;
|
||||
temperature = 0;
|
||||
humidity = 0;
|
||||
eCO2 = 0;
|
||||
TVOC = 0;
|
||||
noise = false;
|
||||
lastMillis = 0;
|
||||
currentMillis = 0;
|
||||
}
|
||||
|
||||
// function to check for errors in sensors
|
||||
bool checkForError(){
|
||||
if (!sgp.IAQmeasure()) {
|
||||
Serial.println("SGP30: BAD");
|
||||
errorSGP30 = true;
|
||||
} else {
|
||||
Serial.println("SGP30: OK");
|
||||
errorSGP30 = false;
|
||||
}
|
||||
|
||||
if (isnan(temperature) || isnan(humidity)){
|
||||
Serial.println("DHT11: BAD");
|
||||
errorDHT11 = true;
|
||||
} else {
|
||||
Serial.println("DHT11: OK");
|
||||
errorDHT11 = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// function to update when interval is met (see intervalCounter variable)
|
||||
void update(){
|
||||
// display sensordata on oled screen
|
||||
displayData();
|
||||
|
||||
// webSocket.sendTXT("{\"Temp\":\"" + String(temperature) + "\",\"Humi\":\"" + String(humidity) + "\",\"eCO2\":\"" + String(sgp.eCO2) + "\",\"TVOC\":\"" + String(sgp.TVOC) + "\"}");
|
||||
webSocket.sendTXT("{\"node\": \"" + String(WiFi.macAddress()) + "\", \"Temp\":\"" + String(temperature) + "\",\"Humi\":\"" + String(humidity) + "\",\"eCO2\":\"" + String(sgp.eCO2) + "\",\"TVOC\":\"" + String(sgp.TVOC) + "\"}");
|
||||
|
||||
sgp.getIAQBaseline(&eCO2_base, &TVOC_base);
|
||||
|
||||
// read dht11 sensor
|
||||
temperature = float(dht.readTemperature());
|
||||
humidity = float(dht.readHumidity());
|
||||
|
||||
// check if any errors occured when reading sensors
|
||||
checkForError();
|
||||
}
|
||||
|
||||
// function to display data on oled screen
|
||||
void displayData() {
|
||||
// clear display for new info
|
||||
display.clearDisplay();
|
||||
|
||||
// set custom text properties
|
||||
display.setTextSize(2);
|
||||
display.setTextColor(SH110X_WHITE);
|
||||
display.setCursor(0, 0);
|
||||
|
||||
// display info on oled screen
|
||||
display.println((String) "Temp: " + int(temperature) + "C" + '\n'
|
||||
+ "Humi: " + int(humidity) + "%" + '\n'
|
||||
+ "eCO2: " + int(sgp.eCO2) + '\n'
|
||||
+ "TVOC: " + int(sgp.TVOC));
|
||||
|
||||
// display the screen
|
||||
display.display();
|
||||
}
|
18
arduino/node-code/nodeCode.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "arduino.h"
|
||||
#include "nodeCodeHeader.h"
|
||||
|
||||
nodeReadings::nodeReadings() {
|
||||
}
|
||||
|
||||
void nodeReadings::resetValues() {
|
||||
counter = 0;
|
||||
eCO2 = 0;
|
||||
TVOC = 0;
|
||||
temperature = 0;
|
||||
humidity = 0;
|
||||
currentMillis = 0;
|
||||
lastMillis = 0;
|
||||
errorSGP30 = false;
|
||||
errorDHT11 = false;
|
||||
noise = false;
|
||||
}
|
13
arduino/node-code/nodeCodeFinal/nodeCodeFinal.ino
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <nodeCodeHeader.h>
|
||||
#include "websockets.h"
|
||||
nodeReadings esp32Node;
|
||||
|
||||
|
||||
void setup() {
|
||||
esp32Node.setup();
|
||||
esp32Node.resetValues();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
esp32Node.loop();
|
||||
}
|
115
arduino/node-code/nodeCodeFinal/nodeCodeHeader.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "nodeCodeHeader.h"
|
||||
|
||||
nodeReadings::nodeReadings() {
|
||||
|
||||
//Making all the new object as defined in the .h file
|
||||
dht = new DHT(DHTPIN, DHTTYPE);
|
||||
display = new Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
webSocket = new websockets();
|
||||
sgp = new Adafruit_SGP30();
|
||||
|
||||
//setting the reding for every 5 sec
|
||||
interval = 5000;
|
||||
resetValues();
|
||||
|
||||
}
|
||||
|
||||
//Script for simpley reseting every value to 0
|
||||
void nodeReadings::resetValues() {
|
||||
counter = 0;
|
||||
eCO2 = 0;
|
||||
TVOC = 0;
|
||||
temperature = 0;
|
||||
humidity = 0;
|
||||
currentMillis = 0;
|
||||
lastMillis = 0;
|
||||
errorSGP30 = false;
|
||||
errorDHT11 = false;
|
||||
noise = false;
|
||||
}
|
||||
|
||||
//Setup for initilising the dht and sgp sensors. Also the display is set up.
|
||||
void nodeReadings::setup(){
|
||||
// make serial connection at 115200 baud
|
||||
Serial.begin(115200);
|
||||
|
||||
// tell display what settings to use
|
||||
display->begin(i2c_adress, true);
|
||||
display->clearDisplay();
|
||||
|
||||
// tell sensors to start reading
|
||||
dht->begin();
|
||||
sgp->begin();
|
||||
|
||||
pinMode(MICPIN, INPUT);
|
||||
pinMode(DHTPIN, INPUT);
|
||||
|
||||
webSocket->websocketSetup();
|
||||
|
||||
}
|
||||
|
||||
void nodeReadings::loop() {
|
||||
// update when interval is met
|
||||
if (currentMillis - lastMillis >= interval){
|
||||
lastMillis = millis();
|
||||
update();
|
||||
}
|
||||
|
||||
// update the counter
|
||||
currentMillis = millis();
|
||||
|
||||
// loop the websocket connection so it stays alive
|
||||
webSocket->loop();
|
||||
}
|
||||
|
||||
void nodeReadings::update(){
|
||||
|
||||
// display sensordata on oled screen
|
||||
displayData();
|
||||
|
||||
//send the data to the websockets
|
||||
webSocket->sendMyText("{\"node\": \"" + String(WiFi.macAddress()) + "\", \"Temp\":\"" + String(temperature) + "\",\"Humi\":\"" + String(humidity) + "\",\"eCO2\":\"" + String(sgp->eCO2) + "\",\"TVOC\":\"" + String(sgp->TVOC) + "\"}");
|
||||
|
||||
sgp->getIAQBaseline(&eCO2_base, &TVOC_base);
|
||||
|
||||
// read dht11 sensor
|
||||
temperature = float(dht->readTemperature());
|
||||
humidity = float(dht->readHumidity());
|
||||
|
||||
// check if any errors occured when reading sensors
|
||||
checkForError();
|
||||
}
|
||||
|
||||
void nodeReadings::displayData() {
|
||||
// clear display for new info
|
||||
display->clearDisplay();
|
||||
|
||||
// display the data on the oled screen
|
||||
display->setTextSize(2);
|
||||
display->setTextColor(SH110X_WHITE);
|
||||
display->setCursor(0,0);
|
||||
display->println("Temp: " + String(int(temperature)) + "C");
|
||||
display->println("Humi: " + String(int(humidity)) + "%");
|
||||
display->println("eCO2: " + String(sgp->eCO2));// + " ppm");
|
||||
display->println("TVOC: " + String(sgp->TVOC));// + " ppb");
|
||||
display->display();
|
||||
}
|
||||
|
||||
//function
|
||||
void nodeReadings::checkForError(){
|
||||
if (!sgp->IAQmeasure()) {
|
||||
Serial.println("SGP30: BAD");
|
||||
errorSGP30 = true;
|
||||
} else {
|
||||
Serial.println("SGP30: OK");
|
||||
errorSGP30 = false;
|
||||
}
|
||||
|
||||
if (isnan(temperature) || isnan(humidity)){
|
||||
Serial.println("DHT11: BAD");
|
||||
errorDHT11 = true;
|
||||
} else {
|
||||
Serial.println("DHT11: OK");
|
||||
errorDHT11 = false;
|
||||
}
|
||||
}
|
55
arduino/node-code/nodeCodeFinal/nodeCodeHeader.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef nodeReading_h
|
||||
#define nodeReading_h
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_SH110X.h>
|
||||
#include <DHT.h>
|
||||
#include <Adafruit_SGP30.h>
|
||||
#include "websockets.h"
|
||||
|
||||
// define pins on esp32
|
||||
#define MICPIN 6
|
||||
#define DHTPIN 7
|
||||
#define SCL 9
|
||||
#define SDA 8
|
||||
#define DHTTYPE DHT22
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define i2c_adress 0x3c
|
||||
#define OLED_RESET -1 // QT-PY / XIAO
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
class nodeReadings
|
||||
{
|
||||
|
||||
public:
|
||||
nodeReadings();
|
||||
void setup();
|
||||
void loop();
|
||||
void resetValues();
|
||||
void update();
|
||||
void checkForError();
|
||||
void displayData();
|
||||
|
||||
private:
|
||||
DHT *dht;
|
||||
Adafruit_SH1106G *display;
|
||||
websockets *webSocket;
|
||||
Adafruit_SGP30 *sgp;
|
||||
|
||||
uint16_t TVOC_base, eCO2_base;
|
||||
uint16_t counter;
|
||||
uint16_t eCO2;
|
||||
uint16_t TVOC;
|
||||
uint16_t interval;
|
||||
float temperature;
|
||||
float humidity;
|
||||
unsigned long currentMillis;
|
||||
unsigned long lastMillis;
|
||||
bool errorSGP30;
|
||||
bool errorDHT11;
|
||||
bool noise;
|
||||
};
|
||||
|
||||
#endif
|
81
arduino/node-code/nodeCodeFinal/websockets.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "websockets.h"
|
||||
|
||||
websockets::websockets(){
|
||||
webSocket = new WebSocketsClient();
|
||||
_WiFiMulti = new WiFiMulti();
|
||||
}
|
||||
|
||||
// hexdump function for websockets binary handler
|
||||
void websockets::hexdump(const void *mem, uint32_t len, uint8_t cols) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
||||
// special function to setup websocket
|
||||
void websockets::websocketSetup(){
|
||||
_WiFiMulti->addAP("iotroam", "vbK9gbDBIB");
|
||||
_WiFiMulti->addAP("LansanKPN-boven", "19sander71vlieland14");
|
||||
|
||||
while(_WiFiMulti->run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// server address, port and URL
|
||||
webSocket->begin("145.92.8.114", 80, "/ws");
|
||||
|
||||
// try ever 500 again if connection has failed
|
||||
webSocket->setReconnectInterval(500);
|
||||
}
|
||||
|
||||
void websockets::loop(){
|
||||
webSocket->loop();
|
||||
}
|
||||
|
||||
// handler for websocket events
|
||||
void websockets::webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket->sendTXT("{\"message\": \"Connected\"}");
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
// send message to server
|
||||
// webSocket->sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
// USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket->sendBIN(payload, length);
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void websockets::sendMyText(String message) {
|
||||
|
||||
webSocket->sendTXT(message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
25
arduino/node-code/nodeCodeFinal/websockets.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef websockets_h
|
||||
#define websockets_h
|
||||
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFi.h>
|
||||
#include <WebSocketsClient.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define USE_SERIAL Serial
|
||||
|
||||
class websockets {
|
||||
public:
|
||||
websockets();
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16);
|
||||
void websocketSetup();
|
||||
void loop();
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
void sendMyText(String message);
|
||||
|
||||
private:
|
||||
WebSocketsClient *webSocket;
|
||||
WiFiMulti *_WiFiMulti;
|
||||
};
|
||||
|
||||
#endif
|
112
arduino/websockets/websocket.ino
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* WebSocketClient.ino
|
||||
*
|
||||
* Created on: 24.05.2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
#define USE_SERIAL Serial1
|
||||
|
||||
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
|
||||
const uint8_t* src = (const uint8_t*) mem;
|
||||
USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
if(i % cols == 0) {
|
||||
USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
|
||||
}
|
||||
USE_SERIAL.printf("%02X ", *src);
|
||||
src++;
|
||||
}
|
||||
USE_SERIAL.printf("\n");
|
||||
}
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Disconnected!\n");
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
// send message to server when Connected
|
||||
webSocket.sendTXT("Connected");
|
||||
break;
|
||||
case WStype_TEXT:
|
||||
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
|
||||
|
||||
// send message to server
|
||||
// webSocket.sendTXT("message here");
|
||||
break;
|
||||
case WStype_BIN:
|
||||
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
|
||||
hexdump(payload, length);
|
||||
|
||||
// send data to server
|
||||
// webSocket.sendBIN(payload, length);
|
||||
break;
|
||||
case WStype_ERROR:
|
||||
case WStype_FRAGMENT_TEXT_START:
|
||||
case WStype_FRAGMENT_BIN_START:
|
||||
case WStype_FRAGMENT:
|
||||
case WStype_FRAGMENT_FIN:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// USE_SERIAL.begin(921600);
|
||||
USE_SERIAL.begin(115200);
|
||||
|
||||
//Serial.setDebugOutput(true);
|
||||
USE_SERIAL.setDebugOutput(true);
|
||||
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
USE_SERIAL.println();
|
||||
|
||||
for(uint8_t t = 4; t > 0; t--) {
|
||||
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
|
||||
USE_SERIAL.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP("iotroam", "vbK9gbDBIB");
|
||||
|
||||
//WiFi.disconnect();
|
||||
while(WiFiMulti.run() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// server address, port and URL
|
||||
webSocket.begin("145.92.8.114", 80, "/ws");
|
||||
|
||||
// event handler
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
// use HTTP Basic Authorization this is optional remove if not needed
|
||||
|
||||
|
||||
// try ever 5000 again if connection has failed
|
||||
webSocket.setReconnectInterval(5000);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
webSocket.loop();
|
||||
|
||||
webSocket.sendTXT("test websocket 45050");
|
||||
}
|
20
docs/.pages
@@ -8,11 +8,31 @@ nav:
|
||||
- Links: opdracht/links
|
||||
- 🎮 Arduino documentation:
|
||||
- I2C: arduino-documentation/i2c-ESP32
|
||||
- TFT screen : node-documentation/TFT-screen
|
||||
- Classes : arduino-documentation/classes
|
||||
- Node Documentation: node-documentation/node
|
||||
- Node Class: node-documentation/NodeClassDocumentation
|
||||
- Node Uml Diagram: node-documentation/NodeClassUml
|
||||
- 🍓 RPi Documentation:
|
||||
- Raspberry pi: Sp1SchetsProject/InfrastructuurDocumentatie/raspberryPi
|
||||
- MariaDB: rpi-documentation/mariadb-installation
|
||||
- phpMyAdmin: rpi-documentation/phpmyadmin-installation
|
||||
- Websockets: rpi-documentation/websockets
|
||||
- Reverse Proxy: rpi-documentation/Reverse-Proxy
|
||||
- Db - Ws connection: rpi-documentation/Databaseconnection
|
||||
- Put-request: rpi-documentation/Put-Request
|
||||
- 🧠 Brainstorm:
|
||||
- Ideeën: brainstorm/ideeën
|
||||
- Database design: brainstorm/Database
|
||||
- Feedback: brainstorm/Feedback
|
||||
- Problem: brainstorm/Problem
|
||||
- InfrastructureUml: brainstorm/UML-infrastructure
|
||||
- Infrascructure: brainstorm/infrasturcture
|
||||
- Taskflow: brainstorm/Taskflow
|
||||
- Design: Sp1SchetsProject/FirstDesign
|
||||
- Interview facility manager: brainstorm/gebouwBeheer
|
||||
- Questions enquete: brainstorm/QuestionsEnquete
|
||||
- 🖨️ Software:
|
||||
- Dev page: brainstorm/SoftwareDocumentatie/Dev_page
|
||||
- Graph classes: brainstorm/SoftwareDocumentatie/classes
|
||||
|
@@ -0,0 +1,86 @@
|
||||
#include "DHT.h"
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <WebSocketsClient.h>
|
||||
|
||||
#define DHTPIN 4
|
||||
#define DHTTYPE DHT11
|
||||
|
||||
uint8_t h;
|
||||
uint8_t t;
|
||||
|
||||
uint16_t interval = 5000;
|
||||
unsigned long currentMillis;
|
||||
unsigned long lastMillis;
|
||||
|
||||
WiFiMulti wifiMulti;
|
||||
WebSocketsClient webSocket;
|
||||
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
|
||||
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
// Handle WebSocket events here if needed
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
Serial.println(F("DHTxx test!"));
|
||||
dht.begin();
|
||||
|
||||
wifiMulti.addAP("iotroam", "sGMINiJDcU");
|
||||
wifiMulti.addAP("Ziggo6565749", "Ziggobroek1@");
|
||||
|
||||
Serial.println("Connecting Wifi...");
|
||||
if (wifiMulti.run() == WL_CONNECTED) {
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
// Connect to WebSocket server
|
||||
webSocket.begin("145.92.8.114", 80, "/ws"); // Replace with your Raspberry Pi's IP address and port
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
webSocket.setReconnectInterval(500);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// update when interval is met
|
||||
if (currentMillis - lastMillis >= interval){
|
||||
lastMillis = millis();
|
||||
update();
|
||||
}
|
||||
|
||||
// update the counter
|
||||
currentMillis = millis();
|
||||
|
||||
float h = dht.readHumidity();
|
||||
// Read temperature as Celsius (the default)
|
||||
float t = dht.readTemperature();
|
||||
|
||||
if (isnan(h) || isnan(t)) {
|
||||
Serial.println(F("Failed to read from DHT sensor!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute heat index in Celsius (isFahrenheit = false)
|
||||
float hic = dht.computeHeatIndex(t, h, false);
|
||||
|
||||
Serial.print(F("Humidity: "));
|
||||
Serial.print(h);
|
||||
Serial.print(F("% Temperature: "));
|
||||
Serial.print(t);
|
||||
Serial.print(F("°C "));
|
||||
Serial.print(hic);
|
||||
Serial.print(F("°C "));
|
||||
|
||||
|
||||
|
||||
// Ensure WebSocket communication
|
||||
webSocket.loop();
|
||||
}
|
||||
|
||||
void update(){
|
||||
webSocket.sendTXT("{\"node\": \"" + String(WiFi.macAddress()) + "\", \"Temp\":\"" + String(t) + "\",\"Humi\":\"" + String(h) + "\"}");
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
### Connecting With The websocket.
|
||||
#### The reason.
|
||||
During our project we needed more esp's to connect to the websocket, so i was given the task to make a connection to wifi, connect to the websocket, and then send information to it.
|
||||
|
||||
#### Before the setup.
|
||||
I used library's for: connecting to multiple wifi's, connecting to the websocket and being able to read infromation form a DHT11.
|
||||
These were called uppon in the first few lines.
|
||||
|
||||
Together with this a few variables are named to be used later in the code.
|
||||
|
||||
#### The Setup
|
||||
Firstoff, start with identifying which serial port will be used and work from there.
|
||||
It Then tells the DHT to send a test message and start it up.
|
||||
|
||||
Then the several wifi connections get told here and it looks for the one that connects.
|
||||
(This is made bij giving the wifi name and pasword)
|
||||
In this sequence a print is made, showing that there is an atempt to connect to a wifi.
|
||||
|
||||
*This was used because the node should be able to connect to several wifi's and not be stuck t one in perticulair.
|
||||
|
||||
After the wifi is connected it sends a print to indicate a connection and pings the ip adress of the used wifi.
|
||||
|
||||
The websocket connection which was then made is made using the uri, port, and type of connection.
|
||||
In case of websocket events it gets sent.
|
||||
In case of connection failiure, try this.
|
||||
|
||||
#### The loop
|
||||
We start with setting a timer because a "delay" function would break the connection with the websocket resulting in an error.
|
||||
|
||||
This relates back to some some variables that were made in the beginning.
|
||||
|
||||
We make variables for the different results we are gathering, so these can be used later.
|
||||
|
||||
Then the variables get printed for overview.
|
||||
|
||||
To ensure the websocket connection , the process gets looped.
|
||||
|
||||
#### Update File.
|
||||
Here the text thathas te be sent to the websocket gets sent.
|
||||
|
||||
### The fysical product.
|
||||
it is shown here:
|
||||

|
||||
It also turns on:
|
||||

|
||||
|
||||
Here are my fritzing and wireframe, the components used are shown but The DHT11 is replaced by a DHT22.
|
||||

|
||||

|
||||
|
||||
### The code.
|
||||
Here the c++ code is shown:
|
||||
https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/blob/main/docs/LearningProcessBram/ArduinoExperience/NodeWithWebConnection.ino?ref_type=heads
|
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 788 KiB |
After Width: | Height: | Size: 816 KiB |
@@ -0,0 +1,58 @@
|
||||
### Buzzer class
|
||||
To provide a demonstration of how classes work in C++/Arduino, I decided to code something simple and repeatable.
|
||||
|
||||
This class is intended to assign an input and output source for a button to activate a buzzer, and for a buzzer to be activated by a button. This is achieved by using private variables and public functions that access these variables.
|
||||
|
||||
This class code allows the user to easily add new buzzers by simply creating an object and calling the appropriate function.
|
||||
|
||||
##### Constructor
|
||||
Inside the class, a constructor is defined. In C++, this constructor shares the same name as the class itself. Every time the class is called, the constructor is activated with the given data.
|
||||
|
||||
##### Class functions
|
||||
Within a class, functions can be defined. These functions can interact with the variables made inside the class. These functions can then be called outside the class to execute their action.
|
||||
|
||||
In this case, the "activation" function is defined within the class and is used in the loop function. This function contains the if-statement that determines if the button is pressed and activates the buzzer pin accordingly.
|
||||
|
||||
##### Object Creation
|
||||
After defining the class, an object needs to be made. This object will immediately trigger the constructor and ask for input variables. These given data points will be inserted into the private variables.
|
||||
|
||||
In this instance, the buzzer pin is set to 12 and the button pin to 20.
|
||||
|
||||
##### Using the class
|
||||
In the loop function, the new object is placed along with the function defined in the class to activate it. This function executes with the variable data provided in the constructor. Here, it checks if the specified pin is receiving a signal and then only outputs a signal to the buzzer when there is one.
|
||||
|
||||
##### Link to code
|
||||
(https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/blob/main/docs/LearningProcessBram/ArduinoExperience/classesArduino/buzzerclasses.ino?ref_type=heads)
|
||||
|
||||
### The board
|
||||
The fysical board should look something like this:
|
||||

|
||||
The board is simple and easy to recreate and has lots of space left for other functions.
|
||||
|
||||
By making this class, the addition of more buzzers is very easy. As long as there are pins, there can be a buzzer.
|
||||
|
||||
For this example, I have only used one, but adding more would be no problem. Just make a object, give the pin numbers and call the function.
|
||||
|
||||
The wireframe for this board would looke something like this:
|
||||

|
||||
|
||||
I tried making it as clear as possible by moving some parts around and clearing some intertwining wires.
|
||||
|
||||
###### My Fysical Recreation.
|
||||
To properly demonstrate this code in action, I recreated the board. In the image, you can see that I plugged in three different LEDs.
|
||||

|
||||
In the image, you can see that I plugged in three different LEDs.
|
||||
This was done to show off that the board/code works, as it's not possible to see if a buzzer is working on camera.
|
||||
|
||||
For the time being, pretend that the LED and resistor combinations are separate buzzers.
|
||||
|
||||
To make this board turn all the buzzers/LEDs on, I needed to create three different objects. These objects looked like this:
|
||||

|
||||
The first variable is where I want the buzzer to connect, and the second variable is where I want the button to be connected.
|
||||
|
||||
After this, I simply placed the objects in the loop and called the function we made in the class:
|
||||

|
||||
|
||||
Now, we simply push the code to The Esp and try it out.
|
||||

|
||||
Now, we have effectively made the LEDs/buzzers turn on with the push of a single button.
|
@@ -0,0 +1,30 @@
|
||||
class BuzzerPin{
|
||||
private:
|
||||
int buzzerPin;
|
||||
int button;
|
||||
public:
|
||||
BuzzerPin(int bp, int but){
|
||||
buzzerPin = bp;
|
||||
button = but;
|
||||
pinMode(button, INPUT);
|
||||
pinMode(buzzerPin, OUTPUT);
|
||||
}
|
||||
|
||||
void activate(){
|
||||
if(digitalRead(button) == HIGH){
|
||||
digitalWrite(buzzerPin, HIGH);
|
||||
}else{
|
||||
digitalWrite(buzzerPin, LOW);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
BuzzerPin buzzerOne(12, 20);
|
||||
|
||||
void setup(){
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
buzzerOne.activate();
|
||||
}
|
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 5.9 KiB |
@@ -1,9 +0,0 @@
|
||||
## Bram's Learning Curve
|
||||
Here i post my progress on learning and mastering arduino. I originally did the Gamedevelopment study but decided to switch to "Technische Informatica". That is why i need to learn everything from scratch, and everything is new to me.
|
||||
This is the reason that i made these documents, in order to track my progression in this new study.
|
||||
|
||||
|
||||
### Buzzer
|
||||
For one of my first projects I wanted to learn how to use a buzzer with different notes.
|
||||
To achieve this, i went on a search accross sites to see how i can use frequenties to make different sounds.
|
||||
Then i came accross a teaching site (https://www.codingkids.nl/arduino-buzzer.html) that taught me the language to communicate to the buzzer what frequenties to use. This way i can make any sound come out of this simple buzzer.
|
3
docs/LearningProcessBram/documentatie/FeedbackRetro.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Personal Learning
|
||||
Keep documenting my personal progression, but ad my personal way of learning, like video's and such.
|
||||
Do update the Team document, because the current version has a bit too much generic points.
|
290
docs/LearningProcessBram/documentatie/FirstDocumentation.md
Normal file
@@ -0,0 +1,290 @@
|
||||
## Bram's Learning Curve
|
||||
Here I post my progress on learning and mastering Arduino. I originally did the Game development study but decided to switch to "Technische Informatica". That is why I need to learn everything from scratch, and everything is new to me.
|
||||
This is the reason that I made these documents, in order to track my progression in this new study.
|
||||
|
||||
### Buzzer
|
||||
For one of my first projects, I wanted to learn how to use a buzzer with different notes.
|
||||
To achieve this, I went on a search across sites to see how I can use frequencies to make different sounds.
|
||||
Then I came across a teaching site (https://www.codingkids.nl/arduino-buzzer.html) that taught me the language to communicate to the buzzer what frequencies to use. This way I can make any sound come out of this simple buzzer.
|
||||
|
||||
### Arduino Video
|
||||
I watched a video about using Arduino and took a lot of op notes along the way.
|
||||
The link is: (https://www.youtube.com/watch?v=BLrHTHUjPuw).
|
||||
```
|
||||
// $Arduino information:
|
||||
|
||||
//pinnumber(locatie, in-/output)
|
||||
|
||||
//digitalwrite(locatie, high/low)
|
||||
|
||||
//delay(time in millisec)
|
||||
|
||||
//int... <- variable
|
||||
|
||||
//with a decimal its a double -> 1,2
|
||||
|
||||
//a character is a char -> "a"
|
||||
|
||||
// $serial communications:
|
||||
|
||||
setup:
|
||||
Serial.begin(9600) -> the text speed
|
||||
Serial.sprintLn(text)
|
||||
|
||||
Loop:
|
||||
Serial.print("text")
|
||||
Serial.printLn(....) -> variable because no "
|
||||
|
||||
//Ctrl + shift + M = serial monitor.
|
||||
The text speed needs to be the same as given.
|
||||
|
||||
// $If Statements:
|
||||
|
||||
if(condition){
|
||||
|
||||
action
|
||||
|
||||
}else{
|
||||
|
||||
action
|
||||
|
||||
}
|
||||
|
||||
// && = "and"
|
||||
|
||||
// || = "or"
|
||||
|
||||
\/\/For loops:
|
||||
|
||||
For(int*i; i <= 10 ; i++){
|
||||
|
||||
serial.print(i)
|
||||
|
||||
}
|
||||
|
||||
// The fading of led's:
|
||||
|
||||
examples, basics, fade
|
||||
|
||||
// servo's
|
||||
|
||||
examples, servo, sweep
|
||||
```
|
||||
### Linux and raspberry PI.
|
||||
To gain more knowledge about Linux, I first asked my classmates if they could get me started.
|
||||
|
||||
They showed me how to gain access to a server and told me how to navigate through files.
|
||||
By doing this I got taught the following commands:
|
||||
```
|
||||
~ $ 'ls -la' = show file / folders
|
||||
|
||||
~ $ 'top' = see currently running programs
|
||||
|
||||
~ $ 'cd ' = change directory
|
||||
|
||||
~ $ 'mkdir name' = make directory
|
||||
|
||||
~ $ 'touch name' = make file
|
||||
|
||||
~ $ 'ping ip addres'
|
||||
|
||||
~ $ 'ssh username@ip address' = open ssh connection.
|
||||
```
|
||||
### Air, temperature, and all sort of stuff.
|
||||
|
||||
After the Linux coding I decided to take a step back and began gaining experience with sensors.
|
||||
I began trying to make our group project's "node" for myself.
|
||||
I did this by using one of the main sensors and tried programing it myself.
|
||||
I used this website for the information and for the right library:(https://randomnerdtutorials.com/esp32-dht11-dht22-temperature-humidity-sensor-arduino-ide/).
|
||||
Aside from the website I used my teammates for help where it was needed.
|
||||
I wanted to make my own spin on the original design by including a button to activate the sensor and an LED to show if its on.
|
||||
The rest of the tutorial was clear and worked like a charm.
|
||||
the code used looks like this:
|
||||
|
||||
Begin by including a specific library for the DHT11.
|
||||
```
|
||||
#include "DHT.h"
|
||||
#define DHTPIN 4
|
||||
#define DHTTYPE DHT11
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
```
|
||||
using This perticulair serial port, means that you do have to switch to it when you want to see results coming in.
|
||||
The dht.begin command starts the process.
|
||||
```
|
||||
void setup() {
|
||||
//the serial port:
|
||||
Serial.begin(9600);
|
||||
|
||||
//the initial test if the code works
|
||||
Serial.println(F("DHTxx test!"));
|
||||
//the library start
|
||||
dht.begin();
|
||||
}
|
||||
```
|
||||
It starts by making float variables, to give over the information.
|
||||
It also includes a error message in case of no feedback.
|
||||
|
||||
```
|
||||
void loop() {
|
||||
delay(2000);
|
||||
//a float has decimal numbers and the library reads the measurements.
|
||||
float h = dht.readHumidity();
|
||||
float t = dht.readTemperature();
|
||||
float f = dht.readTemperature(true);
|
||||
|
||||
//isnan = there is no reading , the || is "or"
|
||||
if (isnan(h) || isnan(t) || isnan(f)) {
|
||||
|
||||
Serial.println(F("Failed to read from DHT sensor!"));
|
||||
|
||||
return;
|
||||
}
|
||||
float hif = dht.computeHeatIndex(f, h);
|
||||
float hic = dht.computeHeatIndex(t, h, false);
|
||||
|
||||
//all serial.print's send stuff to the serial board to showcase.
|
||||
Serial.print(F("Humidity: "));
|
||||
Serial.print(h);
|
||||
Serial.print(F("% Temperature: "));
|
||||
Serial.print(t);
|
||||
Serial.print(F("°C "));
|
||||
Serial.print(f);
|
||||
Serial.print(F("°F Heat index: "));
|
||||
Serial.print(hic);
|
||||
Serial.print(F("°C "));
|
||||
Serial.print(hif);
|
||||
Serial.println(F("°F"));
|
||||
}
|
||||
```
|
||||
And the physical board looks like this:
|
||||

|
||||
And here it looks in action:
|
||||

|
||||
|
||||
Later on, I could expand this code and the physical product to include the rest of the sensors.
|
||||
|
||||
The wiring is shown here:
|
||||

|
||||
The red cables are 3v, the black cables are the ground and the green cable is the echo for data.
|
||||
This version is using a DHT22, this is a updated version of a DHT11 but still provides the same information and still uses the same pins. So i decided to compromise for it, using it in my fritzing diagram.
|
||||
|
||||
The wire-frame is shown below:
|
||||

|
||||
This helps visualise all connections and shows what parts were used for reproductional .
|
||||
|
||||
### Buzzers .pt 2
|
||||
I found out how to make multiple buzzers go off with the press of one button and increase as Mutch as there are pins.
|
||||
I tried to not look up anything for this one but did ask questions from time to time.
|
||||
I designed it to work with scanning if there is any input and then output this signal to activate the buzzers.
|
||||
This output signal can activate over multiple pins so this one button can set off all sorts of stuff.
|
||||
The code is short and simple:
|
||||
|
||||
```
|
||||
//set up some variables
|
||||
int button = 20;
|
||||
int buzzerone = 12;
|
||||
int buzzertwo = 11;
|
||||
```
|
||||
Now we set the pins up to either input or output a signal.
|
||||
```
|
||||
void setup() {
|
||||
//put down some pins that will output , and some that input.
|
||||
pinMode(button, INPUT);
|
||||
pinMode(buzzerone, OUTPUT);
|
||||
pinMode(buzzertwo, OUTPUT);
|
||||
}
|
||||
```
|
||||
Here the button pin will seek a signal, when it is given it will send signals to the other given pins in the if-statement.
|
||||
```
|
||||
void loop() {
|
||||
//read is there is input on the button pin, if so send output to the other pins, otherwise keep them off.
|
||||
if(digitalRead(button) == HIGH){
|
||||
digitalWrite(buzzerone, HIGH);
|
||||
digitalWrite(buzzertwo, HIGH);
|
||||
}else{
|
||||
digitalWrite(buzzerone, LOW);
|
||||
digitalWrite(buzzertwo, LOW);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here I made the physical design but instead of buzzers I used lights in order to show it working.
|
||||

|
||||
And here is the the board working:
|
||||

|
||||
|
||||
To Show my wiring more clearly, here is my fritzing board:
|
||||

|
||||
the red wires are 3v, the black wires are the ground connections.
|
||||
|
||||
Here the wireframe is shown for parts specification and possible reproduction:
|
||||

|
||||
|
||||
### Python For Dummies.
|
||||
My job was to make a connection between the WebSocket and the database we had set up, and to do this we wanted to use python.
|
||||
To give an easy picture, here is where i would come:
|
||||

|
||||
It looks easy, but for someone who never worked wit hpython and linux, this will prove to be a challenge.
|
||||
|
||||
Because I was totally new to all of python I began asking friends for advice and started asking chatgpt for some examples.
|
||||
and worked in reverse in order to understand python fully.
|
||||
I went and looked up fitting tutorials on W3SChools.
|
||||
The following were used:
|
||||
|
||||
(https://www.w3schools.com/python/python_mysql_getstarted.asp)
|
||||
|
||||
(https://websockets.readthedocs.io/en/stable/)
|
||||
|
||||
(https://www.w3schools.com/python/python_mysql_insert.asp)
|
||||
|
||||
(https://www.w3schools.com/python/python_json.asp)
|
||||
|
||||
After still not getting it very well i asked Dano (a teammate of mine) if he could teach me some basics, and so we did.
|
||||
He taught me how to make a simple calculator and told me why my code worked the way it did.
|
||||
(This was the code:
|
||||
|
||||
// this prints a cheatsheet to know if the user wants plus or minus.
|
||||
print("1 = + 2 = -")
|
||||
c = int(input())
|
||||
|
||||
// a input is given for the first number.
|
||||
print("first number")
|
||||
a = input()
|
||||
|
||||
//a input is given for the second number.
|
||||
print("second number")
|
||||
b= input()
|
||||
|
||||
//a if-statement to see if it is plus or minus.
|
||||
if c == 1:
|
||||
print(int(a) + int(b))
|
||||
elif c == 2:
|
||||
print(int(a) - int(b))
|
||||
)
|
||||
|
||||
Even if it looked simple, this was the ignition I needed to understand python better and continue my own research.
|
||||
|
||||
### Python for dummmies pt2
|
||||
After some intense trail and error, I managed to connect to the websocket.
|
||||
After wich I also managed to send infromation to the database by including details like pasword and such.
|
||||
I began investigating deeper and asked for other people's vision on my code.
|
||||
|
||||
It wasa hard to notice what problems there were, but eventualy me and a classmate found out that the problem was inside of the database itself instead of the code. So after fixing some issues with the primary keys and some tesing with the code, I managed to fix the issues that popped up.
|
||||
|
||||
Now the code is able to send websocket data to the database under the name of node "1".
|
||||
This will have to be updated so all names could be sent to the database without causing issues.
|
||||
But the current code does what we expect from sprint two but I will surely continue working on making it perfect.
|
||||
|
||||
### python for dummies pt3
|
||||
After the sprint review for sprint two, we as a team decided that it was time to make progress with connecting more nodes, and so I did.
|
||||
|
||||
I began searching for leads on how to grab information from a database, and used this website to teach me:
|
||||
https://www.w3schools.com/python/python_mysql_select.asp
|
||||
|
||||
Once I figured out how to grab information, I wanted to put it in an array and look if the connected node(wich I put in a varriable) was already known in the array. The webpage for this was: https://stackabuse.com/python-check-if-array-or-list-contains-element-or-value/
|
||||
|
||||
This originaly didn't work, and by printing all my variables and the array I initially didn't see anything that would prevent it from working.
|
||||
But for some reason the given node wouldn't compare itself to the nodes in the array.
|
||||
That is when I found out the data from the array was in a tuple. So when I changed the variable to turn into a tuple, it worked like a charm.
|
||||
|
||||
Then after all of this trouble, I finished by putting the new node MAC (in string format) into the correct collum in the database so this will MAC will be saved in the future.
|
BIN
docs/LearningProcessBram/documentatie/assets/2Covers.jpg
Normal file
After Width: | Height: | Size: 492 KiB |
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/LearningProcessBram/documentatie/assets/Buzzer board on.jpg
Normal file
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 215 KiB |
After Width: | Height: | Size: 99 KiB |
BIN
docs/LearningProcessBram/documentatie/assets/DHT11 state 1.jpg
Normal file
After Width: | Height: | Size: 572 KiB |
BIN
docs/LearningProcessBram/documentatie/assets/DHT11 state 2.jpg
Normal file
After Width: | Height: | Size: 596 KiB |
BIN
docs/LearningProcessBram/documentatie/assets/DHT11 wires.png
Normal file
After Width: | Height: | Size: 298 KiB |
After Width: | Height: | Size: 198 KiB |
After Width: | Height: | Size: 89 KiB |
BIN
docs/LearningProcessBram/documentatie/assets/myconnection.png
Normal file
After Width: | Height: | Size: 18 KiB |
41
docs/Sp1SchetsProject/FirstDesign.md
Normal file
@@ -0,0 +1,41 @@
|
||||
## 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.
|
||||

|
||||
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 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.
|
||||
|
||||
The nodes will be powerd by batteries and wil be mounted on walls around eye height. They will latch on a mount that is stuck using dubble sidded tape. this way we can mount and dismount the nodes when the batteries need to be replaced.
|
||||
|
||||
(The mount and the sode profile are shown on the bottom of the page.)
|
||||
|
||||
Next up is the central node that has a questionaire built into it.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
This node still has all the sensors like all of the others, except this one has a built in questionaire.
|
||||
|
||||
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.
|
||||
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.
|
||||

|
@@ -1,6 +1,6 @@
|
||||
#Rasberry Pi
|
||||
# Rasberry Pi
|
||||
|
||||
##Table of contents
|
||||
## Table of contents
|
||||
1. [Introduction](##introduction)
|
||||
2. [Rasberry Pi](##Rasberry-Pi)
|
||||
3. [Dev-Page](###Dev-Page)
|
||||
@@ -8,20 +8,24 @@
|
||||
5. [Database software](###Database-software)
|
||||
6. [Esp to database](###Esp-to-database)
|
||||
|
||||
##Introduction
|
||||
## Introduction
|
||||
|
||||
The backend of this project there is a raspberry pi 3 for handeling the dev page (more on this later) and the database. The Esp nodes are going to send a api request to the dev page wich is going to make a POST request to the database.
|
||||
In the backend of this project, there is a Raspberry Pi 3 for handling the dev page (more on this later) and the database. The ESP nodes are going to send an API request to the dev page, which is going to make a POST request to the database.
|
||||
|
||||
##Rasberry Pi
|
||||
## Rasberry Pi
|
||||
|
||||
The Raspberry 3 can be descriped as a "little" computer running a quad-code 64-bit prossesor, the previus Raspberry witch is 50% slower than this one
|
||||
The Raspberry 3 can be descriped as a "little" computer running a quad-code 64-bit prossesor, the previus Raspberry witch is the pi 2 and is 50% slower. The operaiting system is linux, it is a open source os system, we are using it for database and website hosting purposes, but it can do a wide range of things. The GPIO pins make it usefull for even more things, like home automation with sensors.
|
||||
|
||||
The Raspberry Pi 3 is equipped with a quad-core 64-bit Broadcom BCM2837 ARM Cortex-A53 SoC processor running at 1.2 GHz, making it about 50% more powerful than the Pi 2.
|
||||
### Dev Page
|
||||
|
||||
###Dev Page
|
||||
For monitoring porpoises we are going to implement a dev page, this means that there basicey is a debug page. On this page we will be displaying the current readings that are comming in in to graphs and also the data form the last 10 redings from all the nodes, the readings are sorted in there respective graphs like temp, humidity and noice redings for example. This is handy for quick access to the data ouwr nodes are sending out. So it will be easy to see if one is malvuntion and monetoring the state off the battery to check if its nessesery to replace it.
|
||||
|
||||
##Database
|
||||
### Database
|
||||
|
||||
###Database software
|
||||
## Database
|
||||
|
||||
###Esp to database
|
||||
The database is set up on the raspberry so that we dont always have to have a computewr
|
||||
|
||||
### Database software
|
||||
|
||||
### Esp to database
|
34
docs/Sprint1/sprint1Revieuw.md
Normal file
@@ -0,0 +1,34 @@
|
||||
### Begin met een introductie van het team (jullie namen + teamnaam)
|
||||
|
||||
Welkom bij de sprint review, wij zijn *insert namen*.
|
||||
|
||||
### Leg uit wat jullie van plan zijn om op te leveren; wat is de opdracht, wat gaat er waarschijnlijk uitkomen.
|
||||
|
||||
Wij hebben de opdracht gekregen om de studieruimte te optimaliseren. Hiervoor moeten we data verzamelen over de studieomgeving en de meningen van onze medeleerlingen. We hebben feedback gevraagd bij studenten en daar is uit gebleken dat mensen moeite hebben met een rustige omgeving te vinden. Daarom gaan we een systeem bouwen waardoor je makkelijk rustige studieplekken kan vinden.
|
||||
|
||||
Dit gaan we doen door het plaatsen van een centrale hub node en een aantal losse hub nodes. Deze nodes zullen verschillende datapunten verzamelen met behulp van sensoren, namelijk: temperatuur, luchtvochtigheid, ppm van koolstof en TVOC. Daarnaast hebben we een display waarop de huidige metingen worden getoond. In de centrale hub is ook een meetstation en een tweede scherm met enkele enquêteachtige vragen, waarbij gebruikers hun mening kunnen geven met behulp van 3 knoppen. We moeten nog testen of dit toegankelijk genoeg is. We hebben ook al een basisidee van hoe het design van de nodes eruit zal zien. *insert bram funny pic*
|
||||
|
||||
### Bespreek welke User Stories jullie hebben gemaakt voor de Product Backlog.
|
||||
|
||||
*laat belangrijke user stories zien*
|
||||
|
||||
*leg uit waarom*
|
||||
|
||||
### Bespreek welke User Stories jullie hebben opgepakt in de Sprint Backlog.
|
||||
|
||||
- [Luchtmeten](https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/issues/36)
|
||||
- [Temperatuur meten](https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/issues/18)
|
||||
- [Schermpje op node](https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/issues/39)
|
||||
|
||||
In de eerste sprint werken we vooral aan het algehele plan en de basis van het project, met name de Raspberry Pi die tot onze beschikking is gesteld voor de backend. Deze moeten we zelf ontwerpen. Daarnaast moeten we zaken zoals de wireflows, de infrastructuur: , en het [uml diagram](../brainstorm/UML%20infrastructure.md) regelen.
|
||||
|
||||
### Geef een demonstratie van het product.
|
||||
|
||||
*show node*
|
||||
|
||||
### Geef een overzicht van jullie portfoliowebsite (highlights).
|
||||
|
||||
We hebben op onze portfoliopagina verschillende documentaties geplaatst, met name:
|
||||
- [Het algehele idee](https://opti.smikkelbakje.nl/brainstorm/idee%C3%ABn/)
|
||||
- [Databaseontwerp](https://opti.smikkelbakje.nl/brainstorm/Database/)
|
||||
- [I2C-communicatie](https://opti.smikkelbakje.nl/arduino-documentation/i2c-ESP32/)
|
8
docs/Sprint2/sprint2Review.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## Wie doet wat:
|
||||
|
||||
dano laat website zien, ik laat het dynamisch toevoegen van nodes zien, en een kleine uitleg waarom dit zo belangrijk is. Bram laat dan zien dat alle data in de database komt door een python script. Sam laat dan het fysieke model zien van het feedback scherm. Sietse laat de userstories zien. Dan laat dano de volgende documentatie zien:
|
||||
|
||||
- OOP - class grafiek
|
||||
- Infrastructuur - UML
|
||||
- Gebruikerstest - feedback scherm vragen
|
||||
- embedded ontwerpen en maken - tft screen van sam
|
73
docs/arduino-documentation/classes.md
Normal file
@@ -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/
|
||||
|
||||
|
||||
|
BIN
docs/assets/ImagesSp1/Sp13DDesignNode.png
Normal file
After Width: | Height: | Size: 656 KiB |
BIN
docs/assets/ImagesSp1/Sp13DDesignUpdated.png
Normal file
After Width: | Height: | Size: 718 KiB |
BIN
docs/assets/ImagesSp1/Sp1NodeBottomSide.png
Normal file
After Width: | Height: | Size: 338 KiB |
BIN
docs/assets/ImagesSp1/Sp1NodeUpperSide.png
Normal file
After Width: | Height: | Size: 347 KiB |
BIN
docs/assets/ImagesSp1/Sp1NodeUpperSideNew.png
Normal file
After Width: | Height: | Size: 500 KiB |
BIN
docs/assets/ImagesSp1/Sp1questionBoxNode.jpg
Normal file
After Width: | Height: | Size: 470 KiB |
BIN
docs/assets/ImagesSp1/assemblyOfNodeSideview.jpg
Normal file
After Width: | Height: | Size: 465 KiB |
BIN
docs/assets/ImagesSp1/assemblyOfNodeTopview.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/assets/ImagesSp1/sp1NodeSketch.jpg
Normal file
After Width: | Height: | Size: 445 KiB |
BIN
docs/assets/Node.fzz
Normal file
BIN
docs/assets/Node.png
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
docs/assets/Retrospectif.png
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/assets/Technical/Enquete box.f3d
Normal file
BIN
docs/assets/Technical/node casing v3.f3d
Normal file
BIN
docs/assets/Technical/node lower body.stl
Normal file
BIN
docs/assets/Technical/node upper body.stl
Normal file
BIN
docs/assets/funcionalInfra.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
docs/assets/imagesSp2/IMG_1131.jpg
Normal file
After Width: | Height: | Size: 2.1 MiB |
BIN
docs/assets/imagesSp2/fritzingscreen.png
Normal file
After Width: | Height: | Size: 151 KiB |
BIN
docs/assets/imagesSp3/retrosprint3.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
docs/assets/imagesSp3/wiringDiagramNode.png
Normal file
After Width: | Height: | Size: 130 KiB |
BIN
docs/assets/technicalInfra.png
Normal file
After Width: | Height: | Size: 32 KiB |
94
docs/brainstorm/Feedback.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# 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.
|
||||
|
||||
### Design questions led by bram
|
||||
For the nodes we designed to be placed around the 5th floor we were stuck between two designs:
|
||||
The wooden design: takes less time to create,is more fragile, and more eco-friendly.
|
||||
The Plastic: less eco-friendly, takes a longer time, looks objectively better.
|
||||
|
||||
since we can't decide on what we should use, I (Bram) went out to asks the public for their opinion.
|
||||
|
||||
To do this i took the front of the plastic design, and the front of the wooden design.
|
||||
They looked like this:
|
||||

|
||||
1. which design is more likable
|
||||
|
||||
/Sebas : plastic looks better and goes straight to the point.
|
||||
|
||||
/Skip : plastic looks more clean.
|
||||
|
||||
/Dano : plastic is more smooth.
|
||||
|
||||
/Sietse : plastic is better.
|
||||
|
||||
/Ishak : Wood is more ecofriendly.
|
||||
|
||||
/Nailah : PLastic looks cooler
|
||||
|
||||
|
||||
2. which design is more distracting.
|
||||
|
||||
/Sebas : wood is more distracting and more obvious.
|
||||
|
||||
/Skip : wood, because the school walls are more darker themed.
|
||||
|
||||
/Dano : wood looks off.
|
||||
|
||||
/Sietse : wood would be out of place.
|
||||
|
||||
/Ishak : Wood, but in a good way.
|
||||
|
||||
/Nailah : plastic looks more interesting.
|
||||
|
||||
|
||||
3. Any further comments about the design?
|
||||
|
||||
/Sebas : Don't do wood, plastic is more sleek.
|
||||
|
||||
/Skip : plastic looks more professional.
|
||||
|
||||
/Dano : no.
|
||||
|
||||
/Sietse: no.
|
||||
|
||||
/Ishak : in the wood you can burn in your logo.
|
||||
|
||||
/Nailah : The wood can look better inside the school.
|
||||
|
||||
|
||||
In conclusion, Even though the wood would atract more attention, the plastic looks better according to the students.
|
||||
So from this information we will continue to make plastic cases for the nodes.
|
@@ -1,5 +0,0 @@
|
||||
# Questions
|
||||
|
||||
How clean are the toilets (clean, normal, disgusting)
|
||||
How clean is the study area (clean, normal, disgusting)
|
||||
What do you think of the temparature in the study area (hot, perfect, cold)
|
31
docs/brainstorm/QuestionsEnquete.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Questions
|
||||
|
||||
## Criteria
|
||||
Questions shouldn't be able to measure using sensors. 3 possible answers.
|
||||
|
||||
## 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 on the 5th floor? (no, decently, yes).
|
||||
|
||||
### Feedback questions
|
||||
|
||||
- Zijn de vragen duidelijk en snel te beantwoorden hierboven?
|
||||
|
||||
- Hebben jullie nog andere feedback voor gebouwbeheer, die niet gemeten kan worden door sensoren?
|
||||
|
||||
## Feedback
|
||||
|
||||
1. vraag 5 is onduidelijk. Wat bedoel je met genoeg hulp? Docenten, schoonmakers? Andere manier formuleren over welke hulp. Andere vragen zijn duidelijk. Er kan een vraag worden toegevoegd over of het goed gaat met de studie of over de dag. Dit is niet heel hulpvol voor gebouwbeheer maar voor de studenten zelf wel.
|
||||
|
||||
|
||||
2. andere variant van antwoord geven op de vragen. Bijvoorbeeld een schaal van 1 tot 5. Of een schaal van 1 tot 10. Dit is makkelijker te verwerken en te analyseren. Voor de rest zijn de vragen duidelijk. Deze persoon heeft geen andere feedback voor gebouwbeheer want deze vragen zijn genoeg
|
||||
|
||||
3. De vragen zijn duidelijk en snel te beantwoorden. behalve vraag 5 die onduidleijk is. geen andere vragen vragen als feedback.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The questions are clear and easy to answer, except for question 5 which is unclear.
|
76
docs/brainstorm/SoftwareDocumentatie/Dev_page.md
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
|
||||
### 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);
|
||||
```
|
||||
|
||||
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) {
|
||||
nodeNumber = data.node;
|
||||
temperature = data.Temp;
|
||||
humidity = data.Humi;
|
||||
CO2 = data.eCO2;
|
||||
TVOC = data.TVOC;
|
||||
|
||||
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,
|
||||
'temp': temperature,
|
||||
'humi': humidity,
|
||||
'CO2': CO2,
|
||||
'TVOC': TVOC,
|
||||
});
|
||||
```
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
updateNodeData(nodeNumber, temperature, humidity, CO2, TVOC);
|
||||
```
|
||||
|
||||
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;
|
||||
document.getElementById("humidity" + node).textContent = humidity;
|
||||
document.getElementById("CO2" + node).textContent = eCO2;
|
||||
document.getElementById("TVOC" + node).textContent = TVOC;
|
||||
|
||||
// Update the status text
|
||||
document.getElementById("tempStatus").textContent = "Connected";
|
||||
document.getElementById("humidStatus").textContent = "Connected";
|
||||
document.getElementById("CO2Status").textContent = "Connected";
|
||||
document.getElementById("TVOCStatus").textContent = "Connected";
|
||||
}
|
||||
```
|
120
docs/brainstorm/SoftwareDocumentatie/classes-website.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Nodes
|
||||
|
||||
## Introduction
|
||||
|
||||
The nodes are the devices that are placed in the rooms. The nodes are used to collect the data from the sensors. Every node is connected to the websocket, and sends their data with their mac address in json format. The websocket broadcasts the node data back to all clients, and since our website functions as a client it also receives the data. Every node will, depending on what node, be made into a class.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Sensornode
|
||||
|
||||
- Every node has to have a unique nodeID
|
||||
- Every node has to have their corresponding sensorsvalues in form of arrays
|
||||
|
||||
### Feedbacknodes
|
||||
|
||||
- Every node has to have a unique nodeID
|
||||
- Every node has to have their corresponding feedback in form of a 2D array
|
||||
|
||||
## Class diagrams
|
||||
|
||||
### Node
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
|
||||
Node <-- SensorNode : extends
|
||||
Node <-- FeedbackNode : extends
|
||||
|
||||
class Node {
|
||||
+nodeID
|
||||
+processNodeData()
|
||||
+updateNodeData()
|
||||
}
|
||||
|
||||
class SensorNode {
|
||||
+tempArray
|
||||
+humiArray
|
||||
+eco2Array
|
||||
+tvocArray
|
||||
}
|
||||
|
||||
class FeedbackNode {
|
||||
+feedbackArray
|
||||
}
|
||||
```
|
||||
|
||||
# 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
|
||||
|
||||
### Graphs
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
|
||||
liveGraph --> graph: extends
|
||||
class graph {
|
||||
+nodeId
|
||||
makeGraph()
|
||||
}
|
||||
|
||||
class liveGraph {
|
||||
+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
|
||||
|
||||
### Node
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Node
|
||||
participant Raspberry pi
|
||||
participant Website
|
||||
|
||||
Node->>Raspberry pi: node data via websocket every 5 seconds
|
||||
Raspberry pi->>Website: Make a new object depending on what node it is
|
||||
Website->>Website: updateNodeData()
|
||||
Website->>Website: processNodeData()
|
||||
```
|
117
docs/brainstorm/SoftwareDocumentatie/classes.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Nodes
|
||||
|
||||
## Introduction
|
||||
|
||||
The nodes are the devices that are placed in the rooms. The nodes are used to collect the data from the sensors. Every node is connected to the websocket, and sends their data with their mac address in json format. The websocket broadcasts the node data back to all clients, and since our website functions as a client it also receives the data. Every node will, depending on what node, be made into a class.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Sensornode
|
||||
|
||||
- Every node has to have a unique nodeID
|
||||
- Every node has to have their corresponding sensorsvalues in form of arrays
|
||||
|
||||
### Feedbacknodes
|
||||
|
||||
- Every node has to have a unique nodeID
|
||||
- Every node has to have their corresponding feedback in form of a 2D array
|
||||
|
||||
## Class diagrams
|
||||
|
||||
### Node
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Node {
|
||||
+nodeID
|
||||
+processNodeData()
|
||||
+updateNodeData()
|
||||
}
|
||||
```
|
||||
|
||||
#### Sensornode
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class SensorNode extends Node {
|
||||
+tempArray
|
||||
+humiArray
|
||||
+eco2Array
|
||||
+tvocArray
|
||||
}
|
||||
```
|
||||
|
||||
#### Feedbacknode
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class FeedbackNode extends Node {
|
||||
+feedbackArray
|
||||
}
|
||||
```
|
||||
|
||||
# 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
|
||||
|
||||
### Graphs
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class graph {
|
||||
+nodeId
|
||||
makeGraph()
|
||||
}
|
||||
```
|
||||
|
||||
### Live graphs
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class liveGraph extends graph {
|
||||
+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
|
||||
|
||||
|
@@ -11,6 +11,9 @@ Raspberry pi <--> EnqueteNode : Websocket
|
||||
|
||||
namespace Server {
|
||||
class Raspberry pi {
|
||||
+MariaDB
|
||||
+Apache2
|
||||
+Python
|
||||
Database()
|
||||
Webserver()
|
||||
Websocket()
|
||||
@@ -27,7 +30,6 @@ namespace Server {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace User {
|
||||
class Website {
|
||||
+Co2
|
77
docs/brainstorm/UML-infrastructureV2.md
Normal file
@@ -0,0 +1,77 @@
|
||||
```mermaid
|
||||
classDiagram
|
||||
setup --> websocketSetup
|
||||
loop --> screenButtonHandler
|
||||
screenButtonHandler --> DisplayText
|
||||
screenButtonHandler --> sendData
|
||||
sendData --> Server : Websocket
|
||||
setup --> loop
|
||||
python --> Server
|
||||
Server --> website : Websocket
|
||||
|
||||
|
||||
namespace ESP32Questionbox {
|
||||
class setup {
|
||||
+int questionID
|
||||
+char*[] Question
|
||||
+char*[] Answer
|
||||
+DisplayText displayText
|
||||
+void websocketSetup()
|
||||
}
|
||||
|
||||
class loop {
|
||||
+void screenButtonHandler()
|
||||
+void sendData(int question, String answer)
|
||||
+void hexdump(const void* mem, uint32_t len, uint8_t cols)
|
||||
}
|
||||
|
||||
class websocketClient {
|
||||
+loop()
|
||||
+begin()
|
||||
+sendTXT()
|
||||
}
|
||||
|
||||
class websocketSetup {
|
||||
+connectWifi()
|
||||
+websocketConnect()
|
||||
}
|
||||
|
||||
class screenButtonHandler {
|
||||
-bool redButton
|
||||
-bool greenButton
|
||||
-bool whiteButton
|
||||
+displayText.writeText()
|
||||
+sendData()
|
||||
}
|
||||
class DisplayText {
|
||||
+void writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom)
|
||||
-int centerText(char* text)
|
||||
-void printWordsFull(char* text, bool bottom)
|
||||
}
|
||||
class sendData{
|
||||
+webSocket.sendTXT
|
||||
}
|
||||
}
|
||||
namespace server {
|
||||
class python {
|
||||
+databaseScript()
|
||||
+websocketScript()
|
||||
+flaskScript()
|
||||
}
|
||||
class Server {
|
||||
+websocket()
|
||||
+flask()
|
||||
+mariaDB()
|
||||
}
|
||||
}
|
||||
|
||||
namespace user {
|
||||
class website {
|
||||
+ getLiveData()
|
||||
+ getHistoricalData()
|
||||
+ showData()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
```
|
24
docs/brainstorm/gebouwBeheer.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Talk with building management
|
||||
|
||||
## Introduction
|
||||
We interviewed building management so we can clarify what they expect from the project and what they think of the state the project is in right now and if there need to be some adjustments. We also asked them some questions about the website and the node itself and the website. We primaly wanted clarity on what they thought on the website design because they are the ones that are going to use it the most.
|
||||
|
||||
## Questions for building management
|
||||
|
||||
1. Design of page? (current page, new design or own idea)
|
||||
2. What do they expect of a page made for building management?
|
||||
3. Do they think they can work with the incomming feedback from the enquete?
|
||||
4. Design of the node? (plastic or wood)
|
||||
|
||||
## Answers
|
||||
1. The current page is a bit too techincal and a bit unorganized. you couldnt tell that there is a new node added to the page. They also said that we needed to point out that there is another node connected for example start with half the ui of that specific node at the bottom of the screen.
|
||||
2. They expect a page that is easy to use and dummy proof.
|
||||
3. They think they can work with the incomming feedback from the enquete. And they thought it was a good idea to measure things that sensors cant measure for example peoples opinions.
|
||||
4. plastic is better because it is easier to clean and it is more durable. It also looks nicer on the wall, it blends in better.
|
||||
|
||||
## Feedback:
|
||||
|
||||
Building management had some good feedback points about the page itself, about the idea and some good pointers for the execution. They would also look into making the data they are already measuring accessible for us so we can compare it to our own sensors. The things they had to say about the website are: they found the first design a bit unorganized and said that they would rather see the second design we had in figma where you can select the node you want to see, maybe also a search function to specify the node that is displayed. What also was said was to try to make it idiot-proof because not all of the building management people are very technical. They had some things to say about the node design, like maybe make the color white to make it better with blending into the white walls of the total area. They also asked the question of does it matter at what height the node is placed. One other thing they said was to write something onto the node to make it clear to the people in the area what it was doing, something like ReaderNode™. And the last thing they said was if we thought about how to make sure it doesnt get vandalized.
|
||||
|
||||
## Conclusion
|
||||
Building management thought it was a good and interesting project. They wanna actively help us with the data they are already measuring and they had some good feedback points about the website and the node itself. They also had some good questions about the node itself that we need to look into. For example how are we are going to make sure it doesnt get vandalized. Furthermore they had good feedback on the website and they preffered our figma design over our current design and we needed to make the website dummy proof so everyone can use it even without technical knowledge.
|
83
docs/brainstorm/infrasturcture.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# The infrastructure
|
||||
|
||||
###
|
||||
|
||||
## Three layers
|
||||
|
||||
###
|
||||
|
||||
### functional
|
||||
|
||||
In the top layer of the infrastructure documentation, we are showing the functional flows of the information trafic between the user and the sensor/enquete that are located in the same room. The traffic consists of enviromental sensor values like temperature, humidity etc. Also it is showing the user input at the enquete device to the database that is hosted at the brain of the operation.
|
||||
|
||||

|
||||
|
||||
### Technical
|
||||
|
||||
In the middel layer we are showing the data flow and processing of the data at component level. It consists of 2 area's with 3 parts, namelie the server room and the building as in the common area. Here we send the data in JSON form that is collected at the enquete node (this is the feedback data) and the sensor node (this is the environmental data). This is sent to the database through the websocket that is running on the raspberry pi and than via a rest api sent to the database. If one of the operational manager would log in to the website. They would see the incomming sensor node data that is comming through, but also the data that is already collected and stored in the database.
|
||||
|
||||

|
||||
|
||||
### UML diagram of software
|
||||
|
||||
At the lowest level of our system we are showing how the software is designed. This is shown as a UML diagram. The diagram is made with mermaid. This shows the work flow of the different parts of the software which is running on the main server, for which we are using a Raspberry pi. The pi is located on the 6th floor of the school building in a locked server room.
|
||||
|
||||
``` mermaid
|
||||
classDiagram
|
||||
|
||||
Node --> Raspberry pi : Websocket
|
||||
Raspberry pi --> Website : getData
|
||||
Raspberry pi <--> EnqueteNode : Websocket
|
||||
|
||||
namespace Server {
|
||||
class Raspberry pi {
|
||||
+MariaDB
|
||||
+Apache2
|
||||
+Python
|
||||
Database()
|
||||
Webserver()
|
||||
Websocket()
|
||||
|
||||
}
|
||||
class Node {
|
||||
+Co2
|
||||
+Temperature
|
||||
+Humidity
|
||||
+Tfok
|
||||
+Sound
|
||||
collectData()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace User {
|
||||
class Website {
|
||||
+Co2
|
||||
+Temperature
|
||||
+Humidity
|
||||
+Tfok
|
||||
+Sound
|
||||
+Graph
|
||||
+Map
|
||||
+Settings
|
||||
GetData()
|
||||
}
|
||||
|
||||
class EnqueteNode {
|
||||
+Co2
|
||||
+Temperature
|
||||
+Humidity
|
||||
+Tfok
|
||||
+Sound
|
||||
+Graph
|
||||
+Map
|
||||
+QuestionResponse
|
||||
EnqueteDisplay()
|
||||
EnqueteButtons()
|
||||
GetData()
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
BIN
docs/brainstorm/samenwerkingTijdlijn.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
@@ -1,8 +1,10 @@
|
||||
# TI Portfolio Website
|
||||
|
||||
## Team deurMat
|
||||
Welkom op jullie portfolio website! Hier kunnen jullie documentatie kwijt
|
||||
die jullie gaan schrijven voor jullie project.
|
||||
|
||||
Maak je pagina's vooral leuk door [plaatjes](https://knowledgebase.hbo-ict-hva.nl/1_beroepstaken/software/realiseren/talen/declaratief/markdown/1_markdown_basics/#afbeeldingen), [video's](https://knowledgebase.hbo-ict-hva.nl/1_beroepstaken/software/realiseren/talen/declaratief/markdown/videos/) en [diagrammen](https://knowledgebase.hbo-ict-hva.nl/1_beroepstaken/software/realiseren/talen/declaratief/markdown/mermaid_diagrammen/) toe te voegen; dit kan allemaal in [markdown](https://knowledgebase.hbo-ict-hva.nl/1_beroepstaken/software/realiseren/talen/declaratief/markdown/0_markdown/)!
|
||||
|
||||
|
||||
|
||||
{{ mdocotion_header('https://images.unsplash.com/photo-1498050108023-c5249f4df085?q=80&w=2072&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D') }}
|
||||
|
20
docs/node-documentation/NodeClassDocumentation.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# OOP within Arduino
|
||||
|
||||
Object-Oriented Programming (OOP) is a way of programing that provides a means of structuring your code so the code is modular and can be used more often without making huge changes or having to copy past the same code.
|
||||
|
||||
## Abstraction
|
||||
|
||||
Abstraction in OOP is the process of exposing only the required essential variables and functions. This means hiding the complexity and only showing the essential features of the object. In Arduino, this could mean creating a class like `Sensor node` with methods such as `setUp()`, `displayData()`, and `checkForError()`.
|
||||
|
||||
## Encapsulation
|
||||
|
||||
Encapsulation is the technique used to hide the data and methods within an object and prevent outside access. In Arduino, this could mean having private variables and methods in a class that can only be accessed and modified through public methods.
|
||||
|
||||
## Which classes did we use
|
||||
|
||||
In this Arduino project, we used several classes to organize our code and manage the complexity of the project. Some of these classes include:
|
||||
|
||||
- `websockets`: This class is responsible for managing the WebSocket connections.
|
||||
- `nodeReadings`: This class is responsible for managing the sensor readings.
|
||||
|
||||
Each of these classes encapsulates the data and methods related to a specific part of the project, making the code easier to understand and maintain.
|
43
docs/node-documentation/NodeClassUml.md
Normal file
@@ -0,0 +1,43 @@
|
||||
### Uml diagram:
|
||||
|
||||
``` mermaid
|
||||
classDiagram
|
||||
|
||||
namespace Esp {
|
||||
class Websockets{
|
||||
+webSocket
|
||||
+_WiFiMulti
|
||||
hexdump()
|
||||
websocketSetup()
|
||||
loop()
|
||||
webSocketEvent()
|
||||
sendMyText()
|
||||
}
|
||||
|
||||
class NodeReadings{
|
||||
|
||||
+TVOC_base, eCO2_base
|
||||
+counter
|
||||
+eCO2
|
||||
+TVOC
|
||||
+interval
|
||||
+temperature
|
||||
+humidity
|
||||
+currentMillis
|
||||
+lastMillis
|
||||
+errorSGP30
|
||||
+errorDHT11
|
||||
+noise
|
||||
|
||||
setup()
|
||||
loop()
|
||||
resetValues()
|
||||
update()
|
||||
checkForError()
|
||||
displayData()
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
```
|
111
docs/node-documentation/TFT-screen.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# TFT screen
|
||||
|
||||
|
||||
## Prequesites
|
||||
|
||||
To use the TFT screen, you need to install the following libraries:
|
||||
|
||||
``` SPI.h , Adafruit_GFX.h, Adafruit_ST7796S_kbv.h ```
|
||||
|
||||
|
||||
## Programming the screen
|
||||
To program the screen we need to first declare all the pins and give it to the Adafruit_ST7796S_kbv.h library. Then we need to initialize the screen and we can start using it.
|
||||
|
||||
```cpp
|
||||
#define TFT_CS 14
|
||||
#define TFT_DC 13
|
||||
#define TFT_RST 12
|
||||
#define MOSI 11
|
||||
#define SCK 10
|
||||
#define MISO 9
|
||||
|
||||
//simplify the name of the library and feed all the correct pins to it
|
||||
|
||||
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, MOSI, SCK, TFT_RST, MISO);
|
||||
```
|
||||
|
||||
## Drawing on the screen
|
||||
|
||||
To draw on the screen we can use the following functions:
|
||||
|
||||
```cpp
|
||||
tft.fillScreen(0x0000); //clear the screen
|
||||
tft.fillRect(0, 0, 240, 240, 0xFFFF); //draw a white rectangle
|
||||
tft.fillCircle(120, 120, 50, 0xF800); //draw a red circle
|
||||
tft.fillTriangle(0, 0, 240, 240, 0, 240, 0x1F); //draw a blue triangle
|
||||
tft.fillRoundRect(0, 0, 240, 240, 10, 0xF81F); //draw a pink rounded rectangle
|
||||
tft.drawChar(120, 120, 'A', 0xFFFF, 0x0000, 2); //draw a character
|
||||
tft.setTextSize(2); //set the text size
|
||||
tft.setTextColor(0xFFFF); //set the text color
|
||||
tft.setCursor(0, 0); //set the cursor
|
||||
tft.println("Hello World!"); //print a string
|
||||
```
|
||||
|
||||
To write Hello world on the screen we can use the following code:
|
||||
|
||||
```cpp
|
||||
tft.fillScreen(0x0000); //clear the screen
|
||||
tft.setTextSize(2); //set the text size
|
||||
tft.setTextColor(0xFFFF); //set the text color
|
||||
tft.setCursor(0, 0); //set the cursor so it starts at the top right, you can also make this other numbers to change the position
|
||||
tft.println("Hello World!"); //print a string
|
||||
```
|
||||
|
||||
To clear the screen for new text you can use the following code:
|
||||
|
||||
```cpp
|
||||
tft.fillScreen(0x0000); //clear the screen
|
||||
```
|
||||
## Wiring
|
||||
You can connect the wires to any pin except the vcc and the ground. The vcc and ground need to be connected to the 3.3v and ground of the esp32. The other pins can be connected to any pin of the esp32.
|
||||
|
||||

|
||||
|
||||
We aren't using the cs2 and the pen pin because we arent utilizing the touch function of the screen.
|
||||
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
|
||||
displayText <|-- Adafruit_ST7796S_kbv
|
||||
|
||||
|
||||
class displayText{
|
||||
+text
|
||||
+color
|
||||
+size
|
||||
+posx
|
||||
+posy
|
||||
+void writeText()
|
||||
-int bottomText(char* text)
|
||||
-void printWordsFull(char* text)
|
||||
-int centerText(char* text)
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Adafruit_ST7796S_kbv{
|
||||
+fillScreen()
|
||||
+fillRect()
|
||||
+fillCircle()
|
||||
+fillTriangle()
|
||||
+fillRoundRect()
|
||||
+drawChar()
|
||||
+setTextSize()
|
||||
+setTextColor()
|
||||
+setCursor()
|
||||
+println()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Why did we choose for this screen?
|
||||
|
||||
We chose the screen too fast without going over all the functions and researching what we actually needed. For example we aren't using the touchscreen function of the screen so we could've gotten a different screen without touchscreen. We've attempted to use a screen for the raspberry pi with some pin headers on it but we couldn't get it to work with the esp32. We wanted to have a bigger screen than the small oled screens we already have because it isn't nice to read from and you need to get up close to see what it displays. With a bigger screen thats less of a issue. After the purchase we did some more research for screens but the bottomline was this was the best one we could get because there aren't screens that are this big without touchscreen.
|
||||
|
||||
|
||||
## Sources
|
||||
* https://www.tinytronics.nl/en/displays/tft/4-inch-tft-display-320*480-pixels-with-touchscreen-spi-st7796s Source for Driver
|
||||
* https://github.com/prenticedavid/Adafruit_ST7796S_kbv Download link for the library
|
||||
|
89
docs/node-documentation/node-design.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 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:
|
||||
|
||||

|
||||
|
||||
### 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:
|
||||
|
||||

|
||||
|
||||
### 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:
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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 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]
|
||||
```
|
||||
|
||||
## 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:
|
80
docs/node-documentation/node.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Node
|
||||
|
||||
Since the node is what gathers all the data from the sensors, it is the most important part of the system. The node is responsible for reading the data from the sensors, processing it, and sending it to the server.
|
||||
|
||||
## Hardware
|
||||
|
||||
The node is composed of the following hardware components:
|
||||
|
||||
- [ESP32 S3 DevkitC](https://www.espressif.com/en/products/socs/esp32-s3)
|
||||
- [SGP30](https://www.sensirion.com/en/environmental-sensors/gas-sensors/sgp30/)
|
||||
- [DHT11](https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT11.pdf)
|
||||
- [OLED Display](https://www.tinytronics.nl/nl/displays/oled/1.3-inch-oled-display-128*64-pixels-wit-i2c)
|
||||
|
||||
## Software
|
||||
|
||||
The node is programmed using the Arduino IDE. The code is written in C++ and is responsible for reading the data from the sensors, processing it, and sending it to the server. The first couple versions of the code were written by Sietse, and because we all had to use Object Oriented Programming, Dano rewrote the code to be object-oriented. Which is now final version
|
||||
|
||||
### Libraries
|
||||
|
||||
The following libraries are used in the node code:
|
||||
|
||||
- Wire.h
|
||||
- Adafruit_SH110X.h
|
||||
- Adafruit_SGP30.h
|
||||
- DHT.h
|
||||
- WiFiMulti.h
|
||||
- WiFi.h
|
||||
- WebSocketsClient.h
|
||||
- nodeCodeHeader.h
|
||||
|
||||
### Code
|
||||
|
||||
The code is divided into the following classes:
|
||||
|
||||
- Node readings
|
||||
- Websockets
|
||||
|
||||
The two classes that are used are split into the 2 becouse the node readings handels everything about reading information from the sensors and displaying them on the screen, all the local stuff is handeled here so to speak. And into Websockets this handels every thing from connecting to the wifi to sending the data that is recorded from the sensors into json format and sending that data to the websockets so that the data can be prossed over there.
|
||||
|
||||
### Communication
|
||||
|
||||
The node communicates with the server using WebSockets. The node sends the data to our website which uses a reverse proxy to route it to the websocket. The server then processes the data and stores it in the database / puts it on the website. We use the WebSocketsClient library to communicate with the server. Because [websocket connections](docs\rpi-documentation\websockets.md) are stateful, we need to keep the connection alive. So we do not use any delays in the code, but instead use the millis() function to keep track of time.
|
||||
|
||||
Flow of the data:
|
||||
|
||||
```mermaid
|
||||
|
||||
flowchart LR
|
||||
A(Sensors)
|
||||
B(Node)
|
||||
D(Websocket)
|
||||
E(Website)
|
||||
F(DB-Client)
|
||||
G(Database)
|
||||
|
||||
A-->|sensordata| B
|
||||
B -->|JSONData| D
|
||||
D -->|JSONData| E
|
||||
D -->|JSONData| F
|
||||
F -->|Data| G
|
||||
```
|
||||
|
||||
### Wiring Diagram
|
||||
|
||||
The wiring diagram for the node is as follows:
|
||||
|
||||

|
||||
|
||||
|
||||
### Fritsing Diagram
|
||||
|
||||

|
||||
|
||||
## Future Improvements
|
||||
|
||||
The node is currently working as intended, but there are some improvements that could be made:
|
||||
|
||||
- The node could be made more energy efficient by putting the ESP32 in deep sleep mode when it is not sending data.
|
||||
- The node could be made more robust by adding error handling to the code.
|
||||
- The node could be made more secure by adding encryption to the data that is sent to the server.
|
298
docs/rpi-documentation/Databaseconnection.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# Original Database - Websocket connection(by bram)
|
||||
For our project, we needed to establish an efficient and functional connection between a live data collector and a database where this data would be stored.
|
||||
|
||||
The data we collected originated from live "nodes" which were small boxes equipped with various types of sensors to gather specific data from their surroundings.
|
||||
|
||||
This collected data needed to be transmitted to a database to facilitate its presentation on a website we were developing. The website would retrieve the data from the database and display it in various formats.
|
||||
|
||||
This is what the connection would be inserted.
|
||||

|
||||
|
||||
Given the high demand of this data connection for our project, it was imprtant that it was reliably. Bram was given the task to designing a connection in Python between the WebSocket (live server) and the database (data storage).
|
||||
|
||||
Since we had the WebSocket data on a Raspberry Pi, it made sense to make the connection on the Pi itself. This became an opportunity for Bram to gain knowledge about Python, considering he originaly didn't have experience with this programming language.
|
||||
## Python code + explaination
|
||||
In the given Raspberry Pi, a file named "data.py" was created, from which this script could be called when needed.
|
||||
|
||||
At the beginning of the file, the code starts with importing the different required libraries.
|
||||
```py
|
||||
#this library makes functions run simultaneously
|
||||
import asyncio
|
||||
#This library makes the connection to the websocket possible.
|
||||
import websockets
|
||||
#This library makes a connection with the database
|
||||
import mysql.connector
|
||||
#This library makes json data readable.
|
||||
import json
|
||||
```
|
||||
Afterward, a function would be called related to the "mysql.connector" library, where you would provide the login credentials of the database you have set up to establish a solid connection. This connection will be utilized multiple times later in the code.
|
||||
```py
|
||||
#async is making use of the asyncio library.
|
||||
async def process_data(data):
|
||||
try:
|
||||
mydb = mysql.connector.connect(
|
||||
host="localhost",
|
||||
user="root",
|
||||
# pasword hidden for privacy
|
||||
password="********",
|
||||
database="NodeData"
|
||||
)
|
||||
cursor = mydb.cursor()
|
||||
```
|
||||
This next part has a lot of different functions, so it will be split up for clarity.
|
||||
|
||||
It begins with creating a variable to retrieve information from a specific part of the database. This information is then stored in an array later on. In this case, it is selecting the existing MAC addresses from the database.
|
||||
|
||||
Afterward, a query is made for a different part of the code and acts as a "mold" for the data to be sent to the database. The values are not inserted yet because these will be the data collected from the nodes.
|
||||
```py
|
||||
#variable to connect to the DB
|
||||
MACDataReading = mydb.cursor()
|
||||
#get data from DB
|
||||
MACDataReading.execute("SELECT MAC FROM Node")
|
||||
#make a mold for the data to get to the DB
|
||||
query = "INSERT INTO `Measurement` (NodeID, Type, Value) VALUES (%s, %s, %s)"
|
||||
```
|
||||
In the next part of the code, the data collected from the node (which is done later on) is processed here and made readable for the Python code.
|
||||
|
||||
This processed data is then split up into five different types: the temperature, the humidity, the eCO2 and TVOC values, and the MAC address from which this information was sent.
|
||||
|
||||
The MAC address is then taken and turned into a tuple. This is done because the database expects a tuple to be inserted instead of a string.
|
||||
|
||||
(for more information on tuples I suggest visiting https://www.w3schools.com/python/python_tuples.asp)
|
||||
```py
|
||||
#load the json data and make it readable.
|
||||
processedData = json.loads(data)
|
||||
#divide the data into types
|
||||
processedTemp = (processedData['Temp'])
|
||||
processedHumi = (processedData['Humi'])
|
||||
processedeCO2 = (processedData['eCO2'])
|
||||
processedTvoc = (processedData['TVOC'])
|
||||
processedMAC = (processedData['node'])
|
||||
#make a tuple of the MAC by placing a comma.
|
||||
MACTuple = (processedMAC,)
|
||||
```
|
||||
Coming back to the previous lines of code, the data which was first asked for is now gathered and put into an array.
|
||||
|
||||
This array is then examined, and all the data is compared to the newly obtained MAC address.
|
||||
|
||||
If it is not found, then the new MAC address is added to the database. This makes automation much easier and makes the process of adding a new node easy.
|
||||
```py
|
||||
#fetching data and adding to an array.
|
||||
MACDataFetching = MACDataReading.fetchall()
|
||||
MACArray = list(MACDataFetching)
|
||||
#see if the given MAC is not in the array.
|
||||
if MACTuple not in MACArray:
|
||||
#a query to insert the new MAC in the DB
|
||||
addingNode = "INSERT INTO `Node` (MAC) VALUES (%s)"
|
||||
#combine the query and the data and push it.
|
||||
cursor.execute(addingNode, MACTuple)
|
||||
mydb.commit()
|
||||
```
|
||||
From here the data which was collected from the websocket gets placed in an array together with a few guidlines to propperly place it in the correct files on the database.
|
||||
|
||||
After going along all instances of the array, the data gets pushed together with the query to propperly enter the database.
|
||||
|
||||
Sadly this version of the code is only able to push the data from the one node because of some errors within the datase.
|
||||
(This is later fixed in the updated version my teammate made.)
|
||||
```py
|
||||
#making an array with the data to sort it and be able to be pushed to the database.
|
||||
pushingDataArray = [(1, "Temp", processedTemp), (1, "Humi", processedHumi), (1, "eCO2", processedeCO2), (1, "TVOC", processedTvoc)]
|
||||
#go along all instances in the array, and combine this with the query.
|
||||
for i in pushingDataArray:
|
||||
print(query ,i)
|
||||
cursor.execute(query, i)
|
||||
mydb.commit()
|
||||
#in the case of an error, show what and where, and after, close the database connection.
|
||||
except mysql.connector.Error as err:
|
||||
print("MySQL Error:", err)
|
||||
finally:
|
||||
cursor.close()
|
||||
mydb.close()
|
||||
```
|
||||
In the next function, the connection is established with the WebSocket and collects the data sent by the nodes. This data is then stored in a variable named "data". (This data is the same data that was being processed to make it readable for Python and was split up in differnt types.)
|
||||
|
||||
This function also verifies if the WebSocket connection can be established and provides an error message when this is not the case.
|
||||
```py
|
||||
async def receive_data():
|
||||
uri = "ws://145.92.8.114/ws"
|
||||
|
||||
try:
|
||||
async with websockets.connect(uri) as websocket:
|
||||
while True:
|
||||
data = await websocket.recv()
|
||||
print(f"Received data: {data}")
|
||||
await process_data(data)
|
||||
except websockets.ConnectionClosedError as e:
|
||||
print("WebSocket connection closed:", e)
|
||||
```
|
||||
This is one of the last functions where the file is instructed to wait for a WebSocket connection before executing the code. This is done to prevent false data from entering the database.
|
||||
```py
|
||||
async def main():
|
||||
await receive_data()
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
As a summary, this code is meant to establish connections both to the database and the WebSocket to enable a data connection between them. When new data arrives, it will be pushed to the database, and if a new MAC address is encountered, it will be added to the list of addresses.
|
||||
|
||||
(The link to the code https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59/-/blob/main/server/web-data-connection/data.py?ref_type=heads)
|
||||
|
||||
# New Version (by sietse)
|
||||
|
||||
## Changes made
|
||||
|
||||
The original code was a good start, but it had some issues. The code could only handle the data from the sensorNodes and didn't include the nodeID for measurements.
|
||||
|
||||
Since we have 2 kind of nodes (sensorNodes and enqueteNodes) we needed to make another function to commit the enqueteData in the database. I have also made a filter to know which data is from the sensorNodes and which data is from the enqueteNodes. This way we can commit the data to the right table in the database.
|
||||
|
||||
I have also added a function to get the nodeID from the MAC address. This way we can commit the data to the right node in the database.
|
||||
|
||||
## The new "filter" code
|
||||
|
||||
### Function to get a list with macAdresses from the sensorNodes and enqueteNodes
|
||||
|
||||
To filter i have made 2 lists, one with all the mac adresses of the sensorNodes and the other with the mac adresses of the enqueteNodes.
|
||||
|
||||
The function that handles that and updates the list is the following:
|
||||
|
||||
```python
|
||||
async def getNodeInfo(type):
|
||||
global sensorNodeArray
|
||||
global enqueteNodeArray
|
||||
|
||||
nodeInfoArray = []
|
||||
|
||||
id = (type,)
|
||||
mydb = dbLogin()
|
||||
cursor = mydb.cursor()
|
||||
cursor.execute("""SELECT MAC FROM Node WHERE Type = %s""", id)
|
||||
nodeInfo = cursor.fetchall()
|
||||
|
||||
for tuples in nodeInfo:
|
||||
for item in tuples:
|
||||
nodeInfoArray.append(item)
|
||||
print(nodeInfoArray)
|
||||
|
||||
cursor.close()
|
||||
mydb.close()
|
||||
|
||||
if type == 'sensor':
|
||||
sensorNodeArray = nodeInfoArray
|
||||
print(sensorNodeArray)
|
||||
return sensorNodeArray
|
||||
|
||||
elif type == 'enquete':
|
||||
enqueteNodeArray = nodeInfoArray
|
||||
return enqueteNodeArray
|
||||
```
|
||||
|
||||
As you can it works like this:
|
||||
|
||||
1. It gets the MAC adresses from the database with the type of node you want to get the data from. (sensor or enquete)
|
||||
|
||||
2. It executes the command and puts the data in a list.
|
||||
|
||||
3. It uses a nested for loop to get the data out of the tuples and puts it in the nodeInfoArray.
|
||||
|
||||
4. It updates, depending on what type, the sensorNodeArray or the enqueteNodeArray with the new data (NodeInfoArray).
|
||||
|
||||
5. It returns the array with the data.
|
||||
|
||||
### The filter code
|
||||
|
||||
Now that we have the data we can filter the data from the websocket.
|
||||
|
||||
```python
|
||||
data = await websocket.recv()
|
||||
|
||||
processedData = json.loads(data)
|
||||
macAdress = processedData['node']
|
||||
|
||||
if "Temp" in processedData:
|
||||
type = 'sensor'
|
||||
else:
|
||||
type = 'enquete'
|
||||
|
||||
await getNodeInfo('sensor')
|
||||
await getNodeInfo('enquete')
|
||||
|
||||
if macAdress in sensorNodeArray:
|
||||
nodeID = await getNodeID(macAdress)
|
||||
await processSensorNodeData(data, nodeID)
|
||||
elif macAdress in enqueteNodeArray:
|
||||
nodeID = await getNodeID(macAdress)
|
||||
await processEnqueteNodeData(data, nodeID)
|
||||
else:
|
||||
await newNode(macAdress, type)
|
||||
```
|
||||
|
||||
As you can see its alot of code to explain. So to make it easier i made a mermaid diagram to show how the code works / what it does.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Get data from websocket] --> B{Is it sensor data or enquete data?}
|
||||
B -->|sensor| C[Get sensorNodeArray]
|
||||
B -->|enquete| D[Get enqueteNodeArray]
|
||||
B -->|New node| E[Add new node to database]
|
||||
C -->|data| G[Process sensorNodeData]
|
||||
D -->|data| H[Process enqueteNodeData]
|
||||
```
|
||||
|
||||
## The function to get the nodeID
|
||||
|
||||
This function is used to get the nodeID from the MAC adress. This way we can commit the data with the right id in the database.
|
||||
|
||||
The function to get the nodeID from the MAC adress is the following:
|
||||
|
||||
```python
|
||||
async def getNodeID(macAdress):
|
||||
id = (macAdress,)
|
||||
mydb = dbLogin()
|
||||
cursor = mydb.cursor()
|
||||
cursor.execute("""SELECT nodeID FROM Node WHERE MAC = %s""", id)
|
||||
data = cursor.fetchall()
|
||||
|
||||
for tuples in data:
|
||||
for item in tuples:
|
||||
nodeID = item
|
||||
|
||||
return nodeID
|
||||
```
|
||||
|
||||
1. It gets the nodeID from the database with the MAC adress.
|
||||
2. It executes the command and puts the data in a list.
|
||||
3. It uses a nested for loop to get the data out of the tuples and puts it in the nodeID.
|
||||
4. It returns the nodeID.
|
||||
|
||||
## The function to commit the data from the sensorNodes
|
||||
|
||||
This function is alot like the original one, with the only 2 changes being that it now also commits the nodeID and that the code to make a new node is now in a different function.
|
||||
|
||||
[link to code](../../server/web-data-connection/data.py)
|
||||
|
||||
## The function to commit the data from the enqueteNodes
|
||||
|
||||
This function is alot like the sensorNode function. It just commits the data to the enqueteData table in the database. And it has another data.
|
||||
|
||||
[Link to code](server\data.py)
|
||||
|
||||
## The function to add a new node to the database
|
||||
|
||||
This function is used to add a new node to the database. This is used when a new node is connected to the websocket, but not yet in the database.
|
||||
|
||||
The function to add a new node to the database is the following:
|
||||
|
||||
```python
|
||||
async def newNode(mac, type):
|
||||
id = (mac, type)
|
||||
mydb = dbLogin()
|
||||
|
||||
cursor = mydb.cursor()
|
||||
cursor.execute("INSERT INTO `Node` (MAC, Type) VALUES (%s, %s)", id)
|
||||
print("new node assigned")
|
||||
mydb.commit()
|
||||
```
|
||||
|
||||
1. It gets the MAC adress and the type of node from the arguments.
|
||||
2. It executes the command to add the new node to the database.
|
||||
3. It prints that a new node is assigned.
|
||||
4. It commits the data to the database.
|
16
docs/rpi-documentation/Flask.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Flask
|
||||
|
||||
|
||||
## Introduction
|
||||
Flask is a micro web framework written in Python. It is easy to use and has a lot of documentation. We are going to use Flask to serve our REST api.
|
||||
|
||||
## Cheatsheet
|
||||
```python
|
||||
print(f"Hello world have a nice {args}!")
|
||||
```
|
||||
This way you can put variables in a string. This is called f-strings.
|
||||
|
||||
|
||||
|
||||
## Rules for python
|
||||
* You can only use one return statement in a function.
|
BIN
docs/rpi-documentation/MyConnection.png
Normal file
After Width: | Height: | Size: 24 KiB |