Self-contained Raspberry Pi surveillance System Without Continue Internet
A self-contained Raspberry Pi surveillance system that:
-
Runs autonomously (like EyeOS) — camera always active and streaming.
-
Keeps searching for a known Wi-Fi hotspot (your phone).
-
Starts streaming automatically when the phone hotspot is available.
-
Lets you view the camera feed on your phone (via browser or app).
Here’s a detailed, production-ready setup:
⚙️ Step 1: Setup Raspberry Pi Camera & Software
1. Enable the camera
sudo raspi-config
-
Go to Interface Options → Camera → Enable
-
Reboot:
sudo reboot
2. Install dependencies
sudo apt update
sudo apt install python3-picamera2 python3-flask git -y
📸 Step 2: Create a Local Flask Streaming App
Create file /home/pi/camera_stream.py:
from flask import Flask, Response
from picamera2 import Picamera2
import time
app = Flask(__name__)
piCam = Picamera2()
piCam.configure(piCam.create_preview_configuration(main={"size": (640, 480)}))
piCam.start()
def gen_frames():
while True:
frame = piCam.capture_array()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' +
piCam.encode_jpeg(frame) + b'\r\n')
@app.route('/')
def index():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Test it:
python3 /home/pi/camera_stream.py
Open in your phone browser (later):
http://:8080
🔁 Step 3: Auto-Connect to Your Phone’s Hotspot
-
Turn on your phone hotspot (note SSID & password).
-
Edit Wi-Fi config:
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
Add your phone hotspot details:
network={
ssid="YourHotspotName"
psk="YourHotspotPassword"
priority=10
}
-
Add a Wi-Fi reconnect loop service to always search for it:
Create file /usr/local/bin/wifi_reconnect.sh:
#!/bin/bash
while true
do
if ! iwgetid -r > /dev/null; then
echo "No Wi-Fi. Trying to reconnect..."
sudo wpa_cli -i wlan0 reconfigure
fi
sleep 15
done
Make it executable:
sudo chmod +x /usr/local/bin/wifi_reconnect.sh
🔄 Step 4: Autostart on Boot
Create systemd service /etc/systemd/system/camera.service:
[Unit]
Description=Camera Stream Service
After=network.target
[Service]
ExecStart=/usr/bin/python3 /home/pi/camera_stream.py
Restart=always
User=pi
[Install]
WantedBy=multi-user.target
And Wi-Fi watcher service /etc/systemd/system/wifi-reconnect.service:
[Unit]
Description=Wi-Fi Auto Reconnect
[Service]
ExecStart=/usr/local/bin/wifi_reconnect.sh
Restart=always
User=root
[Install]
WantedBy=multi-user.target
Enable both:
sudo systemctl enable camera.service
sudo systemctl enable wifi-reconnect.service
sudo systemctl start camera.service
sudo systemctl start wifi-reconnect.service
📱 Step 5: Access from Phone
When you enable your phone hotspot:
-
Pi connects automatically (within ~15s).
-
Visit http://192.168.43.x:8080 (Pi IP shown in hotspot device list).
-
You’ll see live camera feed.
💡 Optional Enhancements
-
Use
ngrokor localtunnel to access remotely later (if internet is available). -
Add motion detection with
motionoropencv-python. -
Use
systemd watchdogorcronto reboot if Wi-Fi drops too long.
Here’s how to extend your setup to add motion detection + offline snapshot saving, all still working without internet and auto-starting when your phone hotspot appears.
⚙️ Step 6: Add Motion Detection with Snapshots
We’ll modify the Flask camera script to:
-
Continuously capture frames.
-
Compare each frame to detect movement.
-
Save snapshots locally when motion occurs.
-
Keep the live stream accessible at
http://<pi_ip>:8080.
📄 Replace your /home/pi/camera_stream.py with this:
from flask import Flask, Response
from picamera2 import Picamera2
import cv2, numpy as np, time, os
app = Flask(__name__)
piCam = Picamera2()
piCam.configure(piCam.create_preview_configuration(main={"size": (640, 480)}))
piCam.start()
last_frame = None
save_path = "/home/pi/motion_captures"
os.makedirs(save_path, exist_ok=True)
def gen_frames():
global last_frame
while True:
frame = piCam.capture_array()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
if last_frame is None:
last_frame = gray
continue
delta = cv2.absdiff(last_frame, gray)
thresh = cv2.threshold(delta, 25, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
if cv2.contourArea(c) < 1500: # ignore small movements
continue
timestamp = time.strftime("%Y%m%d-%H%M%S")
filename = f"{save_path}/motion_{timestamp}.jpg"
cv2.imwrite(filename, frame)
print(f"Motion detected, snapshot saved: {filename}")
time.sleep(1) # avoid saving too many per second
break
last_frame = gray
# Stream JPEG frame
_, jpeg = cv2.imencode('.jpg', frame)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + jpeg.tobytes() + b'\r\n')
@app.route('/')
def index():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
🗂️ Step 7: Verify Motion Capture Folder
All motion-triggered snapshots will be stored in:
/home/pi/motion_captures/
You can access them later using:
ls /home/pi/motion_captures/
Or even download them through SFTP from your phone if you use an app like CX File Explorer or Termius.
🌀 Step 8: Auto-Restart Service (if not already)
Your existing systemd service (camera.service) already keeps this running on boot and restart.
Just restart it once to load the new version:
sudo systemctl restart camera.service
✅ Final Behavior
-
Raspberry Pi boots up and keeps scanning for your phone’s hotspot.
-
Once your hotspot is on, it connects automatically.
-
The Flask camera service starts streaming on
http://192.168.43.x:8080. -
Any motion triggers snapshots saved under
/home/pi/motion_captures/. -
Works completely offline.

Comments