diff --git a/public/sensors_data.json b/public/sensors_data.json deleted file mode 100644 index cfb97d16fcd76cd4ff6e78a0bc8a9d33a7564eea..0000000000000000000000000000000000000000 --- a/public/sensors_data.json +++ /dev/null @@ -1,61 +0,0 @@ -[ - { - "id": 1234, - "name": "Température Bureau", - "type": "TEMPERATURE", - "data": { - "values": [23, 23, 22, 21, 23, 23, 23, 25, 25], - "labels": [ - "2023-01-19T08:00:00.000Z", - "2023-01-19T09:00:00.000Z", - "2023-01-19T10:00:00.000Z", - "2023-01-19T11:00:00.000Z", - "2023-01-19T12:00:00.000Z", - "2023-01-19T13:00:00.000Z", - "2023-01-19T14:00:00.000Z", - "2023-01-19T15:00:00.000Z", - "2023-01-19T16:00:00.000Z" - ] - } - }, - { - "id": 10245, - "name": "Porte du Garage", - "type": "DOOR", - "data": { - "value": 0 - } - }, - { - "id": 2222, - "name": "Ventilateur Ordinateur Bureau", - "type": "FAN_SPEED", - "data": { - "values": [1073, 1800, 2299, 2176, 1899, 1400], - "labels": [ - "2023-01-19T10:00:00.000Z", - "2023-01-19T10:05:00.000Z", - "2023-01-19T10:10:00.000Z", - "2023-01-19T10:15:00.000Z", - "2023-01-19T10:20:00.000Z", - "2023-01-19T10:25:00.000Z" - ] - } - }, - { - "id": 2233, - "name": "Capteur Humidité salle sport", - "type": "HUMIDITY", - "data": { - "values": [28, 34, 19, 25, 48, 34], - "labels": [ - "2023-02-19T10:00:00.000Z", - "2023-02-19T10:05:00.000Z", - "2023-02-19T10:10:00.000Z", - "2023-02-19T10:15:00.000Z", - "2023-02-19T10:20:00.000Z", - "2023-02-19T10:25:00.000Z" - ] - } - } -] diff --git a/src/index.module.css b/src/index.module.css index a85e6095e42b7c99d39b116118eedd2d32e9322b..7870459bff3564112c51cd17c0274cf885bfa261 100644 --- a/src/index.module.css +++ b/src/index.module.css @@ -113,3 +113,9 @@ nav li a:hover { grid-row: 2 / 3; grid-column: 2 / 3; } +.sensors { + color: #ff5900; +} +.mqtt { + font-weight: normal; +} \ No newline at end of file diff --git a/src/routes/rout.jsx b/src/routes/rout.jsx index 95371939ea04b47c7d1186999cbe8f12db8b85e2..6973314bfc8ec2841f83cb17e8a5179301f29ee2 100644 --- a/src/routes/rout.jsx +++ b/src/routes/rout.jsx @@ -1,61 +1,84 @@ import styles from "../index.module.css"; -import React, { useState, useEffect } from 'react'; -import { Outlet, Link, useLoaderData } from "react-router-dom"; +import React, { useState} from 'react'; +import { Outlet, Link} from "react-router-dom"; import mqtt from 'precompiled-mqtt'; +import {creerSensor, existSensor, updateSensor} from '../sensor.js'; + export default function Root() { const [sensors, setSensors] = useState([]); const [brokerUrl, setBrokerUrl] = useState(''); - const topic = 'value/#'; - const client = mqtt.connect(brokerUrl); - - useEffect(() => { - client.on('connect', () => { - console.log(`Connected to MQTT broker ${brokerUrl}`); - client.subscribe(topic, (err) => { - if (err) { - console.error('Error subscribing to topic', err); - } else { - console.log(`Subscribed to topic ${topic}`); - } - }); - }); - client.on('message', (topic, message) => { - const sensorData = JSON.parse(message.toString()); - setSensors((prevSensors) => { - const existingSensor = prevSensors.find((sensor) => sensor.id === sensorData.id); - if (existingSensor) { - return prevSensors.map((sensor) => (sensor.id === sensorData.id ? sensorData : sensor)); - } else { - return [...prevSensors, sensorData]; - } - }); - console.log(`Received sensor data from topic ${topic}:`, sensorData); - }); + const topic = 'value/#'; + const [client, setClient] = useState(null); + //const client = mqtt.connect(brokerUrl); - return () => { - client.end(); - }; - }, [brokerUrl]); // effect will run whenever brokerUrl changes + const [isConnected, setIsConnected] = useState(false); const handleUrlChange = (e) => { const url = e.target.value; setBrokerUrl(url); }; + const handleDisconnect = () => { + if(isConnected) { + client.end(); + setIsConnected(false); + } + }; + + const handleConnect = () => { + if(!isConnected) { + const newClient = mqtt.connect(brokerUrl); + newClient.on('connect', () => { + console.log(`Connected to MQTT broker ${brokerUrl}`); + newClient.subscribe(topic, (err) => { + if (err) { + console.error('Error subscisConnectedribing to topic', err); + } else { + console.log(`Subscribed to topic ${topic}`); + } + }); + }); + + newClient.on('message', (topic, message) => { + const sensorData = JSON.parse(message.toString()); + const name = sensorData.name; + const data = sensorData.value; + console.log(sensorData); + if(existSensor(name)){ + updateSensor(name, data); + }else { + creerSensor(sensorData); + } + setSensors((prevSensors) => { + const existingSensor = prevSensors.find((sensor) => sensor.name === sensorData.name); + if (existingSensor) { + const updatedSensors = [...prevSensors]; + updatedSensors[existingSensor] = sensorData; + return updatedSensors; + } else { + return [...prevSensors, sensorData]; + } + }); + }); + setClient(newClient); + } + setIsConnected(true); + }; + return ( <>
Real time sensors - Other - Foo + Other + Foo
-

Sensors

+

Sensors

-

URL :

- +

MQTT Brocker:

+ + {isConnected ? ( + + ) : ( + + )}
diff --git a/src/routes/sensor.jsx b/src/routes/sensor.jsx index acfed8a652c314e1176512fa4e77be2d2c299a31..eb2ef6baefc01e9857f22c983f6ae9486c34c57a 100644 --- a/src/routes/sensor.jsx +++ b/src/routes/sensor.jsx @@ -1,6 +1,11 @@ import styles from "../index.module.css"; +import Root from "./rout.jsx"; +import {useEffect} from "react"; +import { useParams } from 'react-router-dom'; +import {getSensor, getLastValue} from '../sensor.js'; export default function Sensor(){ + const { sensorName } = useParams(); const sensor = { name: "Exemple sensor name", type: "PERCENT", @@ -9,14 +14,16 @@ export default function Sensor(){ return(
-

{sensor.name}

+

{sensorName}

Valeur actuelle

- {sensor.value} + {getLastValue(sensorName)}

Historique

- + {getSensor(sensorName).map((value, index) => ( +
{value}
+ ))}
); diff --git a/src/sensor.js b/src/sensor.js new file mode 100644 index 0000000000000000000000000000000000000000..53f6a934bd1caf274562e4017d676de12871aba7 --- /dev/null +++ b/src/sensor.js @@ -0,0 +1,84 @@ +export const SensorType = + { + 'TEMPERATURE': 0, + 'PERCENT': 1, + 'OPEN_CLOSE': 2, + 'ON_OFF': 3 + }; +export class Sensor{ + #name; + #data; + #last_value; + constructor(name, data) { + this.#name = name; + this.#data = data; + this.#last_value = data[0]; + } + get name(){ + return this.#name; + } + set name(name){ + this.#name = name; + } + get data(){ + return this.#data; + } + set data(data){ + this.#data.push(data); + } + get last_value(){ + return this.#last_value; + } + set last_value(last_value){ + this.#last_value = last_value; + } +} +export class Temperature extends Sensor{ + +} +export class Percent extends Sensor{ + +} +export class Open_Close extends Sensor{ + +} +export class On_Off extends Sensor{ + +} +export let Sensors = []; +export function creerSensor(donnes){ + let S; + let type = SensorType[donnes.type]; + switch (type){ + case SensorType.TEMPERATURE: + S = new Temperature(donnes.name, [donnes.value]); + break; + case SensorType.PERCENT: + S = new Percent(donnes.name, [donnes.value]); + break; + case SensorType.OPEN_CLOSE: + S = new Open_Close(donnes.name, [donnes.value]); + break; + case SensorType.ON_OFF: + S = new On_Off(donnes.name, [donnes.value]); + break; + default: + throw new Error(`Type de capteur : ${donnes.type} n'est pas reconnu`); + } + Sensors.push(S); + return S; +} +export function existSensor(name) { + return Sensors.filter(s => s.name === name).length > 0; +} +export function updateSensor(name, value){ + const sensor = Sensors.find(s => s.name === name) + sensor.data.push(value); + sensor.last_value = value; +} +export function getSensor(name) { + return Sensors.find(s => s.name === name).data; +} +export function getLastValue(name) { + return Sensors.find(s => s.name === name).last_value; +} \ No newline at end of file