10.13. Mengunggah bingkai yang dipicu ke cloud¶
Ketika gerakan mendeteksi kamera, dasbor sekarang menyala. Itu cukup untuk penggunaan langsung, tetapi pemilik juga menginginkan arsip permanen dari setiap bingkai yang dipicu, tersimpan di suatu tempat di luar kamera. Itu adalah panggilan HTTP keluar -- kamera bertindak sebagai klien.
10.13.1. Kamera sebagai klien¶
Modul requests adalah klien HTTP keluar kamera. Antarmukanya adalah salinan yang disengaja dari requests CPython -- fungsi modul dengan nama kata kerja yang sama, argumen kata kunci files=, json=, headers=, auth= yang sama. Jika Anda sudah pernah melakukan panggilan HTTP dari CPython, Anda sudah mengenal API-nya:
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() membuka koneksi TCP, mengirim permintaan, dan mengembalikan Response dengan status_code, reason, headers, content, json(), dan properti familiar lainnya.
files={...} membangun isi multipart/form-data. Nilainya adalah tuple (filename, file-like); requests.post() membaca file-like dalam potongan sehingga seluruh JPEG tidak harus di-buffer ulang menjadi string terlebih dahulu. io.BytesIO membungkus byte JPEG yang sudah ada di memori sehingga mengekspos antarmuka baca-sebagai-file.
headers={...} adalah dict biasa yang dikirim sebagai header permintaan -- di sini, token bearer dalam posisi Authorization standar. Penyedia arsip mendokumentasikan format token yang mereka inginkan; contoh ini adalah format yang paling umum.
10.13.2. Menghubungkannya ke detektor gerakan¶
Coroutine detektor gerakan yang diperkenalkan sebelumnya sudah berjalan pada setiap bingkai baru dan aktif ketika change > state['threshold']. Tambahkan pengunggahan di sana, tetapi jalankan sebagai tugas latar belakang sehingga detektor tidak berhenti memantau selama pengunggahan berlangsung:
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() menjadwalkan coroutine pengunggahan dan langsung kembali. Detektor terus mengambil bingkai; pengunggahan berjalan di sampingnya; kamera tidak pernah terhenti.
10.13.3. Mode kegagalan¶
Kode jaringan bisa gagal. Kamera mungkin sedang offline, arsip mungkin sedang down, token bearer mungkin sudah kedaluwarsa. Kategori yang perlu ditangani:
OSError-- koneksi TCP tidak dapat dibuka atau ditutup di tengah transfer. Kegagalan DNS, tidak ada rute, koneksi direset.requestsmemunculkan pengecualian ini secara langsung.status_code >= 400-- server menerima permintaan dan menolaknya. 401 untuk token yang kedaluwarsa, 403 untuk yang dicabut, 413 untuk isi yang terlalu besar, 5xx untuk arsip yang tidak sehat.Timeout diam --
requestsmenggunakan timeout socket default (beberapa detik); setelah itu memunculkanOSErrordenganerrno.ETIMEDOUT.
Untuk arsip yang benar-benar penting, Anda akan mengantrekan bingkai yang ditolak ke /sdcard/pending/ dan mencoba lagi pada loop yang lebih lambat -- itu beberapa baris lagi per kasus, di atas yang ditampilkan.
10.13.4. Apa yang tidak dilakukan requests¶
Port MicroPython sengaja dibuat kecil. Beberapa hal yang dilakukan requests CPython yang tidak dilakukan oleh yang ini:
Pooling koneksi. Setiap panggilan membuka koneksi TCP baru.
Percobaan ulang otomatis pada kesalahan sementara. Bungkus panggilan sendiri.
Respons streaming.
r.contentdibaca ke dalam RAM sepenuhnya; tidak ada padananstream=True.Dekompresi otomatis respons gzip. Atur header
Accept-Encodingsecara eksplisit hanya jika server dikonfigurasi untuk itu.
Lihat requests --- Klien HTTP untuk daftar metode lengkap dan apa yang termasuk/tidak termasuk dalam cakupan.
HTTPS berfungsi di luar kotak -- skema URL mengendalikannya, dan konteks SSL default dibuat secara otomatis. Untuk memverifikasi sertifikat arsip terhadap bundle CA yang telah Anda muat ke kamera, lihat bagian sebagai klien dari Memverifikasi server publik (kamera sebagai klien).
Aplikasinya sudah sepenuhnya dikirimkan: pratinjau langsung, deteksi gerakan, dasbor dengan login, HTTPS, CORS/CSRF, arsip cloud.