Compare commits

..

22 Commits

Author SHA1 Message Date
marcus 77db82b875 done 2024-10-20 19:13:54 +11:00
marcus 296775bc2e Fix improper indentation in process_snapshot function
- Corrected inconsistent indentation to avoid runtime .
- Ensured that all indentation levels match Python's expected format.
2024-10-20 19:10:44 +11:00
marcus b2db064021 Fix indentation issues in main function for proper script execution
- Corrected inconsistent indentation in the main function to avoid runtime `IndentationError`.
- Ensured the MQTT client properly connects and publishes when processing images from the command line.
2024-10-20 19:08:00 +11:00
marcus fe209a9c2a IndentationError 2024-10-20 19:06:33 +11:00
marcus c948bdfd6c Add startup log message for Dayglo Detector script
- Added a log message to indicate when the Dayglo Detector script starts.
2024-10-20 19:01:10 +11:00
marcus b427ad12ec remove dup 2024-10-20 18:54:42 +11:00
marcus 96bf583eb7 Fix coroutine warning by properly awaiting async MQTT methods
- Wrapped `on_connect` and `on_message` methods with `asyncio.create_task()` to ensure they are properly awaited.
- Created separate handler functions for connection and message handling.
2024-10-20 18:52:00 +11:00
marcus 998ad12e61 Fix syntax error and redundant connection call in MQTT client
- Removed duplicate `async` keyword from `on_connect` method.
- Removed redundant `await client.connect()` to avoid double connection attempt.
2024-10-20 18:50:11 +11:00
marcus 564c963af1 Fix coroutine warning and replace MQTT client loop handling
- Properly awaited the `on_connect` method to resolve RuntimeWarning.
- Replaced `loop_forever()` with an async event loop using `asyncio.get_event_loop().create_future()`.
2024-10-20 18:48:18 +11:00
marcus 917aa913c1 move from paha-mqtt to gmqtt 2024-10-20 18:47:53 +11:00
marcus 0a4ebf1fec Replace paho-mqtt with gmqtt for modern MQTT 5.0 support
- Switched to `gmqtt` for better MQTT 5.0 compatibility and to address deprecation warnings.
- Refactored the MQTT client to use asynchronous handling with `asyncio`.
- Updated snapshot processing and MQTT communication to use async functions.
2024-10-20 18:44:47 +11:00
marcus 795b527f90 Fix indentation errors in on_connect function to resolve runtime issues
- Corrected inconsistent indentation to match the expected Python format.
- Ensured proper alignment of the `on_connect` function code block to avoid `IndentationError`.
2024-10-20 18:38:03 +11:00
marcus 8274d5c698 Fix indentation errors in on_connect function to prevent runtime issues
- Corrected inconsistent indentation to match the expected Python format.
- Ensured proper alignment of the `on_connect` function code block.
2024-10-20 18:35:15 +11:00
marcus 3b7cc953d6 Fix MQTT connection loop and enhance dayglo color detection
- Wrapped on_connect with a try-except block to prevent connection loop.
- Updated color thresholds for dayglo green and yellow to improve detection accuracy.
- Adjusted pixel calculation to focus on the cropped image area for better analysis.
2024-10-20 18:33:24 +11:00
marcus 9297c3cf12 Enhance dayglo color detection and resolve MQTT client deprecation warning
- Added broader color ranges for dayglo green and dayglo yellow to improve detection accuracy.
- Updated MQTT client to use a unique client ID to avoid deprecated callback usage.
2024-10-20 18:28:49 +11:00
marcus cbec68ccd8 Update MQTT client to use MQTTv5 and fix callback arguments
- Updated MQTT client to use MQTTv5 to eliminate deprecated usage.
- Corrected on_connect function signature and replaced deprecated `rc` with `reasonCode` for compatibility.
2024-10-20 18:17:46 +11:00
marcus 41248a2f2b Fix MQTT client configuration and callback to resolve breaking issues
- Reverted MQTT client to MQTTv311 to avoid compatibility issues.
- Updated on_connect method to match expected arguments for MQTTv5.
- Fixed deprecation and runtime errors for proper operation.
2024-10-20 18:15:08 +11:00
marcus 1b6c07376a Fix MQTT client configuration and add image analysis improvements
- Updated MQTT client to use MQTTv5 without deprecated `clean_session` to resolve ValueError.
- Fine-tuned color thresholds for better dayglo detection accuracy.
- Added cropping to focus analysis on the central area of the image for improved rating calculation.
- Provided command-line option for analyzing specific images, enabling debugging and fine-tuning.
2024-10-20 18:12:12 +11:00
marcus 994e814823 Fix deprecated MQTT client usage and enhance dayglo detection
- Updated MQTT client to use MQTTv5 to resolve deprecation warning.
- Fine-tuned color thresholds for dayglo detection.
- Added cropping to focus on the center 80% of the image for more accurate analysis.
- Improved functionality to process an image provided via command line before continuing with MQTT message handling.
2024-10-20 18:09:59 +11:00
marcus 53807d79c1 Add command-line image processing option and fix deprecated MQTT client usage
- Removed deprecated MQTTv311 protocol usage.
- Added functionality to process an image provided via command line.
- Retained MQTT handling for normal message flow.
2024-10-20 18:01:31 +11:00
marcus df5e959ff4 Add mechanism to request a fresh snapshot upon connecting
- Added a function to request a fresh snapshot from Frigate or similar system upon connecting.
- Removed client disconnection to allow continued listening for snapshot messages.
2024-10-20 17:55:05 +11:00
marcus 9e84d2aa75 Retrieve retained MQTT snapshot and disconnect after receiving
- Modified the script to disconnect after receiving the retained snapshot message.
- Simplified MQTT loop handling to ensure reliable retrieval of retained messages.
2024-10-20 17:52:41 +11:00
5 changed files with 77 additions and 301 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Install OpenCV # Install OpenCV
RUN pip install --no-cache-dir paho-mqtt opencv-python-headless numpy requests RUN pip install --no-cache-dir gmqtt opencv-python-headless numpy requests
# Copy the dayglo detector script # Copy the dayglo detector script
COPY dayglo_detector.py test_mqtt.py /app/ COPY dayglo_detector.py test_mqtt.py /app/
+67 -292
View File
@@ -1,11 +1,13 @@
import os import os
import time import time
import paho.mqtt.client as mqtt
import numpy as np import numpy as np
import cv2 import cv2
import base64 import base64
import json import json
import tempfile import tempfile
import sys
import asyncio
from gmqtt import Client as MQTTClient
# Configuration # Configuration
MQTT_BROKER = os.environ.get('MQTT_BROKER', '10.59.221.172') MQTT_BROKER = os.environ.get('MQTT_BROKER', '10.59.221.172')
@@ -20,24 +22,43 @@ DISCOVERY_PREFIX = "homeassistant"
last_rating = 0 last_rating = 0
# Default color thresholds for dayglo detection # Default color thresholds for dayglo detection
LOWER_COLOR = np.array([20, 100, 100]) # Expanded color thresholds for dayglo detection
UPPER_COLOR = np.array([40, 255, 255]) LOWER_COLOR_GREEN = np.array([35, 50, 50])
UPPER_COLOR_GREEN = np.array([100, 255, 255])
LOWER_COLOR_YELLOW = np.array([15, 80, 80])
UPPER_COLOR_YELLOW = np.array([40, 255, 255])
# Track if the initial snapshot has been processed # Track if the initial snapshot has been processed
initial_snapshot_processed = False initial_snapshot_processed = False
connected_once = False
def on_connect(client, userdata, flags, rc): class DaygloDetectorMQTTClient(MQTTClient):
if rc == 0: async def handle_on_connect(self, client, flags, rc, properties):
asyncio.create_task(self.handle_on_connect(client, flags, rc, properties))
global connected_once
if rc == 0 and not connected_once:
print("Connected successfully to MQTT broker") print("Connected successfully to MQTT broker")
client.subscribe(MQTT_SNAPSHOT_TOPIC, qos=1) await client.subscribe(MQTT_SNAPSHOT_TOPIC, qos=1)
print(f"Subscribed to topic: {MQTT_SNAPSHOT_TOPIC}") print(f"Subscribed to topic: {MQTT_SNAPSHOT_TOPIC}")
publish_discovery_configurations() connected_once = True
await publish_discovery_configurations(client)
# Publish initial rating of 0 # Publish initial rating of 0
publish_rating(0) await publish_rating(client, 0)
else: else:
print(f"Failed to connect, return code {rc}") print(f"Failed to connect, return code {rc}")
def publish_discovery_configurations(): async def handle_on_message(self, client, topic, payload, qos, properties):
asyncio.create_task(self.handle_on_message(client, topic, payload, qos, properties))
if topic == MQTT_SNAPSHOT_TOPIC:
print("Snapshot received")
if len(payload) == 0:
print("Received an empty payload, skipping processing.")
else:
print(f"Payload length: {len(payload)} bytes")
print(f"Payload (first 100 bytes): {payload[:100]}...")
await process_snapshot(self, payload)
async def publish_discovery_configurations(client):
rating_config = { rating_config = {
"name": "Dayglo Rating", "name": "Dayglo Rating",
"state_topic": MQTT_TOPIC_PUBLISH, "state_topic": MQTT_TOPIC_PUBLISH,
@@ -46,26 +67,14 @@ def publish_discovery_configurations():
"icon": "mdi:brush", "icon": "mdi:brush",
"unique_id": "mqtt_dayglo_rating" "unique_id": "mqtt_dayglo_rating"
} }
client.publish(f"{DISCOVERY_PREFIX}/sensor/dayglo_rating/config", json.dumps(rating_config), retain=True) await client.publish(f"{DISCOVERY_PREFIX}/sensor/dayglo_rating/config", json.dumps(rating_config), retain=True)
def publish_rating(rating): async def publish_rating(client, rating):
global last_rating global last_rating
last_rating = rating last_rating = rating
client.publish(MQTT_TOPIC_PUBLISH, json.dumps({"rating": rating})) await client.publish(MQTT_TOPIC_PUBLISH, json.dumps({"rating": rating}))
def on_message(client, userdata, msg): async def process_snapshot(client, payload):
global initial_snapshot_processed
if msg.topic == MQTT_SNAPSHOT_TOPIC:
print("Snapshot received")
if len(msg.payload) == 0:
print("Received an empty payload, skipping processing.")
else:
print(f"Payload length: {len(msg.payload)} bytes")
print(f"Payload (first 100 bytes): {msg.payload[:100]}...")
process_snapshot(msg.payload)
initial_snapshot_processed = True
def process_snapshot(payload):
if not payload: if not payload:
print("Empty payload received, skipping processing.") print("Empty payload received, skipping processing.")
return return
@@ -83,7 +92,7 @@ def process_snapshot(payload):
if image is not None: if image is not None:
rating = calculate_dayglo_rating(image) rating = calculate_dayglo_rating(image)
print("Dayglo Rating calculated:", rating) print("Dayglo Rating calculated:", rating)
publish_rating(rating) await publish_rating(client, rating)
else: else:
print("Invalid image format or corrupted image received") print("Invalid image format or corrupted image received")
except Exception as e: except Exception as e:
@@ -91,281 +100,47 @@ def process_snapshot(payload):
def calculate_dayglo_rating(image): def calculate_dayglo_rating(image):
print("Calculating dayglo rating...") print("Calculating dayglo rating...")
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # Crop the image to focus on the center area
mask = cv2.inRange(hsv_image, LOWER_COLOR, UPPER_COLOR) height, width = image.shape[:2]
crop_margin = 0.1 # 10% margin
cropped_image = image[int(height * crop_margin):int(height * (1 - crop_margin)),
int(width * crop_margin):int(width * (1 - crop_margin))]
hsv_image = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2HSV)
mask_green = cv2.inRange(hsv_image, LOWER_COLOR_GREEN, UPPER_COLOR_GREEN)
mask_yellow = cv2.inRange(hsv_image, LOWER_COLOR_YELLOW, UPPER_COLOR_YELLOW)
mask = cv2.addWeighted(mask_green, 1.0, mask_yellow, 1.0, 0)
dayglo_pixels = cv2.countNonZero(mask) dayglo_pixels = cv2.countNonZero(mask)
total_pixels = image.shape[0] * image.shape[1] total_pixels = cropped_image.shape[0] * cropped_image.shape[1]
rating = (dayglo_pixels / total_pixels) * 100 rating = (dayglo_pixels / total_pixels) * 100
return rating return rating
def connect_mqtt(): async def main():
while True: print("Starting Dayglo Detector...")
try: # Handle command line argument for image file
client.connect(MQTT_BROKER, MQTT_PORT, 60) if len(sys.argv) > 1:
break image_file = sys.argv[1]
except Exception as e: if os.path.exists(image_file):
print(f"Connection failed: {e}. Retrying in 5 seconds...") client = DaygloDetectorMQTTClient("dayglo_detector")
time.sleep(5) client.set_auth_credentials(MQTT_USERNAME, MQTT_PASSWORD)
await client.connect(MQTT_BROKER, MQTT_PORT, keepalive=60)
client = mqtt.Client(protocol=mqtt.MQTTv311) print(f"Processing image from file: {image_file}")
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD) image = cv2.imread(image_file)
client.on_connect = on_connect
client.on_message = on_message
client.enable_logger()
connect_mqtt()
client.loop_start()
# Keep the script running
while True:
time.sleep(1)
import os
import time
import paho.mqtt.client as mqtt
import numpy as np
import cv2
import base64
import json
import tempfile
# Configuration
MQTT_BROKER = os.environ.get('MQTT_BROKER', '10.59.221.172')
MQTT_PORT = int(os.environ.get('MQTT_PORT', '1883'))
MQTT_USERNAME = os.getenv('MQTT_USERNAME', 'your_username')
MQTT_PASSWORD = os.getenv('MQTT_PASSWORD', 'your_password')
MQTT_SNAPSHOT_TOPIC = "/frigate/patiocam/person/snapshot"
MQTT_TOPIC_PUBLISH = "homeassistant/sensor/dayglo_rating/state"
DISCOVERY_PREFIX = "homeassistant"
# Default rating
last_rating = 0
# Default color thresholds for dayglo detection
LOWER_COLOR = np.array([20, 100, 100])
UPPER_COLOR = np.array([40, 255, 255])
# Track if the initial snapshot has been processed
initial_snapshot_processed = False
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected successfully to MQTT broker")
client.subscribe(MQTT_SNAPSHOT_TOPIC, qos=1)
print(f"Subscribed to topic: {MQTT_SNAPSHOT_TOPIC}")
publish_discovery_configurations()
# Publish initial rating of 0
publish_rating(0)
# Attempt to request the retained snapshot message
client.publish(MQTT_SNAPSHOT_TOPIC, "", qos=1)
else:
print(f"Failed to connect, return code {rc}")
def publish_discovery_configurations():
rating_config = {
"name": "Dayglo Rating",
"state_topic": MQTT_TOPIC_PUBLISH,
"unit_of_measurement": "%",
"value_template": "{{ value_json.rating }}",
"icon": "mdi:brush",
"unique_id": "mqtt_dayglo_rating"
}
client.publish(f"{DISCOVERY_PREFIX}/sensor/dayglo_rating/config", json.dumps(rating_config), retain=True)
def publish_rating(rating):
global last_rating
last_rating = rating
client.publish(MQTT_TOPIC_PUBLISH, json.dumps({"rating": rating}))
def on_message(client, userdata, msg):
global initial_snapshot_processed
if msg.topic == MQTT_SNAPSHOT_TOPIC:
print("Snapshot received")
if len(msg.payload) == 0:
print("Received an empty payload, skipping processing.")
else:
print(f"Payload length: {len(msg.payload)} bytes")
print(f"Payload (first 100 bytes): {msg.payload[:100]}...")
process_snapshot(msg.payload)
initial_snapshot_processed = True
def process_snapshot(payload):
if not payload:
print("Empty payload received, skipping processing.")
return
print("Processing snapshot...")
try:
image_data = base64.b64decode(payload)
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as temp_image_file:
temp_image_file.write(image_data)
temp_image_path = temp_image_file.name
# Attempt to read the saved image with OpenCV
image = cv2.imread(temp_image_path)
if image is not None: if image is not None:
rating = calculate_dayglo_rating(image) rating = calculate_dayglo_rating(image)
print("Dayglo Rating calculated:", rating) print("Dayglo Rating calculated from file:", rating)
publish_rating(rating) await publish_rating(client, rating)
else: else:
print("Invalid image format or corrupted image received") print("Invalid image file provided.")
except Exception as e:
print(f"Error processing snapshot: {e}")
def calculate_dayglo_rating(image):
print("Calculating dayglo rating...")
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_image, LOWER_COLOR, UPPER_COLOR)
dayglo_pixels = cv2.countNonZero(mask)
total_pixels = image.shape[0] * image.shape[1]
rating = (dayglo_pixels / total_pixels) * 100
return rating
def connect_mqtt():
while True:
try:
client.connect(MQTT_BROKER, MQTT_PORT, 60)
break
except Exception as e:
print(f"Connection failed: {e}. Retrying in 5 seconds...")
time.sleep(5)
client = mqtt.Client(protocol=mqtt.MQTTv311)
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.on_connect = on_connect
client.on_message = on_message
client.enable_logger()
connect_mqtt()
client.loop_start()
# Keep the script running
while True:
time.sleep(1)
import os
import time
import paho.mqtt.client as mqtt
import numpy as np
import cv2
import base64
import json
import tempfile
# Configuration
MQTT_BROKER = os.environ.get('MQTT_BROKER', '10.59.221.172')
MQTT_PORT = int(os.environ.get('MQTT_PORT', '1883'))
MQTT_USERNAME = os.getenv('MQTT_USERNAME', 'your_username')
MQTT_PASSWORD = os.getenv('MQTT_PASSWORD', 'your_password')
MQTT_SNAPSHOT_TOPIC = "/frigate/patiocam/person/snapshot"
MQTT_TOPIC_PUBLISH = "homeassistant/sensor/dayglo_rating/state"
DISCOVERY_PREFIX = "homeassistant"
# Default rating
last_rating = 0
# Default color thresholds for dayglo detection
LOWER_COLOR = np.array([20, 100, 100])
UPPER_COLOR = np.array([40, 255, 255])
# Track if the initial snapshot has been processed
initial_snapshot_processed = False
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected successfully to MQTT broker")
client.subscribe(MQTT_SNAPSHOT_TOPIC, qos=1)
print(f"Subscribed to topic: {MQTT_SNAPSHOT_TOPIC}")
publish_discovery_configurations()
# Publish initial rating of 0
publish_rating(0)
else: else:
print(f"Failed to connect, return code {rc}") print(f"File not found: {image_file}")
def publish_discovery_configurations(): # Set up MQTT client for normal operation
rating_config = { client = DaygloDetectorMQTTClient("dayglo_detector")
"name": "Dayglo Rating", client.set_auth_credentials(MQTT_USERNAME, MQTT_PASSWORD)
"state_topic": MQTT_TOPIC_PUBLISH,
"unit_of_measurement": "%",
"value_template": "{{ value_json.rating }}",
"icon": "mdi:brush",
"unique_id": "mqtt_dayglo_rating"
}
client.publish(f"{DISCOVERY_PREFIX}/sensor/dayglo_rating/config", json.dumps(rating_config), retain=True)
def publish_rating(rating): await client.connect(MQTT_BROKER, MQTT_PORT, keepalive=60)
global last_rating await asyncio.get_event_loop().create_future()
last_rating = rating
client.publish(MQTT_TOPIC_PUBLISH, json.dumps({"rating": rating}))
def on_message(client, userdata, msg): if __name__ == "__main__":
global initial_snapshot_processed asyncio.run(main())
if msg.topic == MQTT_SNAPSHOT_TOPIC:
print("Snapshot received")
if len(msg.payload) == 0:
print("Received an empty payload, skipping processing.")
else:
print(f"Payload length: {len(msg.payload)} bytes")
print(f"Payload (first 100 bytes): {msg.payload[:100]}...")
process_snapshot(msg.payload)
initial_snapshot_processed = True
def process_snapshot(payload):
if not payload:
print("Empty payload received, skipping processing.")
return
print("Processing snapshot...")
try:
image_data = base64.b64decode(payload)
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as temp_image_file:
temp_image_file.write(image_data)
temp_image_path = temp_image_file.name
# Attempt to read the saved image with OpenCV
image = cv2.imread(temp_image_path)
if image is not None:
rating = calculate_dayglo_rating(image)
print("Dayglo Rating calculated:", rating)
publish_rating(rating)
else:
print("Invalid image format or corrupted image received")
except Exception as e:
print(f"Error processing snapshot: {e}")
def calculate_dayglo_rating(image):
print("Calculating dayglo rating...")
hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_image, LOWER_COLOR, UPPER_COLOR)
dayglo_pixels = cv2.countNonZero(mask)
total_pixels = image.shape[0] * image.shape[1]
rating = (dayglo_pixels / total_pixels) * 100
return rating
def connect_mqtt():
while True:
try:
client.connect(MQTT_BROKER, MQTT_PORT, 60)
break
except Exception as e:
print(f"Connection failed: {e}. Retrying in 5 seconds...")
time.sleep(5)
client = mqtt.Client(protocol=mqtt.MQTTv311)
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.on_connect = on_connect
client.on_message = on_message
client.enable_logger()
connect_mqtt()
client.loop_start()
# Allow some time for the retained message to be received
time.sleep(5)
# Keep the script running
while True:
time.sleep(1)
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

+1
View File
@@ -66,6 +66,7 @@ services:
restart: always restart: always
volumes: volumes:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /home/docker/compose/frigate/debug-image/:/tmp/debug-image/
environment: environment:
MQTT_BROKER: '10.59.221.172' MQTT_BROKER: '10.59.221.172'
MQTT_PORT: '1883' MQTT_PORT: '1883'