241 Commits

Author SHA1 Message Date
Dano van den Bosch
013ff4cffa Set up for making the class for the graph page 2024-03-23 11:46:18 +01:00
Sietse Jonker
e5d2f23d59 Add classes and graphs documentation 2024-03-22 12:45:02 +01:00
Sietse Jonker
8ae69a6fbe Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-22 12:35:23 +01:00
Sietse Jonker
dcc99c1258 Add graph class and extend liveGraph from graph 2024-03-22 12:35:22 +01:00
Bram Barbieri
7104331e4c Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-22 12:28:25 +01:00
Bram Barbieri
11f9f53f6b database documentation updated 2024-03-22 12:28:23 +01:00
Dano van den Bosch
4708c9c71e Stand up note 2024-03-22 12:07:50 +01:00
Sietse Jonker
cb1dbe8b11 Fix import statement in node.md and remove extra line in main.py 2024-03-22 11:52:51 +01:00
Bram Barbieri
61c8d09760 Bram documentation 2024-03-21 16:48:52 +01:00
sietse jonker
f2907117be Add Node Documentation to navigation 2024-03-21 16:34:34 +01:00
sietse jonker
0ecc2457e7 adds future improvements 2024-03-21 16:33:26 +01:00
sietse jonker
fde715d7ed Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-21 16:32:13 +01:00
sietse jonker
e2ffcc4fa1 Add node documentation and wiring diagram 2024-03-21 16:32:11 +01:00
Bram Barbieri
adce47db3a Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-21 16:23:39 +01:00
Bram Barbieri
3d85220adc added fritzing to BRam documentation 2024-03-21 16:23:36 +01:00
54a2eef7c5 Added so you can change node information 2024-03-21 13:22:09 +01:00
09522218f3 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-21 12:19:04 +01:00
4cf78ddb0b Added reverseproxy script 2024-03-20 16:09:20 +01:00
6ce7ac8c97 Added documenation about put request 2024-03-20 16:09:15 +01:00
Dano van den Bosch
cd56c45c47 Daily stand up for 20/03 2024-03-20 13:18:08 +01:00
Bram Barbieri
5bf19a82ff bram documentation 2024-03-20 12:02:22 +01:00
Bram Barbieri
38d34cce91 Bram comment 2024-03-20 11:30:52 +01:00
Bram Barbieri
c0034acf65 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-20 11:16:34 +01:00
Bram Barbieri
d52eabbb61 Bram documentation 2024-03-20 11:16:31 +01:00
5b327942be Added comment 2024-03-19 16:01:53 +01:00
89956bc4c8 Added put request 2024-03-19 15:50:00 +01:00
15504eaea6 Daily standup 2024-03-19 12:21:15 +01:00
Bram Barbieri
a82acc526c BramDocs 2024-03-19 11:59:37 +01:00
Bram Barbieri
5fa07f3a82 foldername change 2024-03-19 11:15:59 +01:00
Bram Barbieri
54fc6f2306 hoofdletter correctie. 2024-03-15 12:40:38 +01:00
Bram Barbieri
a707c4f9bb pages updated 2024-03-15 12:39:27 +01:00
Bram Barbieri
b8fbf0dfaf database documentation presentable 2024-03-15 12:13:51 +01:00
Bram Barbieri
b4dcdf7609 daily standup. 2024-03-15 11:18:58 +01:00
1c7fd2ab68 REST APi 2024-03-14 19:20:01 +01:00
6ea17a63c7 Added a script that sends junk to the websocket to act as a node 2024-03-14 19:19:52 +01:00
Bram Barbieri
a2ff97d7fb database websocket
documentation
2024-03-14 18:46:46 +01:00
Bram Barbieri
6c60a184b8 database websocket connection documentation. 2024-03-14 18:05:38 +01:00
Bram Barbieri
28ff778ce8 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-14 14:30:44 +01:00
Bram Barbieri
d20e6db9fe standup 2024-03-14 14:30:41 +01:00
ef8821fe48 Merge branch '44-als-gebruiker-wil-ik-dat-de-website-automatisch-het-aantal-nodes-dat-ik-heb-aangesloten-op-de' into 'main'
working version to main

See merge request propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59!6
2024-03-14 12:03:16 +01:00
Sietse Jonker
072ff99624 Merge branch 'main' into '44-als-gebruiker-wil-ik-dat-de-website-automatisch-het-aantal-nodes-dat-ik-heb-aangesloten-op-de'
# Conflicts:
#   arduino/node-code/node-code-final/node-code-final.ino
#   arduino/node-code/node-code-final/nodeCodeFinal.ino
#   arduino/node-code/node-code-final/nodeCodeHeader.h
2024-03-14 12:02:13 +01:00
035a7f4c72 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-13 17:56:09 +01:00
23bfbdada5 Removed PK nodeID at measurement 2024-03-13 17:56:05 +01:00
47f1f393da Added parameters 2024-03-13 17:55:50 +01:00
Dano van den Bosch
10eee12189 Arduino oop adding functions from the original aduino code 2024-03-13 16:06:10 +01:00
Dano van den Bosch
c4880ce0e2 Added the header files to for changing the arduino code to OOP 2024-03-13 15:47:42 +01:00
Dano van den Bosch
3801b074f6 Arduino oop 2024-03-13 15:03:11 +01:00
Sietse Jonker
25de52c54b Refactor classes and update documentation 2024-03-13 14:53:40 +01:00
7b6f8463cd Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-13 14:45:33 +01:00
b8f8f5ea7e Added flask script 2024-03-13 14:45:29 +01:00
6efac7b179 New Flask documentation 2024-03-13 14:45:23 +01:00
023a1b0781 Moved files 2024-03-13 14:45:13 +01:00
Sietse Jonker
6c3b523208 Update webSocket message format and add classes for websockets 2024-03-13 14:44:32 +01:00
Bram Barbieri
7f5db74732 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-13 13:08:05 +01:00
Bram Barbieri
ddb7df5679 bram docs + daily standup 2024-03-13 13:08:03 +01:00
Dano van den Bosch
d7a762f30c Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-13 13:08:02 +01:00
Dano van den Bosch
85a49151ac JSON format message 2024-03-13 13:07:49 +01:00
Bram Barbieri
0ab0b433ab Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-13 12:49:49 +01:00
Bram Barbieri
8b0be0d6bd bram documentation 2024-03-13 12:49:48 +01:00
Dano van den Bosch
5d2223e5d7 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-13 11:49:29 +01:00
Dano van den Bosch
dd6b5caa33 Begin aan OOP in arduino 2024-03-13 11:49:25 +01:00
8da5b9f215 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-12 19:48:50 +01:00
4fd0badd3c Added Enquete box 2024-03-12 19:48:46 +01:00
15f897f4d9 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-12 16:24:30 +01:00
d542da7db9 attempt to write text in full 2024-03-12 16:24:26 +01:00
Bram Barbieri
8aeca410fc Bram documentation updated and code explained 2024-03-12 11:28:30 +01:00
Bram Barbieri
57ee918b64 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-12 11:06:56 +01:00
Bram Barbieri
57a556ab6c daily standup, bram documentation 2024-03-12 11:06:54 +01:00
1bafce0015 Added documentation 2024-03-12 11:05:11 +01:00
Bram Barbieri
fd260d9c56 Bram documentation spelling check 2024-03-11 16:17:46 +01:00
Bram Barbieri
f8489bca01 Bram documentation 2024-03-11 15:15:18 +01:00
Bram Barbieri
cc92eff4f8 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-11 14:46:31 +01:00
Bram Barbieri
4d0bd8aa43 Bram assets + docs 2024-03-11 14:46:28 +01:00
dec48091f4 Typo 2024-03-11 14:19:42 +01:00
Sam
3fe74603ca Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-11 13:52:09 +01:00
Sam
c90fda2977 Updated uml tft screen class 2024-03-11 13:52:06 +01:00
Bram Barbieri
b27f9f8ed6 Bram Evidence folder 2024-03-10 16:04:14 +01:00
Bram Barbieri
d21776cfc4 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-10 15:50:58 +01:00
Bram Barbieri
3bdc81b320 Bram Documentation 2024-03-10 15:50:55 +01:00
Sietse Jonker
856775c2a8 Update WiFi password and handle node addresses 2024-03-08 16:46:02 +01:00
sam
649ea5e1a6 Edited database 2024-03-08 14:25:33 +01:00
sam
60d86bc0d5 Added comments and cleanup 2024-03-08 14:25:24 +01:00
sam
77636f2a60 Documentation 2024-03-08 14:24:53 +01:00
Sietse Jonker
9acd2b44a8 Add header file and refactor code 2024-03-08 13:26:23 +01:00
Sietse Jonker
3886292110 Refactor code and update websocket connection 2024-03-08 12:58:33 +01:00
Dano van den Bosch
3a8998c00a Fix typo in software documentation path 2024-03-08 12:52:39 +01:00
Dano van den Bosch
5df0bfa0dc brodcast added 2024-03-08 11:46:46 +01:00
Sietse Jonker
08c9bedb44 adds mac adress code to arduino folder 2024-03-08 11:38:31 +01:00
Sam
28bfd3a300 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-07 19:55:05 +01:00
Sam
56abd5cbde removed libraryies and made delay longer 2024-03-07 19:55:02 +01:00
Sam
3b375266ee Moved libraries over 2024-03-07 19:54:48 +01:00
Sam
2351c515f3 Added function to header 2024-03-07 19:54:41 +01:00
Sam
aa6c35044e Added a function to attempt to diplay the words in full 2024-03-07 19:54:31 +01:00
Dano van den Bosch
67aaaca588 Merge branch '43-als-gebruiker-wil-ik-een-grafiek-hebben-met-live-data-zodat-de-dat-van-de-laatste-paar-minuten' into 'main'
Resolve "Als gebruiker wil ik een grafiek hebben met live data, zodat de dat van de laatste paar minuten live kan terugzien en veranderingen beter zie"

