10.8. Dvosmjerno upravljanje pomoću WebSocketa¶
Server-Sent Events služe samo za guranje podataka. Kada vlasnik na nadzornoj ploči dodirne „spremi snimku odmah” ili „ponovno postavi brojač okidanja”, nadzorna ploča mora poslati poruku prema kameri. To su WebSocketi – jedna TCP utičnica, uokvirene poruke koje teku u oba smjera.
10.8.1. Ruta /control¶
microdot.websocket.with_websocket() izvodi rukovanje za nadogradnju na WebSocket i predaje rukovatelju WebSocket objekt. Rukovatelj se vrti zauvijek, čitajući naredbe i šaljući potvrde:
from microdot.websocket import with_websocket
from microdot.websocket import WebSocketError
import json
@app.get('/control')
@with_websocket
async def control(request, ws):
while True:
try:
msg = await ws.receive()
except WebSocketError:
break
try:
cmd = json.loads(msg)
except ValueError:
await ws.send({'error': 'bad json'})
continue
if cmd.get('cmd') == 'snapshot_now':
if latest_jpeg:
path = '/sdcard/snaps/manual-{}.jpg'.format(
int(time.time()))
with open(path, 'wb') as f:
f.write(latest_jpeg)
await ws.send({'ok': True, 'saved': path})
else:
await ws.send({'ok': False, 'reason': 'no frame yet'})
elif cmd.get('cmd') == 'reset':
state['trigger_count'] = 0
await ws.send({'ok': True, 'counters': 'reset'})
else:
await ws.send({'error': 'unknown command'})
receive() vraća niz za tekstualne okvire i bajtove za binarne okvire. WebSocket.send(...) na strani preglednika prema zadanom šalje tekst, pa su JSON-kodirane naredbe prirodan izbor.
send() prihvaća nizove, bajtove ili bilo što serijalizirano u JSON – rječnik se šalje kao JSON tekstualni okvir.
WebSocketError podiže se kada se klijent prekine veza (čisto zatvaranje, prekid mreže ili pogreška protokola). Rukovatelj izlazi iz petlje i vraća se; microdot pospremi utičnicu.
10.8.2. Nadzorna ploča šalje naredbe¶
Dvije tipke idu u index.html pokraj klizača:
<button id="snap-btn">Save snapshot</button>
<button id="reset-btn">Reset counter</button>
a app.js jednom otvara WebSocket i povezuje obje tipke s send:
const proto = location.protocol === 'https:' ? 'wss://' : 'ws://';
const ws = new WebSocket(proto + location.host + '/control');
document.getElementById('snap-btn').addEventListener('click', () =>
ws.send(JSON.stringify({cmd: 'snapshot_now'})));
document.getElementById('reset-btn').addEventListener('click', () =>
ws.send(JSON.stringify({cmd: 'reset'})));
ws.addEventListener('message', (e) => {
console.log('cam:', JSON.parse(e.data));
});
Izbor između ws:// i wss:// zrcali http:// naspram https:// – WebSocket nasljeđuje isto rukovanje TLS-om. S uspostavljenim HTTPS-om nadzorna ploča automatski se povezuje putem wss://.
10.8.3. Kada odabrati SSE, a kada WebSockete¶
Koristite SSE kada kamera gura podatke, a preglednik samo sluša – obavijesti, telemetrija, promjene statusa. Komunikacija je običan HTTP, klijentska strana je jedan redak (new EventSource), a ponovno povezivanje je automatsko.
Koristite WebSockete kada i preglednik treba gurati podatke – tipke, klizači koji šalju ažuriranja brzinom pritiska tipki, sve gdje bi čekanje na sljedeći zahtjev bilo presporo. Veza je dvosmjerna i uokvirena, ali API je složeniji s obje strane.
Kamera je sada interaktivna stvar – promatra, gura događaje prema van i prihvaća naredbe prema unutra.