iot sensor finished

1)with validation on front and backend
2)fixed seed route generating value 0 for data
This commit is contained in:
newtbot
2024-01-14 02:43:27 +08:00
parent a7e1a0028e
commit c00a57d5f6
12 changed files with 417 additions and 148 deletions

View File

@ -0,0 +1,75 @@
"use strict";
const { Sequelize, DataTypes } = require("sequelize");
const { sequelize } = require("./mySQL");
const { isAlphaNumericwithSpaces } = require('../../Web-Server/functions/validateData')
//sequelize.sync();
const locationModel = sequelize.define(
"location",
{
id: {
type: DataTypes.INTEGER,
allowNull: true,
primaryKey: true,
autoIncrement: true,
validate: {
isNumeric: true,
},
},
name: {
type: DataTypes.STRING,
allowNull: false,
length: 10,
unique: true,
validate: {
notEmpty: true,
len: [1, 20],
//accept only alphanumeric and spaces
isAlphaNumericwithSpaces(value){
if(!isAlphaNumericwithSpaces(value)){
throw new Error('Invalid characters in name')
}
}
},
},
added_by: {
type: DataTypes.STRING,
allowNull: false,
length: 10,
validate: {
notEmpty: true,
len: [1, 20],
is: ["^[a-z0-9]+$", "i"],
isIn: [['admin', 'system' , 'Admin', 'System']],
},
},
description: {
type: DataTypes.STRING,
allowNull: true,
length: 100,
validate: {
notEmpty: true,
len: [1, 100],
/*
//will not validate this and fail it
"hello@123" (contains a symbol)
"" (empty string)
*/
is: ["^[a-zA-Z0-9 ]+$", "i"]
},
},
createdAt: {
type: DataTypes.DATE,
allowNull: true,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
timestamps: true,
}
);
module.exports = { locationModel };

View File

@ -0,0 +1,34 @@
const dotenv = require("dotenv");
const path = require('path')
require('dotenv').config({ path: path.resolve(__dirname, '../../.env') })
const Sequelize = require("sequelize");
const fs = require('fs');
const sequelize = new Sequelize(
"eco_saver",
process.env.DB_USER,
process.env.DB_PASS,
{
host: "mpsqldatabase.mysql.database.azure.com",
dialect: 'mysql',
// attributeBehavior?: 'escape' | 'throw' | 'unsafe-legacy';
attributeBehavior: 'escape',
dialectOptions: {
ssl: {
ca: fs.readFileSync(path.resolve(__dirname, '../../cert/DigiCertGlobalRootCA.crt.pem')),
},
},
},
);
sequelize.authenticate().then(() => {
console.log('Connection has been established successfully.');
}).catch((error) => {
console.error('Unable to connect to the database: ', error);
});
module.exports = { sequelize };

View File

@ -0,0 +1,110 @@
"use strict";
const { Sequelize, DataTypes } = require("sequelize");
const { sequelize } = require("./mySQL");
const { locationModel } = require("./locationModel");
const {
isAlphaNumericwithSpaces,
isAlphaNumericWithSpacesAndDash,
isMacAddress,
} = require("../../Web-Server/functions/validateData");
//sequelize.sync();
const sensorModel = sequelize.define(
"sensors",
{
id: {
type: DataTypes.INTEGER,
allowNull: true,
primaryKey: true,
autoIncrement: true,
unique: true,
validate: {
notEmpty: true,
isNumeric: true,
},
},
name: {
type: DataTypes.STRING,
allowNull: false,
length: 10,
unique: true,
validate: {
notEmpty: true,
len: [1, 30],
//accept only alphanumeric and spaces
isAlphaNumericWithSpacesAndDash(value) {
if (!isAlphaNumericWithSpacesAndDash(value)) {
throw new Error("Invalid characters in name");
}
},
},
},
added_by: {
type: DataTypes.STRING,
allowNull: false,
length: 10,
validate: {
notEmpty: { msg: "Added by cannot be empty" },
len: [1, 20],
is: ["^[a-z0-9]+$", "i"],
isIn: [["admin", "system", "Admin", "System"]],
},
},
mac_address: {
type: DataTypes.STRING,
allowNull: false,
length: 12,
unique: true,
validate: {
notEmpty: true,
len: [12, 18],
isMacAddress(value) {
if (!isMacAddress(value)) {
throw new Error("Invalid Mac Address");
}
},
},
},
description: {
type: DataTypes.STRING,
allowNull: true,
length: 100,
validate: {
notEmpty: true,
len: [1, 100],
isAlphaNumericwithSpaces(value) {
if (!isAlphaNumericwithSpaces(value)) {
throw new Error("Invalid characters in name");
}
},
},
},
locationid: {
type: DataTypes.INTEGER,
allowNull: true,
length: 100,
//one to many relationship
references: {
model: locationModel,
key: "id",
},
validate: {
notEmpty: true,
isNumeric: true,
},
},
createdAt: {
type: DataTypes.DATE,
allowNull: true,
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
timestamps: true,
}
);
module.exports = { sensorModel };

View File

@ -0,0 +1,23 @@
const { locationModel } = require("../Database/locationModel");
const { sensorModel } = require("../Database/sensorModel");
async function getLocation() {
const location = locationModel.findAll({
raw: true,
order: [["id", "ASC"]],
attributes: ["id"],
});
return location;
}
async function getSensor() {
const sensor = sensorModel.findAll({
raw: true,
order: [["id", "ASC"]],
attributes: ["id"],
});
return sensor;
}
module.exports = { getLocation, getSensor };

View File

@ -1,34 +1,34 @@
const { iot_sensor_data } = require("./modules/IoT-sensor");
const { run } = require("./modules/IoT-sensor");
const client = require("./modules/mqtt");
function publishData() {
let data = iot_sensor_data();
// MQTT logic
client.publish("iot-data", JSON.stringify(data), { qos: 1 }, (err) => {
if (err) {
console.error("Error publishing message:", err);
} else {
console.log("Message published");
}
});
async function publishData() {
try {
const data = await run();
console.log(data);
client.publish("iot-data", JSON.stringify(data));
} catch (err) {
console.error(err);
}
}
client.on("connect", () => {
console.log("Connected to MQTT broker");
publishData();
console.log("Connected to MQTT broker");
publishData();
});
client.on("end", () => {
console.log("Disconnected from MQTT broker");
client.reconnect = true;
console.log("Disconnected from MQTT broker");
client.reconnect = true;
});
client.on("error", (err) => {
console.error("Error:", err);
client.end();
console.error("Error:", err);
client.end();
});
//every 15 minutes
setInterval(publishData, 900000);
//setInterval(publishData, 600);
//every 1 minute
//setInterval(publishData, 60000);

View File

@ -1,57 +1,71 @@
/*
1) PSI metric data
2) Humidity
3) Gases (O3,NO2,SO2)
4) temperature
5) Air pressure?
6) windspeed?
8) time when data was collected / generated
*/
const { getLocation, getSensor } = require("../functions/dbFunctions");
/*
1) generate random data for each sensor
2) pass to mqtt broker
*/
//class to generate random data
var dataAray = [];
class IoTdataGenerator {
constructor() {
}
async getLocationAndSensorId() {
try {
const loc = await getLocation();
const sen = await getSensor();
return { loc, sen };
} catch (err) {
console.error(err);
}
}
let region = ["central", "north-east", "north", "east", "west"];
async generateData() {
try {
const { loc, sen } = await this.getLocationAndSensorId();
for (let i = 0; i < sen.length; i++) {
//console.log(sen[i].id);
//console.log(loc[i].id);
//console.log("you should appear 6 times only")
dataAray.push(firstDataRow(sen[i].id, loc[i].id));
}
} catch (err) {
console.error(err);
}
return dataAray;
function generateRandomData() {
const psiData = getRandomValue(0, 500);
const humidityData = getRandomValue(0, 100);
const o3Data = getRandomValue(0, 600); //max 600
const no2Data = getRandomValue(0, 1000); //max 1000
const so2Data = getRandomValue(0, 1000); //max 1000
const coData = getRandomValue(0 , 100);
const temperatureData = getRandomValue(24, 40);
const windspeedData = getRandomValue(0, 35);
const currentTime = new Date(Date.now() + 28800000)
.toISOString()
.slice(0, 19)
.replace("T", " ");
const regionData = region[Math.floor(Math.random() * region.length)];
}
}
var json = {
psi: psiData.toFixed(0),
humidity: humidityData.toFixed(0) + "%",
o3: o3Data.toFixed(0) + "ppm",
no2: no2Data.toFixed(0) + "ppm",
so2: so2Data.toFixed(0) + "ppm",
co: coData.toFixed(0) + "ppm",
temperature: temperatureData.toFixed(0) + "°C",
windspeed: windspeedData.toFixed(0) + "km/h",
time: currentTime,
region: regionData,
//helper function to generate random data
function firstDataRow(sensorId, locationId) {
return {
sensorid: sensorId,
locationid: locationId,
measurement: {
psi: Math.floor(Math.random() * 30) + 5,
humidity: Math.floor(Math.random() * (90 - 80 + 1) + 80),
o3: Math.floor(Math.random() * (100 - 20 + 1) + 30),
no2: Math.floor(Math.random() * 30) + 5,
so2: Math.floor(Math.random() * 30) + 5,
co: Math.floor(Math.random() * 25 - 0.5),
temperature: Math.floor(Math.random() * (30 - 23 + 1) + 25),
windspeed: Math.floor(Math.random() * (10 - 1 + 1) + 1),
},
//time stamp are auto generated by sequelize
//createdAt: convertDateToUTC(startDate),
};
return json;
}
function getRandomValue(min, max) {
return Math.random() * (max - min) + min;
/*
1) get location and sensor id from db
2) loop through each sensor id and location id and generate random data and pass to mqtt
*/
async function run() {
let iotData = new IoTdataGenerator();
const result = await iotData.generateData();
console.log(result);
return result;
}
module.exports = { run };
function iot_sensor_data() {
return generateRandomData();
}
module.exports = { iot_sensor_data };