Closes #43

See merge request propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59!5
2024-03-07 14:26:19 +01:00
Dano van den Bosch
54f52bce48 path updated for page 2024-03-07 14:22:30 +01:00
Sietse Jonker
083858f9cf Merge branch 'Website_websocket' into 'main'
Website websocket

See merge request propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59!4
2024-03-07 14:20:52 +01:00
sietse jonker
866af9253e Add graph documentation 2024-03-07 14:20:21 +01:00
Dano van den Bosch
185a972f1b dev page documentation 2024-03-07 14:01:20 +01:00
Bram Barbieri
fb304af3a4 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-07 13:59:03 +01:00
Bram Barbieri
c7ee23afd7 Bram docs, daily standups 2024-03-07 13:59:01 +01:00
sietse jonker
598dd54521 Add new lines for temperature, humidity, eCO2, and TVOC in liveGraph class 2024-03-07 13:18:12 +01:00
Dano van den Bosch
9566148fa6 Merge branch 'Website_websocket' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 into Website_websocket 2024-03-07 13:11:03 +01:00
Dano van den Bosch
878fb9f491 Refactor JSON parsing and data handling functions 2024-03-07 13:11:01 +01:00
sietse jonker
1472c17125 Fix variable name and update amount of nodes 2024-03-07 13:09:28 +01:00
Sam
d1c962f71c added so the answer text is at the bottom 2024-03-07 13:04:14 +01:00
Sam
f2964ebce8 added new function to have text automaticly at the bottom 2024-03-07 13:03:58 +01:00
sietse jonker
0b8ae0ef34 Refactor main.js: Add descriptions, declare variables, and update loop condition 2024-03-07 13:03:28 +01:00
sietse jonker
bc8cc500cb Refactor code to dynamically create node data and live graphs 2024-03-07 13:00:22 +01:00
sietse jonker
2e394f3d45 Update liveGraphs to include temperature, humidity, eCO2, and TVOC data 2024-03-07 12:57:54 +01:00
sietse jonker
6070ba7480 edits css 2024-03-07 11:22:25 +01:00
sietse jonker
656cd83aee Refactor CSS styles and remove unnecessary code 2024-03-06 21:27:19 +01:00
sietse jonker
bd66f21082 Update interval delay and refactor liveGraph creation 2024-03-06 21:16:30 +01:00
Sietse Jonker
36277a7e5d Update file index.html 2024-03-06 20:56:19 +01:00
sietse jonker
2c0b7df0a1 Refactor HTML structure in index.html 2024-03-06 20:55:43 +01:00
Sietse Jonker
55f94387cc Merge branch 'Website_websocket' into 'main'
Website websocket to main

