pumaguard 21.post12__py3-none-any.whl → 21.post15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pumaguard/camera_heartbeat.py +26 -0
- pumaguard/pumaguard-ui/main.dart.js +47091 -46599
- pumaguard/server.py +5 -0
- pumaguard/web_routes/dhcp.py +137 -2
- pumaguard/web_ui.py +8 -2
- {pumaguard-21.post12.dist-info → pumaguard-21.post15.dist-info}/METADATA +1 -1
- {pumaguard-21.post12.dist-info → pumaguard-21.post15.dist-info}/RECORD +11 -11
- {pumaguard-21.post12.dist-info → pumaguard-21.post15.dist-info}/WHEEL +0 -0
- {pumaguard-21.post12.dist-info → pumaguard-21.post15.dist-info}/entry_points.txt +0 -0
- {pumaguard-21.post12.dist-info → pumaguard-21.post15.dist-info}/licenses/LICENSE +0 -0
- {pumaguard-21.post12.dist-info → pumaguard-21.post15.dist-info}/top_level.txt +0 -0
pumaguard/camera_heartbeat.py
CHANGED
|
@@ -12,6 +12,9 @@ import logging
|
|
|
12
12
|
import socket
|
|
13
13
|
import subprocess
|
|
14
14
|
import threading
|
|
15
|
+
from collections.abc import (
|
|
16
|
+
Callable,
|
|
17
|
+
)
|
|
15
18
|
from datetime import (
|
|
16
19
|
datetime,
|
|
17
20
|
timezone,
|
|
@@ -48,6 +51,7 @@ class CameraHeartbeat:
|
|
|
48
51
|
tcp_port: int = 80,
|
|
49
52
|
tcp_timeout: int = 3,
|
|
50
53
|
icmp_timeout: int = 2,
|
|
54
|
+
status_change_callback: Callable[[str, dict], None] | None = None,
|
|
51
55
|
):
|
|
52
56
|
"""
|
|
53
57
|
Initialize the camera heartbeat monitor.
|
|
@@ -61,6 +65,9 @@ class CameraHeartbeat:
|
|
|
61
65
|
tcp_port: TCP port to check (default: 80 for HTTP)
|
|
62
66
|
tcp_timeout: TCP connection timeout in seconds (default: 3)
|
|
63
67
|
icmp_timeout: ICMP ping timeout in seconds (default: 2)
|
|
68
|
+
status_change_callback: Optional callback function to be called
|
|
69
|
+
when camera status changes. Signature:
|
|
70
|
+
callback(event_type: str, camera_data: dict)
|
|
64
71
|
"""
|
|
65
72
|
self.webui = webui
|
|
66
73
|
self.interval = interval
|
|
@@ -69,6 +76,7 @@ class CameraHeartbeat:
|
|
|
69
76
|
self.tcp_port = tcp_port
|
|
70
77
|
self.tcp_timeout = tcp_timeout
|
|
71
78
|
self.icmp_timeout = icmp_timeout
|
|
79
|
+
self.status_change_callback = status_change_callback
|
|
72
80
|
|
|
73
81
|
self._running = False
|
|
74
82
|
self._thread: threading.Thread | None = None
|
|
@@ -171,6 +179,8 @@ class CameraHeartbeat:
|
|
|
171
179
|
camera = self.webui.cameras[mac_address]
|
|
172
180
|
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
173
181
|
|
|
182
|
+
status_changed = False
|
|
183
|
+
|
|
174
184
|
if is_reachable:
|
|
175
185
|
# Camera is reachable - update status to connected
|
|
176
186
|
if camera["status"] != "connected":
|
|
@@ -179,6 +189,7 @@ class CameraHeartbeat:
|
|
|
179
189
|
camera["hostname"],
|
|
180
190
|
camera["ip_address"],
|
|
181
191
|
)
|
|
192
|
+
status_changed = True
|
|
182
193
|
camera["status"] = "connected"
|
|
183
194
|
camera["last_seen"] = timestamp
|
|
184
195
|
else:
|
|
@@ -189,12 +200,27 @@ class CameraHeartbeat:
|
|
|
189
200
|
camera["hostname"],
|
|
190
201
|
camera["ip_address"],
|
|
191
202
|
)
|
|
203
|
+
status_changed = True
|
|
192
204
|
camera["status"] = "disconnected"
|
|
193
205
|
# Don't update last_seen on failure - keep the last successful time
|
|
194
206
|
|
|
195
207
|
# Persist changes to settings
|
|
196
208
|
self._save_camera_list()
|
|
197
209
|
|
|
210
|
+
# Notify callback if status changed
|
|
211
|
+
if status_changed and self.status_change_callback:
|
|
212
|
+
try:
|
|
213
|
+
event_type = (
|
|
214
|
+
"camera_status_changed_online"
|
|
215
|
+
if is_reachable
|
|
216
|
+
else "camera_status_changed_offline"
|
|
217
|
+
)
|
|
218
|
+
self.status_change_callback(event_type, dict(camera))
|
|
219
|
+
except Exception as e: # pylint: disable=broad-except
|
|
220
|
+
logger.error(
|
|
221
|
+
"Error calling status change callback: %s", str(e)
|
|
222
|
+
)
|
|
223
|
+
|
|
198
224
|
def _save_camera_list(self) -> None:
|
|
199
225
|
"""Save the camera list to settings file."""
|
|
200
226
|
try:
|