Skip to content

Commit a0c232e

Browse files
authored
Merge pull request #97 from chvvkumar/dev
Make MQTT and Home Assistant settings optional
2 parents c7417da + 8519257 commit a0c232e

File tree

3 files changed

+127
-18
lines changed

3 files changed

+127
-18
lines changed

.gitignore

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,33 @@
1-
docker-compose.yaml
1+
docker-compose.yaml
2+
3+
# Python
4+
__pycache__/
5+
*.py[cod]
6+
*$py.class
7+
*.so
8+
.Python
9+
10+
# Virtual environments
11+
.venv/
12+
venv/
13+
ENV/
14+
env/
15+
16+
# IDE
17+
.vscode/
18+
.idea/
19+
*.swp
20+
*.swo
21+
*~
22+
23+
# OS
24+
.DS_Store
25+
Thumbs.db
26+
27+
# Testing
28+
.pytest_cache/
29+
.coverage
30+
htmlcov/
31+
32+
# Logs
33+
*.log

detect.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ class Config:
3131
image_url: str
3232
model_path: str
3333
label_path: str
34-
broker: str
34+
broker: Optional[str]
3535
port: int
36-
topic: str
36+
topic: Optional[str]
3737
detect_interval: int
3838
mqtt_username: Optional[str]
3939
mqtt_password: Optional[str]
@@ -50,15 +50,19 @@ def from_env(cls) -> 'Config':
5050
discovery_mode = os.getenv('MQTT_DISCOVERY_MODE', 'legacy').lower()
5151

5252
# Base required vars for all modes
53-
required_vars = ['IMAGE_URL', 'MQTT_BROKER', 'DETECT_INTERVAL']
53+
required_vars = ['IMAGE_URL', 'DETECT_INTERVAL']
5454

55-
# Legacy mode requires MQTT_TOPIC
56-
if discovery_mode == 'legacy':
57-
required_vars.append('MQTT_TOPIC')
58-
# HA discovery mode requires DEVICE_ID
59-
elif discovery_mode == 'homeassistant':
60-
if not os.getenv('DEVICE_ID'):
61-
raise ValueError("DEVICE_ID is required when MQTT_DISCOVERY_MODE is 'homeassistant'")
55+
broker = os.getenv('MQTT_BROKER')
56+
57+
# Validate MQTT settings only if broker is configured
58+
if broker:
59+
# Legacy mode requires MQTT_TOPIC
60+
if discovery_mode == 'legacy' and not os.getenv('MQTT_TOPIC'):
61+
required_vars.append('MQTT_TOPIC')
62+
# HA discovery mode requires DEVICE_ID
63+
elif discovery_mode == 'homeassistant':
64+
if not os.getenv('DEVICE_ID'):
65+
raise ValueError("DEVICE_ID is required when MQTT_DISCOVERY_MODE is 'homeassistant'")
6266

6367
missing = [var for var in required_vars if not os.getenv(var)]
6468
if missing:
@@ -68,17 +72,17 @@ def from_env(cls) -> 'Config':
6872
image_url=os.environ['IMAGE_URL'],
6973
model_path=os.getenv('MODEL_PATH', 'keras_model.h5'),
7074
label_path=os.getenv('LABEL_PATH', 'labels.txt'),
71-
broker=os.environ['MQTT_BROKER'],
72-
port=int(os.getenv('MQTT_PORT', '1883')),
73-
topic=os.getenv('MQTT_TOPIC', ''),
75+
broker=broker or None,
76+
port=int(os.getenv('MQTT_PORT') or '1883'),
77+
topic=os.getenv('MQTT_TOPIC') or None,
7478
detect_interval=int(os.environ['DETECT_INTERVAL']),
75-
mqtt_username=os.getenv('MQTT_USERNAME'),
76-
mqtt_password=os.getenv('MQTT_PASSWORD'),
79+
mqtt_username=os.getenv('MQTT_USERNAME') or None,
80+
mqtt_password=os.getenv('MQTT_PASSWORD') or None,
7781
verify_ssl=os.getenv('VERIFY_SSL', 'false').lower() == 'true',
7882
mqtt_discovery_mode=discovery_mode,
7983
mqtt_discovery_prefix=os.getenv('MQTT_DISCOVERY_PREFIX', 'homeassistant'),
8084
device_name=os.getenv('DEVICE_NAME', 'Cloud Detector'),
81-
device_id=os.getenv('DEVICE_ID')
85+
device_id=os.getenv('DEVICE_ID') or None
8286
)
8387

8488
class HADiscoveryManager:
@@ -190,7 +194,7 @@ def __init__(self, config: Config, mqtt_client=None):
190194
self.ha_discovery = None
191195

192196
# Initialize HA discovery if enabled
193-
if self.config.mqtt_discovery_mode == 'homeassistant':
197+
if self.mqtt_client and self.config.mqtt_discovery_mode == 'homeassistant':
194198
self.ha_discovery = HADiscoveryManager(self.config, self.mqtt_client)
195199
self.ha_discovery.publish_discovery_configs()
196200

@@ -332,6 +336,9 @@ def detect(self, return_image: bool = False) -> dict:
332336

333337
def publish_result(self, result: dict):
334338
"""Publish detection result to MQTT"""
339+
if not self.mqtt_client:
340+
return
341+
335342
try:
336343
if self.config.mqtt_discovery_mode == 'homeassistant':
337344
# Use HA discovery publishing

tests/test_config_optional_mqtt.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import os
2+
import unittest
3+
from unittest.mock import patch
4+
from detect import Config
5+
6+
class TestConfigOptionalMqtt(unittest.TestCase):
7+
8+
def setUp(self):
9+
# Clear relevant environment variables before each test
10+
self.env_vars = {
11+
'IMAGE_URL': 'http://example.com/image.jpg',
12+
'DETECT_INTERVAL': '60',
13+
'MQTT_BROKER': '',
14+
'MQTT_PORT': '',
15+
'MQTT_TOPIC': '',
16+
'MQTT_USERNAME': '',
17+
'MQTT_PASSWORD': '',
18+
'MQTT_DISCOVERY_MODE': '',
19+
'DEVICE_ID': ''
20+
}
21+
self.patcher = patch.dict(os.environ, self.env_vars)
22+
self.patcher.start()
23+
24+
def tearDown(self):
25+
self.patcher.stop()
26+
27+
def test_config_no_mqtt(self):
28+
"""Test that Config can be initialized without MQTT settings."""
29+
# Ensure MQTT variables are unset/empty
30+
if 'MQTT_BROKER' in os.environ:
31+
del os.environ['MQTT_BROKER']
32+
33+
config = Config.from_env()
34+
35+
self.assertIsNone(config.broker)
36+
self.assertIsNone(config.topic)
37+
self.assertEqual(config.image_url, 'http://example.com/image.jpg')
38+
39+
def test_config_with_mqtt(self):
40+
"""Test that Config is initialized correctly with MQTT settings."""
41+
os.environ['MQTT_BROKER'] = 'mqtt.example.com'
42+
os.environ['MQTT_TOPIC'] = 'test/topic'
43+
44+
config = Config.from_env()
45+
46+
self.assertEqual(config.broker, 'mqtt.example.com')
47+
self.assertEqual(config.topic, 'test/topic')
48+
49+
def test_config_legacy_mode_missing_topic(self):
50+
"""Test that legacy mode requires topic only if broker is set."""
51+
os.environ['MQTT_BROKER'] = 'mqtt.example.com'
52+
os.environ['MQTT_DISCOVERY_MODE'] = 'legacy'
53+
# MQTT_TOPIC is missing
54+
55+
with self.assertRaises(ValueError) as cm:
56+
Config.from_env()
57+
self.assertIn("Missing required environment variables", str(cm.exception))
58+
59+
def test_config_ha_mode_missing_device_id(self):
60+
"""Test that HA mode requires DEVICE_ID only if broker is set."""
61+
os.environ['MQTT_BROKER'] = 'mqtt.example.com'
62+
os.environ['MQTT_DISCOVERY_MODE'] = 'homeassistant'
63+
# DEVICE_ID is missing
64+
65+
with self.assertRaises(ValueError) as cm:
66+
Config.from_env()
67+
self.assertIn("DEVICE_ID is required", str(cm.exception))
68+
69+
if __name__ == '__main__':
70+
unittest.main()

0 commit comments

Comments
 (0)