See merge request propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59!3
2024-03-06 20:36:11 +01:00
Sietse Jonker
24164841a9 Merge branch 'main' into 'Website_websocket'
# Conflicts:
#   arduino/node-code/node-code-final/node-code-final.ino
#   web/classes.js
#   web/index.html
#   web/main.js
#   web/styles.css
2024-03-06 20:35:56 +01:00
Sietse Jonker
c14c18deb0 Remove commented out code and update graph in main.js 2024-03-06 17:38:09 +01:00
sam
f4840775ed Added uml 2024-03-06 16:05:31 +01:00
Sietse Jonker
63be84e287 Update graph colors and scale for temperature, eCO2, and TVOC 2024-03-06 15:59:54 +01:00
Sietse Jonker
199283d3e0 Add live graph plots for humidity, eCO2, and TVOC 2024-03-06 15:51:01 +01:00
sam
27742cfa89 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-06 15:46:42 +01:00
sam
5a8e13c0d6 Added class 2024-03-06 15:46:39 +01:00
sam
284071b4ee Class creation 2024-03-06 15:46:32 +01:00
Sietse Jonker
8ed556d856 Refactor liveGraph class and updateNodeData function 2024-03-06 15:38:46 +01:00
Sietse Jonker
951fc64e6d adds graph class 2024-03-06 15:03:47 +01:00
Sietse Jonker
65783ac3b6 Add liveGraph class and update index.html 2024-03-06 15:02:34 +01:00
Sietse Jonker
9b01523f0e makes class for graphs 2024-03-06 15:01:20 +01:00
Dano van den Bosch
b971fe0b54 dev page documentation added to pages 2024-03-06 11:25:58 +01:00
Sietse Jonker
a2219fa03a Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-05 16:37:02 +01:00
Sietse Jonker
67d77d59d1 changes html and css for testing class 2024-03-05 16:36:58 +01:00
Sietse Jonker
db9c984446 adds class for graph 2024-03-05 16:36:42 +01:00
Dano van den Bosch
026bd92d65 I did it 😊 2024-03-05 16:03:15 +01:00
sam
698b3055a4 File creation + text centre + split array 2024-03-05 16:02:34 +01:00
sam
2b31f80655 File creation 2024-03-05 16:02:17 +01:00
sam
d3952306b2 Added reset 2024-03-05 16:02:12 +01:00
Dano van den Bosch
de1ae975a4 added code for muliple nodes 2024-03-05 14:46:43 +01:00
sam
f99d7b5c3d Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-05 14:22:43 +01:00
sam
21ef8604c2 changed asset 2024-03-05 14:22:40 +01:00
sam
e09651a90c Added asset 2024-03-05 14:22:06 +01:00
sam
0886352a1c added script 2024-03-05 14:21:57 +01:00
sam
307257eefc Added writetext function 2024-03-05 14:21:47 +01:00
sam
fba7ada367 Simple button script 2024-03-05 14:21:35 +01:00
Sietse Jonker
1596f0c641 Fix grammatical error from dano 2024-03-05 14:10:52 +01:00
Dano van den Bosch
3ebe661de0 Fix node identification number in webSocket message 2024-03-05 14:03:10 +01:00
Sietse Jonker
fed0adb299 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-05 13:48:56 +01:00
Sietse Jonker
7476f98590 Commented out debug print statements in webSocketEvent function 2024-03-05 13:48:54 +01:00
Dano van den Bosch
db9380816c added node identivication 2024-03-05 13:42:12 +01:00
Dano van den Bosch
d127a6001d Add WebSocket connection error handling and JSON in to array 2024-03-05 13:38:09 +01:00
Sietse Jonker
bcbb8080c2 Add Arduino code for sensor data collection and websocket communication 2024-03-05 11:40:25 +01:00
Sietse Jonker
072752cec8 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-05 11:27:31 +01:00
Sietse Jonker
9193a753ce Refactor survey questions and add conclusion 2024-03-05 11:27:29 +01:00
Dano van den Bosch
902031cfd5 Fixt arduino file location 2024-03-05 10:55:58 +01:00
Dano van den Bosch
d24744823b Set the websocket data to JSON format 2024-03-05 10:48:15 +01:00
Bram Barbieri
5b26d6b844 Bram documentation buzzers pt 2 2024-03-04 15:28:05 +01:00
Bram Barbieri
ce24a782ed Bram Documentation themperature sensors. 2024-03-04 14:15:16 +01:00
Sietse Jonker
5d9d377010 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-03-01 14:14:25 +01:00
Sietse Jonker
a70575d8b8 adds comments 2024-03-01 14:14:24 +01:00
Sietse Jonker
4db11e3035 adds gebruikerstest voor questions enquete 2024-03-01 14:14:11 +01:00
sam
20a5446c8c Added UML 2024-03-01 14:09:23 +01:00
sam
5c59dc033c Updated documentation 2024-03-01 14:00:45 +01:00
sam
ff296eefb0 Updated documenation 2024-03-01 13:56:17 +01:00
sam
2389c068bf Added new script 2024-03-01 13:52:36 +01:00
sam
f533e1a9c1 Added to pages 2024-03-01 13:52:16 +01:00
Bram Barbieri
7b48a4a04e standup 2024-03-01 11:48:30 +01:00
Dano van den Bosch
d1714fabec Added code for handeling websocket data, And made the html code fariable in a js function 2024-02-29 16:59:04 +01:00
Bram Barbieri
eee106a402 name change 2024-02-29 15:36:10 +01:00
Sam
5f88a8f495 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-29 14:50:58 +01:00
Sam
0d1da4503e Added documentation 2024-02-29 14:50:55 +01:00
Bram Barbieri
14b07da103 daily standup updated 2024-02-29 12:37:00 +01:00
Sietse Jonker
9238d9841e test commit 2024-02-28 12:09:34 +01:00
Sietse Jonker
734dca30bc fixes interval and stuff 2024-02-28 12:06:43 +01:00
Dano van den Bosch
503ef68e67 Add dev page and database setup on Raspberry Pi 2024-02-28 11:57:28 +01:00
sietse jonker
1d76c5ff7a fixes sgp30 sensor not displaying data 2024-02-28 09:40:06 +01:00
sietse jonker
3afc7797ab display function now executes every loop instead of 5 seconds 2024-02-28 09:24:16 +01:00
sietse jonker
ddb21adc52 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-27 21:55:48 +01:00
sietse jonker
b0731f739b adds last changes to code that clean it up 2024-02-27 21:55:47 +01:00
Bram Barbieri
982a275aa0 linux and rapsberry documentation bram 2024-02-27 20:45:42 +01:00
Bram Barbieri
3e82990c97 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-27 20:22:35 +01:00
Bram Barbieri
1b594b503a feedback and arduino video documentation bram 2024-02-27 20:22:33 +01:00
sietse jonker
dcb2f37694 finishes up code for node 2024-02-27 19:46:52 +01:00
sietse jonker
5558289ba2 cleans up code and adds comments 2024-02-27 19:17:47 +01:00
sietse jonker
dc3566f5e5 cleans up code and fixes counter 2024-02-27 19:06:27 +01:00
Sietse Jonker
63ad49675b Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-27 16:55:51 +01:00
Sietse Jonker
984e5e748d Add update functionality and counter variables 2024-02-27 16:55:48 +01:00
sam
17588c38b3 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-27 16:12:55 +01:00
sam
3f60a08695 Added definition of done 2024-02-27 16:12:51 +01:00
sam
53af1d5858 Added screen scripts 2024-02-27 16:12:43 +01:00
sam
766d03282b Added library 2024-02-27 16:12:33 +01:00
Sietse Jonker
540d80a545 Add WiFi and WebSockets functionality to node code 2024-02-27 16:11:07 +01:00
Sietse Jonker
a084960f0f Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-27 15:35:08 +01:00
Sietse Jonker
9adbde7e5c adds websocket code for esp32 2024-02-27 15:35:07 +01:00
Bram Barbieri
79ec11a7a2 samenwerkings tijdlijn gepost 2024-02-27 13:43:06 +01:00
sam
cf6aaa2f33 Samenwerkingscontract 2024-02-16 16:56:48 +01:00
Dano van den Bosch
71981d193a Update navigation links and styling*** 2024-02-16 13:15:38 +01:00
Dano van den Bosch
9255b8ab97 Refactor HTML and JavaScript code, update graph data 2024-02-16 12:28:41 +01:00
Sietse Jonker
44b1317e33 save website from rpi 2024-02-16 11:56:11 +01:00
sam
16105122dd Added page 2024-02-16 11:25:10 +01:00
sam
a0f8378cc9 deurMat 2024-02-16 10:57:03 +01:00
sam
270cff0435 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-16 10:46:45 +01:00
sam
955dab9dd4 Added additional info about feedback 2024-02-16 10:44:43 +01:00
Sam
515792b03f Updated mermaid requirements 2024-02-15 20:10:42 +01:00
Sam
6ddb09112e Update infrastructure UML 2024-02-15 20:06:13 +01:00
Sam
aa31eeaaef Added solution 2024-02-15 20:01:40 +01:00
Sam
26f075ee78 Name change 2024-02-15 19:55:17 +01:00
Sam
22e30063c4 Updated pages 2024-02-15 19:55:12 +01:00
Dano van den Bosch
35117663b1 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-15 16:29:40 +01:00
Dano van den Bosch
613a01924d Mic arduino files 2024-02-15 16:29:36 +01:00
sietse jonker
ea8cbe7c88 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-15 14:15:56 +01:00
sietse jonker
e6b3e07a71 adds assembly documentation of node and changes 2024-02-15 14:15:55 +01:00
Sam
154b10b66c Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-15 14:05:09 +01:00
Sam
885d2978a2 Added reverse proxy documentation 2024-02-15 14:05:05 +01:00
Bram Barbieri
b622902221 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-15 12:07:20 +01:00
Bram Barbieri
ccfa8c75d0 questions updated 2024-02-15 12:04:57 +01:00
sietse jonker
faa49c7a21 adds cad file from node casing 2024-02-15 11:09:20 +01:00
sietse jonker
02c92a9a70 adds criteria to enquete questions 2024-02-15 11:03:17 +01:00
Bram Barbieri
c0af3e3cd4 updated design node 2024-02-15 10:46:50 +01:00
Bram Barbieri
d3f810ecf7 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-15 10:42:39 +01:00
Bram Barbieri
ce88a119c6 feedback updated 2024-02-15 10:42:37 +01:00
sietse jonker
23a2f623a6 adds credit on work 2024-02-14 23:07:59 +01:00
sietse jonker
1ba6b305bb adds node design files to assets 2024-02-14 23:07:51 +01:00
sietse jonker
8ee0774602 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-14 23:00:02 +01:00
sietse jonker
41b678bf9c adds documentation about node design in fusion360 2024-02-14 23:00:00 +01:00
Bram Barbieri
55fbb73a89 feedback verwerkt in node design. 2024-02-14 22:51:09 +01:00
sam
816f25757f Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-14 17:18:37 +01:00
sam
85fc96cb63 Spelling updates 2024-02-14 17:18:33 +01:00
sam
ceb52b70fa Added documentation about issues with websockets 2024-02-14 17:18:25 +01:00
sam
fc0b96ec0a Added feedback 2024-02-14 17:18:09 +01:00
Sietse Jonker
5791b373e9 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-14 16:58:09 +01:00
Sietse Jonker
bfeb8169eb updates node code 2024-02-14 16:58:07 +01:00
Sietse Jonker
e8ab30fbb1 adds website for rpi 2024-02-14 16:58:00 +01:00
Dano van den Bosch
0d00f4a874 Update studieruimte opdracht en sensoren 2024-02-14 16:06:49 +01:00
Bram Barbieri
b276ef1199 Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-14 15:42:50 +01:00
Bram Barbieri
183f49f8c6 documentation of The sirst sketches and images added 2024-02-14 15:42:48 +01:00
Dano van den Bosch
762dbee696 spelling check 2024-02-14 15:27:00 +01:00
Dano van den Bosch
39250f33d8 Spelling check 2024-02-14 15:26:57 +01:00
Dano van den Bosch
ef90e4000a edited spelling 2024-02-14 15:22:47 +01:00
Dano van den Bosch
8a664f39ae Merge branch 'main' of gitlab.fdmci.hva.nl:propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-3/qaajeeqiinii59 2024-02-14 15:18:25 +01:00
Dano van den Bosch
26d88ce281 Update formatting and fix typos in raspberryPi.md 2024-02-14 15:18:23 +01:00
Dano van den Bosch
d253fd8394 Add sprint1Revieuw.md file with sprint review content 2024-02-14 15:18:19 +01:00
Sietse Jonker
23a3bc2cb2 Add Arduino code for environmental monitoring 2024-02-14 14:07:53 +01:00
Sietse Jonker
ccd94c260e Add initial version of node-code-final.ino 2024-02-14 11:11:27 +01:00
81 changed files with 3287 additions and 37 deletions

