Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

internet-controlled-safety

Two demos in "letting the internet touch something at home, carefully":

  1. See where people are, without ever seeing the room. local/ runs YOLO person detection on a webcam and streams only coordinates outbound to remote/, a DigitalOcean droplet that republishes them as a public API. See below.
  2. Let the internet draw on a physical e-ink photo frame. frame-pi/ runs a live, multiplayer paint canvas on a Raspberry Pi Zero W wired to a Waveshare e-ink HAT; frame-droplet/ is a dumb reverse-proxy droplet that tunnels public traffic down to it over autossh — the Pi never accepts an inbound connection. See frame-pi/README.md and frame-droplet/README.md, and examples/reverse-proxy-tunnel/ for the underlying pattern both halves follow.
local/           webcam -> YOLO person detection -> outbound-only WebSocket
remote/          DigitalOcean droplet: ingest coordinates, publish them as a public API

frame-pi/        multiplayer paint app + e-ink renderer, runs on the Pi, dials out via autossh
frame-droplet/   dedicated droplet: TLS + reverse proxy only, no app code, tunnel endpoint for frame-pi

Demo 1: coordinate API

How the separation works

  • local/ opens an outbound WebSocket connection to remote/. It never listens on any inbound port, so nothing on the internet can reach into it.
  • The only thing that crosses the wire is a small JSON payload of normalized detections (x, y, width, height, confidence, timestamp, and for the general object feed, a label). Video frames are read, run through YOLO, and discarded in the same function — see the comment in local/main.py.
  • remote/ never touches a camera, a frame, or an image decoder. It just holds the latest JSON snapshot in memory and republishes it over a public REST/SSE API.
  • The ingest path (local -> remote) requires a shared-secret bearer token. The public read path (remote -> internet) is intentionally open, since the point is to make the coordinates public.

Quickstart

Remote first (needs a DigitalOcean droplet — see remote/README.md for the Ansible deploy):

cd remote
cp .env.example .env   # set INGEST_TOKEN
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --host 0.0.0.0 --port 8000

Local:

cd local
cp .env.example .env   # set RTSP_URL, REMOTE_WS_URL, INGEST_TOKEN (must match remote)
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
python main.py

Then hit the public API:

curl https://your-droplet/api/people      # just person positions
curl https://your-droplet/api/objects     # everything YOLO currently sees, labeled
curl -N https://your-droplet/api/stream   # live SSE feed of both

Threat model notes

This is a demo, not a hardened product. Things worth calling out if you take it further: the ingest token is a static shared secret (fine for a demo, rotate/replace with mTLS or per-device tokens for anything real), the public API has no rate limiting, and remote/ trusts whatever coordinates arrive — it has no way to verify they came from a real camera versus a script feeding it fake positions.

Demo 2: paint frame

frame-pi/ and frame-droplet/ follow the inverse network shape from the demo above: instead of the internet-facing side hosting the real app, the real app (a live, multiplayer paint canvas) runs on the Pi, and the droplet is just a dumb TLS-terminating reverse proxy. The Pi reaches it via an outbound autossh reverse tunnel — same "never accept an inbound connection" principle, just tunneling a whole app instead of one WebSocket. See examples/reverse-proxy-tunnel/README.md for the underlying pattern, and frame-pi/README.md / frame-droplet/README.md for quickstart, the hardware constraints (the e-ink panel only does full-frame refreshes, so the physical frame updates on a timer, not per stroke), and deploy order.

The shared canvas has no content moderation by design — anyone with the URL can draw anything, and it renders periodically on a physical object at home. The only guardrails are technical (a per-connection rate limit, an owner-only reset endpoint), not content filtering.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages