10.13. Kiváltott képkockák feltöltése a felhőbe¶
Amikor a mozgás aktiválódik, a kamera most kivilágítja az irányítópultot. Ez elegendő az élő használathoz, de a tulajdonos minden kiváltott képkockáról állandó archívumot is szeretne, valahol a kamerán kívül tárolva. Ez egy kimenő HTTP-hívás – a kamera kliensként viselkedik.
10.13.1. A kamera mint kliens¶
A requests modul a kamera kimenő HTTP-kliense. Felülete a CPython requests moduljának szándékos másolata – ugyanazok az ige nevű modulfüggvények, ugyanazok a files=, json=, headers=, auth= kulcsszavas argumentumok. Ha már intéztél HTTP-hívásokat a CPythonból, akkor már ismered az API-t:
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
A requests.post() megnyit egy TCP-kapcsolatot, elküldi a kérést, és visszaad egy Response objektumot a status_code, reason, headers, content, json() és a többi ismerős tulajdonsággal.
A files={...} egy multipart/form-data törzset épít fel. Az érték egy (filename, file-like) tuple; a requests.post() darabokban olvassa be a fájlszerű objektumot, így az egész JPEG-et nem kell előbb újrapufferelni egy stringbe. A io.BytesIO becsomagolja a memóriában már jelen lévő JPEG-bájtokat, hogy fájlként olvasható felületet biztosítsanak.
A headers={...} egy egyszerű dict, amely kérésfejlécként kerül elküldésre – itt egy bearer token a szabványos Authorization pozícióban. Az archívumszolgáltató dokumentálja, hogy milyen tokenformátumot vár; a példa a leggyakoribb forma.
10.13.2. Bekötés a mozgásérzékelőbe¶
A korábban bemutatott mozgásérzékelő korutin már minden új képkockán lefut, és akkor aktiválódik, amikor change > state['threshold']. Add hozzá ott a feltöltést, de háttérfeladatként indítsd el, hogy az érzékelő ne hagyja abba a figyelést, amíg a feltöltés folyamatban van:
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)
Az asyncio.create_task() ütemezi a feltöltési korutint, és azonnal visszatér. Az érzékelő tovább kapja a képkockákat; a feltöltés mellette fut; a kamera soha nem akad meg.
10.13.3. Hibamódok¶
A hálózati kód meghibásodik. A kamera offline lehet, az archívum leállhat, a bearer token lejárhat. Az érdemes elkapni kategóriák:
Az
OSError– a TCP-kapcsolatot nem lehetett megnyitni, vagy az átvitel közepén zárult le. DNS-hiba, nincs útvonal, kapcsolat-visszaállítás. Arequestspontosan ezt a kivételt dobja.status_code >= 400– a szerver megkapta a kérést és elutasította azt. 401 lejárt token esetén, 403 visszavont esetén, 413 túl nagy törzs esetén, 5xx ha az archívum nem egészséges.Csendes időtúllépés – a
requestsegy alapértelmezett socket-időtúllépést használ (néhány másodperc); ezen túlOSErrorkivételt doberrno.ETIMEDOUTértékkel.
Egy valóban fontos archívum esetén az elutasított képkockákat a /sdcard/pending/ mappába sorolnád, és egy lassabb ciklusban próbálkoznál újra – ez esetenként néhány sornyi pluszt jelent a bemutatottakon felül.
10.13.4. Amit a requests nem csinál¶
A MicroPython port szándékosan kicsi. Néhány dolog, amit a CPython requests megtesz, ez viszont nem:
Kapcsolatok poolingja. Minden hívás új TCP-kapcsolatot nyit.
Automatikus újrapróbálkozás átmeneti hibák esetén. Csomagold be magad a hívást.
Streamelt válaszok. Az
r.contentteljes egészében a RAM-ba kerül beolvasásra; nincsstream=Truemegfelelő.Gzippelt válaszok automatikus kicsomagolása. Csak akkor állítsd be explicit módon az
Accept-Encodingfejlécet, ha a szerver erre van konfigurálva.
A teljes metóduslistáért és arról, hogy mi tartozik a hatókörbe és mi nem, lásd: requests — HTTP-kliens.
A HTTPS azonnal működik – az URL-séma vezérli, és az alapértelmezett SSL-kontextus menet közben jön létre. Az archívum tanúsítványának egy a kamerára betöltött CA-csomag elleni ellenőrzéséről lásd a Nyilvános szerver ellenőrzése (a kamera mint kliens) mint kliens szakaszát.
Az alkalmazás teljesen kész: élő előnézet, mozgásérzékelés, irányítópult bejelentkezéssel, HTTPS, CORS/CSRF, felhőarchívum.