View 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
View 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);
}

Binary file not shown.

View 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);
}

View File

@@ -0,0 +1,76 @@
#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);
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) {
const int screenWidth = 320; // replace with your TFT display width
const int lineHeight = 22; // replace with your text line height
char* word = strtok(text, " ");
char line[100] = "";
int lineCount = 0;
while (word != NULL) {
char tempLine[100];
strcpy(tempLine, line);
strcat(tempLine, word);
strcat(tempLine, " ");
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(tempLine, 0, 0, &x1, &y1, &w, &h);
if (w > screenWidth && strlen(line) > 0) {
tft.setCursor(0, lineHeight * lineCount);
tft.println(line);
lineCount++;
strcpy(line, word);
strcat(line, " ");
} else {
strcpy(line, tempLine);
}
word = strtok(NULL, " ");
}
// print the last line
tft.setCursor(0, lineHeight * lineCount);
tft.println(line);
}

View 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);
public:
DisplayText(Adafruit_ST7796S_kbv& tftDisplay);
void writeText(char* text, int size, int posX, int posY, int screenTime, bool center, bool bottom);
};
#endif

View 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

View 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
}

View 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;
}

View 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
}

View 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
View 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(){
}

View File

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

View File

@@ -0,0 +1,42 @@
// 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>
// 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);
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;

View 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();
}

View 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;
}

View File

@@ -0,0 +1,17 @@
#include <nodeCodeHeader.h>
nodeReadings esp32Node();
void setup()
{
// put your setup code here, to run once:
esp32Node.setup();
esp32Node.websocketSetup();
esp32Node.resetValues();
}
void loop()
{
// put your main code here, to run repeatedly:
esp32Node.loop();
}

View File

@@ -0,0 +1,63 @@
#include "arduino.h"
#include "nodeCodeHeader.h"
nodeReadings::nodeReadings() {
}
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);
}
void nodeReadings::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();
}
void nodeReadings::resetValues() {
counter = 0;
eCO2 = 0;
TVOC = 0;
temperature = 0;
humidity = 0;
currentMillis = 0;
lastMillis = 0;
errorSGP30 = false;
errorDHT11 = false;
noise = false;
}
// 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");
}

View File

@@ -0,0 +1,18 @@
#ifndef nodeReading_h
#define nodeReading_h
#include "Arduino.h"
#include "headerFile.h"
class nodeReadings {
public:
nodeReadings();
void setup();
void loop();
void resetValues();
private:
};
#endif

View 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");
}

View File

@@ -8,11 +8,24 @@ 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
- 🍓 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
- 🧠 Brainstorm:
- Ideeën: brainstorm/ideeën
- Database design: brainstorm/Database
- Feedback: brainstorm/Feedback
- Problem: brainstorm/Problem
- Infrastructure: brainstorm/UML-infrastructure
- Taskflow: brainstorm/Taskflow
- Design: Sp1SchetsProject/FirstDesign
- 🖨️ Software:
- Dev page: brainstorm/SoftwareDocumentatie/Dev_page

View File

@@ -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.

View 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.

View File

@@ -0,0 +1,271 @@
## 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:
```
#include "DHT.h"
#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
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();
}
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.ptint'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:
![Physical DHT11 board off](<assets/DHT11 state 1.jpg>)
And here it looks in action:
![physical DHT11 board on](<assets/DHT11 state 2.jpg>)
Later on, I could expand this code and the physical product to include the rest of the sensors.
The wiring is shown here:
![the wiring](<assets/DHT11 wires.png>)
The red cables are 3v, the black cables are the ground and the green cable is the echo for data.
This version of a DHT11 has a built-in resistor otherwise this would have to be included.
### 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;
void setup() {
//put down some pins that will output , and some that input.
pinMode(button, INPUT);
pinMode(buzzerone, OUTPUT);
pinMode(buzzertwo, OUTPUT);
}
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.
![board turned off.](<assets/Buzzer board off.jpg>)
And here is the the board working:
![board working and turned on.](<assets/Buzzer board on.jpg>)
### 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:
![my datqa-websocket connection](assets/myconnection.png)
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View 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.
![The First Node Sketch(Bram)](../assets/ImagesSp1/sp1NodeSketch.jpg)
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.
![The First Questionaire Node Sketch(Bram)](../assets/ImagesSp1/Sp1questionBoxNode.jpg)
On the top Of the page The front of the node is drawn. The node has two screens to show both the statistics and the questionaire. On the node, three Buttons are show wich the user can press in order to take the questionaire.
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.
![3D design by Sietse](../assets/ImagesSp1/Sp13DDesignUpdated.png)

View File

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

View 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: ![de infrastructuur](../assets/ImagesSp1/digitaleInfrastructuur.png), 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/)

View 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/

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

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

View File

@@ -1,5 +1,31 @@
# 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)
## 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? (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.

View 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";
}
```

