3. Miniprojekt

Rozšiřte stávající IoT systém o databázi a REST API. Navrhněte a implementujte službu, která průběžně ukládá data z MQTT brokeru do SQLite databáze a zpřístupňuje je prostřednictvím REST API.

1. Databázové schéma (4 body): Navrhněte a implementujte SQLite databázi s alespoň 2 tabulkami. Jedna tabulka bude uchovávat záznamy měření (teplota, časová známka ISO 8601), druhá bude sloužit jako registr zařízení. Každé zařízení identifikované ČVUT loginem bude mít v tabulce zařízení právě jeden záznam obsahující identifikátor zařízení, časovou známku první detekované zprávy, časovou známku poslední detekované zprávy, uptime získaný z poslední přijaté zprávy, aktuálně nastavenou periodu měření a celkový počet detekovaných zpráv. Mezi tabulkami musí být definován vztah prostřednictvím cizího klíče. Schéma databáze bude uloženo v samostatném souboru schema.sql. Při inicializaci Flask aplikace musí být automaticky ověřeno a zajištěno, že: databázový soubor existuje, obě tabulky jsou přítomny a mají správně definované sloupce. Pokud databáze nebo schéma neexistuje, aplikace je automaticky vytvoří. Na pozadí aplikace musí běžet MQTT klient odebírající téma cvut/nsi/2026/+/telemetry. Logika zpracování příchozí zprávy musí postupovat následovně:

  1. Ověří se, že payload je validní JSON obsahující všechna povinná pole (teplota, časová známka měření, perioda měření). Zpráva s chybějícím nebo nevalidním polem (například chybějící teplota, časová známka ve špatném formátu) se zahodí a do konzole se vypíše popis chyby – aplikace nesmí havarovat.
  2. Ze struktury tématu se extrahuje identifikátor zařízení (ČVUT login). Pokud pro toto zařízení dosud neexistuje záznam v registru, nový záznam se vytvoří.
  3. Je-li zpráva validní, zpracuje se payload: vloží se nový záznam měření a aktualizuje se záznam zařízení (uptime, časová známka poslední zprávy, perioda měření, počet zpráv).

2. REST API (4 body): Implementujte REST API s následujícími endpointy. Každý endpoint musí vracet správný HTTP stavový kód dle situace a tělo odpovědi vždy ve formátu JSON (včetně chybových stavů):

Metoda Endpoint Popis
GET /api/devices Vrátí seznam detekovaných zařízení; 4xx pokud žádné zařízení neexistuje; 2xx při úspěchu.
GET /api/devices/<device_id> Vrátí detail konkrétního zařízení; 4xx pokud neexistuje; 2xx při úspěchu.
GET /api/telemetry/<id> Vrátí konkrétní záznam telemetrie (měření); 4xx pokud neexistuje; 2xx při úspěchu.
DELETE /api/telemetry/<id> Smaže konkrétní záznam telemetrie (měření); 4xx pokud neexistuje; 2xx při úspěchu.
DELETE /api/devices/<device_id> Smaže zařízení včetně všech jeho telemetrických záznamů (kaskádové smazání); 4xx pokud neexistuje, 2xx při úspěchu.
POST /api/telemetry Umožní vložení záznamu. Nutná validace struktury těla požadavku; při úspěchu vrací 2xx. V těle požadavku se očekává JSON struktura s položkami: device (povinné), timestamp (povinné), measure-period (povinné), temperature (povinné), uptime (student musí vyřešit logiku aktualizace záznamu zařízení, pokud uptime není součástí payloadu – viz bod 1) a led.

3. Pokročilé dotazování (4 body): Přidejte endpoint GET /api/telemetry, který bude podporovat následující query parametry a HTTP hlavičky.

URL Query parametry:

  • device_id - filtrování záznamů pro konkrétní zařízení,
  • from a to - časový rozsah ve formátu ISO 8601. Pokud je from větší než to, server vrací 4xx s vysvětlujícím JSON tělem.

HTTP hlavičky požadavků:

  • X-Sort-Field - pole, podle kterého se výsledky řadí; povolené hodnoty: timestamp, temperature; výchozí hodnota: timestamp. Neznámá hodnota musí být odmítnuta stavem 4xx s vysvětlujícím JSON tělem.
  • X-Sort-Order - směr řazení; povolené hodnoty: asc, desc; výchozí hodnota: desc.

HTTP hlavičky odpovědí:

  • X-Current-Count - počet záznamů odpovídajících zadaným filtrům
  • X-Total –Count - celkový počet záznamů v tabulce (bez ohledu na filtry)

Hodnotí se správnost SQL dotazů generovaných pro filtrování a řazení. Řešení, která načtou veškerá data do paměti Pythonu a teprve poté třídí nebo filtrují, nebudou uznána.

4. Vizualizace historických dat (3 body): Implementujte webovou stránku dostupnou na /dashboard, která zobrazuje graf vývoje teploty v čase pro zvolené zařízení a zvolené časové okno. Stránka musí obsahovat HTML formulář s následujícími ovládacími prvky:

  • Výběr zařízení prostřednictvím vhodného elementu (například select nebo datalist) generovaného ze seznamu registrovaných zařízení.
  • Volba časového okna, přičemž musí být podporovány oba režimy:
    • absolutní – zadání konkrétního rozsahu „od“ a „do”,
    • relativní – „do“ je aktuální čas a volí se velikost časového okna (např. posledních 30 minut, 2 hodiny, 1 den) s explicitním zohledněním jednotky (sekunda/minuta/hodina/den).

Student si může zvolit přístup dle vlastního uvážení – server-side rendering nebo client-side rendering. Bez ohledu na zvolenou technologii se hodnotí kvalita a použitelnost výstupu: graf musí mít popsané osy, název, správně formátované časové popisky na ose X a musí být přehledný i při řádu stovek záznamů.

BONUS (+3 body): Implementujte endpoint POST /api/telemetry/batch, který přijme JSON pole obsahující 1–1000 telemetrických záznamů najednou. Celá dávka musí být vložena v rámci jediné transakce – buď se uloží všechny záznamy, nebo žádný. Pokud jakýkoliv záznam v dávce nesplní validaci (chybějící povinné pole, nevalidní datový typ, časová známka ve špatném formátu), transakce se celá zruší a server vrátí 4xx s tělem obsahujícím index prvního chybného záznamu a popis chyby. Při úspěchu vrátí 2xx s počtem vložených záznamů.

Součástí řešení musí být testovací skript batch_test.py, který demonstruje obě větve: úspěšné vložení validní dávky a odmítnutí dávky obsahující jeden nevalidní záznam uprostřed. Skript musí po odmítnuté dávce ověřit, že databáze neobsahuje žádná částečně vložená data – tzn. explicitně dotázat databázi a výsledek vypsat do konzole.

Hodnoty HTTP stavových kódů musí student pečlivě uvážit a pro každý případ zvolit vhodný kód. Nápověda: určitě všechny 2xx kódy nemají být “200 OK”.
courses/b0b37nsi/miniprojects/03.txt · Last modified: 2026/04/23 14:21 by spicajak