NB-IoT Offline Camera System

Ultra-budget timelapse for remote sites — local image storage with NB-IoT status heartbeats

~$178
Cheapest DSLR Build
ESP32 + DSLR (excl. camera)
144
Images / Day
Every 5 min, 6am–6pm
14B
Heartbeat Packet
Status, storage, GPS coords
$1–3
Per Month
NB-IoT data cost (M2MSIM)

Daily Cycle

Wake
RTC alarm 06:00 — Pi boots (25s) or ESP32 wakes (138ms)
📷
Capture
Every 5 min via gphoto2, shutter cable, or Termux cron
💾
Store
Locally on SD card — up to 3 months before extraction
📡
Heartbeat
14-byte NB-IoT UDP packet every 30 min via Telstra
🌙
Sleep
18:00 shutdown — 8µA deep sleep or 0.5mA PV HAT

System Variants

Pi Zero 2W + DSLR — “Full Control”
  • Cost: ~$359 (excl. DSLR + housing)
  • Controller: Pi Zero 2W + PV PI HAT (MPPT, RTC wake)
  • Capture: gphoto2 over USB — full image management
  • Storage: 128GB microSD (OverlayFS root, ext4 images)
  • Extraction: WiFi AP web interface — browser download
  • Solar: 20W panel, 72Wh LiFePO4 (6-day autonomy)
  • NB-IoT: Waveshare SIM7028 HAT (GPIO, 0.8µA PSM)
  • Daily power: ~12Wh
ESP32 + DSLR — “Minimal Trigger”
  • Cost: ~$178 (excl. DSLR + housing)
  • Controller: LILYGO T-SIM7000G (ESP32 + NB-IoT + GPS)
  • Capture: 2.5mm shutter cable via optocoupler
  • Storage: 128GB SD card in DSLR directly
  • Extraction: Physically swap or copy DSLR SD card
  • Solar: 10W panel, 22–37Wh LiFePO4
  • Wake: 138ms from deep sleep (8µA overnight)
  • Daily power: ~5–7Wh
Samsung Galaxy — “Phone Camera”
  • Cost: ~$103 + phone (excl. housing)
  • Capture: Termux cron — termux-camera-photo every 5 min
  • Resolution: 12MP (200MP headless inaccessible)
  • Storage: 256GB phone — ~300 days capacity
  • Extraction: WiFi hotspot + HTTP server (~30 seconds)
  • Solar: 5W USB panel — smallest footprint
  • NB-IoT: Separate ESP32 + SIM7028 sidecar module
  • Daily power: ~3–5Wh

Heartbeat Packet (14 bytes)

Data Fields (12 bytes)
  • camera_id [2B] — Unique device identifier (uint16)
  • flags [1B] — Shooting, modem_alive, camera_connected, undervoltage
  • storage_pct [1B] — Storage used 0–100%
  • image_count [2B] — Images since last extraction
  • minutes_since_capture [2B] — Freshness indicator
  • cpu_temp [1B] — °C (ambient for ESP32)
  • uptime_hours [2B] — Total runtime since boot
Protocol Notes
  • Size: 14 bytes total (12 data + 2 HMAC)
  • Transport: UDP via SIM7000G AT+CIPSTART
  • Auth: Truncated SHA-256 HMAC per camera
  • Byte order: Big-endian (network byte order)
  • Interval: Every 30 min (daytime), PSM between sends
  • GPS: Separate 15-byte packet (magic byte 0xBB)
  • Data cost: ~$1–3/month (M2MSIM NB-IoT)

Software Stack

Device-Side
  • Pi Zero: Python 3 + pyserial + python-gphoto2
  • ESP32: C++ Arduino + TinyGSM library + DS3231 RTC
  • Phone: Termux + termux-api + Python cron scripts
  • AT commands: UART to SIM7000G / SIM7028 HAT at 115200 baud
  • Service: systemd nbiot-camera.service (Pi variant)
  • Pi UART: Bluetooth disabled (dtoverlay=disable-bt)
Server-Side (PHP + MySQL)
  • UDP listener: PHP CLI daemon — socket_recvfrom()
  • Database: MySQL — nbiot_cameras, nbiot_camera_status, heartbeat_log
  • HTTP APIs: PHP 8 — status, history, command queue
  • Alert cron: Offline detection and email notifications
  • Downlink: Commands queued and sent on next heartbeat
  • Error log: /camera-systems/nb-iot-basic/server/api/debug.php

Related Tools