View 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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -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') }}

View File

@@ -0,0 +1,105 @@
# 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.
![TFT screen diagram](../assets/imagesSp2/fritzingscreen.png)
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()
}
```
## 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

View File

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

View File

@@ -0,0 +1,72 @@
# 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.>
- <nodeCodeHeader.h>
### Code
The code is divided into the following classes:
uitleg dano
### 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:
![Wiring diagram of node](docs\assets\imagesSp3\wiringDiagramNode.png)
## 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.

View File

@@ -0,0 +1,97 @@
## Python code + explaination
We wanted to make a working connection between our websocket wich runs all the data gatherd by our nodes and a live feed to our database.
So we set out to make this connection using python.
At first we needed to import the folowing librarys:
```js
// everything is running async so the code can run together and not interfere with eachother.
import asyncio
import websockets
// a library to connect to the database.
import mysql.connector
import json
```
Then we began the process of connecting with both the websocket and the database.
First-off, we began making a connection to the database by using a mysql library in wich we gave the log in in order to connect to our ow database.
```js
//the data that has to be pushed needs to be
async def process_data(data):
try:
mydb = mysql.connector.connect(
host="localhost",
user="*****",
password="*********",
database="*******"
)
```
Then after this we code in the infromation we want to put inside of the database.
The data collected from the websocket is json data, so this has to be changed.
```js
//Making a variable for the database connection
cursor = mydb.cursor()
//Making a variable for the database connection
MACDataReading = mydb.cursor()
//find the correct section and interact with it.
MACDataReading.execute("SELECT MAC FROM Node")
//the query for what needs to be inserted into the database ( atleast where it has to go).
query = "INSERT INTO `Measurement` (NodeID, Type, Value) VALUES (%s, %s, %s)"
//the recieved data from the websocket is json data so needs to be changed.
processedData = json.loads(data)
//variables about the recieved data points.
processedTemp = (processedData['Temp'])
processedHumi = (processedData['Humi'])
processedECo = (processedData['eCO2'])
processedTvoc = (processedData['TVOC'])
processedMAC = (processedData['node'])
//change the recieved macadress to a tuple.
MACTuple = (processedMAC,)
//fetch the data from the database an[d put it in an array.
MACDataFetching = MACDataReading.fetchall()
MACArray = list(MACDataFetching)
//see if the fetched data is not in the gotten array.
//otehrwise insert it into the database directly.
if MACTuple not in MACArray:
addingNode = "INSERT INTO `Node` (MAC) VALUES (%s)"
cursor.execute(addingNode, MACTuple)
mydb.commit()
//the websocket data that needs to be sent to the database.
pushingDataArray = [(1, "Temp", processedTemp), (1, "Humi", processedHumi), (1, "eCO2", processedECo), (1, "TVOC", processedTvoc)]
// forloop, go allong the array.
for i in pushingDataArray:
print(query ,i)
cursor.execute(query, i)
mydb.commit()
// show me the error it there is one.
except mysql.connector.Error as err:
print("MySQL Error:", err)
finally:
cursor.close()
mydb.close()
```
After fully connecting t othe database, making statements of what to put there and telling the code what to do, we ofcourse need to write the code to connect to the weebsocket.
We begin by telling our websocket id and what type of port we are using.
Then we will collect live data from the conected websocket, store it in a variable, and then in the previous code
```js
//here the connection to the websocked is made
async def receive_data():
uri = "****************"
try:
async with websockets.connect(uri) as websocket:
while True:
// the data collected from the websocket is.
data = await websocket.recv()
// data recieved: conformation.
print(f"Received data: {data}")
await process_data(data)
// error sowing.
except websockets.ConnectionClosedError as e:
print("WebSocket connection closed:", e)
async def main():
await receive_data()
asyncio.run(main())
```

View 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.

View File

@@ -0,0 +1,71 @@
# To edit data in the database we wanna use PUT request.
### What is a put request?
To edit data in the database we wanna use PUT request. A PUT request is used to update an existing resource. If the resource does not exist, it will create a new one. The PUT request requires the client to send the entire updated resource, not just the changes. This means that the client must send all the data, even if only one field has changed.
A put request is a json its for example looks like this:
```json
{
"NodeID": 1,
"Location": "testlocation",
"Name": "testname",
}
```
### How to use a put request
We have been trying to use a PUT request with flask. But that didn't work because the reverse proxy would reform the request to a GET request. So we tried to let apache 2 run it with wsgi.
### What is wsgi?
WSGI stands for Web Server Gateway Interface. It is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request. WSGI is a Python standard, and it is implemented by most Python web frameworks.
We couldnt get it to work even though we worked trough all the errors apache 2 gave us.
We first had some paths misconfigured. Then we had Forbidden error because we didn't give permission for apache2 to use that path.
And now we ended on not found and we verified that all configuration is in the correct syntrax with ```apachectl configtest```
### How to use wsgi
To use wsgi you need to install mod_wsgi with the following command:
```bash
sudo apt-get install libapache2-mod-wsgi
```
Then you need to enable the module with the following command:
```bash
sudo a2enmod wsgi
```
Then you need to create a wsgi file in the same directory as your python file. The wsgi file should look like this:
```python
import sys
sys.path.insert(0, '/home/pi/webapp')
from mainflask import app as application
```
Then you need to configure your apache2 configuration file to use the wsgi file. The configuration file should look like this:
```apache
<VirtualHost *:80>
DocumentRoot /home/pi/www/html/
WSGIDaemonProcess webapp python-path=/home/pi/webapp
WSGIScriptAlias /flask /home/pi/webapp/main.wsgi
<Directory /home/pi/webapp>
WSGIProcessGroup webapp
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
# Logging
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```
Then you need to restart apache2 with the following command:
```bash
sudo systemctl restart apache2
```

View File

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

View File

@@ -7,8 +7,83 @@ With websockets you can establish a connection between the client and the server
### How to use websockets
There are different languages to serve websockets with, but we are going to use Python with the library `websockets`. This library is easy to use and has a lot of documentation.
## Issues
Not all ports are open so we need to make a reverse proxy to use websockets.
### Ports
We can only use certain ports like 113, 80, 443. These are common ports and are not blocked by firewalls. Something in the network is blocking all other ports which makes it hard to use websockets.
A solution for this is to use a reverse proxy. (See [Reverse Proxy](./Reverse-Proxy.md))
## Classes
For the websockets we are going to use 2 classes. One for the nodes and one for the websites. The nodes are going to send data to the website and have multiple variables like temperature, humidity, eCO2, TVOC and sound. The website is going to send data to the nodes like names and settings. For this they have to use a userName and password.
``` mermaid
classDiagram
client --> User : website client
client --> Node : esp32 client
namespace raspberry pi clients {
class client {
+MacAdress
sendData()
}
class Node {
+eCO2
+Temperature
+Humidity
+TVOC
+Sound
+Settings
changeNodeName(name)
updateData(data)
}
class User {
+userName
+password
changeNodeName(data)
}
}
```
Code of the classes:
``` python
class client:
def __init__(self, macAdress):
self.macAdress = macAdress
class node(client):
def __init__(self, name, node, temperature, humidity, eCO2, TVOC, sound):
super().__init__(macAdress)
self.nodeNumber = node
self.temperature = temperature
self.humidity = humidity
self.eCO2 = eCO2
self.TVOC = TVOC
self.sound = sound
self.name = name
def updateData(self, temperature, humidity, eCO2, TVOC, sound):
self.temperature = temperature
self.humidity = humidity
self.eCO2 = eCO2
self.TVOC = TVOC
self.sound = sound
class Website(client):
def __init__(self, macAdress, user, password):
super().__init__(macAdress)
self.passWord = passWord
self.userName = userName
```
#### Sources:
* https://websockets.readthedocs.io/en/stable/index.html
* https://websockets.readthedocs.io/en/stable/index.html
**Written by Sam & Sietse**

View File

@@ -2,7 +2,7 @@ mkdocs ~= 1.4.0
Jinja2==3.1.0
mkdocs-material ~= 9.1.12
mkdocs-video ~= 1.3
mkdocs-mermaid2-plugin ~= 0.6.0
mkdocs-mermaid2-plugin ~= 1.0.4
mkdocs-macros-plugin ~= 0.7.0
mkdocs-awesome-pages-plugin ~= 2.8.0
mkdocs-autolinks-plugin ~= 0.6.0

View File

@@ -0,0 +1,117 @@
-- MySQL Script generated by MySQL Workbench
-- Wed Mar 13 16:04:58 2024
-- Model: New Model Version: 1.0
-- MySQL Workbench Forward Engineering
-- CHANGE NODEID TO AUTO INCREMENET IN NODE TABLE
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
-- -----------------------------------------------------
-- Schema NodeData
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema NodeData
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `NodeData` DEFAULT CHARACTER SET utf8 ;
USE `NodeData` ;
-- -----------------------------------------------------
-- Table `NodeData`.`Question`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `NodeData`.`Question` (
`QuestionID` INT NOT NULL,
`Question` VARCHAR(45) NULL,
PRIMARY KEY (`QuestionID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `NodeData`.`Node`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `NodeData`.`Node` (
`NodeID` INT NOT NULL,
`Name` VARCHAR(45) NULL,
`Location` VARCHAR(45) NULL,
`MAC` VARCHAR(45) NULL,
PRIMARY KEY (`NodeID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `NodeData`.`Measurement`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `NodeData`.`Measurement` (
`NodeID` INT NOT NULL,
`TimeStamp` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`Type` VARCHAR(45) NULL,
`Value` FLOAT NULL,
CONSTRAINT `fk_Measurement_Node1`
FOREIGN KEY (`NodeID`)
REFERENCES `NodeData`.`Node` (`NodeID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `NodeData`.`Enquete`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `NodeData`.`Enquete` (
`EnqueteID` INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`EnqueteID`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `NodeData`.`enqueteQuestion`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `NodeData`.`enqueteQuestion` (
`Enquete_EnqueteID` INT NOT NULL,
`Question_QuestionID` INT NOT NULL,
PRIMARY KEY (`Enquete_EnqueteID`, `Question_QuestionID`),
INDEX `fk_Enquete_has_Question_Question1_idx` (`Question_QuestionID` ASC) VISIBLE,
INDEX `fk_Enquete_has_Question_Enquete1_idx` (`Enquete_EnqueteID` ASC) VISIBLE,
CONSTRAINT `fk_Enquete_has_Question_Enquete1`
FOREIGN KEY (`Enquete_EnqueteID`)
REFERENCES `NodeData`.`Enquete` (`EnqueteID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Enquete_has_Question_Question1`
FOREIGN KEY (`Question_QuestionID`)
REFERENCES `NodeData`.`Question` (`QuestionID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `NodeData`.`Reply`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `NodeData`.`Reply` (
`Node_NodeID` INT NOT NULL,
`enqueteQuestion_Enquete_EnqueteID` INT NOT NULL,
`enqueteQuestion_Question_QuestionID` INT NOT NULL,
`Result` INT NULL,
`Time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
`AnswerID` INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`AnswerID`, `Node_NodeID`, `enqueteQuestion_Enquete_EnqueteID`, `enqueteQuestion_Question_QuestionID`),
INDEX `fk_Node_has_enqueteQuestion_enqueteQuestion1_idx` (`enqueteQuestion_Enquete_EnqueteID` ASC, `enqueteQuestion_Question_QuestionID` ASC) VISIBLE,
INDEX `fk_Node_has_enqueteQuestion_Node1_idx` (`Node_NodeID` ASC) VISIBLE,
CONSTRAINT `fk_Node_has_enqueteQuestion_Node1`
FOREIGN KEY (`Node_NodeID`)
REFERENCES `NodeData`.`Node` (`NodeID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Node_has_enqueteQuestion_enqueteQuestion1`
FOREIGN KEY (`enqueteQuestion_Enquete_EnqueteID` , `enqueteQuestion_Question_QuestionID`)
REFERENCES `NodeData`.`enqueteQuestion` (`Enquete_EnqueteID` , `Question_QuestionID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

54
server/Flask/main.py Normal file
View File

@@ -0,0 +1,54 @@
from flask import Flask, request, jsonify
import mysql.connector
from queries import *
app = Flask(__name__)
@app.route('/')
def index():
node = request.args.get('node', default = None)
dataType = request.args.get('dataType', default = None)
MAC = request.args.get('MAC', default = None)
return getData(node, dataType, MAC)
@app.route('/updateData')
def updateDataIndex():
node_id = request.args.get('node', None)
new_name = request.args.get('name', None)
new_location = request.args.get('location', None)
return updateData(node_id, new_name, new_location)
def updateData(node, name, location):
mydb = loginDB()
query = update_query(node, name, location)
cursor = mydb.cursor(dictionary=True) # Enable dictionary output
cursor.execute(query)
mydb.commit()
result = cursor.fetchall() # Fetch the results
cursor.close()
mydb.close()
return result
def loginDB():
mydb = mysql.connector.connect(
host="localhost",
user="root",
password="Dingleberries69!",
database="NodeData"
)
return mydb
def getData(node, dataType, MAC):
mydb = loginDB()
query = get_query(node, dataType, MAC)
cursor = mydb.cursor(dictionary=True) # Enable dictionary output
cursor.execute(query)
result = cursor.fetchall() # Fetch the results
cursor.close()
mydb.close()
return result
if __name__ == '__main__':
app.run(debug=True, host='localhost')

23
server/Flask/queries.py Normal file
View File

@@ -0,0 +1,23 @@
def get_query(node, dataType, MAC):
if node and dataType:
query = f"SELECT * FROM Measurement WHERE NodeID = {node} AND Type = '{dataType}'"
elif node:
query = f"SELECT * FROM Measurement WHERE NodeID = {node}"
elif dataType:
query = f"SELECT * FROM Measurement WHERE Type = '{dataType}'"
elif MAC:
query = f"SELECT * FROM Node WHERE MAC = '{MAC}'"
else:
query = "SELECT * FROM `Measurement`"
return query
def update_query(node, name, location):
if node and name and location:
query = f"""
UPDATE Node
SET Name = '{name}', Location = '{location}'
WHERE NodeID = {node};
"""
return query

View File

@@ -1,21 +1,34 @@
import websockets;
import asyncio;
import websockets
import asyncio
connected = set()
async def handler(websocket):
while True:
#Save the incoming message in variable message.
message = await websocket.recv()
print(message)
# Register.
connected.add(websocket)
try:
while True:
message = await websocket.recv()
print(message)
await broadcast(message)
except websockets.ConnectionClosedOK:
print("Client disconnected")
finally:
connected.remove(websocket)
async def broadcast(message):
if connected: # asyncio.wait doesn't accept an empty list
await asyncio.wait([ws.send(message) for ws in connected])
async def sendClientId():
if connected: # asyncio.wait doesn't accept an empty list
await asyncio.wait([ws.send(message) for ws in connected])
async def main():
async with websockets.serve(handler, "145.92.8.114" , 8001):
async with websockets.serve(handler, "0.0.0.0", 8001):
await asyncio.Future() # run forever
if __name__ == "__main__":
asyncio.run(main())
asyncio.run(main())
#https://websockets.readthedocs.io/en/stable/reference/sync/server.html#websockets.sync.server.serve

33
server/bullshitSender.py Normal file
View File

@@ -0,0 +1,33 @@
import asyncio
import websockets
import json
import random
import time
async def send_data(uri):
async with websockets.connect(uri) as websocket:
print("Connected to WebSocket server")
while True:
data = {
"node": "69:42:08:F5:00:00",
"Temp": str(round(random.uniform(0, 25), 2)),
"Humi": str(round(random.uniform(0, 90), 2)),
"eCO2": str(round(random.uniform(350, 2000), 0)),
"TVOC": str(round(random.uniform(100, 1200), 0))
}
await websocket.send(json.dumps(data))
print("Data sent")
response = await websocket.recv()
print("Received message:", response)
await asyncio.sleep(2) # Wait a bit before sending the next message
# Start the WebSocket connection
while True:
try:
asyncio.get_event_loop().run_until_complete(send_data("ws://145.92.8.114/ws"))
except Exception as e:
print("Exception:", e)
time.sleep(1) # Wait a bit before trying to reconnect

20
server/reverseproxy Normal file
View File

@@ -0,0 +1,20 @@
<VirtualHost *:80>
ProxyPreserveHost On
DocumentRoot /home/pi/www/html/
# Enable proxying WebSockets
ProxyPass /ws ws://localhost:8001/
ProxyPassReverse /ws ws://localhost:8001/
# Enable proxying HTTP
ProxyPass /http http://localhost:8080/
ProxyPass /putData http://localhost:5000/putData
ProxyPassReverse /putData http://localhost:5000/putData
ProxyPass /flask http://localhost:5000/
ProxyPassReverse /flask http://localhost:5000/
ProxyPreserveHost On
# Logging
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

View File

@@ -0,0 +1,83 @@
### Sprint 2: The product.
28 - 2 - 2024: {
At the standup we made soem finishing touches on who is gonna do what and what each role will feature.
Dano and Bram are going to start with doing research about extracting information from the PI and wil be setting up a HTML page for the information to display.
Sam and Sietse are going to be busy with connecting to the websocket and will do some minor tweaking to the current node moddel that we have.
}
29 - 2 - 2024: {
At today's standup we got together to talk about our progression in each of our tasks. Where we found that our tasks for today will be moreso the same but wit hsome minor ajusting.
Sam and Sietse will be designing the pcb aswell as making some progress on the questionaire, while Dano and Bram will be making the connection between the websocket and the devpage/ html page aswell as making some user-stories.
}
1 - 3 - 2024: {
From yesterday's standup, Sietse made a digital PCD schematic, Dano and Bram made great progress with connecting the PI to the html website and are trying to finish it today. Sam has made progress with documentation and was helping Sietse.
Today we are going to continue our tasks and try to finish these, so we can continue with our project.
}
5 - 3 - 2024: {
At the standup we discussed our goals for today, Sam is going to get the screen going, Sietse is gonna help Sam, Dano is working on kthe website, and Bram is going to send live info to the database in linux.
}
6 - 3 - 2024 {
Sietse is going to make a class wich contains all the graphs, Dano is making documentation and OOP, Sam is also making OOP,
and im going to continue with working on the connection between the websocket and the database. }
7 - 3 - 2024 {
Sietse is going to make more progress on updating the graph on the website.
Sam is going to finish the code for the big questionaire screen.
Dano is going to be writing some documentation and will be working with classes in arduino.
Bram will do research on python to finish the connection to the database and the websocket.
}
12 - 3 - 2024 {
Sam is going to continue to build his custom library for out custom questionaire screen.
Sietse is going to make a class in python.
Dano is making classes for the code of the node.
Bram is correcting some of his documentation and will continue the coding in python( to still make the connection between the database and the websocket.)
}
13 - 3 - 2024 {
Dano: website scaling + css fixing and arduino OOP.
Sam: making a rest api to pull stuff from database.
Sietse: OOP python.
Bram: Finaly finishing connection between database and websocket.
}
14 - 3- 2024 {
Sam: rest api building.
Dano: OOP arduino.
sietse: making the website dynamic.
Bram: Documentation updating for review.
}
15 - 3- 2024 {
We are all making preperations for the sprint-review.
}
3/19/2024
Dano, oop arduino
Bram, nodes registereen als er een nieuwe binnenkomt
Sietse, onderdelen bestellen, verder user story 46: nodes beheren op website.
Sam, tft scherm, rest api ombouwen om data in node tabel te douwen
20/03/2024:
Dano: Adding comments for OOP Arduino
Bram: Python send node data to database
Sam: flask rerouten to use put recuest
Sietse: WireFrame
21/03/2024
Sietse: fritsing node documentation
Bram: personal documetation.
Sam: Rest api improvements
Dano: prepering for retro and making docu for aruidno
22/03/2024
Bram: Fritsing, documentation for code
Sietse: Database
Dano: Docuemtation for arduino
Sam:

View File

@@ -0,0 +1,29 @@
Doelstelling Goed functioneerend product leveren
Werktijden Wanneer afgesproken en op hen zelf
Vergadertijden Tijdens schooltijd en wanneer afgesproken
Afspraken communicatie Discord
Afspraken aanwezigheid Vermeld wanneer deze afspraak niet nagekomen kan worden of elders kom altijd optijd.
Afspraken documenten delen Gitlab, discord
Geen spaties in gitlab documenten/mappen
Procedure bij niet-nakomen afspraken Communicatie is sleutel
Definition of done:
- Code is geschreven
- Code is getest
- Code is gereviewd
- Code is gedocumenteerd
- Code Werkt
- Code is geïntegreerd
Taakverdeling
Veranderd elke sprint
Akkoord gemaakte afspraken
Namen, datum, handtekening
1. Bram datum handtekening
2. Dano
3. Sam Hos
5. Sietse jonko

85
web/classes.js Normal file
View File

@@ -0,0 +1,85 @@
class liveGraph {
// Constructor to initialize the graph
constructor(id) {
this.timeArray = [];
this.tempArray = [];
this.humiArray = [];
this.eco2Array = [];
this.tvocArray = [];
this.cnt = 0;
this.nodeId = "liveGraph" + id;
}
// Fuction to create a graph
makeGraph() {
// Create a new line for temperature
Plotly.plot(this.nodeId, [
{
x: this.timeArray, // Use timeArray as x values
y: this.tempArray,
mode: "lines",
line: { color: "#FF0000" },
name: "Temperature",
},
]);
// Create a new line for humidity
Plotly.plot(this.nodeId, [
{
x: this.timeArray, // Use timeArray as x values
y: this.humiArray,
mode: "lines",
line: { color: "#80CAF6" },
name: "Humidity",
},
]);
// Create a new line for eCO2
Plotly.plot(this.nodeId, [
{
x: this.timeArray, // Use timeArray as x values
y: this.eco2Array,
mode: "lines",
line: { color: "#FFA500" },
name: "eCO2 / 10",
},
]);
// Create a new line for TVOC
Plotly.plot(this.nodeId, [
{
x: this.timeArray, // Use timeArray as x values
y: this.tvocArray,
mode: "lines",
line: { color: "#000000" },
name: "TVOC / 10",
},
]);
}
// Function to update the graph with new values got from updateData function
updateGraph() {
let time = new Date();
this.timeArray.push(new Date());
let update = {
x: [[this.timeArray]],
y: [[this.tempArray], [this.humiArray], [this.eco2Array], [this.tvocArray]]
};
let olderTime = time.setMinutes(time.getMinutes() - 1);
let futureTime = time.setMinutes(time.getMinutes() + 1);
let minuteView = {
xaxis: {
type: "date",
range: [olderTime, futureTime],
},
};
Plotly.relayout(this.nodeId, minuteView);
if (this.cnt === 10) clearInterval(interval);
}
// function to get the new data for graph
updateData(temperature, humidity, eCO2, TVOC) {
// Update the graph
this.tempArray.push(temperature);
this.humiArray.push(humidity);
this.eco2Array.push(eCO2 / 10);
this.tvocArray.push(TVOC / 10);
}
}

12
web/graphClass.js Normal file
View File

@@ -0,0 +1,12 @@
class graphClass {
constructor(dataArray) {
this.dataArray = dataArray;
}
createGraph() {
// make the graphs
liveGraphs.forEach((graph) => {
graph.makeGraph();
});
}
}

0
web/graphPage.js Normal file
View File

33
web/index.html Normal file
View File

@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="https://cdn.plot.ly/plotly-latest.min.js" charset="utf-8"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Node dev page</title>
<!-- <link rel="icon" type="image/x-icon" href="favicon.ico"> -->
</head>
<body>
<!-- Make a new header with a navigation bar -->
<header>
<nav class="navbar">
<ul>
<li><a href="climate-monitor.html">Dashboard
</a></li>
<li><a href="Map.html">Graph</a></li>
</li>
</ul>
</nav>
</header>
<div id="nodeDataLocation"></div>
<!-- Include the js file -->
<script src="classes.js"></script>
<script src="main.js"></script>
</body>
<html>

194
web/main.js Normal file
View File

@@ -0,0 +1,194 @@
// Description: Main JavaScript file for the web application.
// arrays and stuff
const sensorData = {};
let liveGraphs = [];
let nodeArray = [];
let nodeDict = {};
// letiables
let intervalDelay = 5000;
let amountOfNodes = 3;
const socket = new WebSocket("ws://145.92.8.114/ws");
function openConnection() {
// Open connection
socket.addEventListener("open", (event) => {
console.log("Connected to the WebSocket server");
});
// Error handling
socket.addEventListener('error', (event) => {
console.error('WebSocket error:', event);
// Attempt to reconnect
setTimeout(openConnection, 1000); // Retry after 1 second
});
// Message handling
socket.addEventListener("message", (event) => {
try {
const jsonData = JSON.parse(event.data);
// Use the parsed JSON data as needed
handleIncomingData(jsonData);
} catch (error) {
console.error("Error parsing JSON:", error);
}
});
// Close handling
socket.addEventListener('close', (event) => {
console.log('Connection closed');
// Attempt to reconnect
setTimeout(openConnection, 1000); // Retry after 1 second
});
console.log("Connected to the WebSocket server");
}
openConnection();
function handleIncomingData(data) {
nodeAdressHandler(data.Node);
nodeNumber = nodeDict[data.Node];
temperature = data.Temp;
humidity = data.Humi;
CO2 = data.eCO2;
TVOC = data.TVOC;
updateNodeData(nodeNumber, temperature, humidity, CO2, TVOC);
}
function nodeAdressHandler(node) {
if (!nodeArray.includes(node)) {
nodeArray.push(node);
nodeDict[node] = nodeArray.length;
}
}
//function for making the html elements for the following html code
function nodeData(data, node) {
let nodeData = document.createElement("div");
nodeData.innerHTML = data;
// nodeData.setAttribute("id", "node" + node);
document.body.appendChild(nodeData);
// console.log("Hello World");
}
function createNodeData(node) {
// Create main div
let nodeData = document.createElement("div");
nodeData.className = "nodeData";
// Create flex-NodeData div
let flexNodeData = document.createElement("div");
flexNodeData.className = "flex-NodeData";
// Create p element
let pNode = document.createElement("p");
pNode.textContent = "Node " + node;
// Append p to flex-NodeData
flexNodeData.appendChild(pNode);
// Create flex-LiveData div
let flexLiveData = document.createElement("div");
flexLiveData.className = "flex-LiveData";
// Create data divs (Temperature, Humidity, Light Intensity)
let dataTypes = ["Temperatuur", "Luchtvochtigheid", "CO2", "TVOC"];
let ids = ["temperature", "humidity", "CO2", "TVOC"];
let statusIds = ["tempStatus", "humidStatus", "CO2Status", "TVOCStatus"];
for (let i = 0; i < dataTypes.length; i++) {
let dataDiv = document.createElement("div");
let dataTypeDiv = document.createElement("div");
dataTypeDiv.textContent = dataTypes[i] + ": ";
let pElement = document.createElement("p");
pElement.id = ids[i] + node;
pElement.textContent = "Not connected";
dataTypeDiv.appendChild(pElement);
dataDiv.appendChild(dataTypeDiv);
let statusElement = document.createElement("div");
statusElement.className = "statusElement";
let statusText = document.createElement("p");
statusText.className = "statusText";
statusText.id = statusIds[i];
statusText.textContent = "Not connected";
statusElement.appendChild(statusText);
dataDiv.appendChild(statusElement);
flexLiveData.appendChild(dataDiv);
}
// Append flex-LiveData to flex-NodeData
flexNodeData.appendChild(flexLiveData);
// Create flex-graph div
let flexGraph = document.createElement("div");
flexGraph.className = "flex-graph";
let graphDiv = document.createElement("div");
let graphP = document.createElement("p");
graphP.textContent = "Live graph:";
let liveGraph = document.createElement("div");
liveGraph.id = "liveGraph" + node;
graphDiv.appendChild(graphP);
graphDiv.appendChild(liveGraph);
flexGraph.appendChild(graphDiv);
// Append flex-graph to flex-NodeData
flexNodeData.appendChild(flexGraph);
// Append flex-NodeData to main div
nodeData.appendChild(flexNodeData);
// Check if nodeDataLocation element exists
let nodeDataLocation = document.getElementById("nodeDataLocation");
if (nodeDataLocation) {
// Append main div to nodeDataLocation
nodeDataLocation.appendChild(nodeData);
} else {
console.error("Element with ID 'nodeDataLocation' does not exist.");
}
}
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";
// Update the graph
liveGraphs[0].updateData(temperature, humidity, eCO2, TVOC);
liveGraphs[0].updateGraph();
console.log(nodeDict[node]);
console.log(nodeArray);
}
// Call the function to create the HTML structure
for (let i = 1; i <= amountOfNodes; i++) {
createNodeData(i);
liveGraphs.push(new liveGraph(i));
}
// make the graphs
liveGraphs.forEach((graph) => {
graph.makeGraph();
});

166
web/styles.css Normal file
View File

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