Mobi BOX : Différence entre versions

(Page créée avec « {{Tuto Details |Licences=Attribution (CC-BY) |Description=Y |Disciplines scientifiques=Arduino |Difficulty=Technical |Duration=2 |Duration-type=day(s) }} {{Introduction}}... »)
 
 
(10 révisions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
 
{{Tuto Details
 
{{Tuto Details
 +
|Main_Picture=Mobi_BOX_IMG_0412.jpeg
 
|Licences=Attribution (CC-BY)
 
|Licences=Attribution (CC-BY)
|Description=Y
+
|Description=Un dispositif fournissant des informations en temps réel sur la pertinence d’utiliser une voiture ou les transports en commun, en évaluant la qualité de l’air, les niveaux de pollution atmosphérique ainsi que la disponibilité des différents moyens de transport dans la zone
|Disciplines scientifiques=Arduino
+
|Disciplines scientifiques=Arduino, Computing, Electricity, Mechanics
|Difficulty=Technical
+
|Difficulty=Expert
 
|Duration=2
 
|Duration=2
 
|Duration-type=day(s)
 
|Duration-type=day(s)
 +
|Tags=Pollution, transport, mobilité, qualité de l’air
 +
}}
 +
{{Introduction
 +
|Introduction=pour présenter l’expérience ou la réalisation technique de manière attractive.
 +
}}
 +
{{Materials
 +
|ItemList={{ItemList
 +
|Item=Découpeuse laser
 +
}}{{ItemList
 +
|Item=Moteur électrique
 +
}}{{ItemList
 +
|Item=Imprimante 3D
 +
}}{{ItemList
 +
|Item=LED
 +
}}{{ItemList
 +
|Item=Boite en carton
 +
}}{{ItemList
 +
|Item=ESP32
 +
}}
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Comprendre le terme ( Mobilité de transport commun)
 +
|Step_Content=Chaque participant partage sa compréhension du thème. Toutes les idées et les mots-clés sont ensuite notés et organisés sous forme de schéma.
 +
|Step_Picture_00=Mobi_BOX_IMG_1827.jpeg
 +
|Step_Picture_01=Mobi_BOX_IMG_1829.jpeg
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Recherche dans les sources disponibles
 +
|Step_Content=Analyse des sources disponibles sur les sites de TBM et de Bordeaux Métropole pour identifier les bénéfices environnementaux du tramway et du réseau de bus.
 +
|Step_Picture_00=Mobi_BOX_WhatsApp_Image_2026-05-30_at_13.55.11.jpeg
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Élaboration d’un schéma préliminaire
 +
|Step_Content=Conception d’une machine capable d’analyser la qualité de l’air et le trafic, afin de proposer le meilleur moyen de transport entre bus, tram, voiture ou taxi.
 +
|Step_Picture_00=Mobi_BOX_IMG_1832.jpeg
 +
|Step_Picture_01=Mobi_BOX_Capture_d_e_cran_2025-12-05_a_10.36.02.png
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Choisir les matériaux pour la maquette
 +
|Step_Content=Bois, LED, papier transparent, éléments imprimés en 3D, ainsi que des cartes électroniques(Arduino ) pour la rotation et l’éclairage des LED.
 +
|Step_Picture_00=Mobi_BOX_93993C_zoo.jpg
 +
|Step_Picture_01=Mobi_BOX_IMG_0413.jpeg
 +
|Step_Picture_02=Mobi_BOX_IMG_0333.mov
 +
|Step_Picture_03=Mobi_BOX_IMG_0326.jpeg
 +
|Step_Picture_04=Mobi_BOX_WhatsApp_Image_2026-05-30_at_14.12.33.jpeg
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Programmation sur Python
 +
|Step_Content=import requests
 +
 +
from bs4 import BeautifulSoup
 +
 +
class AQIRepository:
 +
 +
URL = "<nowiki>https://www.atmo-nouvelleaquitaine.org/air-commune/Bordeaux/33063/indice-atmo?date=2025-10-14</nowiki>"
 +
 +
def __init__(self):
 +
 +
self.cat_to_conc = {
 +
 +
'Bon':    {'PM2.5': 5.0,  'PM10': 15.0, 'O3': 0.040, 'NO2': 20.0, 'SO2': 5.0},
 +
 +
'Moyen':  {'PM2.5': 20.0, 'PM10': 40.0, 'O3': 0.060, 'NO2': 60.0, 'SO2': 20.0},
 +
 +
'Mauvais':{'PM2.5': 40.0, 'PM10': 100.0,'O3': 0.100, 'NO2': 150.0,'SO2': 100.0},
 +
 +
'Très mauvais':{'PM2.5':120.0,'PM10':300.0,'O3':0.180,'NO2':800.0,'SO2':500.0}
 +
 +
}
 +
 +
self.breakpoints = {
 +
 +
'PM2.5': [(0.0,12.0,0,50),(12.1,35.4,51,100),(35.5,55.4,101,150),(55.5,150.4,151,200)],
 +
 +
'PM10':  [(0,54,0,50),(55,154,51,100),(155,254,101,150),(255,354,151,200)],
 +
 +
'O3':    [(0.000,0.054,0,50),(0.055,0.070,51,100),(0.071,0.085,101,150)],
 +
 +
'NO2':  [(0,53,0,50),(54,100,51,100),(101,360,101,150),(361,649,151,200)],
 +
 +
'SO2':  [(0,35,0,50),(36,75,51,100),(76,185,101,150),(186,304,151,200)],
 +
 +
}
 +
 +
def linear_scale(self, C, C_low, C_high, I_low, I_high):
 +
 +
return round((I_high - I_low) / (C_high - C_low) * (C - C_low) + I_low)
 +
 +
def find_aqi_subindex(self, C, pollutant):
 +
 +
for (C_low, C_high, I_low, I_high) in self.breakpoints[pollutant]:
 +
 +
if C_low <= C <= C_high:
 +
 +
return self.linear_scale(C, C_low, C_high, I_low, I_high)
 +
 +
return None
 +
 +
def scrape_categories(self):
 +
 +
response = requests.get(self.URL, timeout=10)
 +
 +
soup = BeautifulSoup(response.text, "html.parser")
 +
 +
categories = {}
 +
 +
blocks = soup.select(".c-indice-polluant")
 +
 +
for block in blocks:
 +
 +
title_tag = block.select_one(".c-indice-polluant-title span")
 +
 +
cat_tag = block.select_one(".home-map-legend-item span")
 +
 +
if title_tag and cat_tag:
 +
 +
name = title_tag.get_text(strip=True).replace("₂", "2").replace("₃", "3")
 +
 +
cat = cat_tag.get_text(strip=True)
 +
 +
categories[name] = cat
 +
 +
return categories
 +
 +
def compute_aqi(self, categories):
 +
 +
concentrations = {k: self.cat_to_conc[v][k] for k, v in categories.items() if k in self.cat_to_conc[v]}
 +
 +
subindices = {k: self.find_aqi_subindex(concentrations[k], k) for k in concentrations}
 +
 +
aqi_global = max(v for v in subindices.values() if v is not None)
 +
 +
return aqi_global, subindices
 +
 +
import requests
 +
 +
class MeteoRepository:
 +
 +
def __init__(self, latitude=44.8378, longitude=-0.5792):
 +
 +
self.latitude = latitude
 +
 +
self.longitude = longitude
 +
 +
self.api_url = (
 +
 +
"<nowiki>https://api.open-meteo.com/v1/forecast</nowiki>?"
 +
 +
f"latitude={self.latitude}&longitude={self.longitude}"
 +
 +
"&hourly=temperature_2m,precipitation,weathercode"
 +
 +
"&current_weather=true&timezone=Europe%2FParis"
 +
 +
)
 +
 +
def get_weather(self):
 +
 +
response = requests.get(self.api_url, timeout=10)
 +
 +
data = response.json()
 +
 +
return data.get("current_weather", {})
 +
 +
def compute_weather_score(self, weather):
 +
 +
wmo_scores = {
 +
 +
0: 100, 1: 90, 2: 80, 3: 70, 45: 60, 48: 55,
 +
 +
51: 50, 53: 45, 55: 40, 61: 35, 63: 25, 65: 15,
 +
 +
71: 25, 73: 15, 75: 5, 95: 10, 99: 0,
 +
 +
}
 +
 +
temp = weather.get("temperature", 20)
 +
 +
wind = weather.get("windspeed", 10)
 +
 +
code = weather.get("weathercode", 0)
 +
 +
base_score = wmo_scores.get(code, 60)
 +
 +
if temp < 0:
 +
 +
temp_penalty = 30
 +
 +
elif temp < 10:
 +
 +
temp_penalty = 15
 +
 +
elif temp > 30:
 +
 +
temp_penalty = 20
 +
 +
else:
 +
 +
temp_penalty = 0
 +
 +
wind_penalty = 0
 +
 +
if wind > 40:
 +
 +
wind_penalty = 20
 +
 +
elif wind > 25:
 +
 +
wind_penalty = 10
 +
 +
score = base_score - temp_penalty - wind_penalty
 +
 +
return round(max(0, min(100, score)))
 +
 +
import requests
 +
 +
import json
 +
 +
class TrafficRepository:
 +
 +
BASE_URL = "<nowiki>https://data.bordeaux-metropole.fr/geojson</nowiki>"
 +
 +
def __init__(self, api_key="2HH8S7FKPP", typename="ci_trafi_l"):
 +
 +
self.api_key = api_key
 +
 +
self.typename = typename
 +
 +
def get_traffic_by_gid(self, gid=2215):
 +
 +
params = {
 +
 +
"key": self.api_key,
 +
 +
"typename": self.typename,
 +
 +
"filter": json.dumps({"gid": gid}),
 +
 +
}
 +
 +
response = requests.get(self.BASE_URL, params=params, timeout=10)
 +
 +
if response.status_code != 200:
 +
 +
raise Exception(f"Erreur API {response.status_code} : {response.text}")
 +
 +
return response.json()
 +
 +
def compute_traffic_score(self, traffic_data):
 +
 +
features = traffic_data.get("features", [])
 +
 +
if not features:
 +
 +
return 50
 +
 +
props = features[0].get("properties", {})
 +
 +
etat = props.get("etat_trafic") or props.get("etat") or "INCONNU"
 +
 +
mapping = {"FLUIDE": 100, "RALENTI": 70, "EMBOUTEILLE": 30, "INCONNU": 50}
 +
 +
return mapping.get(etat.upper(), 50)
 +
 +
import requests
 +
 +
import json
 +
 +
from datetime import datetime, timezone
 +
 +
class TbmRepository:
 +
 +
BASE_URL = "<nowiki>https://data.bordeaux-metropole.fr/geojson</nowiki>"
 +
 +
def __init__(self, api_key="2HH8S7FKPP", arret_id=4037):
 +
 +
self.api_key = api_key
 +
 +
self.arret_id = arret_id
 +
 +
def get_next_tram(self, max_results=100):
 +
 +
params = {
 +
 +
"key": self.api_key,
 +
 +
"typename": "sv_horai_a",
 +
 +
"filter": json.dumps({"rs_sv_arret_p": self.arret_id}),
 +
 +
"orderby": json.dumps(["hor_theo"]),
 +
 +
"maxfeatures": max_results
 +
 +
}
 +
 +
response = requests.get(self.BASE_URL, params=params)
 +
 +
response.raise_for_status()
 +
 +
data = response.json()
 +
 +
now = datetime.now(timezone.utc)
 +
 +
for feature in data.get("features", []):
 +
 +
props = feature.get("properties", {})
 +
 +
hor_theo = props.get("hor_theo")
 +
 +
if not hor_theo:
 +
 +
continue
 +
 +
try:
 +
 +
tram_time = datetime.fromisoformat(hor_theo)
 +
 +
except ValueError:
 +
 +
continue
 +
 +
if tram_time > now:
 +
 +
diff_sec = int((tram_time - now).total_seconds())
 +
 +
return {"heure": tram_time, "seconds": diff_sec, "etat": props.get("etat"), "type": props.get("type")}
 +
 +
return None
 +
 +
from AQIRepository import AQIRepository
 +
 +
from MeteoRepository import MeteoRepository
 +
 +
from TrafficRepository import TrafficRepository
 +
 +
from TramRepository import TbmRepository
 +
 +
from fastapi import FastAPI
 +
 +
app = FastAPI()
 +
 +
@app.get("/")
 +
 +
def read_root():
 +
 +
longitude = -0.5935101
 +
 +
latitude = 44.8538665
 +
 +
borneTraficGID = 2215
 +
 +
Aqirepo = AQIRepository()
 +
 +
categories = Aqirepo.scrape_categories()
 +
 +
aqi, details = Aqirepo.compute_aqi(categories)
 +
 +
meteo = MeteoRepository(latitude=latitude, longitude=longitude)
 +
 +
weather = meteo.get_weather()
 +
 +
score_M = meteo.compute_weather_score(weather)
 +
 +
traffic = TrafficRepository()
 +
 +
data = traffic.get_traffic_by_gid(borneTraficGID)
 +
 +
score_T = traffic.compute_traffic_score(data)
 +
 +
tbm = TbmRepository(arret_id=4037)
 +
 +
prochain = tbm.get_next_tram()
 +
 +
if prochain and 'seconds' in prochain:
 +
 +
TP_seconds = prochain['seconds']
 +
 +
else:
 +
 +
TP_seconds = 3600
 +
 +
max_tp_seconds = 3600
 +
 +
TP_score = max(0, min(100, 100 - (TP_seconds / max_tp_seconds) * 100))
 +
 +
IMR = (
 +
 +
0.4 * (100 - aqi) +
 +
 +
0.3 * (100 - score_T) +
 +
 +
0.2 * TP_score +
 +
 +
0.1 * score_M
 +
 +
)
 +
 +
return {"IMR": round(IMR, 1)}
 +
 +
 +
 +
 +
 +
<br />
 +
|Step_Picture_00=Mobi_BOX_WhatsApp_Image_2026-05-30_at_13.46.41.jpeg
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Monter les éléments de la maquette et effectuer les tests
 +
|Step_Picture_00=Mobi_BOX_IMG_0308.jpeg
 +
|Step_Picture_01=Mobi_BOX_IMG_0345.mov
 +
|Step_Picture_02=Mobi_BOX_IMG_0418.jpeg
 +
|Step_Picture_03=Mobi_BOX_IMG_0384.mov
 +
|Step_Picture_04=Mobi_BOX_IMG_1836.jpeg
 +
}}
 +
{{Tuto Step
 +
|Step_Title=Vidéo final
 +
|Step_Picture_00=Mobi_BOX_POCL.mp4
 +
}}
 +
{{Notes
 +
|Observations=Une rotation d’un cache dévoilé le moyen de transport conseillé à l’instant t.
 +
|Avertissement=Connexion
 +
 +
Disponibilité des Api externe
 +
|Explanations=L’esp appelle une api sur un serveur (api en fast api). Cette api va appeler les autres apis et faire les calcule.
 +
 +
Cette architecture permet de ne pas être limité par l’esp niveau performance.
 +
|Applications=Ils sont installés dans les lieux publics, aux arrêts de tramway, aux stations de bus et dans les taxis, et sont signalés par un panneau indiquant leur présence.
 +
|Related=- Ajouter un GPS afin d’avoir la position dynamiquement.
 +
 +
- Ajouter un capteur qui permet d’analyser la qualité de l’air pour ne plus dépendre d’un service tier et être  plus précis
 +
|Objectives=Améliorer notre capacité à travailler en équipe Améliorer notre capacité à s’adapter au différent profils et compétence des membres de notre équipe (oral, méthode de travail, contrainte)
 +
|Notes=https://datahub.bordeaux-metropole.fr/pages/accueil/
 +
 +
https://fastapi.tiangolo.com/
 +
 +
https://open-meteo.com/
 
}}
 
}}
{{Introduction}}
 
{{Materials}}
 
{{Tuto Step}}
 
{{Notes}}
 
 
{{Tuto Status
 
{{Tuto Status
 
|Complete=Draft
 
|Complete=Draft
 
}}
 
}}

Version actuelle datée du 30 mai 2026 à 14:12

Auteur avatarAYOUB YACOUBI | Dernière modification 30/05/2026 par AYOUB

Mobi BOX IMG 0412.jpeg
Un dispositif fournissant des informations en temps réel sur la pertinence d’utiliser une voiture ou les transports en commun, en évaluant la qualité de l’air, les niveaux de pollution atmosphérique ainsi que la disponibilité des différents moyens de transport dans la zone
Licence : Attribution (CC-BY)

Introduction

pour présenter l’expérience ou la réalisation technique de manière attractive.

Étape 1 - Comprendre le terme ( Mobilité de transport commun)

Chaque participant partage sa compréhension du thème. Toutes les idées et les mots-clés sont ensuite notés et organisés sous forme de schéma.



Étape 2 - Recherche dans les sources disponibles

Analyse des sources disponibles sur les sites de TBM et de Bordeaux Métropole pour identifier les bénéfices environnementaux du tramway et du réseau de bus.




Étape 3 - Élaboration d’un schéma préliminaire

Conception d’une machine capable d’analyser la qualité de l’air et le trafic, afin de proposer le meilleur moyen de transport entre bus, tram, voiture ou taxi.



Étape 4 - Choisir les matériaux pour la maquette

Bois, LED, papier transparent, éléments imprimés en 3D, ainsi que des cartes électroniques(Arduino ) pour la rotation et l’éclairage des LED.

Étape 5 - Programmation sur Python

import requests

from bs4 import BeautifulSoup

class AQIRepository:

URL = "https://www.atmo-nouvelleaquitaine.org/air-commune/Bordeaux/33063/indice-atmo?date=2025-10-14"

def __init__(self):

self.cat_to_conc = {

'Bon': {'PM2.5': 5.0, 'PM10': 15.0, 'O3': 0.040, 'NO2': 20.0, 'SO2': 5.0},

'Moyen': {'PM2.5': 20.0, 'PM10': 40.0, 'O3': 0.060, 'NO2': 60.0, 'SO2': 20.0},

'Mauvais':{'PM2.5': 40.0, 'PM10': 100.0,'O3': 0.100, 'NO2': 150.0,'SO2': 100.0},

'Très mauvais':{'PM2.5':120.0,'PM10':300.0,'O3':0.180,'NO2':800.0,'SO2':500.0}

}

self.breakpoints = {

'PM2.5': [(0.0,12.0,0,50),(12.1,35.4,51,100),(35.5,55.4,101,150),(55.5,150.4,151,200)],

'PM10': [(0,54,0,50),(55,154,51,100),(155,254,101,150),(255,354,151,200)],

'O3': [(0.000,0.054,0,50),(0.055,0.070,51,100),(0.071,0.085,101,150)],

'NO2': [(0,53,0,50),(54,100,51,100),(101,360,101,150),(361,649,151,200)],

'SO2': [(0,35,0,50),(36,75,51,100),(76,185,101,150),(186,304,151,200)],

}

def linear_scale(self, C, C_low, C_high, I_low, I_high):

return round((I_high - I_low) / (C_high - C_low) * (C - C_low) + I_low)

def find_aqi_subindex(self, C, pollutant):

for (C_low, C_high, I_low, I_high) in self.breakpoints[pollutant]:

if C_low <= C <= C_high:

return self.linear_scale(C, C_low, C_high, I_low, I_high)

return None

def scrape_categories(self):

response = requests.get(self.URL, timeout=10)

soup = BeautifulSoup(response.text, "html.parser")

categories = {}

blocks = soup.select(".c-indice-polluant")

for block in blocks:

title_tag = block.select_one(".c-indice-polluant-title span")

cat_tag = block.select_one(".home-map-legend-item span")

if title_tag and cat_tag:

name = title_tag.get_text(strip=True).replace("₂", "2").replace("₃", "3")

cat = cat_tag.get_text(strip=True)

categories[name] = cat

return categories

def compute_aqi(self, categories):

concentrations = {k: self.cat_to_conc[v][k] for k, v in categories.items() if k in self.cat_to_conc[v]}

subindices = {k: self.find_aqi_subindex(concentrations[k], k) for k in concentrations}

aqi_global = max(v for v in subindices.values() if v is not None)

return aqi_global, subindices

import requests

class MeteoRepository:

def __init__(self, latitude=44.8378, longitude=-0.5792):

self.latitude = latitude

self.longitude = longitude

self.api_url = (

"https://api.open-meteo.com/v1/forecast?"

f"latitude={self.latitude}&longitude={self.longitude}"

"&hourly=temperature_2m,precipitation,weathercode"

"&current_weather=true&timezone=Europe%2FParis"

)

def get_weather(self):

response = requests.get(self.api_url, timeout=10)

data = response.json()

return data.get("current_weather", {})

def compute_weather_score(self, weather):

wmo_scores = {

0: 100, 1: 90, 2: 80, 3: 70, 45: 60, 48: 55,

51: 50, 53: 45, 55: 40, 61: 35, 63: 25, 65: 15,

71: 25, 73: 15, 75: 5, 95: 10, 99: 0,

}

temp = weather.get("temperature", 20)

wind = weather.get("windspeed", 10)

code = weather.get("weathercode", 0)

base_score = wmo_scores.get(code, 60)

if temp < 0:

temp_penalty = 30

elif temp < 10:

temp_penalty = 15

elif temp > 30:

temp_penalty = 20

else:

temp_penalty = 0

wind_penalty = 0

if wind > 40:

wind_penalty = 20

elif wind > 25:

wind_penalty = 10

score = base_score - temp_penalty - wind_penalty

return round(max(0, min(100, score)))

import requests

import json

class TrafficRepository:

BASE_URL = "https://data.bordeaux-metropole.fr/geojson"

def __init__(self, api_key="2HH8S7FKPP", typename="ci_trafi_l"):

self.api_key = api_key

self.typename = typename

def get_traffic_by_gid(self, gid=2215):

params = {

"key": self.api_key,

"typename": self.typename,

"filter": json.dumps({"gid": gid}),

}

response = requests.get(self.BASE_URL, params=params, timeout=10)

if response.status_code != 200:

raise Exception(f"Erreur API {response.status_code} : {response.text}")

return response.json()

def compute_traffic_score(self, traffic_data):

features = traffic_data.get("features", [])

if not features:

return 50

props = features[0].get("properties", {})

etat = props.get("etat_trafic") or props.get("etat") or "INCONNU"

mapping = {"FLUIDE": 100, "RALENTI": 70, "EMBOUTEILLE": 30, "INCONNU": 50}

return mapping.get(etat.upper(), 50)

import requests

import json

from datetime import datetime, timezone

class TbmRepository:

BASE_URL = "https://data.bordeaux-metropole.fr/geojson"

def __init__(self, api_key="2HH8S7FKPP", arret_id=4037):

self.api_key = api_key

self.arret_id = arret_id

def get_next_tram(self, max_results=100):

params = {

"key": self.api_key,

"typename": "sv_horai_a",

"filter": json.dumps({"rs_sv_arret_p": self.arret_id}),

"orderby": json.dumps(["hor_theo"]),

"maxfeatures": max_results

}

response = requests.get(self.BASE_URL, params=params)

response.raise_for_status()

data = response.json()

now = datetime.now(timezone.utc)

for feature in data.get("features", []):

props = feature.get("properties", {})

hor_theo = props.get("hor_theo")

if not hor_theo:

continue

try:

tram_time = datetime.fromisoformat(hor_theo)

except ValueError:

continue

if tram_time > now:

diff_sec = int((tram_time - now).total_seconds())

return {"heure": tram_time, "seconds": diff_sec, "etat": props.get("etat"), "type": props.get("type")}

return None

from AQIRepository import AQIRepository

from MeteoRepository import MeteoRepository

from TrafficRepository import TrafficRepository

from TramRepository import TbmRepository

from fastapi import FastAPI

app = FastAPI()

@app.get("/")

def read_root():

longitude = -0.5935101

latitude = 44.8538665

borneTraficGID = 2215

Aqirepo = AQIRepository()

categories = Aqirepo.scrape_categories()

aqi, details = Aqirepo.compute_aqi(categories)

meteo = MeteoRepository(latitude=latitude, longitude=longitude)

weather = meteo.get_weather()

score_M = meteo.compute_weather_score(weather)

traffic = TrafficRepository()

data = traffic.get_traffic_by_gid(borneTraficGID)

score_T = traffic.compute_traffic_score(data)

tbm = TbmRepository(arret_id=4037)

prochain = tbm.get_next_tram()

if prochain and 'seconds' in prochain:

TP_seconds = prochain['seconds']

else:

TP_seconds = 3600

max_tp_seconds = 3600

TP_score = max(0, min(100, 100 - (TP_seconds / max_tp_seconds) * 100))

IMR = (

0.4 * (100 - aqi) +

0.3 * (100 - score_T) +

0.2 * TP_score +

0.1 * score_M

)

return {"IMR": round(IMR, 1)}







Comment ça marche ?

Observations : que voit-on ?

Une rotation d’un cache dévoilé le moyen de transport conseillé à l’instant t.

Mise en garde : qu'est-ce qui pourrait faire rater l'expérience ?

Connexion

Disponibilité des Api externe

Explications

L’esp appelle une api sur un serveur (api en fast api). Cette api va appeler les autres apis et faire les calcule.

Cette architecture permet de ne pas être limité par l’esp niveau performance.

Applications : dans la vie de tous les jours

Ils sont installés dans les lieux publics, aux arrêts de tramway, aux stations de bus et dans les taxis, et sont signalés par un panneau indiquant leur présence.

Vous aimerez aussi

- Ajouter un GPS afin d’avoir la position dynamiquement.

- Ajouter un capteur qui permet d’analyser la qualité de l’air pour ne plus dépendre d’un service tier et être plus précis

Éléments pédagogiques

Objectifs pédagogiques

Améliorer notre capacité à travailler en équipe Améliorer notre capacité à s’adapter au différent profils et compétence des membres de notre équipe (oral, méthode de travail, contrainte)

Sources et ressources

https://datahub.bordeaux-metropole.fr/pages/accueil/

https://fastapi.tiangolo.com/

https://open-meteo.com/

Dernière modification 30/05/2026 par user:AYOUB.

Commentaires

Draft