From 6fd674f4c94ec33c09639035db238ec53fcedc91 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Wed, 27 Mar 2024 12:16:58 +0100 Subject: [PATCH 1/8] daily stand op 27 maart --- teamdocumentatie/dailyStandupNotes.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/teamdocumentatie/dailyStandupNotes.md b/teamdocumentatie/dailyStandupNotes.md index 64153e3..f5a63bb 100644 --- a/teamdocumentatie/dailyStandupNotes.md +++ b/teamdocumentatie/dailyStandupNotes.md @@ -87,4 +87,11 @@ Sam, tft scherm, rest api ombouwen om data in node tabel te douwen Sam: gebouw beheer vragen, Wall mounted enquete doos Sietse: rest api encete vragen Bram: expert voorbereigen, node data updaten - Dano: Documentatie schreiven, \ No newline at end of file + Dano: Documentatie schreiven, + +27/03/2024 + + Bram: OOP python + Sam: new website + Sietse: enquete screen data sending to database and database cript better + Dano: documentation about oop arduino \ No newline at end of file From 98e47d39fc82753b0fee42349286ea764227f801 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Wed, 27 Mar 2024 12:18:08 +0100 Subject: [PATCH 2/8] Uml node class --- docs/node-documentation/NodeClassUml.md | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/node-documentation/NodeClassUml.md diff --git a/docs/node-documentation/NodeClassUml.md b/docs/node-documentation/NodeClassUml.md new file mode 100644 index 0000000..2259384 --- /dev/null +++ b/docs/node-documentation/NodeClassUml.md @@ -0,0 +1,43 @@ +### Uml diagram: + +``` mermaid +classDiagram + +namespace Esp { + class Websockets{ + +webSocket + +_WiFiMulti + hexdump() + websocketSetup() + loop() + webSocketEvent() + sendMyText() + } + + class NodeReadings{ + + +TVOC_base, eCO2_base + +counter + +eCO2 + +TVOC + +interval + +temperature + +humidity + +currentMillis + +lastMillis + +errorSGP30 + +errorDHT11 + +noise + + setup() + loop() + resetValues() + update() + checkForError() + displayData() + + } + + +} +``` From 6d548f7738e7ac3ab97e2891ccf0e9e063151910 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Wed, 27 Mar 2024 12:19:28 +0100 Subject: [PATCH 3/8] node class OOP --- .../NodeClassDocumentation.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/node-documentation/NodeClassDocumentation.md diff --git a/docs/node-documentation/NodeClassDocumentation.md b/docs/node-documentation/NodeClassDocumentation.md new file mode 100644 index 0000000..d0bc370 --- /dev/null +++ b/docs/node-documentation/NodeClassDocumentation.md @@ -0,0 +1,20 @@ +# OOP within Arduino + +Object-Oriented Programming (OOP) is a way of programing that provides a means of structuring your code so the code is modular and can be used more often without making huge changes or having to copy past the same code. + +## Abstraction + +Abstraction in OOP is the process of exposing only the required essential variables and functions. This means hiding the complexity and only showing the essential features of the object. In Arduino, this could mean creating a class like `Sensor node` with methods such as `setUp()`, `displayData()`, and `checkForError()`. + +## Encapsulation + +Encapsulation is the technique used to hide the data and methods within an object and prevent outside access. In Arduino, this could mean having private variables and methods in a class that can only be accessed and modified through public methods. + +## Which classes did we use + +In this Arduino project, we used several classes to organize our code and manage the complexity of the project. Some of these classes include: + +- `websockets`: This class is responsible for managing the WebSocket connections. +- `nodeReadings`: This class is responsible for managing the sensor readings. + +Each of these classes encapsulates the data and methods related to a specific part of the project, making the code easier to understand and maintain. \ No newline at end of file From b914be9534f7e51585e1453dad1fb52ab3559b91 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Wed, 27 Mar 2024 12:20:36 +0100 Subject: [PATCH 4/8] Pages updates --- docs/.pages | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/.pages b/docs/.pages index effa9ce..ceb3c9b 100644 --- a/docs/.pages +++ b/docs/.pages @@ -11,6 +11,8 @@ nav: - TFT screen : node-documentation/TFT-screen - Classes : arduino-documentation/classes - Node Documentation: node-documentation/node + - Node Class: node-documentation/NodeClassDocumentation + - Node Uml Diagram: node-documentation/NodeUmlDiagram - 🍓 RPi Documentation: - Raspberry pi: Sp1SchetsProject/InfrastructuurDocumentatie/raspberryPi - MariaDB: rpi-documentation/mariadb-installation From b38730e9a14cfd9bc7dffd18251853b5c71609d9 Mon Sep 17 00:00:00 2001 From: Dano van den Bosch Date: Wed, 27 Mar 2024 12:22:35 +0100 Subject: [PATCH 5/8] typo in pages --- docs/.pages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/.pages b/docs/.pages index ceb3c9b..346a632 100644 --- a/docs/.pages +++ b/docs/.pages @@ -12,7 +12,7 @@ nav: - Classes : arduino-documentation/classes - Node Documentation: node-documentation/node - Node Class: node-documentation/NodeClassDocumentation - - Node Uml Diagram: node-documentation/NodeUmlDiagram + - Node Uml Diagram: node-documentation/NodeClassUml - 🍓 RPi Documentation: - Raspberry pi: Sp1SchetsProject/InfrastructuurDocumentatie/raspberryPi - MariaDB: rpi-documentation/mariadb-installation From cf86970605b74cce9f72fee25b661d64e975abed Mon Sep 17 00:00:00 2001 From: Sietse Jonker Date: Wed, 27 Mar 2024 14:13:22 +0100 Subject: [PATCH 6/8] Added filter code to handle sensor and enquete data from websocket --- docs/rpi-documentation/Databaseconnection.md | 183 ++++++++++++++++++- 1 file changed, 177 insertions(+), 6 deletions(-) diff --git a/docs/rpi-documentation/Databaseconnection.md b/docs/rpi-documentation/Databaseconnection.md index 52df974..8f6dd7f 100644 --- a/docs/rpi-documentation/Databaseconnection.md +++ b/docs/rpi-documentation/Databaseconnection.md @@ -1,32 +1,40 @@ +# Original Version (by bram) + ## 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 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 +//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="*******" + 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() @@ -49,7 +57,7 @@ The data collected from the websocket is json data, so this has to be changed. //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: @@ -70,9 +78,11 @@ The data collected from the websocket is json data, so this has to be changed. 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 +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(): @@ -94,4 +104,165 @@ async def main(): await receive_data() asyncio.run(main()) -``` \ No newline at end of file +``` + +# New Version (by sietse) + +## Changes made + +The original code was a good start, but it had some issues. The code could only handle the data from the sensorNodes and didn't include the nodeID for measurements. + +Since we have 2 kind of nodes (sensorNodes and enqueteNodes) we needed to make another function to commit the enqueteData in the database. I have also made a filter to know which data is from the sensorNodes and which data is from the enqueteNodes. This way we can commit the data to the right table in the database. + +I have also added a function to get the nodeID from the MAC address. This way we can commit the data to the right node in the database. + +## The new "filter" code + +### Function to get a list with macAdresses from the sensorNodes and enqueteNodes + +To filter i have made 2 lists, one with all the mac adresses of the sensorNodes and the other with the mac adresses of the enqueteNodes. + +The function that handles that and updates the list is the following: + +```python +async def getNodeInfo(type): + global sensorNodeArray + global enqueteNodeArray + + nodeInfoArray = [] + + id = (type,) + mydb = dbLogin() + cursor = mydb.cursor() + cursor.execute("""SELECT MAC FROM Node WHERE Type = %s""", id) + nodeInfo = cursor.fetchall() + + for tuples in nodeInfo: + for item in tuples: + nodeInfoArray.append(item) + print(nodeInfoArray) + + cursor.close() + mydb.close() + + if type == 'sensor': + sensorNodeArray = nodeInfoArray + print(sensorNodeArray) + return sensorNodeArray + + elif type == 'enquete': + enqueteNodeArray = nodeInfoArray + return enqueteNodeArray +``` + +As you can it works like this: + +1. It gets the MAC adresses from the database with the type of node you want to get the data from. (sensor or enquete) + +2. It executes the command and puts the data in a list. + +3. It uses a nested for loop to get the data out of the tuples and puts it in the nodeInfoArray. + +4. It updates, depending on what type, the sensorNodeArray or the enqueteNodeArray with the new data (NodeInfoArray). + +5. It returns the array with the data. + +### The filter code + +Now that we have the data we can filter the data from the websocket. + +```python + data = await websocket.recv() + + processedData = json.loads(data) + macAdress = processedData['node'] + + if "Temp" in processedData: + type = 'sensor' + else: + type = 'enquete' + + await getNodeInfo('sensor') + await getNodeInfo('enquete') + + if macAdress in sensorNodeArray: + nodeID = await getNodeID(macAdress) + await processSensorNodeData(data, nodeID) + elif macAdress in enqueteNodeArray: + nodeID = await getNodeID(macAdress) + await processEnqueteNodeData(data, nodeID) + else: + await newNode(macAdress, type) +``` + +As you can see its alot of code to explain. So to make it easier i made a mermaid diagram to show how the code works / what it does. + +```mermaid +graph TD + A[Get data from websocket] --> B{Is it sensor data or enquete data?} + B -->|sensor| C[Get sensorNodeArray] + B -->|enquete| D[Get enqueteNodeArray] + B -->|New node| E[Add new node to database] + C -->|data| G[Process sensorNodeData] + D -->|data| H[Process enqueteNodeData] +``` + +## The function to get the nodeID + +This function is used to get the nodeID from the MAC adress. This way we can commit the data with the right id in the database. + +The function to get the nodeID from the MAC adress is the following: + +```python +async def getNodeID(macAdress): + id = (macAdress,) + mydb = dbLogin() + cursor = mydb.cursor() + cursor.execute("""SELECT nodeID FROM Node WHERE MAC = %s""", id) + data = cursor.fetchall() + + for tuples in data: + for item in tuples: + nodeID = item + + return nodeID +``` + +1. It gets the nodeID from the database with the MAC adress. +2. It executes the command and puts the data in a list. +3. It uses a nested for loop to get the data out of the tuples and puts it in the nodeID. +4. It returns the nodeID. + +## The function to commit the data from the sensorNodes + +This function is alot like the original one, with the only 2 changes being that it now also commits the nodeID and that the code to make a new node is now in a different function. + +[Link to code](server\data.py) + +## The function to commit the data from the enqueteNodes + +This function is alot like the sensorNode function. It just commits the data to the enqueteData table in the database. And it has another data. + +[Link to code](server\data.py) + +## The function to add a new node to the database + +This function is used to add a new node to the database. This is used when a new node is connected to the websocket, but not yet in the database. + +The function to add a new node to the database is the following: + +```python +async def newNode(mac, type): + id = (mac, type) + mydb = dbLogin() + + cursor = mydb.cursor() + cursor.execute("INSERT INTO `Node` (MAC, Type) VALUES (%s, %s)", id) + print("new node assigned") + mydb.commit() +``` + +1. It gets the MAC adress and the type of node from the arguments. +2. It executes the command to add the new node to the database. +3. It prints that a new node is assigned. +4. It commits the data to the database. \ No newline at end of file From 5dee5d99abc6e44561037201af373c6d0540fecd Mon Sep 17 00:00:00 2001 From: Sietse Jonker Date: Wed, 27 Mar 2024 14:13:28 +0100 Subject: [PATCH 7/8] Fix QuestionID range in bullshitSenderENQUETE.py --- server/bullshitSenderENQUETE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bullshitSenderENQUETE.py b/server/bullshitSenderENQUETE.py index 1c58863..72bbbd0 100644 --- a/server/bullshitSenderENQUETE.py +++ b/server/bullshitSenderENQUETE.py @@ -12,7 +12,7 @@ async def send_data(uri): data = { "node": "69:42:08:F5:00:00", "Response": str(round(random.uniform(0, 2))), - "QuestionID": str(round(random.uniform(0, 90))), + "QuestionID": str(round(random.uniform(1, 2))), } await websocket.send(json.dumps(data)) print("Data sent") From 502ae3c614705e0297830ab35932204427968bbc Mon Sep 17 00:00:00 2001 From: Sam Hos Date: Wed, 27 Mar 2024 14:19:47 +0100 Subject: [PATCH 8/8] starting gauge --- web/new website/gauge.js | 20 +++++++++++++ web/new website/gauge.png | Bin 0 -> 8885 bytes web/new website/index.html | 32 ++++++++++++++++++++ web/new website/style.css | 59 +++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 web/new website/gauge.js create mode 100644 web/new website/gauge.png create mode 100644 web/new website/index.html create mode 100644 web/new website/style.css diff --git a/web/new website/gauge.js b/web/new website/gauge.js new file mode 100644 index 0000000..6040164 --- /dev/null +++ b/web/new website/gauge.js @@ -0,0 +1,20 @@ +// JavaScript +function updateGauge(value) { + const gaugeValue = document.getElementById('gaugeValue'); + const maxGaugeValue = 100; // Maximum value the gauge can display + const rotationDegree = ((value / maxGaugeValue) * 180) - 90; // Convert value to degree (-90 to 90) + + gaugeValue.style.transform = `rotate(${rotationDegree}deg)`; + + // Change color based on value + if (value <= 40) { + gaugeValue.style.backgroundColor = 'green'; + } else if (value <= 80) { + gaugeValue.style.backgroundColor = 'orange'; + } else { + gaugeValue.style.backgroundColor = 'red'; + } +} + +// Example usage: +updateGauge(50); // Rotates the gauge to 0 degrees (50 out of 100) and changes color to orange \ No newline at end of file diff --git a/web/new website/gauge.png b/web/new website/gauge.png new file mode 100644 index 0000000000000000000000000000000000000000..bc36a2bbc4fec5871910a0fb9aa2d6ada35b9759 GIT binary patch literal 8885 zcmV;mB1+wfP)EX>4Tx04R}tkv&MmKpe$iQ>8^(9PA+KkfA!+MMWG-6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Ya zocD<%tRgAI=fsl+U6A;Z>$1yloXZXiJTqeCGV{a{VzJ!Aau2hLp%Tv!M-^40d?D|$ z!g-6cT5GV*J^2emMQtU^b(&*HVhJgvAwot2Rn%Z1Myp1Oi45&0Jp3b$KTR%~Tvae~ zET9e*lH&*egWuhnrRga*DU<;EUu^qh90=?J?WS#iAKP~O1n@rtS6bI!Zvk_kq&K@- z^avQ-1}?6G?f}D2x@1U>F)18IJu zHW3@jN+qX25<{RUA_!s(1epg}ih(R8004s`#y<7?6l($i1Po&Ynl%AS>4D=+pwSe7 zR$m5;rV4cWvLLI=zm7E4GYFw>QtCu>!YqI>-scZ@9&)+ft4f5fvtoPz^pYQ}N({15 zO2blgB>Q^U0|VfUj#(OEq~@Di zhcOR$gs}t&%Rm7J1Q;Oz8b17)O=JL26hI0F1PUMk!~&vNpeZIHVd!-#T!7b<0BzoY z^Q_yQMWqMd1Ax;MXAw#5644i{)V8n?+u0W$ZM+>CvE2?2Lr-WB#DuSqQKSuNSi$n+!JyWyx3Qsc7 z*dFL#aoTak)Z=N_K{~o5DWz)SLd}~j5JDp)dWh(1m%FAvGFJD2r=#MQzqd3PbFAi5!P1BjXG6R<`$0bY zyQWdt#)UzPlm$~>63{7;Hl%4bCoR*4(IA~OkTh?cvgYp}FD=-8os9Am(bXjP`fI-K zx=XGb^>yAj?q(DkV}{0W;YG#Tc9s z%yoKnD;-${hbER+eDyj-(QPE!i0E@JcW1DF)A7kmc|(!$>NM}&5KBjGp13PplGB>m z_?w4x9{8Hh10|HO;LBG5Bnn6q7ulRN#aR4F+H|X*Su#>k`4`^W!c83rp=%@xiRiN` zc&oQ-b*r~yd#~$yos0M7I3nYD7%Q_qy#;HyF#MIl4olTL@;*Cd4j`w13&*$ufz~e# z*qMS4n1aKtb>)wBAcRPkC!)`+;Afp5tZnslZ5{Jm7(mp{H={%CL#>E{;x~ zZqXtZ+%yuKDr)oJUha!Ib`OR}H{bMima8d)|4ZsMLHL&52~~@1TEXJ4iCxe#D?wgy2gM<4=qm$d)yqzV^&~U!mpWCajki--* zc$yeeW7T46B0HTJ+5}?gdO!@EizX&+n)GGv#nzl(RH9>yE$5uAmXlML>-&QP2YS6- zTgQU~)tU1A6QYrbevh!ASlM{HHJ%(T5t8E@6(Mj_GOd0C%gI(m>lRIRM~g-9lT(*1 zQ8B*Om+&4q?`YXL=IPjwiSP15%OEt7DYpAU0RW!K@kXtCPua@8e%u}RTz#nexyWK@ z&Z7k`xT!ldl%C(rpxsAaw!^!VHUEH zK#aZr=Df)&POeGXf3n0CYN;_){naDMborYYnq|{)+Ks-m)s2e8+}vl-wFV5o`|mgEY6%5zsNaw z@BWtu-a7pLz>%jHT7@|k7GjuKK2uNtV3I?oHO~L_*wx5&#uazkhP*8&wpKnRETrtd z&@%ci3Q=GCcI%H;yS?q}7GhwI%Q^^Sh8Q~2B4AOsDt`Ik#FfTsYWa^30>CQ(aE6Gk zzHI)Lf9U?rGe3Rl9}Z=0Viv3k5m^IClF?_W?=EYrr15o;-sfuG^0gW<##soVHx|OX zp$wOs5f$m+NObC%|K9#jtNJD{u3iiQ`Cm=ruul^JnvA^98Y0m0d(8U2we_#}R+~#- zV=3lDCO74o43=CM7x~?9j-7tt|91cSk!0M(E|wtl$}Ge&4VHyDK&+PRPVbl69_ne? zvV6GmJNlhVo|7=f?`5j&87aD=$fm)_*v?<}A9?jvvK6ZM~ z>G89VPk1|@Sj<5;DH$O`rr72@BWgg@Rf!|Df!;q`>Z<;mqP)UG9LD%`CdjV(Xu%lg z`BR~WAMWxcEuH7@tQ71&Qbn zAh|2)+tF-qdHQ!fzuD?fxN}LUeMl73ki-<|7SPQtnbdF37A8$-{Ks3T+Hn2!zYH1@9-wvRuW<#6H*w6Vw#9PUzr^#U=j8GP{?EK7GlHIs$#$P7J^M><5mPCdV9~p`HnN6c$35fqWq6$IWME&k@F~l<&>+IN>r+U1dn>}%79towpG~F=+QH6-E4v7@V7VTCkbf(FVCFqco zAC1QQi0GfwCvOYf-tqp#*{84Buk45mF(V0~yW^JhkRVfRDv}*Tt~i;;gwHhv5az}? zqoAe%Iz}au7v1#tY&$h}`tY@>D~&|*>5;??$bjy;xdj6fML-c5BUwQRFi;@FhlfjY zSO5kAu%NI2U;zNqJeUF5bHu4UL-6=^KbIwXXbq@Ec18t~=XD1Mx1FE3aJYHm;*Ma_ zpG`t$y3Kb@&QqbmW>R|BQ52EDOTHZw-AO>4QaOlNHaNPq5UD$1>zXkw}^%sYzGDF>bA-H=Fm zKoA2Ur<|Zmje|vSKn|y~>Nv}qw47chNeLFo31F2Zr2$DxfA|GJ_yk3Y zrJ1aGmz|kM$*ta0aL3uni-)h;uQa*iE+Y9Spea@?G#2_Wmb;yCXM@$c{O9H7a#)$Y z1eRIKV@u8Dw+nT)E7@9$>wz*5MRx;0_ZR)YV8UUGB}SY4!JDhYfooYT-wzf!W-QPe zs%R|K3Sxp)q!8#8o?$^Tks1VGMW0FI`rY=Bu2SH*r(*zcYSD=v6BA9%?wik?9D8p& znL_)RTtl9ZMogPIt8(H%=?-6g-kJ~0obk&ghWvTmEoC(n`vKscJ3k+NSzAOY*5nSh zH4M8i+GO`pw2FPSWfm&h`{w&-eL?=IRr^;r4Na|TwwppF_& zi2SabBd_d^druY@rw5A*WM2&$>(7Z|>e%Q1@Q8)^dI^ymvSq+uA#MbU${! zy0IkLwZ&@s$uc0( zi$VA}(kD+^o;!PR-FIKk)fb+cE7|94FiupYT_>k5fBnMHu|;*pTcM@gxx4z&u189m z+E-^UJ+)W`|3hX$=o$cA!x+~O`g;#_OugP<_8nPMERNaCkfx~xezL6|Cv^`;e!Ktr zcn$1b{>?N1yt|+>dS7VtSKm1I7hhW}r?oCC*yuc1wZCs`;fCv##^NIgp*A3VUWQ*k z7I!?=H}O^jcK&wRid08Y0kyF2m6HI09p#AZrc2KC72FW*7 zJbd%9s(s$gd9}?pP1Z4lP#@9xk7oEb0BFM)*Z7w_|7gGS%+}%Ym-1F6nsc*}SiTV7 znE?!CI6#fHJ-tRzAO zg&xOSfo$immzAM#)q;~9%S>(b#J-mCqd^5L7XcviL=UARtb_ON|Ms;XE!b<4))s6( z{-vdRE+iG{U6$6mH`-S53-x~OxrU`V2gdl9GNn5!npYmWI`Q)1<;m-ta?rv$QHR44 zV;uNTs|z+A+3!yVe{a)S#f%XhW32P0g4=)5|HfC{o`rd3tzunG&C<*u!UO zOyo?bnQzV~0iZuE2_e>86CLrK4fyQ;ykv#qShA4bvr?K^-O}^juWsG=e-d{#zsz{D zK(ipZ$)4~uov}AR_hRc0pIvCd*ZK9Eh$uMsV2n*yT~~{9lLH6bqd$A9Hr>{+koxX1 zq>pu%|Bn+5OJDenk;}R?)AQ>yp3%EQL)p%R`^nb^j_xCp6J{{G#{i%|CL|&d!k{YZR<32r>2+JoYOhxhk9S5<WwS`?X*N`^P&vy`x&^&F`wr4scRV~grC`Ws{K*_<)Qp{}Xsj2~sE5G6gm^4YWd zD)(RfJNR$JEH&2^MNeRi-|p5e6(-%Kg3b5#W-AWqxC|YrLjX{~cPw$cPd+Ko#uUc5 zWhO3hoDtFe$)M#oL+`A;>};*g^uWn77GA2$tvR=&d{^_@oaKW=rHsh%PK@!pZH$Ey zSiKVV99@zlxr*oyPq@uEbU1A?2T$*0ZCesCesTZ+=3jJ-v93Ebw9(J|4vu*`GJ2V- zEvxcEQ_0ph{`EsopDi)u4-rT`o`Sm+bb_=4${jGH;?|j4c;k*K6CoU0WRC(Tv<_ zq-FGcRnD>-+sgMG`F9UJO(b6k{dUeWq6m?sgVxi$>s2s_-n9%CGfsBB9J59O=Qk=@ zb!#!kt_R8L4 zzEg@O?O4xcU}o1O`b+p=%WfA}*b4ytb1pi@*z#iUE6e(QJ)1p|@!U)dhJviBOB;$C zU;Fyf$KOW?jSxK+SW}+XO=3Cu`@wcW(g)80798s}878|HL~AtIvRPoP7w%;B`#LWA zzUR?fy`9yuWMF4kpf@A4xz$|STyA^loxfi50+D=y%f58|&ril|hu#h{`F$c#8MpaJ z&kvNKlw-Hu+gx_vEu8zz=K5A&SM_LQY;!#B&d;=hvl#Lxc9d?r_)_Ed-XoGPf@VBL zPp(+|)6+uEzKdR_&?#luq8fvc&Q-=c>I2tbU7-k(`&t@%UrqPH=y-LI_wDHo43uSJ z#eb>lk^Y0#2QMRp`iTaMM)rP3WcUhiFRKkr{O>%Q640q#cPt=K5)6nQ4z%NrVtqw) zPoVH*KTP8atp^qzW32ya@BgcIM z(_VD=tytP;Ou2qhufu6ZwSp&Ukh~nENAw^%wV()8t|<0wPUw}>iX!(@6fMrG=n)~d zf)^4yZ-++;Gp(XG7B{x+uRid4ecqbm2q7m4{YBPaM`#jb{O(}>LC%|YK}qmfy_z<{ zUV;-8ujy{*JR2;9LAHzS);-X6f{4FzxUM+mlUL1DHQD`h%x*Y(90HAGFL~r$V zu5yKkngWsWqD-k&ovCDWN7>GkyNc>hAcR~b%n5g7_xh8;cbV8={^aOSa_9V%SqvaJ zw7_4pfaudq|MwCoKjxWg^qu{WH}6ICX-}_VjMuk%y0(tT-L_1s&?m}vkC*EUPi1LL zL~_EXu<5L>Np9IGzT|~*VP+3o`lJ1DVL}Iyck>`}BJbWL|0t{5NAqp{lUp&y>t{Tp zw|Lsu4tZ`h`JUg-?>uO0VwH@Kq{8I#SQtbBOPl?t6)Z(Hdjmnsnc7-o&p72qmPCJO&#T%Ms- zb2v>wdRPz9_j4iEoDHIf11ur{WoDk43(8i-o^0s$v`yZ|$1o+mc{_YnSCeXQxNpHz6bMr~NDUf53b23$>T{>c9{igG zKpg9}22cL5XhuZG7}q~_?k~&Sakn`WDokf88QoX5{r3iq< z_0-X+@Fq#(4Vh43PgEZmOe@Oq6_!dDX|faU1wE^^E9Ujb{rP_~INhTq6`qDvzY*e> zt-!aNL3CIRF4i$b#L$+L7j$8Xq{LUvl3lPD*@6ERb1URDa{qvYqdwd*T=Z(t4!2-1Uk zh&Nk-?=*wx(tsRg=3eqU(7eE!9jRhPk!$W-^x@c4T|DNfO$jm8H`_N=JbZI`R`oHC zW*wx-PI!R6x=3paJ-IpcmnPXN`=lRY@V15zAcAP$fJlx!LPQUWgr)%D>ek2@Ir%?qu+GGo*$L zAO&Y|KK#L9m1LxdZ~a}>eT)9SNLCLalf9_; z%a?q?B4?s2OHK`|PVkSPmrrsASF{+*$?AI+-JbANPX+ocA>Ny<_KG=JwZG4%$vTD* zBBB#!CVAv;6!VN_$C4#a_sP6oQS-AR33GIuS{ds9{f>JUy*D)6#K_`mwO2^BZIyF- z;ieXZP#+0T!c1m$gixQY{!d%dxvU3MD!!Uo0j-?o%Yz;7uDEB>FF3ESmatNx_6pfm zxwp66Sa^(tCSf)x%vyCU-mtX~kh(8zRQR|?85%0a7#B`k^l&;>-tN4X=S#Q?R9y*{ zO3$9+hRf4g)K4JXXJ&89YW&7!F-PZD^K()uNuv$nW$F0j-f4?I6rI>13z21NuY@h- zyLy&eDo>JdB+P2}uzd4Le$9#=%&2$_NCvGOO;?46&uy5t=vO?qHl$_oAvG7i%~xN)$m;CYXRl+UHV6n*+gDfkC=9A_|o>PcYRu^yS z*l1ft`sRc=Vb!{)k3pri9kWzgwO>eS5oyM}MoE$^UnqK5i0uqV#wyiZ=vvkg+ErBF zi4eL*LXa>=S^b(&*Ki%Q8r5cXBmu((sKTiG_TDcPy)Qi4NKs6+nhRZT$iKe5VAEL= zeuTLsf7iFqVwRmu1rWxFOKJN=fza1WdxDeN<^*uORliXcc?;v4Em=995k4!3@E}_~7 zlx4&QBCMjw>|I627_)uhVO1A2&1yS#7jM2yLXI#WtlRZpE^`L13n)YAxh!ZFc0b@?GRgCBnRtT))MQwfdA=pHEQ)#@lhE_^zUN1qO=KvY^`j zIYRV}eMODuNT?C!lQoBaa8ASNZvcXrDn%F5z>jpo-9--#LPAWiYJ7N>)}(FLWp)4{ zqwR$GZNBSrPV-qYH|EqjpDqFAblzR`&cFajim1wiCh`sWfkS0GJq*K;J?DgZM_jQ) zRP;J^ZfTPNP*A$N=o6tK)fTLxNNsC!mXnom1XYl=^~+w`n4MOs=oFna*|414_ZiXs z$>1)D_dc%Hf_2872hE)E3JEcS8ptg_aE&&w-9UjF2j#R_K`SEzrylu?=sn@#LuxMA zoSYSZUt-87H?I&>fkszwA%&tNm;qI0bww5puD&zNKO_3>;K)+77OI{zC91NjNOTcY z144+87?gy}(dt|dD@!0v4zQmQy)Qhf+G#Z-XA)LrFCo!IP!&Q^IVhY;wNWt8j*nN0 z|3UPT_>^i3R7-Q>Lzb#A2`z$};FfL)BaK0ovp`6}pz-ma6+M(zarYPFfhto;4+$-T zny^-F>tSil03a2vd&hvN2-0GV>pvxWT8OK*K*MsXKUbSgrq&3m!jiZ03ZnR7pm9ot zqSFYtDxC5h_>|~!+_guo1**~JM6>rK2vxA4In&JgObi*3()jGZvDFBB&A}KOYp1Q>o_| z_{fJ1VF~~sC8ZxzYe8}}3wb&#i70|95v>)Va5{B*4j57q=f|SQ#6+EHMW-0ButpM5 z1a)FA1z_~5&FIOP|6|d^LQJ(OlcgBQ(wIm<5!9K8%%wmvTGfi4js-s!JtD+Fy`r;_ z#hFP&5mbpjyChAsT9uv(ivjr9Cq-B996AL^%H}L&4?01eq8sz4Xa#uz)OXf9#sD}e zd@OoMh^n?A1w{xLIXyWij-W~mW@`(bN_GN(>Lfyd0r8QKMGvIayNo=PjdP=<+-I)%_T1G=|OeLrmq{RTV zI!~1X<-_M<005$5T(wusFuEMF^p&7$FoP8kkOZK%!y>Un$5YB5M30MnCjjhKTLDrO z + + + + + bruh + + + + +
+
+
+ + +
+ +
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/web/new website/style.css b/web/new website/style.css new file mode 100644 index 0000000..b17f43c --- /dev/null +++ b/web/new website/style.css @@ -0,0 +1,59 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +.gaugeContainer { + width: 300px; + height: 300px; + border: 3px solid black; + border-radius: 50%; + margin: 50px auto; + position: relative; +} + +.center-point { + width: 20px; + height: 20px; + background-color: black; + border-radius: 50%; + position: absolute; + top: 137px; + left: 137px; +} + +.speedometer-scale { + width: 8px; + height: 280px; + background-color: black; +} + +/* CSS */ +/* CSS */ +.gaugeContainer { + width: 300px; + height: 300px; + border: 3px solid black; + border-radius: 50%; + margin: 50px auto; + position: relative; + display: block; +} + +.gaugeValue { + width: 10px; + height: 150px; + position: absolute; + bottom: 50%; + left: 50%; + transform-origin: bottom; + transition: transform 0.3s ease, background-color 0.3s ease; /* Smooth transition for rotation and color change */ +} + +.gaugeImage { + display: block; + margin-left: auto; + margin-right: auto; + width: 100%; +} \ No newline at end of file