[bin] Fixing bin scripts and adding bus check
This commit is contained in:
111
bin/.bin/checkschoolbus.py
Executable file
111
bin/.bin/checkschoolbus.py
Executable file
@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env -S uv run --script
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.11"
|
||||||
|
# dependencies = [
|
||||||
|
# "requests",
|
||||||
|
# "opencv-python",
|
||||||
|
# "numpy",
|
||||||
|
# "ntfy",
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
import requests
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import time
|
||||||
|
|
||||||
|
# URL for the video stream
|
||||||
|
stream_url = 'http://loge.local:8083/stream'
|
||||||
|
public_url = "https://mail.see.unbl.ink/stream"
|
||||||
|
|
||||||
|
# Load a template image of a school bus (you need to have this template)
|
||||||
|
template = cv2.imread('/home/powellc/var/inbox/school_bus_template.jpg', 0)
|
||||||
|
w, h = template.shape[::-1]
|
||||||
|
|
||||||
|
# Open the stream using OpenCV
|
||||||
|
cap = cv2.VideoCapture(stream_url)
|
||||||
|
|
||||||
|
# Check if the stream opened successfully
|
||||||
|
if not cap.isOpened():
|
||||||
|
print("Error: Could not open video stream.")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
# Configure ntfy server and topic
|
||||||
|
ntfy_server = "https://ntfy.unbl.ink" # Replace with your ntfy server
|
||||||
|
topic = "school-bus-alert" # Replace with your desired topic
|
||||||
|
|
||||||
|
# Send notification function with custom server and topic
|
||||||
|
def send_ntfy_notification(title, message):
|
||||||
|
# Construct the full URL with topic (this is how ntfy expects the URL)
|
||||||
|
url = f"{ntfy_server}"
|
||||||
|
|
||||||
|
# Payload for the notification
|
||||||
|
headers = {"Title": title}
|
||||||
|
payload = {
|
||||||
|
"topic": topic,
|
||||||
|
"message": message,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send the POST request to the ntfy server
|
||||||
|
response = requests.post(url, json=payload, headers=headers)
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
print("Notification sent successfully.")
|
||||||
|
else:
|
||||||
|
print(f"Failed to send notification: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Read a frame from the stream
|
||||||
|
ret, frame = cap.read()
|
||||||
|
|
||||||
|
if not ret:
|
||||||
|
print("Failed to capture frame.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Convert the frame to grayscale for template matching
|
||||||
|
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
# Perform template matching on the current frame
|
||||||
|
res = cv2.matchTemplate(gray_frame, template, cv2.TM_CCOEFF_NORMED)
|
||||||
|
threshold = 0.80 # Set your threshold for matching
|
||||||
|
loc = np.where(res >= threshold)
|
||||||
|
|
||||||
|
# If a match is found, send a notification
|
||||||
|
if len(loc[0]) > 0:
|
||||||
|
print("Bus detected!")
|
||||||
|
|
||||||
|
# Save the frame with bounding boxes to a file in /tmp
|
||||||
|
timestamp = time.strftime("%Y%m%d_%H%M")
|
||||||
|
filename = f"school_bus_detection_{timestamp}.jpg"
|
||||||
|
output_path = f"/media/photos/misc/school_bus/{filename}"
|
||||||
|
|
||||||
|
cv2.imwrite(output_path, frame)
|
||||||
|
print(f"Frame with match locations saved to {output_path}")
|
||||||
|
|
||||||
|
# Send notification using ntfy (with both title and message)
|
||||||
|
title = "School Bus Detected!"
|
||||||
|
message = f"Check the video feed at: {public_url}\nMatched image at https://files.lab.unbl.ink/school_bus/{filename}"
|
||||||
|
|
||||||
|
# Send the notification with both title and message
|
||||||
|
send_ntfy_notification(title, message)
|
||||||
|
|
||||||
|
# Draw bounding boxes on the detected matches
|
||||||
|
for pt in zip(*loc[::-1]): # Switch x and y for rectangle drawing
|
||||||
|
cv2.rectangle(frame, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
|
||||||
|
|
||||||
|
|
||||||
|
print("Pausing for 3 minutes to let the bus leave...")
|
||||||
|
time.sleep(180) # Sleep for 3 minutes (180 seconds)
|
||||||
|
else:
|
||||||
|
print("No bus found, sleeping for 2 seconds")
|
||||||
|
|
||||||
|
# Optional: Display the frame with the match location (for debugging)
|
||||||
|
#for pt in zip(*loc[::-1]):
|
||||||
|
# cv2.rectangle(frame, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
|
||||||
|
|
||||||
|
## Display the frame (for debugging)
|
||||||
|
#cv2.imshow('Frame', frame)
|
||||||
|
|
||||||
|
time.sleep(2) # two seconds so we don't spam the camera
|
||||||
|
# Break the loop on key press (e.g., 'q' to quit)
|
||||||
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
|
break
|
||||||
@ -22,7 +22,7 @@ import re
|
|||||||
# ----------------------
|
# ----------------------
|
||||||
GMAIL_USER = os.getenv("GMAIL_USER", "your-email@gmail.com")
|
GMAIL_USER = os.getenv("GMAIL_USER", "your-email@gmail.com")
|
||||||
GMAIL_APP_PASSWORD = os.getenv("GMAIL_APP_PASSWORD", "your-app-password")
|
GMAIL_APP_PASSWORD = os.getenv("GMAIL_APP_PASSWORD", "your-app-password")
|
||||||
NTFY_TOPIC = os.getenv("NTFY_TOPIC", "dev-notifications")
|
NTFY_TOPIC = os.getenv("NTFY_TOPIC", "KKddGQxVm2LoP0JF")
|
||||||
NTFY_SERVER = os.getenv("NTFY_SERVER", "https://ntfy.sh")
|
NTFY_SERVER = os.getenv("NTFY_SERVER", "https://ntfy.sh")
|
||||||
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "60"))
|
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL", "60"))
|
||||||
JIRA_SENDERS = ["jira@yourcompany.com", "jira@atlassian.net"]
|
JIRA_SENDERS = ["jira@yourcompany.com", "jira@atlassian.net"]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
BASEDIR="/var/photos/misc/nytimes"
|
BASEDIR="/media/photos/misc/nytimes"
|
||||||
DATE=$(date +"%Y-%m-%d")
|
DATE=$(date +"%Y-%m-%d")
|
||||||
TMPFILE=/tmp/nyt.pdf
|
TMPFILE=/tmp/nyt.pdf
|
||||||
OUTFILE=$BASEDIR/$DATE.jpg
|
OUTFILE=$BASEDIR/$DATE.jpg
|
||||||
|
|||||||
@ -64,7 +64,7 @@ for cam in "${WEBCAMS[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# --- Update index.html ---
|
# --- Update index.html ---
|
||||||
INDEX_HTML="$BASE_DIR/index.html"
|
INDEX_HTML="$BASE_DIR/timelapses.html"
|
||||||
|
|
||||||
# Ensure file exists with basic structure
|
# Ensure file exists with basic structure
|
||||||
if [[ ! -f "$INDEX_HTML" ]]; then
|
if [[ ! -f "$INDEX_HTML" ]]; then
|
||||||
@ -87,19 +87,19 @@ fi
|
|||||||
# Build new day's section
|
# Build new day's section
|
||||||
NEW_SECTION="<h2>$YESTERDAY</h2><ul>"
|
NEW_SECTION="<h2>$YESTERDAY</h2><ul>"
|
||||||
for link in "${LINKS[@]}"; do
|
for link in "${LINKS[@]}"; do
|
||||||
cam=\$(echo "\$link" | cut -d']' -f1 | tr -d '[]')
|
cam=$(echo "$link" | cut -d']' -f1 | tr -d '[]')
|
||||||
url=\$(echo "\$link" | awk '{print \$2}')
|
url=$(echo "$link" | awk '{print $2}')
|
||||||
NEW_SECTION+="<li><a href=\"\$url\">\$cam</a></li>"
|
NEW_SECTION+="<li><a href=\"$url\">$cam</a></li>"
|
||||||
done
|
done
|
||||||
NEW_SECTION+="</ul>"
|
NEW_SECTION+="</ul>"
|
||||||
|
|
||||||
# Insert at the top of <div id="days">
|
# Insert at the top of <div id="days">
|
||||||
tmpfile=\$(mktemp)
|
tmpfile=$(mktemp)
|
||||||
awk -v section="\$NEW_SECTION" '
|
awk -v section="$NEW_SECTION" '
|
||||||
/<div id="days">/ { print; print section; next }
|
/<div id="days">/ { print; print section; next }
|
||||||
{ print }
|
{ print }
|
||||||
' "\$INDEX_HTML" > "\$tmpfile"
|
' "$INDEX_HTML" > "$tmpfile"
|
||||||
mv "\$tmpfile" "\$INDEX_HTML"
|
mv "$tmpfile" "$INDEX_HTML"
|
||||||
|
|
||||||
echo "📝 Updated index with $YESTERDAY timelapses (newest on top)"
|
echo "📝 Updated index with $YESTERDAY timelapses (newest on top)"
|
||||||
|
|
||||||
|
|||||||
@ -5,11 +5,11 @@ if [ "$1" = "mailbox" ]; then
|
|||||||
fi
|
fi
|
||||||
if [ "$1" = "basement_table" ]; then
|
if [ "$1" = "basement_table" ]; then
|
||||||
host="loge.local"
|
host="loge.local"
|
||||||
port=8081
|
port=8082
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "frontyard" ]; then
|
if [ "$1" = "frontyard" ]; then
|
||||||
host="loge.local"
|
host="loge.local"
|
||||||
port=8082
|
port=8081
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "basement_tv" ]; then
|
if [ "$1" = "basement_tv" ]; then
|
||||||
port=8081
|
port=8081
|
||||||
@ -24,19 +24,19 @@ if [ "$1" = "bulkhead" ]; then
|
|||||||
host="kiviuq.local"
|
host="kiviuq.local"
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "backyard" ]; then
|
if [ "$1" = "backyard" ]; then
|
||||||
port=8082
|
port=8081
|
||||||
host="mundilfari.local"
|
host="mundilfari.local"
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "backyard_low" ]; then
|
if [ "$1" = "backyard_low" ]; then
|
||||||
port=8083
|
port=8082
|
||||||
host="mundilfari.local"
|
host="mundilfari.local"
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "backyard_north" ]; then
|
if [ "$1" = "backyard_north" ]; then
|
||||||
port=8084
|
port=8083
|
||||||
host="mundilfari.local"
|
host="mundilfari.local"
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "basement_extension" ]; then
|
if [ "$1" = "basement_extension" ]; then
|
||||||
port=8081
|
port=8084
|
||||||
host="mundilfari.local"
|
host="mundilfari.local"
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "orchard" ]; then
|
if [ "$1" = "orchard" ]; then
|
||||||
@ -72,7 +72,7 @@ if [ "$1" = "diningroom" ]; then
|
|||||||
host="kari.local"
|
host="kari.local"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ROOT="/var/photos/misc/webcams"
|
ROOT="/media/photos/misc/webcams"
|
||||||
filepath="$1/$(date +%Y)/$(date +%m)/$(date +%d)/$(date +%Y%m%d%H%M%S).jpg"
|
filepath="$1/$(date +%Y)/$(date +%m)/$(date +%d)/$(date +%Y%m%d%H%M%S).jpg"
|
||||||
mkdir -p /$ROOT/$1/$(date +%Y)/$(date +%m)/$(date +%d)/
|
mkdir -p /$ROOT/$1/$(date +%Y)/$(date +%m)/$(date +%d)/
|
||||||
curl $host:$port/snapshot -o /$ROOT/$filepath
|
curl $host:$port/snapshot -o /$ROOT/$filepath
|
||||||
|
|||||||
Reference in New Issue
Block a user