Miniprojekty

Cílem miniprojektů je vytvořit komplexní IoT aplikaci, na které bude možné experimentálně ověřit probírané technologie a postupy.

Miniprojekty je možné odevzdat do konce 14. týdne (23.5.2025), preferujeme dřívější a průběžné odevzdávání :-)

Student bude své miniprojekty odevzdávat prostřednictvím fakultní GitLabu. Miniprojekty jsou koncipovány tak, že se postupně rozšiřuje funkcionalita jedné webové aplikace - každý student bude mít tedy jeden GitLab projekt, který bude průběžně hodnocen. Je nutné, aby byl repozitář dostupný, tj. viditelnost internal nebo public.

Po dokončení miniprojektu student nahraje změny na GitLab a do BRUTE odevzdá do příslušného miniprojektu (MP01, MP02, …) textový soubor s url adresou projektu (preferujeme rozdělení miniprojektů do jednotlivých větví, např. miniprojekt-1, miniprojekt-2, …).

Pokud je pro vývoj aplikace využito virtuální prostředí (například venv), je nutné odpovídající adresáře a soubory vyloučit z repozitáře pomocí .gitignore. Pro správnou funkčnost je vyžadována správa balíčků pomocí requirements.txt (viz první cvičení).

1. miniprojekt

Vytvořte webovou aplikaci ve frameworku Flask s pomocí knihovny Bootstrap. Součástí aplikace budou alespoň 3 endpointy - Dashboard, Přihlášení, Registrace.

Na stránce Dashboard budou alespoň tyto elementy: Poslední naměřená hodnota s časem zápisu, Tabulka zobrazující posledních 15 naměřených hodnot (sloupce = ID, Teplota, Čas zápisu), Tlačítko pro smazání nejstarší hodnoty. Naměřená data simulujte následujícím slovníkovým seznamem, který definujte v main.py:

