SolarManager unter Versionsverwaltung
Erster Stand der Hintergrundprozesse, die auf der Synology unter /volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins Web-Verzeichnis. Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot), zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat. Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py, gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte. Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein pip, sie muessen neben den Skripten liegen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import sys
|
||||
import mysql.connector as pymysql
|
||||
from mysql.connector import connect, Error
|
||||
import requests
|
||||
import datetime
|
||||
import time
|
||||
import socket
|
||||
import traceback
|
||||
import konfig
|
||||
|
||||
# MySQL-Datenbankverbindung. Zugangsdaten stehen in config.ini, siehe konfig.py.
|
||||
DB_CONFIG = konfig.datenbank("alarm")
|
||||
|
||||
wled_url = "http://192.168.179.139/json" # URL zur WLED JSON API
|
||||
LOG_SERVER = ("localhost", 13377) # UDP Logserver
|
||||
|
||||
# UDP Logging Funktion
|
||||
def send_log(message):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
log_message = f"{datetime.datetime.now().strftime('%b %d %H:%M:%S')} alarm_scheduler: {message}"
|
||||
sock.sendto(log_message.encode(), LOG_SERVER)
|
||||
sock.close()
|
||||
|
||||
def is_holiday():
|
||||
today_str = datetime.datetime.today().strftime("%Y-%m-%d")
|
||||
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = "SELECT COUNT(*) FROM feiertage WHERE datetime = %s"
|
||||
cursor.execute(query, (today_str,))
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
return result[0] > 0
|
||||
|
||||
def is_school_holiday():
|
||||
|
||||
today_str = datetime.datetime.today().strftime("%Y-%m-%d")
|
||||
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = "SELECT COUNT(*) FROM ferien WHERE date_from <= %s AND date_to >= %s"
|
||||
cursor.execute(query, (today_str, today_str))
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
return result[0] > 0
|
||||
|
||||
def get_active_alarms():
|
||||
today = datetime.datetime.today()
|
||||
today_str = today.strftime("%Y-%m-%d")
|
||||
weekday_map = {0: "mo", 1: "di", 2: "mi", 3: "do", 4: "fr", 5: "sa", 6: "so"}
|
||||
weekday_col = weekday_map[today.weekday()]
|
||||
holiday = is_holiday()
|
||||
school_holiday = is_school_holiday()
|
||||
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = f"""
|
||||
SELECT id, TIME_FORMAT(time_1, '%H:%i:%s'), mode FROM alarmtime
|
||||
WHERE onoff != -1 AND {weekday_col} != -1 AND (wecked IS NULL OR wecked != '{today_str}')
|
||||
"""
|
||||
|
||||
if holiday:
|
||||
query += " AND mode NOT IN ('arbeit', 'schule')"
|
||||
elif school_holiday:
|
||||
query += " AND mode != 'schule'"
|
||||
|
||||
cursor.execute(query)
|
||||
alarms = cursor.fetchall()
|
||||
conn.close()
|
||||
|
||||
return [(alarm[0], alarm[1]) for alarm in alarms]
|
||||
|
||||
def trigger_wled_playlist():
|
||||
data = {"ps": 5} # Beispiel: Playlist 1 aktivieren
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
for attempt in range(5):
|
||||
try:
|
||||
response = requests.post(wled_url, json=data, headers=headers)
|
||||
send_log(f"WLED Response (Attempt {attempt + 1}): {response.text}")
|
||||
try:
|
||||
if response.json().get("success"):
|
||||
return
|
||||
except ValueError:
|
||||
send_log(f"Value error: {response.text}") # Falls die Antwort kein gültiges JSON ist, weitermachen
|
||||
except:
|
||||
send_log(f"No response (Attempt {attempt + 1}): {traceback.print_exc()}")
|
||||
time.sleep(4) # Kurze Wartezeit zwischen Versuchen
|
||||
|
||||
def mark_alarm_as_executed(alarm_id):
|
||||
today_str = datetime.datetime.today().strftime("%Y-%m-%d")
|
||||
conn = pymysql.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
query = "UPDATE alarmtime SET wecked = %s WHERE id = %s"
|
||||
cursor.execute(query, (today_str, alarm_id))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def main():
|
||||
last_db_check = 0
|
||||
active_alarms = []
|
||||
|
||||
while True:
|
||||
now = time.time()
|
||||
|
||||
# Nur alle 5 Minuten die Datenbankabfrage ausführen
|
||||
if now - last_db_check >= 300:
|
||||
active_alarms = get_active_alarms()
|
||||
last_db_check = now
|
||||
|
||||
current_time = datetime.datetime.now().strftime("%H:%M:%S")
|
||||
|
||||
for alarm_id, alarm_time in active_alarms:
|
||||
if current_time >= alarm_time:
|
||||
send_log(f"Triggering WLED Playlist at {alarm_time}")
|
||||
trigger_wled_playlist()
|
||||
mark_alarm_as_executed(alarm_id)
|
||||
active_alarms = get_active_alarms()
|
||||
|
||||
time.sleep(20) # Überprüfung alle 20 sec
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user