pumaguard 21__py3-none-any.whl → 21.post4__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/presets.py +2 -0
- pumaguard/pumaguard-ui/main.dart.js +40686 -40493
- pumaguard/sound.py +3 -1
- pumaguard/web_routes/dhcp.py +161 -0
- pumaguard/web_routes/settings.py +15 -1
- pumaguard/web_ui.py +12 -0
- {pumaguard-21.dist-info → pumaguard-21.post4.dist-info}/METADATA +1 -1
- {pumaguard-21.dist-info → pumaguard-21.post4.dist-info}/RECORD +12 -12
- {pumaguard-21.dist-info → pumaguard-21.post4.dist-info}/WHEEL +0 -0
- {pumaguard-21.dist-info → pumaguard-21.post4.dist-info}/entry_points.txt +0 -0
- {pumaguard-21.dist-info → pumaguard-21.post4.dist-info}/licenses/LICENSE +0 -0
- {pumaguard-21.dist-info → pumaguard-21.post4.dist-info}/top_level.txt +0 -0
pumaguard/sound.py
CHANGED
pumaguard/web_routes/dhcp.py
CHANGED
|
@@ -5,6 +5,10 @@ from __future__ import (
|
|
|
5
5
|
)
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
+
from datetime import (
|
|
9
|
+
datetime,
|
|
10
|
+
timezone,
|
|
11
|
+
)
|
|
8
12
|
from typing import (
|
|
9
13
|
TYPE_CHECKING,
|
|
10
14
|
)
|
|
@@ -80,6 +84,32 @@ def register_dhcp_routes(app: "Flask", webui: "WebUI") -> None:
|
|
|
80
84
|
"last_seen": timestamp,
|
|
81
85
|
"status": "connected",
|
|
82
86
|
}
|
|
87
|
+
|
|
88
|
+
# Update settings with camera list
|
|
89
|
+
# Convert cameras dict to list for settings persistence
|
|
90
|
+
camera_list = []
|
|
91
|
+
for _, cam_info in webui.cameras.items():
|
|
92
|
+
camera_list.append(
|
|
93
|
+
{
|
|
94
|
+
"hostname": cam_info["hostname"],
|
|
95
|
+
"ip_address": cam_info["ip_address"],
|
|
96
|
+
"mac_address": cam_info["mac_address"],
|
|
97
|
+
"last_seen": cam_info["last_seen"],
|
|
98
|
+
"status": cam_info["status"],
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
webui.presets.cameras = camera_list
|
|
103
|
+
|
|
104
|
+
# Persist to settings file
|
|
105
|
+
try:
|
|
106
|
+
webui.presets.save()
|
|
107
|
+
logger.info("Camera list saved to settings")
|
|
108
|
+
except Exception as e: # pylint: disable=broad-except
|
|
109
|
+
logger.error(
|
|
110
|
+
"Failed to save camera list to settings: %s", str(e)
|
|
111
|
+
)
|
|
112
|
+
|
|
83
113
|
elif action == "del":
|
|
84
114
|
# Camera disconnected
|
|
85
115
|
logger.info("Camera '%s' disconnected", hostname)
|
|
@@ -88,6 +118,31 @@ def register_dhcp_routes(app: "Flask", webui: "WebUI") -> None:
|
|
|
88
118
|
webui.cameras[mac_address]["status"] = "disconnected"
|
|
89
119
|
webui.cameras[mac_address]["last_seen"] = timestamp
|
|
90
120
|
|
|
121
|
+
# Update settings with updated camera list
|
|
122
|
+
camera_list = []
|
|
123
|
+
for _, cam_info in webui.cameras.items():
|
|
124
|
+
camera_list.append(
|
|
125
|
+
{
|
|
126
|
+
"hostname": cam_info["hostname"],
|
|
127
|
+
"ip_address": cam_info["ip_address"],
|
|
128
|
+
"mac_address": cam_info["mac_address"],
|
|
129
|
+
"last_seen": cam_info["last_seen"],
|
|
130
|
+
"status": cam_info["status"],
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
webui.presets.cameras = camera_list
|
|
135
|
+
|
|
136
|
+
# Persist to settings file
|
|
137
|
+
try:
|
|
138
|
+
webui.presets.save()
|
|
139
|
+
logger.info("Camera list updated in settings")
|
|
140
|
+
except Exception as e: # pylint: disable=broad-except
|
|
141
|
+
logger.error(
|
|
142
|
+
"Failed to save camera list to settings: %s",
|
|
143
|
+
str(e),
|
|
144
|
+
)
|
|
145
|
+
|
|
91
146
|
return (
|
|
92
147
|
jsonify(
|
|
93
148
|
{
|
|
@@ -156,6 +211,104 @@ def register_dhcp_routes(app: "Flask", webui: "WebUI") -> None:
|
|
|
156
211
|
404,
|
|
157
212
|
)
|
|
158
213
|
|
|
214
|
+
@app.route("/api/dhcp/cameras", methods=["POST"])
|
|
215
|
+
def add_camera():
|
|
216
|
+
"""
|
|
217
|
+
Manually add a camera (for testing purposes).
|
|
218
|
+
|
|
219
|
+
Expected JSON payload:
|
|
220
|
+
{
|
|
221
|
+
"hostname": "camera-name",
|
|
222
|
+
"ip_address": "192.168.52.100",
|
|
223
|
+
"mac_address": "aa:bb:cc:dd:ee:ff",
|
|
224
|
+
"status": "connected" // optional, defaults to "connected"
|
|
225
|
+
}
|
|
226
|
+
"""
|
|
227
|
+
try:
|
|
228
|
+
data = request.get_json()
|
|
229
|
+
|
|
230
|
+
if not data:
|
|
231
|
+
return jsonify({"error": "No JSON data provided"}), 400
|
|
232
|
+
|
|
233
|
+
hostname = data.get("hostname")
|
|
234
|
+
ip_address = data.get("ip_address")
|
|
235
|
+
mac_address = data.get("mac_address")
|
|
236
|
+
status = data.get("status", "connected")
|
|
237
|
+
|
|
238
|
+
# Validate required fields
|
|
239
|
+
if not hostname or not ip_address or not mac_address:
|
|
240
|
+
return (
|
|
241
|
+
jsonify(
|
|
242
|
+
{
|
|
243
|
+
"error": "Missing required fields: hostname, "
|
|
244
|
+
"ip_address, mac_address"
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
400,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
# Generate timestamp
|
|
251
|
+
timestamp = datetime.now(timezone.utc).strftime(
|
|
252
|
+
"%Y-%m-%dT%H:%M:%SZ"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Add camera to webui.cameras
|
|
256
|
+
webui.cameras[mac_address] = {
|
|
257
|
+
"hostname": hostname,
|
|
258
|
+
"ip_address": ip_address,
|
|
259
|
+
"mac_address": mac_address,
|
|
260
|
+
"last_seen": timestamp,
|
|
261
|
+
"status": status,
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# Update settings with camera list
|
|
265
|
+
camera_list = []
|
|
266
|
+
for _, cam_info in webui.cameras.items():
|
|
267
|
+
camera_list.append(
|
|
268
|
+
{
|
|
269
|
+
"hostname": cam_info["hostname"],
|
|
270
|
+
"ip_address": cam_info["ip_address"],
|
|
271
|
+
"mac_address": cam_info["mac_address"],
|
|
272
|
+
"last_seen": cam_info["last_seen"],
|
|
273
|
+
"status": cam_info["status"],
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
webui.presets.cameras = camera_list
|
|
278
|
+
|
|
279
|
+
# Persist to settings file
|
|
280
|
+
try:
|
|
281
|
+
webui.presets.save()
|
|
282
|
+
logger.info(
|
|
283
|
+
"Manually added camera '%s' at %s", hostname, ip_address
|
|
284
|
+
)
|
|
285
|
+
except Exception as e: # pylint: disable=broad-except
|
|
286
|
+
logger.error(
|
|
287
|
+
"Failed to save camera list to settings: %s", str(e)
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
jsonify(
|
|
292
|
+
{
|
|
293
|
+
"status": "success",
|
|
294
|
+
"message": "Camera added successfully",
|
|
295
|
+
"camera": webui.cameras[mac_address],
|
|
296
|
+
}
|
|
297
|
+
),
|
|
298
|
+
201,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
except Exception as e: # pylint: disable=broad-except
|
|
302
|
+
logger.error("Error adding camera: %s", str(e))
|
|
303
|
+
return (
|
|
304
|
+
jsonify(
|
|
305
|
+
{
|
|
306
|
+
"error": "Failed to add camera",
|
|
307
|
+
}
|
|
308
|
+
),
|
|
309
|
+
500,
|
|
310
|
+
)
|
|
311
|
+
|
|
159
312
|
@app.route("/api/dhcp/cameras", methods=["DELETE"])
|
|
160
313
|
def clear_cameras():
|
|
161
314
|
"""
|
|
@@ -167,6 +320,14 @@ def register_dhcp_routes(app: "Flask", webui: "WebUI") -> None:
|
|
|
167
320
|
webui.cameras.clear()
|
|
168
321
|
logger.info("Cleared %d camera records", count)
|
|
169
322
|
|
|
323
|
+
# Update settings
|
|
324
|
+
webui.presets.cameras = []
|
|
325
|
+
try:
|
|
326
|
+
webui.presets.save()
|
|
327
|
+
logger.info("Camera list cleared from settings")
|
|
328
|
+
except Exception as e: # pylint: disable=broad-except
|
|
329
|
+
logger.error("Failed to save camera list to settings: %s", str(e))
|
|
330
|
+
|
|
170
331
|
return (
|
|
171
332
|
jsonify(
|
|
172
333
|
{
|
pumaguard/web_routes/settings.py
CHANGED
|
@@ -48,7 +48,21 @@ def register_settings_routes(app: "Flask", webui: "WebUI") -> None:
|
|
|
48
48
|
|
|
49
49
|
@app.route("/api/settings", methods=["GET"])
|
|
50
50
|
def get_settings():
|
|
51
|
-
|
|
51
|
+
settings_dict = dict(webui.presets)
|
|
52
|
+
# Add cameras from webui.cameras (runtime state)
|
|
53
|
+
camera_list = []
|
|
54
|
+
for _, cam_info in webui.cameras.items():
|
|
55
|
+
camera_list.append(
|
|
56
|
+
{
|
|
57
|
+
"hostname": cam_info["hostname"],
|
|
58
|
+
"ip_address": cam_info["ip_address"],
|
|
59
|
+
"mac_address": cam_info["mac_address"],
|
|
60
|
+
"last_seen": cam_info["last_seen"],
|
|
61
|
+
"status": cam_info["status"],
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
settings_dict["cameras"] = camera_list
|
|
65
|
+
return jsonify(settings_dict)
|
|
52
66
|
|
|
53
67
|
@app.route("/api/settings", methods=["PUT"])
|
|
54
68
|
def update_settings():
|
pumaguard/web_ui.py
CHANGED
|
@@ -161,6 +161,18 @@ class WebUI:
|
|
|
161
161
|
# Format: {mac_address: CameraInfo}
|
|
162
162
|
self.cameras: dict[str, CameraInfo] = {}
|
|
163
163
|
|
|
164
|
+
# Load cameras from persisted settings
|
|
165
|
+
for camera in presets.cameras:
|
|
166
|
+
mac = camera.get("mac_address")
|
|
167
|
+
if mac:
|
|
168
|
+
self.cameras[mac] = CameraInfo(
|
|
169
|
+
hostname=camera.get("hostname", ""),
|
|
170
|
+
ip_address=camera.get("ip_address", ""),
|
|
171
|
+
mac_address=mac,
|
|
172
|
+
last_seen=camera.get("last_seen", ""),
|
|
173
|
+
status=camera.get("status", "disconnected"),
|
|
174
|
+
)
|
|
175
|
+
|
|
164
176
|
# mDNS/Zeroconf support
|
|
165
177
|
self.zeroconf: Zeroconf | None = None
|
|
166
178
|
self.service_info: ServiceInfo | None = None
|
|
@@ -5,13 +5,13 @@ pumaguard/main.py,sha256=1Wazv1wjwb46yNlqgWt88HQwKSxGmY24X5OsUv8gYyE,7029
|
|
|
5
5
|
pumaguard/model-registry.yaml,sha256=V-pTaqJrk_jJo568okBDaVhs51qTHttSqKe6PqdX6Bc,10318
|
|
6
6
|
pumaguard/model_cli.py,sha256=nzDv0lXSvRKpLxs579tiHInJPPV-AFO4jzeLk5t2GaA,1394
|
|
7
7
|
pumaguard/model_downloader.py,sha256=zJQgCMOF2AfhB30VsfOMYtgRxcxVxkZBAdtG8KznPyY,12895
|
|
8
|
-
pumaguard/presets.py,sha256=
|
|
8
|
+
pumaguard/presets.py,sha256=CUTOfrk2d1yprDox7h_S_HUiQUq8cVHJPz6Ua9LsFCM,27884
|
|
9
9
|
pumaguard/server.py,sha256=zmzSXabt6K26u8kwBPdm1gI6aMAwJo3gCaSaX5Sh0vk,14705
|
|
10
|
-
pumaguard/sound.py,sha256
|
|
10
|
+
pumaguard/sound.py,sha256=-ceyO9xjfuVSal-CvaM_o2l45gYWUUV3bJN-Eni2XQQ,4732
|
|
11
11
|
pumaguard/stats.py,sha256=ZwocfnFCQ-ky7me-YTTrEoJqsIHOWAgSzeoJHItsIU4,927
|
|
12
12
|
pumaguard/utils.py,sha256=w1EgOLSZGyjq_b49hvVZhBESy-lVP0yRtNHe-sXBoIU,19735
|
|
13
13
|
pumaguard/verify.py,sha256=vfw3PRzDt1uuH5FKV9F5vb1PH7KQ6AEgVNhJ6jck_hQ,5513
|
|
14
|
-
pumaguard/web_ui.py,sha256=
|
|
14
|
+
pumaguard/web_ui.py,sha256=2NtiW35rlLXhWXPAIShsK-pH8HUvog6rDQykeTD8Dy0,16636
|
|
15
15
|
pumaguard/completions/pumaguard-classify-completions.sh,sha256=5QySg-2Jdinj15qpUYa5UzHbTgYzi2gmPVYYyyXny4c,1353
|
|
16
16
|
pumaguard/completions/pumaguard-completions.sh,sha256=bRx3Q3_gM__3w0PyfQSCVdxylhhr3QlzaLCav24dfNc,1196
|
|
17
17
|
pumaguard/completions/pumaguard-server-completions.sh,sha256=33c6GjbTImBOHn0SSNUOJoxqJ2mMHuDv3P3GQJGGHhA,1161
|
|
@@ -22,7 +22,7 @@ pumaguard/pumaguard-ui/flutter.js,sha256=7V1ZIKmGiouT15CpquQWWmKWJyjUq77FoU9gDXP
|
|
|
22
22
|
pumaguard/pumaguard-ui/flutter_bootstrap.js,sha256=Nyt0e7m8U4hq4CmcHhK1ij4hNgUqANM1o4YieKUx4rA,9692
|
|
23
23
|
pumaguard/pumaguard-ui/flutter_service_worker.js,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
pumaguard/pumaguard-ui/index.html,sha256=901-ZY0WysVAZWPwj2xGatoezwm9TX9IV_jpMrlsaXg,1205
|
|
25
|
-
pumaguard/pumaguard-ui/main.dart.js,sha256=
|
|
25
|
+
pumaguard/pumaguard-ui/main.dart.js,sha256=Tz84jjODZPfwWO-wvAwzM1DUew3Kv1hjCzLnDZhzBeE,2733274
|
|
26
26
|
pumaguard/pumaguard-ui/manifest.json,sha256=Hhnw_eLUivdrOlL7O9KGBsGXCKKt3lix17Fh3GB0g-s,920
|
|
27
27
|
pumaguard/pumaguard-ui/version.json,sha256=uXZ6musTJUZaO0N2bEbr3cy9rpx2aesAS2YFMcu2WF8,94
|
|
28
28
|
pumaguard/pumaguard-ui/assets/AssetManifest.bin,sha256=Qzp1G9iPlHSW-PnHyszTxZO31_NjmTlvSBWY_REPH_8,562
|
|
@@ -58,14 +58,14 @@ pumaguard/pumaguard-ui/icons/Icon-maskable-192.png,sha256=0shC4iqfTsnZlrIzc6kFyI
|
|
|
58
58
|
pumaguard/pumaguard-ui/icons/Icon-maskable-512.png,sha256=au4Gzcq2sq73Sxc0xHePRCHS2hALD_nlKyG1UkAgKSk,20998
|
|
59
59
|
pumaguard/web_routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
60
|
pumaguard/web_routes/artifacts.py,sha256=IpnMLdbgAYkwU3TuYJE-JHGnC_x5_XNCrc-1M_n2YKk,3879
|
|
61
|
-
pumaguard/web_routes/dhcp.py,sha256=
|
|
61
|
+
pumaguard/web_routes/dhcp.py,sha256=hQfYLiDmJeDvGzPmx74LovzbhNN2ywPZfP7avXTJ-FA,10971
|
|
62
62
|
pumaguard/web_routes/diagnostics.py,sha256=EIIbjuixJyGXdnVQf8RQ6xQxJar0UHZO8dF-9zQLY9g,3294
|
|
63
63
|
pumaguard/web_routes/directories.py,sha256=yy5TghCEyB4reRGAcVHIEfr2vlHnuiDChIXl9ZFquRM,2410
|
|
64
64
|
pumaguard/web_routes/folders.py,sha256=Z63ap6dRi6NWye70HYurpCnsSXmFgzTbTsFKYdZ1Bjk,6305
|
|
65
65
|
pumaguard/web_routes/photos.py,sha256=Tac_CbaZSeZzOfaJ73vlp3iyZbvfD7ei1YM3tsb0nTY,5106
|
|
66
|
-
pumaguard/web_routes/settings.py,sha256=
|
|
66
|
+
pumaguard/web_routes/settings.py,sha256=Rvt1wWqWi0ZsrmylacrgbPEXOjmaGIsLcMwVGVov5e0,12232
|
|
67
67
|
pumaguard/web_routes/sync.py,sha256=Zvv6VARGE5xP29C5gWH3ul81PISRxoF8n472DITItE0,6378
|
|
68
|
-
pumaguard-21.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
68
|
+
pumaguard-21.post4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
69
69
|
pumaguard-sounds/cougar_call.mp3,sha256=jdPzi7Qneect3ez2G6XAeHWtetU5vSOSB6pceuB26Wc,129048
|
|
70
70
|
pumaguard-sounds/cougarsounds.wav,sha256=hwVmmQ75dkOP3qd07YAvVOSm1neYtxLSzxw3Ulvs2cM,96346
|
|
71
71
|
pumaguard-sounds/dark-engine-logo-141942.mp3,sha256=Vw-qyLTMPJZvsgQcZtH0DpGcP1dd7nJq-9BnHuNPGug,372819
|
|
@@ -83,8 +83,8 @@ pumaguard-sounds/mixkit-vintage-telephone-ringtone-1356.wav,sha256=zWWY2uFF0-l7P
|
|
|
83
83
|
pumaguard-sounds/pumaguard-warning.mp3,sha256=wcCfHsulPo5P5s8MjpQAG2NYHQDsRpjqoMig1-o_MDI,232249
|
|
84
84
|
pumaguard-sounds/short-round-110940.mp3,sha256=vdskGD94SeH1UJyJyR0Ek_7xGXPIZfnPdoBvxGnUt98,450816
|
|
85
85
|
pumaguard-ui/ios/Flutter/ephemeral/flutter_lldb_helper.py,sha256=Bc_jl3_e5ZPvrSBJpPYtN05VxpztyKq-7lVms3rLg4Q,1276
|
|
86
|
-
pumaguard-21.dist-info/METADATA,sha256=
|
|
87
|
-
pumaguard-21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
88
|
-
pumaguard-21.dist-info/entry_points.txt,sha256=rmCdBTPWrbJQvPPwABSVobXE9D7hrKsITGZ6nvCrko8,127
|
|
89
|
-
pumaguard-21.dist-info/top_level.txt,sha256=B-PzS4agkQNhOYbLLIrMVOyMD_pl5F-yujPBm5zYYjY,40
|
|
90
|
-
pumaguard-21.dist-info/RECORD,,
|
|
86
|
+
pumaguard-21.post4.dist-info/METADATA,sha256=q1BEufOhEsWa4cm7W1ufv3CSDO69IMujgirdajdIdA8,8616
|
|
87
|
+
pumaguard-21.post4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
88
|
+
pumaguard-21.post4.dist-info/entry_points.txt,sha256=rmCdBTPWrbJQvPPwABSVobXE9D7hrKsITGZ6nvCrko8,127
|
|
89
|
+
pumaguard-21.post4.dist-info/top_level.txt,sha256=B-PzS4agkQNhOYbLLIrMVOyMD_pl5F-yujPBm5zYYjY,40
|
|
90
|
+
pumaguard-21.post4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|