DATA=[
    {"id": 0,"temperature": 21,"timestamp": "2025-01-01 01:00:00"},
    {"id": 1,"temperature": 33,"timestamp": "2025-01-01 01:05:52"},
    {"id": 2,"temperature": 38,"timestamp": "2025-01-01 01:10:23"},
    {"id": 3,"temperature": 21,"timestamp": "2025-01-01 01:15:17"},
    {"id": 4,"temperature": 24,"timestamp": "2025-01-01 01:20:08"},
    {"id": 5,"temperature": 35,"timestamp": "2025-01-01 01:25:42"},
    {"id": 6,"temperature": 40,"timestamp": "2025-01-01 01:30:00"},
    {"id": 7,"temperature": 37,"timestamp": "2025-01-01 01:35:19"},
    {"id": 8,"temperature": 37,"timestamp": "2025-01-01 01:40:25"},
    {"id": 9,"temperature": 20,"timestamp": "2025-01-01 01:45:53"},
    {"id": 10,"temperature": 35,"timestamp": "2025-01-01 01:50:15"},
    {"id": 11,"temperature": 34,"timestamp": "2025-01-01 01:55:19"},
    {"id": 12,"temperature": 28,"timestamp": "2025-01-01 02:00:46"},
    {"id": 13,"temperature": 23,"timestamp": "2025-01-01 02:05:55"},
    {"id": 14,"temperature": 25,"timestamp": "2025-01-01 02:10:20"},
    {"id": 15,"temperature": 23,"timestamp": "2025-01-01 02:15:43"},
    {"id": 16,"temperature": 23,"timestamp": "2025-01-01 02:20:52"},
    {"id": 17,"temperature": 31,"timestamp": "2025-01-01 02:25:47"},
    {"id": 18,"temperature": 29,"timestamp": "2025-01-01 02:30:35"},
    {"id": 19,"temperature": 31,"timestamp": "2025-01-01 02:35:52"},
    {"id": 20,"temperature": 35,"timestamp": "2025-01-01 02:40:28"},
    {"id": 21,"temperature": 26,"timestamp": "2025-01-01 02:45:53"},
    {"id": 22,"temperature": 35,"timestamp": "2025-01-01 02:50:50"},
    {"id": 23,"temperature": 28,"timestamp": "2025-01-01 02:55:56"},
    {"id": 24,"temperature": 39,"timestamp": "2025-01-01 03:00:31"},
    {"id": 25,"temperature": 36,"timestamp": "2025-01-01 03:05:56"},
    {"id": 26,"temperature": 39,"timestamp": "2025-01-01 03:10:40"},
    {"id": 27,"temperature": 23,"timestamp": "2025-01-01 03:15:47"},
    {"id": 28,"temperature": 31,"timestamp": "2025-01-01 03:20:11"},
    {"id": 29,"temperature": 21,"timestamp": "2025-01-01 03:25:43"},
    {"id": 30,"temperature": 23,"timestamp": "2025-01-01 03:30:58"},
    {"id": 32,"temperature": 28,"timestamp": "2025-01-01 03:35:51"},
    {"id": 31,"temperature": 29,"timestamp": "2025-01-01 03:40:46"},
    {"id": 33,"temperature": 31,"timestamp": "2025-01-01 03:45:38"},
    {"id": 34,"temperature": 40,"timestamp": "2025-01-01 03:50:09"},
    {"id": 35,"temperature": 37,"timestamp": "2025-01-01 03:55:26"},
    {"id": 36,"temperature": 32,"timestamp": "2025-01-01 04:00:25"},
    {"id": 37,"temperature": 39,"timestamp": "2025-01-01 04:05:03"},
    {"id": 38,"temperature": 31,"timestamp": "2025-01-01 04:10:39"},
    {"id": 39,"temperature": 31,"timestamp": "2025-01-01 04:15:16"},
    {"id": 40,"temperature": 32,"timestamp": "2025-01-01 04:20:14"},
    {"id": 41,"temperature": 33,"timestamp": "2025-01-01 04:25:03"},
    {"id": 42,"temperature": 21,"timestamp": "2025-01-01 04:30:01"},
    {"id": 43,"temperature": 34,"timestamp": "2025-01-01 04:35:24"},
    {"id": 44,"temperature": 39,"timestamp": "2025-01-01 04:40:10"},
    {"id": 45,"temperature": 36,"timestamp": "2025-01-01 04:45:47"},
    {"id": 46,"temperature": 40,"timestamp": "2025-01-01 04:50:18"},
    {"id": 47,"temperature": 27,"timestamp": "2025-01-01 04:55:35"},
    {"id": 48,"temperature": 37,"timestamp": "2025-01-01 05:00:11"},
    {"id": 49,"temperature": 38,"timestamp": "2025-01-01 05:05:45"}
]

  1. Funkční endpointy: Dashboard, Login, Register (2b)
  2. Využití dědičnosti šablon pro navbar a tělo stránky. (2b)
  3. Tabulka posledních 15 hodnot, samostatný element s poslední naměřenou hodnotou a časem zápisu (2b)
  4. Funkční tlačítko smazání nejstarší naměřené hodnoty (po smazání hodnoty se musí aktualizovat tabulka) (2b)
  5. Parametrizace počtu zobrazovaných hodnot v tabulce (musí být ošetřen případ, kdy je požadováno zobrazení více hodnot než je naměřeno - konkrétní způsob ošetření dle uvážení studenta) (2b)

Speciální případy, které student musí ošetřit:

  • Uživatel smaže tolik hodnot, že počet naměřených hodnot bude menší, než počet požadovaných hodnot (např. je uloženo 15 naměřených hodnot a tabulka zobrazuje posledních 15 naměřených hodnot - co se stane s tabulkou po stisknutí tlačítka pro smazání nejstarší hodnoty?)
  • Uživatel smaže všechna data - co se bude zobrazovat na dashboardu?
  • Pro bod 5: co se stane pokud uživatel bude chtít zobrazit více hodnot, než je počet uložených hodnot? Pokud se rozhodnete pro parametrizaci zadáním hodnoty - co se stane pokud uživatel zadá znak, který není číslo, nebo zadá 0 či záporné číslo?

BONUS (2b): Na dashboard přidejte graf naměřených hodnot v čase.

2. miniprojekt

Místo slovníkového seznamu implementujte SQLite databázi. Databáze bude mít dvě tabulky - Data, Users. Zprovozněte registraci a přihlašování uživatelů.

Dále definujte REST API s následujícími endpointy:

  • Vložení hodnoty {“temperature“: <value>}
  • Získání poslední naměřené hodnoty
  • Získání hodnoty s daným ID
  • Smazání nejstarší naměřené hodnoty
  • Smazání hodnoty s daným ID

URI endpointy pro API oddělte od ostatních endpointů do vlastního api_routes.py souboru. Endopointy budou mít prefix /api/<api endpoint>.

  1. Funkční čtení naměřených hodnot z databáze (1b)
  2. Funkční API (5b - 1b/endpoint)
  3. Funkční systém registrace a přihlášení s bezpečným ukládáním citlivých údajů (2b)
  4. API endpoint pro mazání hodnot - je vyžadovaná autentizace registrovaným uživatelem (2b)

