Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

T-IOT-902-STG_7

IoT project for monitoring a kennel. The frontend displays environmental KPIs based on temperature, atmospheric pressure, and sound level, plus a map of where each probe (sonde) is reporting from.

Why this project

There are two goals behind the readings this project collects:

  1. Animal welfare. Understand how the dogs' barking relates to temperature — does noise go up when it gets hotter, or colder? Each probe reports temperature, atmospheric pressure, and sound level (as a proxy for barking) from its spot in the kennel, so staff can spot the correlation, catch heat- or cold-related distress early, and act on it (ventilation, shade, or a human round) instead of finding out after the fact.
  2. Legal noise compliance. Check whether the noise reaching the kennel's neighbors stays within the legally allowed limits, so the same sound level data doubles as evidence that the kennel is operating within regulation, not just a welfare signal.

This is also why the dashboard includes a temperature/noise correlation chart, and why the map's noise legend is framed around dog stress levels (calm → distress) rather than generic noise thresholds.

Structure

T-IOT-902-STG_7/
  Front/              # Vue, Vuetify, and Vite frontend
  backend/            # Flask API with WebSocket support
  IoT/                # Sensor and device code
  docker-compose.yml  # Docker orchestration for the project

Frontend

The dashboard is available at:

/dashboard

It fetches readings from GET /api/readings and stays live via the WebSocket (see below), so new measurements show up without reloading the page. It includes:

  • temperature, pressure, and sound level KPIs
  • a sonde filter — view a single probe, or average all of them together
  • time-based curves
  • correlation matrix between sensors
  • temperature vs. noise analysis
  • operational indicators for the kennel

The map is available at:

/map

It plots the latest known position of each probe (from the gps field) on an OpenStreetMap layer, color-coded by noise level, and updates live over the same WebSocket as the dashboard.

Run Without Docker

Go to the frontend folder:

cd Front

Install dependencies:

pnpm install

Start the development server:

pnpm run dev

Open:

http://localhost:5173/
http://localhost:5173/dashboard

Run With Docker

Make sure your .env file is present at the project root, then from the project root:

docker-compose up -d --build

This starts the frontend, backend API, and InfluxDB together.

Service URL
Frontend http://localhost:8080
Dashboard http://localhost:8080/dashboard
Map http://localhost:8080/map
API http://localhost:3001
InfluxDB UI http://localhost:8086

To start only specific services:

docker-compose up -d influxdb       # InfluxDB only
docker-compose up -d influxdb api   # InfluxDB + API (no frontend)

Stop all containers:

docker-compose down

Note (macOS): if using Colima, run colima start before the commands above.

Production Build

To validate the frontend:

cd Front
pnpm run build

Backend

The backend is a Flask API with WebSocket support (via Flask-SocketIO). It receives sensor data, writes it to InfluxDB, and broadcasts it in real time to connected clients.

Environment variables

Create a .env file at the project root before running anything:

API_PORT=3001
SECRET_KEY=your-secret-key

INFLUXDB_INIT_PASSWORD=your-influx-password
INFLUXDB_INIT_ADMIN_TOKEN=your-influx-token

# Only needed when running the API outside Docker (defaults to localhost)
# INFLUXDB_URL=http://localhost:8086

When running with Docker Compose, INFLUXDB_URL is injected automatically and points to the influxdb service.

Run without Docker

cd backend
pip install -r requirements.txt
python app.py

The API is available at http://localhost:3001 (or the port set in .env). InfluxDB must be running separately — start it with:

docker-compose up -d influxdb

REST endpoints

GET /api/test

Health check. Returns 200 if the API is up.

{ "message": "API OK" }

POST /api/sensor

Receives a sensor reading, writes it to InfluxDB, and broadcasts it to all connected WebSocket clients.

Request body:

{
  "id": "sonde-1",
  "temperature": 26.4,
  "pressure": 1013.0,
  "sound": 71.0,
  "gps": "48.8566,2.3522"
}

id, temperature, pressure, and sound are required — returns 400 if any are missing or the body is invalid. gps (as a "lat,lng" string) is used by the map view but isn't validated, so a missing gps currently causes a 500 instead of a 400 rather than being rejected cleanly.

Note: send temperature, pressure, and sound as floats (e.g. 71.0, not 71). InfluxDB fixes a field's type from its first write, and these fields were first written as floats — an integer value for one of them will fail with a 500 due to a type conflict.

Success response 201:

{ "message": "Donnée reçue et traitée" }

Error responses:

Status Reason
400 Missing or invalid JSON body
500 Failed to write to InfluxDB

GET /api/readings

Returns sensor readings stored in InfluxDB, optionally filtered by time range and/or probe.

Query parameters (optional):

Parameter Format Description
from RFC3339 (2026-06-18T00:00:00Z) Start of the time range
to RFC3339 (2026-06-18T23:59:59Z) End of the time range
id string Only return readings from this probe (sonde)

If from/to are omitted, from defaults to the Unix epoch and to defaults to now. If id is omitted, readings from every probe are returned.

Example:

GET /api/readings?from=2026-06-18T00:00:00Z&to=2026-06-18T23:59:59Z&id=sonde-1

Success response 200:

[
  {
    "time": "2026-06-18T14:00:00Z",
    "id": "sonde-1",
    "temperature": 26.4,
    "pressure": 1013.0,
    "sound": 71.0,
    "gps": "48.8566,2.3522"
  }
]

Error responses:

Status Reason
500 Failed to read from InfluxDB

WebSocket

The API uses Socket.IO. Connect to the same host and port as the REST API.

JavaScript example:

import { io } from 'socket.io-client'

const socket = io('http://localhost:3001')

socket.on('connect', () => console.log('Connected'))
socket.on('disconnect', () => console.log('Disconnected'))

// Receive real-time sensor data pushed by the server
socket.on('sensor_data', (data) => {
  console.log(data)
  // { id: 'sonde-1', temperature: 26.4, pressure: 1013.0, sound: 71.0, gps: '48.8566,2.3522' }
})

The dashboard and the map both open this connection on mount and use it to update their view as soon as new data comes in, without polling GET /api/readings again.

Events:

Direction Event Payload Description
Client → Server sensor_update { id, temperature, pressure, sound, gps } Send a sensor reading directly via socket
Server → Client sensor_data { id, temperature, pressure, sound, gps } Broadcast emitted on every POST /api/sensor

Only POST /api/sensor results in a sensor_data broadcast to all connected clients, and is the only path that persists the data to InfluxDB. The sensor_update socket event currently just echoes the payload back to whoever sent it (emit without broadcast=True) — it doesn't reach other clients and doesn't get written to the database.

Docker

Docker Compose orchestrates the frontend, backend API, and InfluxDB together.

About

Epitech Project - IoT project for monitoring a kennel. The frontend displays environmental KPIs based on temperature, atmospheric pressure, and sound level, plus a map of where each probe is reporting from.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages