Regenbasierte automatische Gartenbewässerung + homeMesh-Anbindung für AutoAction-Regeleditor
- Neues stündliches Python-Script (restricted/gartenbewaesserung/auto_watering.py): holt Niederschlags- und Sonnenuntergangsdaten von Open-Meteo, wertet je Zone (Hochbeete/Tröge/Garten vorn) individuelle Regen-Schwellenwerte und Mindest-Bewässerungsdauern aus und startet bei Bedarf per MQTT den passenden Automatik-Modus der Ventilsteuerung im Zeitraum vor Sonnenuntergang; veröffentlicht den Regen-Status zusätzlich stündlich als retained MQTT-Nachricht je Zone. - Web-UI: neue Bewässerungs-Steuerung/-Anzeige (ajax/watering.php, js/solar/solarMQTT.js, assets/img/realtime.svg) inkl. Live-Status-Icons (aus/geplant/pausiert/aktiv per Farbe und Symbol). - AutoAction-Regeleditor (ajax/actorDetails.php, sensorDetails.php, fillActorDD.php, fillSensorDD.php, tahoma.php, AutoAction.php) liest Actor-/Sensor-Parameter jetzt live aus der homeMesh-Datenbank statt aus stark vereinfachten Altfeldern, inkl. zugehöriger Anpassungen am Device-Discovery-Tooling (restricted/deviceDiscovery/*, neues logic_module.py). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -255,10 +255,13 @@ class MQTTDeviceConverter:
|
||||
device_info = device_data.get('device_info')
|
||||
# Gerätename vom ersten Entity oder aus device_info
|
||||
device_name = device_info.get('name', device_id)
|
||||
if not device_name or device_name == device_id:
|
||||
device_mf = device_info.get('model', device_info.get('mdl', device_info.get('mf','MQTT')))
|
||||
if(device_info.get('mf','MQTT') == "OpenDTU"):
|
||||
device_mf = "Wechselrichter"
|
||||
#if not device_name or device_name == device_id:
|
||||
# Fallback: Name vom ersten Entity
|
||||
if entities:
|
||||
device_name = entities[0]['config'].get('name', device_id)
|
||||
# if entities:
|
||||
# device_name = entities[0]['config'].get('name', device_id)
|
||||
|
||||
# Device URL
|
||||
device_url = f"mqtt://{device_id}"
|
||||
@@ -279,11 +282,13 @@ class MQTTDeviceConverter:
|
||||
component = entity['component']
|
||||
object_id = entity.get('object_id', 'unknown')
|
||||
config = entity['config']
|
||||
|
||||
if(device_mf == "MQTT"):
|
||||
device_mf = config.get('device', device_info.get('dev',{'model': 'MQTT'})).get('model', device_info.get('mdl', device_info.get('mf','MQTT')))
|
||||
|
||||
# Command aus der Entity erstellen
|
||||
command_entry = MQTTDeviceConverter._entity_to_command(component, object_id, config)
|
||||
command_entry = MQTTDeviceConverter._entity_to_commands(component, object_id, config)
|
||||
if command_entry:
|
||||
commands.append(command_entry)
|
||||
commands.extend(command_entry)
|
||||
|
||||
# States aus der Entity extrahieren
|
||||
entity_states = MQTTDeviceConverter._entity_to_states(component, object_id, config)
|
||||
@@ -292,7 +297,7 @@ class MQTTDeviceConverter:
|
||||
if commands: # Nur Actor erstellen wenn Commands vorhanden
|
||||
actor_result = {
|
||||
'name': device_name,
|
||||
'type': f"mqtt_device", # Allgemeiner Typ für Multi-Entity-Geräte
|
||||
'type': device_mf, # Allgemeiner Typ für Multi-Entity-Geräte
|
||||
'url': device_url,
|
||||
'commands': commands,
|
||||
'states': states
|
||||
@@ -306,7 +311,8 @@ class MQTTDeviceConverter:
|
||||
component = entity['component']
|
||||
object_id = entity.get('object_id', 'unknown')
|
||||
config = entity['config']
|
||||
|
||||
if(device_mf == "MQTT"):
|
||||
device_mf = device_info.get('model', device_info.get('mdl', device_info.get('mf','MQTT')))
|
||||
# States aus der Entity extrahieren
|
||||
entity_states = MQTTDeviceConverter._entity_to_states(component, object_id, config)
|
||||
states.extend(entity_states)
|
||||
@@ -314,7 +320,7 @@ class MQTTDeviceConverter:
|
||||
if states: # Nur Sensor erstellen wenn States vorhanden
|
||||
sensor_result = {
|
||||
'name': device_name,
|
||||
'type': f"mqtt_device",
|
||||
'type': device_mf,
|
||||
'url': device_url,
|
||||
'states': states
|
||||
}
|
||||
@@ -322,7 +328,7 @@ class MQTTDeviceConverter:
|
||||
return actor_result, sensor_result
|
||||
|
||||
@staticmethod
|
||||
def _entity_to_command(component: str, object_id: str, config: Dict) -> Optional[Dict]:
|
||||
def _entity_to_commands(component: str, object_id: str, config: Dict) -> Optional[Dict]:
|
||||
"""
|
||||
Konvertiert eine MQTT Entity in ein Command
|
||||
|
||||
@@ -336,19 +342,21 @@ class MQTTDeviceConverter:
|
||||
"""
|
||||
# Command Topic - verschiedene mögliche Feldnamen
|
||||
command_topic = config.get('command_topic') or config.get('cmd_t') or config.get('temperature_command_topic')
|
||||
|
||||
base_topic = config.get('~','')
|
||||
command_topic = command_topic.replace("~",base_topic)
|
||||
if not command_topic:
|
||||
return None
|
||||
|
||||
# Command-Name aus object_id ableiten
|
||||
command_name = object_id.replace('_', ' ').title().replace(' ', '')
|
||||
#command_name =
|
||||
# Oder aus dem Namen
|
||||
entity_name = config.get('name', object_id)
|
||||
command_name = config.get('name', object_id.replace('_', ' ').title().replace(' ', ''))
|
||||
|
||||
command_entry = {
|
||||
command_entry = [{
|
||||
'command': command_name,
|
||||
'parameters': []
|
||||
}
|
||||
'parameters': [],
|
||||
'url': command_topic
|
||||
}]
|
||||
|
||||
# Parameter basierend auf Component-Typ
|
||||
if component == 'number':
|
||||
@@ -375,7 +383,7 @@ class MQTTDeviceConverter:
|
||||
if unit:
|
||||
param['unit'] = unit
|
||||
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['parameters'].append(param)
|
||||
|
||||
elif component == 'select':
|
||||
# Select hat Optionen
|
||||
@@ -389,7 +397,7 @@ class MQTTDeviceConverter:
|
||||
if options:
|
||||
param['values'] = options
|
||||
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['parameters'].append(param)
|
||||
|
||||
elif component in ['switch', 'light']:
|
||||
# Switch/Light haben on/off
|
||||
@@ -402,7 +410,7 @@ class MQTTDeviceConverter:
|
||||
config.get('payload_off', config.get('pl_off', 'OFF'))
|
||||
]
|
||||
}
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['parameters'].append(param)
|
||||
|
||||
# Brightness für Light
|
||||
brightness_cmd_topic = (
|
||||
@@ -410,7 +418,7 @@ class MQTTDeviceConverter:
|
||||
config.get('bri_cmd_t')
|
||||
)
|
||||
if component == 'light' and brightness_cmd_topic:
|
||||
command_entry['parameters'].append({
|
||||
command_entry[0]['parameters'].append({
|
||||
'name': 'brightness',
|
||||
'type': 'integer',
|
||||
'min': 0,
|
||||
@@ -432,7 +440,7 @@ class MQTTDeviceConverter:
|
||||
'max': 100,
|
||||
'url': set_pos_topic
|
||||
}
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['parameters'].append(param)
|
||||
else:
|
||||
# Nur open/close/stop
|
||||
param = {
|
||||
@@ -441,7 +449,7 @@ class MQTTDeviceConverter:
|
||||
'url': command_topic,
|
||||
'values': ['OPEN', 'CLOSE', 'STOP']
|
||||
}
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['parameters'].append(param)
|
||||
|
||||
elif component == 'button':
|
||||
# Button hat normalerweise keinen Parameter, nur das Topic
|
||||
@@ -450,7 +458,7 @@ class MQTTDeviceConverter:
|
||||
'type': 'trigger',
|
||||
'url': command_topic
|
||||
}
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['parameters'].append(param)
|
||||
|
||||
elif component == 'climate':
|
||||
# Climate hat Temperatur-Setpoint
|
||||
@@ -469,8 +477,9 @@ class MQTTDeviceConverter:
|
||||
param['min'] = config['min_temp']
|
||||
if 'max_temp' in config:
|
||||
param['max'] = config['max_temp']
|
||||
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry[0]['command'] = "Solltemperatur"
|
||||
command_entry[0]['parameters'].append(param)
|
||||
|
||||
mode_cmd_topic = (
|
||||
config.get('mode_command_topic') or
|
||||
config.get('mode_cmd_t')
|
||||
@@ -482,7 +491,10 @@ class MQTTDeviceConverter:
|
||||
'url': mode_cmd_topic,
|
||||
'values': config.get('modes', [])
|
||||
}
|
||||
command_entry['parameters'].append(param)
|
||||
command_entry.append({
|
||||
'command': "Modus",
|
||||
'parameters': [param]
|
||||
})
|
||||
else:
|
||||
# Generischer Command mit dem Topic
|
||||
param = {
|
||||
@@ -512,8 +524,7 @@ class MQTTDeviceConverter:
|
||||
# State Topic - verschiedene mögliche Feldnamen prüfen
|
||||
state_topic = (
|
||||
config.get('state_topic') or
|
||||
config.get('stat_t') or # Abkürzung
|
||||
config.get('~') and config.get('stat_t') # Mit Base Topic
|
||||
config.get('stat_t')
|
||||
)
|
||||
|
||||
# Bei number/select: oft kein separates state_topic, dann command_topic verwenden
|
||||
@@ -523,6 +534,8 @@ class MQTTDeviceConverter:
|
||||
state_topic = config.get('command_topic') or config.get('cmd_t')
|
||||
|
||||
if state_topic:
|
||||
base_topic = config.get('~','')
|
||||
state_topic = state_topic.replace("~",base_topic)
|
||||
state_entry = {
|
||||
'name': object_id,
|
||||
'type': 'string',
|
||||
@@ -654,7 +667,6 @@ class MQTTModule(BaseModule):
|
||||
actor_data, sensor_data = MQTTDeviceConverter.convert_device_to_actors_and_sensors(
|
||||
device_id, device_data
|
||||
)
|
||||
|
||||
if actor_data:
|
||||
actors.append(actor_data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user