diff --git a/arduino/mac_adress.ino b/arduino/mac_adress.ino new file mode 100644 index 0000000..67dff28 --- /dev/null +++ b/arduino/mac_adress.ino @@ -0,0 +1,13 @@ +// Complete Instructions to Get and Change ESP MAC Address: https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/ +#include + +void setup(){ + Serial.begin(115200); + Serial.println(); + Serial.print("ESP Board MAC Address: "); + Serial.println(WiFi.macAddress()); +} + +void loop(){ + +} \ No newline at end of file diff --git a/arduino/node-code/node-code-final/headerFile.h b/arduino/node-code/node-code-final/headerFile.h new file mode 100644 index 0000000..1ef0ea7 --- /dev/null +++ b/arduino/node-code/node-code-final/headerFile.h @@ -0,0 +1,42 @@ +// include these libraries +#include +#include +#include +#include +#include +#include +#include +#include + +// 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; \ No newline at end of file diff --git a/arduino/node-code/node-code-final/node-code-final.ino b/arduino/node-code/node-code-final/node-code-final.ino index 95695d7..682b509 100644 --- a/arduino/node-code/node-code-final/node-code-final.ino +++ b/arduino/node-code/node-code-final/node-code-final.ino @@ -1,49 +1,40 @@ -// Sietse Jonker & Dano van den Bosch -// 28/02/2024 +// include header file into code +#include -// include these libraries -#include -#include -#include -#include -#include -#include -#include +// setup function +void setup() { + // make serial connection at 115200 baud + Serial.begin(115200); -// 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 USE_SERIAL Serial + // tell display what settings to use + display.begin(i2c_adress, true); + display.clearDisplay(); -// define node identification number -#define nodeIdentificationNumber 1 + // tell sensors to start reading + dht.begin(); + sgp.begin(); -// make new objects -Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire); -DHT dht(DHTPIN, DHTTYPE); -WiFiMulti WiFiMulti; -Adafruit_SGP30 sgp; -WebSocketsClient webSocket; + pinMode(MICPIN, INPUT); + pinMode(DHTPIN, INPUT); + + websocketSetup(); + resetValues(); +} -// 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; +// 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) { @@ -112,7 +103,7 @@ void websocketSetup(){ webSocket.setReconnectInterval(500); } -// fucntion to reset the values if needed +// function to reset the values if needed void resetValues() { TVOC_base; eCO2_base; @@ -153,7 +144,7 @@ void update(){ displayData(); // webSocket.sendTXT("{\"Temp\":\"" + String(temperature) + "\",\"Humi\":\"" + String(humidity) + "\",\"eCO2\":\"" + String(sgp.eCO2) + "\",\"TVOC\":\"" + String(sgp.TVOC) + "\"}"); - webSocket.sendTXT("{\"node\": \"" + String(nodeIdentificationNumber) + "\", \"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); @@ -183,39 +174,4 @@ void displayData() { // display the screen display.display(); -} - -// 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(); } \ No newline at end of file diff --git a/arduino/node-code/node-code-final/nodeCode.cpp b/arduino/node-code/node-code-final/nodeCode.cpp new file mode 100644 index 0000000..c21bd92 --- /dev/null +++ b/arduino/node-code/node-code-final/nodeCode.cpp @@ -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; +} diff --git a/arduino/node-code/node-code-final/nodeCodeFinal.ino b/arduino/node-code/node-code-final/nodeCodeFinal.ino new file mode 100644 index 0000000..eb3c086 --- /dev/null +++ b/arduino/node-code/node-code-final/nodeCodeFinal.ino @@ -0,0 +1,17 @@ +#include + +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(); +} diff --git a/arduino/node-code/node-code-final/nodeCodeHeader.cpp b/arduino/node-code/node-code-final/nodeCodeHeader.cpp new file mode 100644 index 0000000..d2a2ec5 --- /dev/null +++ b/arduino/node-code/node-code-final/nodeCodeHeader.cpp @@ -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"); +} \ No newline at end of file diff --git a/arduino/node-code/node-code-final/nodeCodeHeader.h b/arduino/node-code/node-code-final/nodeCodeHeader.h index 7bfeb88..20ed3e4 100644 --- a/arduino/node-code/node-code-final/nodeCodeHeader.h +++ b/arduino/node-code/node-code-final/nodeCodeHeader.h @@ -1,13 +1,18 @@ -#ifndef nodeClass_h -#define nodeClass_h +#ifndef nodeReading_h +#define nodeReading_h + #include "Arduino.h" +#include "headerFile.h" + + class nodeReadings { - private: public: nodeReadings(); - void readDht(); - void printNode(); -// class code goes here + void setup(); + void loop(); + void resetValues(); + private: }; + #endif \ No newline at end of file diff --git a/docs/rpi-documentation/Flask.md b/docs/rpi-documentation/Flask.md new file mode 100644 index 0000000..a25412f --- /dev/null +++ b/docs/rpi-documentation/Flask.md @@ -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. \ No newline at end of file diff --git a/docs/rpi-documentation/websockets.md b/docs/rpi-documentation/websockets.md index c10d5e6..8e9314c 100644 --- a/docs/rpi-documentation/websockets.md +++ b/docs/rpi-documentation/websockets.md @@ -16,7 +16,74 @@ We can only use certain ports like 113, 80, 443. These are common ports and are 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 -**Written by Sam** \ No newline at end of file +**Written by Sam & Sietse** \ No newline at end of file diff --git a/server/Database.sql b/server/Database/Database.sql similarity index 100% rename from server/Database.sql rename to server/Database/Database.sql diff --git a/server/DatabasewithMAC.sql b/server/Database/DatabasewithMAC.sql similarity index 94% rename from server/DatabasewithMAC.sql rename to server/Database/DatabasewithMAC.sql index 32c3c8a..131cdb7 100644 --- a/server/DatabasewithMAC.sql +++ b/server/Database/DatabasewithMAC.sql @@ -1,5 +1,5 @@ -- MySQL Script generated by MySQL Workbench --- Fri Mar 8 12:25:17 2024 +-- Wed Mar 13 16:04:58 2024 -- Model: New Model Version: 1.0 -- MySQL Workbench Forward Engineering @@ -44,14 +44,11 @@ ENGINE = InnoDB; -- ----------------------------------------------------- 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, - `TimeStamp` DATETIME NULL DEFAULT CURRENT_TIMESTAMP, - `Node_NodeID` INT NOT NULL, - PRIMARY KEY (`NodeID`, `Node_NodeID`), - INDEX `fk_Measurement_Node1_idx` (`Node_NodeID` ASC) VISIBLE, CONSTRAINT `fk_Measurement_Node1` - FOREIGN KEY (`Node_NodeID`) + FOREIGN KEY (`NodeID`) REFERENCES `NodeData`.`Node` (`NodeID`) ON DELETE NO ACTION ON UPDATE NO ACTION) diff --git a/server/Flask/main.py b/server/Flask/main.py new file mode 100644 index 0000000..d2951f0 --- /dev/null +++ b/server/Flask/main.py @@ -0,0 +1,43 @@ +from flask import Flask, request +import mysql.connector + +app = Flask(__name__) + +@app.route('/') +def index(): + node = request.args.get('node', default = None) + dataType = request.args.get('dataType', default = None) + return getData(node, dataType) + +def getData(node, dataType): + try: + mydb = mysql.connector.connect( + host="localhost", + user="root", + password="Dingleberries69!", + database="NodeData" + ) +#turn this into a switch statement + cursor = mydb.cursor() + if node: + query = f"SELECT * FROM Measurement WHERE NodeID = {node}" + elif dataType: + query = f"SELECT * FROM Measurement WHERE Type = '{dataType}'" + else: + query = "SELECT * FROM `Measurement`" + cursor.execute(query) + result = cursor.fetchall() # Fetch the results + + # Convert the results to a string for display + result_str = ', '.join([str(row) for row in result]) + + cursor.close() + mydb.close() + + return result + except mysql.connector.Error as err: + print("MySQL Error:", err) + return "MySQL Error: " + str(err) + +if __name__ == '__main__': + app.run(debug=True, host='localhost') \ No newline at end of file diff --git a/web/index.html b/web/index.html index 1d30d1d..2bb052a 100644 --- a/web/index.html +++ b/web/index.html @@ -8,7 +8,6 @@ Node dev page - @@ -24,11 +23,8 @@ -
- - diff --git a/web/main.js b/web/main.js index 0cd4aad..aa8568b 100644 --- a/web/main.js +++ b/web/main.js @@ -2,6 +2,8 @@ // arrays and stuff const sensorData = {}; let liveGraphs = []; +let nodeArray = []; +let nodeDict = {}; // letiables let intervalDelay = 5000; @@ -45,39 +47,21 @@ function openConnection() { openConnection(); function handleIncomingData(data) { - nodeNumber = data.node; + nodeAdressHandler(data.Node); + + nodeNumber = nodeDict[data.Node]; temperature = data.Temp; humidity = data.Humi; CO2 = data.eCO2; TVOC = data.TVOC; - processNodeData(nodeNumber, temperature, humidity, CO2, TVOC); + updateNodeData(nodeNumber, temperature, humidity, CO2, TVOC); } -function processNodeData(nodeNumber, temperature, humidity, CO2, TVOC) { - // Initialize the array for this node if it doesn't exist yet - if (!sensorData[nodeNumber]) { - sensorData[nodeNumber] = []; - } - - // Push the new data onto the array for this node - sensorData[nodeNumber].push({ - 'node': nodeNumber, - 'temp': temperature, - 'humi': humidity, - 'CO2': CO2, - 'TVOC': TVOC, - }); - - // updateNodeData(node, temperature, humidity, lightIntensity) - updateNodeData(nodeNumber, temperature, humidity, CO2, TVOC); - - // Log the array for this node - console.log(sensorData[nodeNumber]); - - // If the array for this node has more than 10 elements, remove the oldest one - if (sensorData[nodeNumber].length >= 10) { - sensorData[nodeNumber].shift(); +function nodeAdressHandler(node) { + if (!nodeArray.includes(node)) { + nodeArray.push(node); + nodeDict[node] = nodeArray.length; } } @@ -191,8 +175,11 @@ function updateNodeData(node, temperature, humidity, eCO2, TVOC) { document.getElementById("TVOCStatus").textContent = "Connected"; // Update the graph - liveGraphs[node - 1].updateData(temperature, humidity, eCO2, TVOC); - liveGraphs[node - 1].updateGraph(); + 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