commit 055fe4508040b8e7c3d8406a6ad0fd437fcf7afb Author: Denis Denisov Date: Wed Dec 3 23:23:01 2025 +0300 Initial commit diff --git a/config.json b/config.json new file mode 100644 index 0000000..5e54f3c --- /dev/null +++ b/config.json @@ -0,0 +1,9 @@ +{ + "mqtt_host": "localhost", + "mqtt_port": 1883, + "mqtt_username": "", + "mqtt_password": "", + "temperature_sensors": ["sensor1", "sensor2", "wb-ms-12v"], + "target_temperature": 20.0, + "control_topic": "devices/wb-gpio/controls/EXT1_R3A1" + } \ No newline at end of file diff --git a/heat_control.py b/heat_control.py new file mode 100644 index 0000000..450f16f --- /dev/null +++ b/heat_control.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +""" +Wirenboard Temperature Monitoring Script +Monitors temperature sensors and controls GPIO based on threshold +""" + +import json +import time +import logging +from typing import Dict, Any +import paho.mqtt.client as mqtt +import threading + +# Configuration +CONFIG_FILE = "/etc/wb-temperature-monitor/config.json" + +# Global dictionary for temperature values +temperature_data: Dict[str, float] = {} +config: Dict[str, Any] = {} + +# MQTT client +mqtt_client = None + +# Setup logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +def load_config(): + """Load configuration from file""" + global config + try: + with open(CONFIG_FILE, 'r') as f: + config = json.load(f) + logger.info(f"Configuration loaded: {config}") + except FileNotFoundError: + logger.error(f"Config file not found: {CONFIG_FILE}") + raise + except json.JSONDecodeError: + logger.error(f"Invalid JSON in config file: {CONFIG_FILE}") + raise + except Exception as e: + logger.error(f"Error loading config: {e}") + raise + +def on_connect(client, userdata, flags, rc): + """MQTT connection callback""" + if rc == 0: + logger.info("Connected to MQTT broker") + # Subscribe to all temperature sensor topics + for sensor in config.get('temperature_sensors', []): + topic = f"devices/{sensor}/controls/t" + client.subscribe(topic) + logger.info(f"Subscribed to: {topic}") + else: + logger.error(f"Connection failed with code: {rc}") + +def on_message(client, userdata, msg): + """MQTT message callback - store temperature values""" + try: + # Extract sensor name from topic + # Topic format: devices/%NAME%/controls/t + parts = msg.topic.split('/') + if len(parts) >= 2: + sensor_name = parts[1] # Get the %NAME% part + + # Convert payload to float + temperature = float(msg.payload.decode('utf-8')) + + # Store in global dictionary + temperature_data[sensor_name] = temperature + logger.debug(f"Updated {sensor_name}: {temperature}°C") + + except ValueError: + logger.error(f"Invalid temperature value: {msg.payload}") + except Exception as e: + logger.error(f"Error processing message: {e}") + +def check_temperatures(): + """Check temperatures against target and control GPIO""" + target_temp = config.get('target_temperature') + control_topic = config.get('control_topic', 'devices/wb-gpio/controls/EXT1_R3A1') + + if target_temp is None: + logger.error("Target temperature not configured") + return + + any_below_target = False + + # Check all sensors + for sensor, temp in temperature_data.items(): + if temp < target_temp: + logger.info(f"Sensor {sensor} below target: {temp} < {target_temp}") + any_below_target = True + break # No need to check further if one is below + + # Control GPIO + if any_below_target: + # Send "1" to turn on/activate + mqtt_client.publish(control_topic, "1", retain=True) + logger.info(f"Activated: {control_topic}") + else: + # Send "0" to turn off/deactivate + mqtt_client.publish(control_topic, "0", retain=True) + logger.debug(f"Deactivated: {control_topic}") + +def main_cycle(): + """Main 5-second cycle""" + while True: + try: + check_temperatures() + except Exception as e: + logger.error(f"Error in main cycle: {e}") + + # Wait 5 seconds + time.sleep(5) + +def setup_mqtt(): + """Setup and connect MQTT client""" + global mqtt_client + + mqtt_client = mqtt.Client(client_id="wb_temperature_monitor") + mqtt_client.on_connect = on_connect + mqtt_client.on_message = on_message + + # Configure from config + mqtt_host = config.get('mqtt_host', 'localhost') + mqtt_port = config.get('mqtt_port', 1883) + mqtt_username = config.get('mqtt_username', '') + mqtt_password = config.get('mqtt_password', '') + + if mqtt_username: + mqtt_client.username_pw_set(mqtt_username, mqtt_password) + + try: + mqtt_client.connect(mqtt_host, mqtt_port, 60) + mqtt_client.loop_start() + except Exception as e: + logger.error(f"Failed to connect to MQTT broker: {e}") + raise + +def main(): + """Main function""" + logger.info("Starting Wirenboard Temperature Monitor") + + # Load configuration + load_config() + + # Setup MQTT + setup_mqtt() + + # Start main cycle in a separate thread + # This allows MQTT to run in background + cycle_thread = threading.Thread(target=main_cycle, daemon=True) + cycle_thread.start() + + # Keep main thread alive + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + logger.info("Shutting down...") + mqtt_client.loop_stop() + mqtt_client.disconnect() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..12891f7 --- /dev/null +++ b/install.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Install required packages +apt-get update +apt-get install python3-pip +pip3 install paho-mqtt \ No newline at end of file diff --git a/wb-heat-control.service b/wb-heat-control.service new file mode 100644 index 0000000..9912de1 --- /dev/null +++ b/wb-heat-control.service @@ -0,0 +1,13 @@ +[Unit] +Description=Wirenboard Temperature Monitor +After=network.target mosquitto.service + +[Service] +Type=simple +ExecStart=/usr/local/bin/wb-temperature-monitor.py +Restart=on-failure +RestartSec=10 +User=root + +[Install] +WantedBy=multi-user.target