10.13. Učitavanje aktiviranih sličica u oblak

Kada se pokrene detekcija pokreta, kamera sada osvjetljava nadzornu ploču. To je dovoljno za uporabu uživo, ali vlasnik želi i trajnu arhivu svake aktivirane sličice, pohranjenu negdje izvan kamere. To je odlazni HTTP poziv – kamera se ponaša kao klijent.

10.13.1. Kamera kao klijent

Modul requests odlazni je HTTP klijent kamere. Njegovo je sučelje namjerna kopija CPythonovog requests modula – iste funkcije modula nazvane po glagolima, isti files=, json=, headers=, auth= imenovani argumenti. Ako ste ikada radili HTTP pozive iz CPythona, već poznajete API:

import requests
import io

ARCHIVE_URL = 'https://api.backyard-cloud.com/frames'
ARCHIVE_TOKEN = load_archive_token()

async def archive_frame(jpeg, ts):
    try:
        r = requests.post(
            ARCHIVE_URL,
            files={'image': (
                'frame-{}.jpg'.format(ts),
                io.BytesIO(jpeg),
            )},
            headers={'Authorization': 'Bearer ' + ARCHIVE_TOKEN},
        )
    except OSError as e:
        print('upload failed:', e)
        return False
    if r.status_code >= 400:
        print('archive rejected:', r.status_code, r.reason)
        return False
    return True

requests.post() otvara TCP vezu, šalje zahtjev i vraća Response s status_code, reason, headers, content, json() i ostalim poznatim svojstvima.

files={...} izgrađuje tijelo zahtjeva u formatu multipart/form-data. Vrijednost je (filename, file-like) torka; requests.post() čita objekt sličan datoteci u dijelovima tako da se cijeli JPEG ne mora prvo ponovno spremiti u međuspremnik kao niz. io.BytesIO omata JPEG bajtove koji su već u memoriji tako da nude sučelje za čitanje poput datoteke.

headers={...} običan je rječnik koji se šalje kao zaglavlja zahtjeva – ovdje, bearer token na standardnoj poziciji Authorization. Pružatelj arhive dokumentira koji format tokena želi; primjer prikazuje najčešći oblik.

10.13.2. Povezivanje s detektorom pokreta

Korutina detektora pokreta predstavljena ranije već se izvodi na svakoj novoj sličici i pokreće se kada change > state['threshold']. Dodajte učitavanje tamo, ali pokrenite ga kao pozadinski zadatak tako da detektor ne prestane motriti dok je učitavanje u tijeku:

async def motion_detector():
    global last_motion
    prev = None
    while True:
        await new_frame.wait()
        change = compute_change(prev, latest_jpeg)
        if change > state['threshold']:
            state['trigger_count'] += 1
            ts = int(time.time())
            last_motion = {'ts': ts,
                           'count': state['trigger_count'],
                           'change': change}
            motion_event.set()
            asyncio.create_task(archive_frame(latest_jpeg, ts))
        prev = latest_jpeg
        await asyncio.sleep_ms(50)

asyncio.create_task() raspoređuje korutinu za učitavanje i odmah se vraća. Detektor nastavlja dohvaćati sličice; učitavanje se izvodi usporedno s njim; kamera se nikada ne zaustavlja.

10.13.3. Načini otkazivanja

Mrežni kod ne uspijeva. Kamera može biti izvan mreže, arhiva može biti nedostupna, bearer token mogao je isteći. Kategorije koje vrijedi hvatati:

  • OSError – TCP veza nije se mogla otvoriti ili je zatvorena usred prijenosa. Pogreška DNS-a, nema rute, ponovno postavljanje veze. requests podiže upravo ovu iznimku.

  • status_code >= 400 – poslužitelj je primio zahtjev i odbio ga. 401 za istekli token, 403 za opozvani, 413 za preveliko tijelo, 5xx za arhivu koja je u lošem stanju.

  • Tihi istek vremena – requests koristi zadani istek vremena utičnice (nekoliko sekundi); nakon toga podiže OSError s errno.ETIMEDOUT.

Za arhivu koja je doista važna, odbijene biste sličice stavili u red u /sdcard/pending/ i ponovno pokušali u sporijoj petlji – to je nekoliko redaka više po slučaju, povrh onoga što je prikazano.

10.13.4. Što requests ne radi

Port za MicroPython namjerno je malen. Nekoliko stvari koje CPythonov requests radi, a ovaj ne:

  • Udruživanje veza. Svaki poziv otvara novu TCP vezu.

  • Automatsko ponavljanje pri prolaznim pogreškama. Sami omotajte poziv.

  • Strujanje odgovora. r.content čita se u RAM u cijelosti; ne postoji ekvivalent za stream=True.

  • Automatsko raspakiravanje gzip odgovora. Zaglavlje Accept-Encoding postavite eksplicitno samo ako je poslužitelj konfiguriran za to.

Pogledajte requests — HTTP klijent za potpuni popis metoda i što jest / nije u opsegu.

HTTPS radi bez dodatnih postavki – shema URL-a ga pokreće, a zadani SSL kontekst stvara se u hodu. Za provjeru certifikata arhive prema CA paketu koji ste učitali na kameru, pogledajte odjeljak kao klijent u Provjera javnog poslužitelja (kamera kao klijent).

Aplikacija je u potpunosti isporučena: pregled uživo, detekcija pokreta, nadzorna ploča s prijavom, HTTPS, CORS/CSRF, arhiva u oblaku.