BONUS (2b): Definujte endpoint pro získání všech naměřených hodnot. Součástí endpointu bude nepovinný argument sort, který bude rozhodovat o tom, zda budou data v odpovědi řazena od nejnovější, nebo od nejstarší hodnoty. Argument může nabývat hodnot [asc, desc].

3. miniprojekt

Naprogramujte Raspberry Pi Pico W tak, aby periodicky odesílalo data o aktuální teplotě do SQLite databáze. Ke komunikaci použijte MQTT protokol.

  1. Raspberry Pi Pico W odesílá data, která jsou ukládána do SQLite databáze. MQTT komunikace. (6b)
  2. Společně s hodnotou teploty je odesílaný timestamp měření a timestamp odeslání. Web server přidává timestamp přijetí/uložení dat. Všechny 3 časové hodnoty jsou zobrazeny v tabulce dat na dashboard stránce. (4b)

BONUS (2 b): Zajistěte MQTT QoS třídy 1.

4. miniprojekt

Rozšiřte funkcionalitu webové aplikace a programu pro Raspberry Pi Pico W o obousměrnou MQTT komunikaci. Pico W bude kromě odesílání naměřených dat také přijímat příkazy z webového serveru pro ovládání LED diody a řízení měření.

  1. Funkční odesílání příkazu k zastavení/spuštění měření a rozsvícení/zhasnutí LED (5b)
  2. Rozšíření webové aplikace o ovládací prvky pro zastavení/spuštění měření, rozsvícení/zhasnutí LED, vizuální indikace aktuálního stavu LED a měření (5b)

BONUS (2b): Implementujte možnost nastavení periody měření přes webové rozhraní. Uživatel může zadat požadovanou periodu v sekundách, webserver odešle hodnotu přes MQTT a Pico W podle ní upraví interval měření.

5. miniprojekt

Nasaďte svou Flask aplikaci do produkčního prostředí pomocí WSGI serveru.

  1. Instalace a konfigurace WSGI serveru. např. Gunicorn (Linux/WSL) nebo Waitress (Windows). Nápověda 1, Nápověda 2, Nápověda 3 (3b)
  2. Implementace HTTPS pomocí self-signed certifikátů. RSA klíč o délce minimálně 2048 bitů, platnost certifikátu minimálně 365 dní, přesměrování HTTP požadavků na HTTPS. Vytvoření dokumentace pro uživatele, jak přidat certifikát mezi důvěryhodné. Nápověda 1, Nápověda 2 (3b)
  3. Implementace strukturovaného logování do souboru. Různé úrovně logování (DEBUG, INFO, WARNING, ERROR, CRITICAL). Formát logu musí obsahovat časovou značku, úroveň logu, název modulu, zprávu. Logování všech HTTP požadavků (metoda, cesta, status kód). Nápověda 1 (2b)
  4. Vytvoření endpointu /health pro kontrolu stavu aplikace. Kontrola bude zahrnovat dostupnost a funkčnost databáze (provedení testovací query), dostupnost MQTT brokeru, dobu běhu aplikace, počet zpracovaných požadavků od startu. Odpověď bude ve formátu JSON. (2b)

BONUS (2b): Omezte počet požadavků na jednotlivých API endpointech pomocí rate-limitingu. O stavu limitů informujte v odpovídajících hodnotách HTTP hlavičky (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset). Při překročení server odpovídá správným HTTP kódem.

6. miniprojekt

Virtualizujte svou Flask aplikaci pomocí Docker technologií.

  1. Implementace multi-stage Dockerfile. První fáze = instalace závislostí a sestavení aplikace, druhá fáze = vytvoření produkčního obrazu. Správné nastavení uživatelů - aplikace neběží pod root uživatelem. Nápověda 1, Nápověda 2 (3b)
  2. Vytvoření docker-compose souboru se službami: Flask aplikace, InfluxDB, MQTT broker. Nastavení závislostí mezi kontejnery (depends_on). Nápověda 1, Nápověda 2, Nápověda 3 5b
  3. Implementace healthcheck pro kontejnery Flask aplikace a InfluxDB. Kontrola může proběhnout alespoň 2x, maximálně 5x. Timeout bude specifikovaný na 10-30 sekund. Nápověda (2b)

BONUS (2b): Konfigurace Docker volumes pro persistenci dat (alespoň pro InfluxDB). Po zastavení, odstranění, znovuvytvoření a spuštění kontejneru jsou dostupná data z doby před zastavením kontejneru.

courses/b0b37nsi/miniprojects/start.txt · Last modified: 2025/05/06 11:01 by spicajak