diff --git a/backend/Api/Program.cs b/backend/Api/Program.cs index 02c216a..5802836 100644 --- a/backend/Api/Program.cs +++ b/backend/Api/Program.cs @@ -22,7 +22,7 @@ class Program public static async void RunMigrations(IWebHost app) { await using var scope = app.Services.CreateAsyncScope(); - await using var db = scope.ServiceProvider.GetService(); + await using var db = scope.ServiceProvider.GetService(); if (db != null) { await db.Database.MigrateAsync(); diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..fbe12ea --- /dev/null +++ b/deploy.sh @@ -0,0 +1,16 @@ +#!/usr/bin + +BASEPATH=/home/developers/temperature-alarm + +# Fetch changes +git -C $BASEPATH pull + +# Update frontend +cp $BASEPATH/frontend/* -r /var/www/html +chown www-data:www-data -R /var/www/html + +# Update backend +docker stop api +docker build --tag api $BASEPATH/backend/Api +docker run -d -p 8080:80 -p 8081:443 -p 5000:5000 --name api --rm api + diff --git a/frontend/mockdata/temperature-logs.mockdata.js b/frontend/mockdata/temperature-logs.mockdata.js index eaef375..e6056ae 100644 --- a/frontend/mockdata/temperature-logs.mockdata.js +++ b/frontend/mockdata/temperature-logs.mockdata.js @@ -1,28 +1,28 @@ export const mockTemperatureLogs = [ - { Id: 1, Temperature: 18.9, Date: "2025-03-19T17:00:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 19.1, Date: "2025-03-19T17:10:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 19.5, Date: "2025-03-19T17:20:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 19.8, Date: "2025-03-19T17:30:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.1, Date: "2025-03-19T17:40:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.3, Date: "2025-03-19T17:50:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.6, Date: "2025-03-19T18:00:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.9, Date: "2025-03-19T18:10:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.8, Date: "2025-03-19T18:20:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.7, Date: "2025-03-19T18:30:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.5, Date: "2025-03-19T18:40:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.3, Date: "2025-03-19T18:50:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.1, Date: "2025-03-19T19:00:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 18.9, Date: "2025-03-19T20:00:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 19.1, Date: "2025-03-19T20:10:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 19.5, Date: "2025-03-19T20:20:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 19.8, Date: "2025-03-19T20:30:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.1, Date: "2025-03-19T20:40:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 20.3, Date: "2025-03-19T20:50:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 22.6, Date: "2025-03-19T21:00:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 22.9, Date: "2025-03-19T21:10:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 22.8, Date: "2025-03-19T21:20:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 22.7, Date: "2025-03-19T21:30:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 22.5, Date: "2025-03-19T21:40:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 23.3, Date: "2025-03-19T21:50:00Z", TempHigh: 22.0, TempLow: 18.0 }, - { Id: 1, Temperature: 24.1, Date: "2025-03-19T22:00:00Z", TempHigh: 22.0, TempLow: 18.0 }, -]; + { id: 1, temperature: 18.9, date: "2025-03-19T17:00:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 19.1, date: "2025-03-19T17:10:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 19.5, date: "2025-03-19T17:20:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 19.8, date: "2025-03-19T17:30:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.1, date: "2025-03-19T17:40:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.3, date: "2025-03-19T17:50:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.6, date: "2025-03-19T18:00:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.9, date: "2025-03-19T18:10:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.8, date: "2025-03-19T18:20:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.7, date: "2025-03-19T18:30:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.5, date: "2025-03-19T18:40:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.3, date: "2025-03-19T18:50:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.1, date: "2025-03-19T19:00:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 18.9, date: "2025-03-19T20:00:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 19.1, date: "2025-03-19T20:10:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 19.5, date: "2025-03-19T20:20:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 19.8, date: "2025-03-19T20:30:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.1, date: "2025-03-19T20:40:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 20.3, date: "2025-03-19T20:50:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 22.6, date: "2025-03-19T21:00:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 22.9, date: "2025-03-19T21:10:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 22.8, date: "2025-03-19T21:20:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 22.7, date: "2025-03-19T21:30:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 22.5, date: "2025-03-19T21:40:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 23.3, date: "2025-03-19T21:50:00Z", tempHigh: 22.0, tempLow: 18.0 }, + { id: 1, temperature: 24.1, date: "2025-03-19T22:00:00Z", tempHigh: 22.0, tempLow: 18.0 }, +] diff --git a/frontend/pages/home/home.css b/frontend/pages/home/home.css index 1f47ee0..d0c75f3 100644 --- a/frontend/pages/home/home.css +++ b/frontend/pages/home/home.css @@ -1,28 +1,113 @@ body { - margin: 0; - font-family: Arial, Helvetica, sans-serif; - } - - .topnav { - overflow: hidden; - background-color: #333; - } - - .topnav a { - float: left; - color: #f2f2f2; - text-align: center; - padding: 14px 16px; - text-decoration: none; - font-size: 17px; - } - - .topnav a:hover { - background-color: #ddd; - color: black; - } - - .topnav a.active { - background-color: #04AA6D; - color: white; - } \ No newline at end of file + margin: 0; + font-family: Arial, Helvetica, sans-serif; +} + +#container { + background-color: white; + opacity: 100%; +} + +.topnav { + overflow: hidden; + background-color: #333; +} + +.topnav a { + float: left; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; + font-size: 17px; +} + +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.topnav a.active { + background-color: #04aa6d; + color: white; +} + +table { + font-family: arial, sans-serif; + border-collapse: collapse; + width: 100%; +} + +td, +th { + border: 1px solid #dddddd; + text-align: left; + padding: 8px; +} + +tr:nth-child(even) { + background-color: #dddddd; +} + +.tempHigh { + color: #ff0000; + width: 20px; +} + +.tempMidHigh { + color: #fffb00; + width: 20px; +} + +.tempNormal { + color: #02ed26; + width: 20px; +} + +.tempMidLow { + color: #16fae7; + width: 20px; +} + +.tempLow { + color: #0004ff; + width: 20px; +} + +/* The Modal (background) */ +.modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + background-color: rgb(0, 0, 0); /* Fallback color */ + background-color: rgba(0, 0, 0, 0.6); /* Black w/ opacity */ +} + +/* Modal Content/Box */ +.modal-content { + border-radius: 20px; + background-color: #fefefe; + margin: 15% auto; /* 15% from the top and centered */ + padding: 20px; + border: 1px solid #888; + width: 80%; /* Could be more or less, depending on screen size */ +} + +/* The Close Button */ +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} diff --git a/frontend/pages/home/home.html b/frontend/pages/home/home.html index f06efff..c3727a5 100644 --- a/frontend/pages/home/home.html +++ b/frontend/pages/home/home.html @@ -1,21 +1,38 @@ - - - + + + Temperature-Alarm-Web - - -
+ + + +
+ - - - - - - \ No newline at end of file + + + + + + + + + + + + +
NameTemperatureDateTempHighTempLow
+
+ + + + diff --git a/frontend/pages/home/home.js b/frontend/pages/home/home.js index 6f739c7..d8f59dc 100644 --- a/frontend/pages/home/home.js +++ b/frontend/pages/home/home.js @@ -1,30 +1,84 @@ import { mockTemperatureLogs } from "../../mockdata/temperature-logs.mockdata.js"; // Import data -const xValues = mockTemperatureLogs.map(log => new Date(log.Date).toLocaleString()); // Full Date labels -const yValues = mockTemperatureLogs.map(log => log.Temperature); // Temperature values - +const xValues = mockTemperatureLogs.map((log) => + new Date(log.date).toLocaleString() +); // Full Date labels +const yValues = mockTemperatureLogs.map((log) => log.temperature); // Temperature values +buildTable(mockTemperatureLogs); new Chart("myChart", { - type: "line", - data: { - labels: xValues, - datasets: [{ - fill: false, - lineTension: 0.4, - backgroundColor: "rgba(0,0,255,1.0)", - borderColor: "rgba(0,0,255,0.1)", - data: yValues - }] + type: "line", + data: { + labels: xValues, + datasets: [ + { + fill: false, + lineTension: 0.4, + backgroundColor: "rgba(0,0,255,1.0)", + borderColor: "rgba(0,0,255,0.1)", + data: yValues, + }, + ], + }, + options: { + tooltips: { + callbacks: { + title: function (tooltipItem) { + return `Date: ${tooltipItem[0].label}`; + }, + label: function (tooltipItem) { + return `Temperature: ${tooltipItem.value}°C`; + }, + }, }, - options: { - tooltips: { - callbacks: { - title: function(tooltipItem) { - return `Date: ${tooltipItem[0].label}`; - }, - label: function(tooltipItem) { - return `Temperature: ${tooltipItem.value}°C`; - }, - } - } - } + }, }); + +function buildTable(data) { + var table = document.getElementById(`TemperatureTable`); + data.forEach((log) => { + var averageTemp = (log.tempHigh + log.tempLow) / 2.0; + var color; + if (log.temperature > log.tempHigh) { + color = "tempHigh"; + } else if ( + log.temperature < log.tempHigh && + log.temperature > averageTemp + ) { + color = "tempMidHigh"; + } else if (log.temperature < log.tempLow) { + color = "tempLow"; + } else if (log.temperature > log.tempLow && log.temperature < averageTemp) { + color = "tempMidLow"; + } else { + color = "tempNormal"; + } + var row = ` + Name + ${log.temperature} + ${log.date} + ${log.tempHigh} + ${log.tempLow} + `; + table.innerHTML += row; + }); +} + +// Get the modal +var modal = document.getElementById("chartModal"); +var btn = document.getElementById("myBtn"); +var span = document.getElementsByClassName("close")[0]; +btn.onclick = function () { + modal.style.display = "block"; +}; + +// When the user clicks on (x), close the modal +span.onclick = function () { + modal.style.display = "none"; +}; + +// When the user clicks anywhere outside of the modal, close it +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = "none"; + } +}; diff --git a/frontend/pages/login/login.css b/frontend/pages/login/login.css index e69de29..ad00dbe 100644 --- a/frontend/pages/login/login.css +++ b/frontend/pages/login/login.css @@ -0,0 +1,41 @@ +body {font-family: Arial, Helvetica, sans-serif;} + +.container{ + display: flex; + justify-content: center; +} + +/* Full-width input fields */ +input[type=text], input[type=password], input[type=email] { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: inline-block; + border: 1px solid #ccc; + box-sizing: border-box; +} + +/* Set a style for all buttons */ +button { + background-color: #04AA6D; + color: white; + padding: 14px 20px; + margin: 8px 0; + border: none; + cursor: pointer; + width: 100%; +} + +button:hover { + opacity: 0.8; +} + +.form-container { + width: 800px; + padding: 16px; +} + +.registerText{ +display: flex; +justify-content: space-between; +} \ No newline at end of file diff --git a/frontend/pages/login/login.html b/frontend/pages/login/login.html index e69de29..c0d7fe6 100644 --- a/frontend/pages/login/login.html +++ b/frontend/pages/login/login.html @@ -0,0 +1,36 @@ + + + + + + + + +
+
+
+

Login

+ + + + + + + + +
+ + +
+
+
+
+ + + + + \ No newline at end of file diff --git a/frontend/pages/login/login.js b/frontend/pages/login/login.js index e69de29..55e303b 100644 --- a/frontend/pages/login/login.js +++ b/frontend/pages/login/login.js @@ -0,0 +1,13 @@ +import { login } from "../../services/users.service.js"; + +document.getElementById("loginForm").addEventListener("submit", function(event) { + event.preventDefault(); // Prevents default form submission + + // Get form values + const emailOrUsername = document.getElementById("emailorusn").value; + const password = document.getElementById("psw").value; + + + // Call function with form values + login(emailOrUsername, password); +}); \ No newline at end of file diff --git a/frontend/pages/register/register.css b/frontend/pages/register/register.css index e69de29..ed7bcfc 100644 --- a/frontend/pages/register/register.css +++ b/frontend/pages/register/register.css @@ -0,0 +1,41 @@ +body {font-family: Arial, Helvetica, sans-serif;} + +.container{ + display: flex; + justify-content: center; +} + +/* Full-width input fields */ +input[type=text], input[type=password], input[type=email] { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: inline-block; + border: 1px solid #ccc; + box-sizing: border-box; +} + +/* Set a style for all buttons */ +button { + background-color: #04AA6D; + color: white; + padding: 14px 20px; + margin: 8px 0; + border: none; + cursor: pointer; + width: 100%; +} + +button:hover { + opacity: 0.8; +} + +.form-container { + width: 800px; + padding: 16px; +} + +.loginText{ +display: flex; +justify-content: flex-end; +} \ No newline at end of file diff --git a/frontend/pages/register/register.html b/frontend/pages/register/register.html index e69de29..cc8e996 100644 --- a/frontend/pages/register/register.html +++ b/frontend/pages/register/register.html @@ -0,0 +1,39 @@ + + + + + + + +
+
+
+

Create Account

+ + + + + + + + + + + + + + +
+ +
+
+
+
+ + + + + + \ No newline at end of file diff --git a/frontend/pages/register/register.js b/frontend/pages/register/register.js index e69de29..c61efa6 100644 --- a/frontend/pages/register/register.js +++ b/frontend/pages/register/register.js @@ -0,0 +1,14 @@ +import { create } from "../../services/users.service.js"; + +document.getElementById("registerForm").addEventListener("submit", function(event) { + event.preventDefault(); // Prevents default form submission + + // Get form values + const email = document.getElementById("email").value; + const username = document.getElementById("uname").value; + const password = document.getElementById("psw").value; + const repeatPassword = document.getElementById("rpsw").value; + + // Call function with form values + create(email, username, password, repeatPassword); +}); \ No newline at end of file diff --git a/frontend/services/users.service.js b/frontend/services/users.service.js index 4b7d530..d53f238 100644 --- a/frontend/services/users.service.js +++ b/frontend/services/users.service.js @@ -1,32 +1,35 @@ const address = "http://10.135.51.116/temperature-alarm-webapi/users" -function login(username, password) { +export function login(usernameOrEmail, password) { + console.log(usernameOrEmail); + console.log(password); + fetch(`${address}/login`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({username: username, password: password}) + body: JSON.stringify({usernameOrEmail: usernameOrEmail, password: password}) }) .then(response => response.json()) .then(data => console.log("Success:", data)) .catch(error => console.error("Error:", error)); } -function create(email, username, password){ +export function create(email, username, password, repeatPassword){ fetch(`${address}/create`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({email: email, username: username, password: password}) + body: JSON.stringify({email: email, username: username, password: password, repeatPassword: repeatPassword}) }) .then(response => response.json()) .then(data => console.log("Success:", data)) .catch(error => console.error("Error:", error)); } -function update(email, username, password){ +export function update(email, username, password){ fetch(`${address}/update`, { method: "PATCH", headers: { diff --git a/iot/main.c b/iot/main.c index 06b99d6..8430bb3 100644 --- a/iot/main.c +++ b/iot/main.c @@ -10,12 +10,12 @@ void *watch_temperature(void *arg) { - init_temperature(); + temperature_handle_t temp_handle = init_temperature(); - get_temperature(); + get_temperature(temp_handle); while (true) { - double temperature = get_temperature(); + double temperature = get_temperature(temp_handle); char *str = malloc(snprintf(NULL, 0, "%lf", temperature) + 1); sprintf(str, "%lf", temperature); diff --git a/iot/temperature.c b/iot/temperature.c index 7f8348e..1719733 100644 --- a/iot/temperature.c +++ b/iot/temperature.c @@ -9,6 +9,8 @@ #include #include +#include "temperature.h" + #define MPC9808_BUS "/dev/i2c-2" #define MPC9808_ADR 0x18 @@ -21,14 +23,12 @@ #define DEVID_REG 0x07 #define RES_REG 0x08 -int file; - uint8_t get_byte_in_integer(int num, int n) { return (num >> (8*n)) & 0xff; } -double get_temperature() +double get_temperature(temperature_handle_t file) { double temperature; int32_t reg32; @@ -51,9 +51,10 @@ double get_temperature() return temperature; } -void init_temperature(void) +temperature_handle_t init_temperature(void) { - file = open(MPC9808_BUS, O_RDWR); + int file = open(MPC9808_BUS, O_RDWR); + if (file < 0) { fprintf(stderr, "Error opening temperature sensor device (%s): %s\n", MPC9808_BUS, strerror(errno)); exit(1); @@ -71,24 +72,26 @@ void init_temperature(void) // Read manufactorer ID reg32 = i2c_smbus_read_word_data(file, MANID_REG); - if ( reg32 < 0 ) { + if (reg32 < 0) { fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", MANID_REG,strerror(errno)); exit(1); } if (bswap_16(reg16poi[0]) != 0x0054) { - fprintf(stderr, "Manufactorer ID wrong is 0x%x should be 0x54\n",__bswap_16(reg16poi[0])); - exit(1); + fprintf(stderr, "Manufactorer ID wrong is 0x%x should be 0x54\n",__bswap_16(reg16poi[0])); + exit(1); } // Read device ID and revision reg32 = i2c_smbus_read_word_data(file, DEVID_REG); if (reg32 < 0) { - fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", DEVID_REG,strerror(errno) ); - exit(1); + fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", DEVID_REG,strerror(errno) ); + exit(1); } if (reg8poi[0] != 0x04) { - fprintf(stderr, "Manufactorer ID OK but device ID wrong is 0x%x should be 0x4\n",reg8poi[0]); - exit(1); + fprintf(stderr, "Manufactorer ID OK but device ID wrong is 0x%x should be 0x4\n",reg8poi[0]); + exit(1); } + + return file; } diff --git a/iot/temperature.h b/iot/temperature.h index 8bd0a39..e1f1471 100644 --- a/iot/temperature.h +++ b/iot/temperature.h @@ -1,4 +1,6 @@ -void init_temperature(); +typedef int temperature_handle_t; -double get_temperature(); +temperature_handle_t init_temperature(); + +double get_temperature(temperature_handle_t handle);