Track reviewed status for discovered sensors
Changes: - Added 'reviewed' field to DiscoveredSensor dataclass - By default, only show new (unreviewed) pending sensors - Mark sensors as reviewed when shown in approval CLI - Add --all flag to show all pending sensors (including reviewed) - Add --ignored flag to show ignored sensors - Prevent repeatedly asking for approval of same sensor Usage: approve-sensors # Only new sensors approve-sensors --all # All pending sensors approve-sensors --ignored # Ignored sensors approve-sensors --all --ignored # Everything
This commit is contained in:
@@ -8,6 +8,7 @@ Interactive tool to manage pending and ignored sensors.
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
@@ -191,6 +192,9 @@ def process_sensors(sensors: List[DiscoveredSensor], manager: DiscoveryManager):
|
|||||||
print(f"\nFound {len(sensors)} sensor(s) to review")
|
print(f"\nFound {len(sensors)} sensor(s) to review")
|
||||||
|
|
||||||
for i, sensor in enumerate(sensors, 1):
|
for i, sensor in enumerate(sensors, 1):
|
||||||
|
# Mark as reviewed when shown
|
||||||
|
manager.mark_reviewed(sensor.mac)
|
||||||
|
|
||||||
display_sensor(sensor, i, len(sensors))
|
display_sensor(sensor, i, len(sensors))
|
||||||
|
|
||||||
choice = get_user_choice()
|
choice = get_user_choice()
|
||||||
@@ -209,6 +213,31 @@ def process_sensors(sensors: List[DiscoveredSensor], manager: DiscoveryManager):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Main entry point for approve-sensors CLI."""
|
"""Main entry point for approve-sensors CLI."""
|
||||||
|
# Parse command line arguments
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Approve or ignore discovered Bluetooth sensors",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog="""
|
||||||
|
Examples:
|
||||||
|
%(prog)s # Show only new pending sensors
|
||||||
|
%(prog)s --all # Show all pending sensors (including reviewed)
|
||||||
|
%(prog)s --ignored # Show only ignored sensors
|
||||||
|
%(prog)s --all --ignored # Show all sensors
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--all', '-a',
|
||||||
|
action='store_true',
|
||||||
|
help='Show all pending sensors, including previously reviewed ones'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--ignored', '-i',
|
||||||
|
action='store_true',
|
||||||
|
help='Show ignored sensors'
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Setup logging
|
# Setup logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.WARNING,
|
level=logging.WARNING,
|
||||||
@@ -223,26 +252,37 @@ def main():
|
|||||||
# Load discovery manager
|
# Load discovery manager
|
||||||
manager = DiscoveryManager()
|
manager = DiscoveryManager()
|
||||||
|
|
||||||
# Get pending and ignored sensors
|
# Get sensors based on flags
|
||||||
|
if args.all:
|
||||||
pending = manager.get_pending()
|
pending = manager.get_pending()
|
||||||
ignored = manager.get_ignored()
|
pending_label = "all pending"
|
||||||
|
else:
|
||||||
|
pending = manager.get_new_pending()
|
||||||
|
pending_label = "new pending"
|
||||||
|
|
||||||
|
ignored = manager.get_ignored() if args.ignored else []
|
||||||
|
|
||||||
if not pending and not ignored:
|
if not pending and not ignored:
|
||||||
print("\n✅ No pending or ignored sensors found")
|
if args.all or args.ignored:
|
||||||
print("\nDiscovered sensors will appear here when detected.")
|
print(f"\n✅ No {pending_label if pending else 'ignored'} sensors found")
|
||||||
|
else:
|
||||||
|
print("\n✅ No new sensors to review")
|
||||||
|
all_pending = manager.get_pending()
|
||||||
|
if all_pending:
|
||||||
|
print(f"\nThere are {len(all_pending)} previously reviewed pending sensor(s).")
|
||||||
|
print("Run with --all to review them again.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Process pending sensors first
|
# Process pending sensors
|
||||||
if pending:
|
if pending:
|
||||||
print(f"\n📋 Processing {len(pending)} pending sensor(s)...")
|
print(f"\n📋 Processing {len(pending)} {pending_label} sensor(s)...")
|
||||||
process_sensors(pending, manager)
|
process_sensors(pending, manager)
|
||||||
|
|
||||||
# Ask about ignored sensors
|
# Process ignored sensors if requested
|
||||||
if ignored:
|
if ignored:
|
||||||
print(f"\n\nThere are {len(ignored)} ignored sensor(s).")
|
if pending:
|
||||||
review = input("Review ignored sensors? [y/N]: ").strip().lower()
|
print("\n" + "=" * 70)
|
||||||
|
print(f"\n📋 Processing {len(ignored)} ignored sensor(s)...")
|
||||||
if review == 'y':
|
|
||||||
process_sensors(ignored, manager)
|
process_sensors(ignored, manager)
|
||||||
|
|
||||||
print("\n" + "=" * 70)
|
print("\n" + "=" * 70)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class DiscoveredSensor:
|
|||||||
last_seen: str
|
last_seen: str
|
||||||
sample_reading: Dict[str, float]
|
sample_reading: Dict[str, float]
|
||||||
status: str = "pending" # pending, approved, ignored
|
status: str = "pending" # pending, approved, ignored
|
||||||
|
reviewed: bool = False # Has been shown in approval CLI
|
||||||
ignored_at: Optional[str] = None
|
ignored_at: Optional[str] = None
|
||||||
ignore_reason: Optional[str] = None
|
ignore_reason: Optional[str] = None
|
||||||
|
|
||||||
@@ -195,10 +196,26 @@ class DiscoveryManager:
|
|||||||
"""Get list of sensors with status 'pending'."""
|
"""Get list of sensors with status 'pending'."""
|
||||||
return [s for s in self.sensors.values() if s.status == "pending"]
|
return [s for s in self.sensors.values() if s.status == "pending"]
|
||||||
|
|
||||||
|
def get_new_pending(self) -> List[DiscoveredSensor]:
|
||||||
|
"""Get list of pending sensors that haven't been reviewed yet."""
|
||||||
|
return [s for s in self.sensors.values() if s.status == "pending" and not s.reviewed]
|
||||||
|
|
||||||
def get_ignored(self) -> List[DiscoveredSensor]:
|
def get_ignored(self) -> List[DiscoveredSensor]:
|
||||||
"""Get list of sensors with status 'ignored'."""
|
"""Get list of sensors with status 'ignored'."""
|
||||||
return [s for s in self.sensors.values() if s.status == "ignored"]
|
return [s for s in self.sensors.values() if s.status == "ignored"]
|
||||||
|
|
||||||
|
def mark_reviewed(self, mac: str):
|
||||||
|
"""
|
||||||
|
Mark a sensor as reviewed (shown in approval CLI).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mac: MAC address
|
||||||
|
"""
|
||||||
|
mac = mac.upper()
|
||||||
|
if mac in self.sensors:
|
||||||
|
self.sensors[mac].reviewed = True
|
||||||
|
self.save()
|
||||||
|
|
||||||
def send_ntfy_notification(self, sensor: DiscoveredSensor):
|
def send_ntfy_notification(self, sensor: DiscoveredSensor):
|
||||||
"""
|
"""
|
||||||
Send ntfy notification for a newly discovered sensor.
|
Send ntfy notification for a newly discovered sensor.
|
||||||
|
|||||||
Reference in New Issue
Block a user