Skip to content

Commit a3ba940

Browse files
authored
Merge pull request #107 from chvvkumar/snd
Fix config regressions, sanitize settings, and enhance condition safety
2 parents 1f606fc + 7071a62 commit a3ba940

File tree

1 file changed

+54
-4
lines changed

1 file changed

+54
-4
lines changed

alpaca/config.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,32 @@ def get_current_time(timezone_str: str = 'UTC') -> datetime:
2828
ERROR_NOT_CONNECTED = 0x407 # 1031
2929
ERROR_UNSPECIFIED = 0x500 # 1280
3030

31-
# Available cloud conditions from ML model
32-
ALL_CLOUD_CONDITIONS = ['Clear', 'Mostly Cloudy', 'Overcast', 'Rain', 'Snow', 'Wisps of clouds']
31+
# Dynamically load cloud conditions from labels file
32+
def load_labels():
33+
"""Load cloud condition labels from labels.txt file"""
34+
label_path = os.environ.get('LABEL_PATH', 'labels.txt')
35+
try:
36+
if os.path.exists(label_path):
37+
with open(label_path, 'r') as f:
38+
labels = []
39+
for line in f:
40+
clean_line = line.strip()
41+
# Handle "0 Clear" format if present
42+
if " " in clean_line and clean_line.split(" ", 1)[0].isdigit():
43+
clean_line = clean_line.split(" ", 1)[1]
44+
if clean_line:
45+
labels.append(clean_line)
46+
logger.info(f"Loaded {len(labels)} classes from {label_path}")
47+
return labels
48+
except Exception as e:
49+
logger.error(f"Failed to load labels from {label_path}: {e}")
50+
51+
# Fallback to defaults if file missing or error
52+
logger.warning("Using fallback default cloud conditions")
53+
return ['Clear', 'Mostly Cloudy', 'Overcast', 'Rain', 'Snow', 'Wisps of clouds']
54+
55+
# Available cloud conditions from ML model (loaded dynamically from labels.txt)
56+
ALL_CLOUD_CONDITIONS = load_labels()
3357

3458

3559
@dataclass
@@ -46,7 +70,7 @@ class AlpacaConfig:
4670
update_interval: int = 30 # seconds between cloud detection updates
4771
location: str = "AllSky Camera"
4872
image_url: str = field(default_factory=lambda: os.environ.get('IMAGE_URL', ''))
49-
unsafe_conditions: list = field(default_factory=lambda: ['Rain', 'Snow', 'Mostly Cloudy', 'Overcast'])
73+
unsafe_conditions: list = field(default_factory=lambda: ALL_CLOUD_CONDITIONS.copy())
5074

5175
# Confidence threshold settings
5276
default_threshold: float = 50.0 # Default threshold for any class not explicitly configured
@@ -102,7 +126,33 @@ def load_settings_from_file(cls) -> dict:
102126

103127
# Filter dictionary to only include valid fields for this dataclass
104128
valid_fields = {f.name for f in cls.__dataclass_fields__.values()}
105-
return {k: v for k, v in config_dict.items() if k in valid_fields}
129+
settings = {k: v for k, v in config_dict.items() if k in valid_fields}
130+
131+
# Sanitize loaded settings against current labels from labels.txt
132+
# Remove saved 'unsafe_conditions' that are no longer in ALL_CLOUD_CONDITIONS
133+
if 'unsafe_conditions' in settings:
134+
valid_labels = set(ALL_CLOUD_CONDITIONS)
135+
original_count = len(settings['unsafe_conditions'])
136+
settings['unsafe_conditions'] = [
137+
c for c in settings['unsafe_conditions']
138+
if c in valid_labels
139+
]
140+
removed_count = original_count - len(settings['unsafe_conditions'])
141+
if removed_count > 0:
142+
logger.info(f"Removed {removed_count} obsolete unsafe condition(s) from saved configuration")
143+
144+
# Clean up stale class thresholds
145+
if 'class_thresholds' in settings:
146+
original_count = len(settings['class_thresholds'])
147+
settings['class_thresholds'] = {
148+
k: v for k, v in settings['class_thresholds'].items()
149+
if k in ALL_CLOUD_CONDITIONS
150+
}
151+
removed_count = original_count - len(settings['class_thresholds'])
152+
if removed_count > 0:
153+
logger.info(f"Removed {removed_count} obsolete class threshold(s) from saved configuration")
154+
155+
return settings
106156
except Exception as e:
107157
logger.error(f"Failed to load configuration from {filepath}: {e}")
108158
return {}

0 commit comments

Comments
 (0)