import json
import httpx
from datetime import datetime, timedelta
import math
# Parameter - diese können später als Eingabe konfiguriert werden
METER_NUMBER = "Any - Als Parameter" # Wird durch tatsächliche Zählernummer ersetzt
CHART_TYPE = "line" # line, bar, area
GROUP_BY = "hour" # hour, day, week
INCLUDE_STATISTICS = True
# GraphQL Queries
FIND_SENSORS_QUERY = """
query FindSensors($meterNumber: String!) {
sensorsForMeterNumber(meterNumber: $meterNumber) {
sensorId
sensorName
sensorNameExtern
descr
measureConcept {
id
name
descr
}
}
}
"""
GET_VARIABLES_QUERY = """
query GetVariables($sensorId: ID!) {
availableVariableUnits(sensorId: $sensorId) {
variableUnitId
variableName
unitName
}
}
"""
FIND_OBSERVATIONS_QUERY = """
query FindObservations($measurementConceptId: ID!, $sensorName: String, $startTime: String, $endTime: String) {
findObservation(
measurementConceptId: $measurementConceptId
sensorName: $sensorName
startTime: $startTime
endTime: $endTime
) {
id
moment
value
meterValue
observationVariableUnit {
observationVariable {
name
description
}
unit {
name
description
}
}
quality
}
}
"""
def make_graphql_request(query, variables):
"""GraphQL Request ausführen"""
try:
with httpx.Client() as client:
response = client.post(
f"{EXTERNAL_BASE_URL}/graphql",
headers=AUTH_HEADERS,
json={"query": query, "variables": variables}
)
response.raise_for_status()
return response.json()
except Exception as e:
return {"errors": [str(e)]}
def calculate_statistics(observations):
"""Berechnet Statistiken für die Messwerte"""
if not observations:
return {}
values = [obs.get('value', 0) for obs in observations]
meter_values = [obs.get('meterValue', 0) for obs in observations]
return {
'total_readings': len(observations),
'value_min': min(values) if values else 0,
'value_max': max(values) if values else 0,
'value_avg': sum(values) / len(values) if values else 0,
'meter_min': min(meter_values) if meter_values else 0,
'meter_max': max(meter_values) if meter_values else 0,
'meter_avg': sum(meter_values) / len(meter_values) if meter_values else 0,
'consumption': max(meter_values) - min(meter_values) if meter_values else 0
}
def format_datetime(dt_string):
"""Formatiert DateTime für Chart.js"""
try:
dt = datetime.fromisoformat(dt_string.replace('Z', '+00:00'))
return dt.strftime('%Y-%m-%d %H:%M:%S')
except:
return dt_string
# Hauptlogik
result_html = ""
try:
# 1. Sensoren für Zählernummer finden
sensors_response = make_graphql_request(FIND_SENSORS_QUERY, {
"meterNumber": METER_NUMBER
})
if "errors" in sensors_response:
result = f"
Fehler beim Abrufen der Sensoren: {sensors_response['errors']}
"
else:
sensors = sensors_response.get('data', {}).get('sensorsForMeterNumber', [])
if not sensors:
result = f"Keine Sensoren für Zählernummer '{METER_NUMBER}' gefunden.
"
else:
sensor = sensors[0] # Ersten Sensor verwenden
sensor_id = sensor['sensorId']
sensor_name = sensor['sensorName']
measure_concept_id = sensor['measureConcept']['id']
# 2. Verfügbare Variablen abrufen
variables_response = make_graphql_request(GET_VARIABLES_QUERY, {
"sensorId": sensor_id
})
available_vars = variables_response.get('data', {}).get('availableVariableUnits', [])
# 3. Zeitraum: Letzten 3 Monate
end_time = datetime.now()
start_time = end_time - timedelta(days=90)
# 4. Messwerte abrufen
observations_response = make_graphql_request(FIND_OBSERVATIONS_QUERY, {
"measurementConceptId": measure_concept_id,
"sensorName": sensor_name,
"startTime": start_time.isoformat(),
"endTime": end_time.isoformat()
})
observations = observations_response.get('data', {}).get('findObservation', [])
# 5. Statistiken berechnen
stats = calculate_statistics(observations)
# 6. Daten für Chart vorbereiten
chart_labels = []
chart_values = []
chart_meter_values = []
for obs in observations:
chart_labels.append(format_datetime(obs['moment']))
chart_values.append(obs.get('value', 0))
chart_meter_values.append(obs.get('meterValue', 0))
# 7. HTML mit Chart.js generieren
result_html = f"""
Messwerte Dashboard - {sensor_name}
"""
# Statistiken hinzufügen
if INCLUDE_STATISTICS and stats:
result_html += f"""
{stats['total_readings']:,}
Gesamte Messwerte
{stats['consumption']:,.2f}
Verbrauch (Differenz)
{stats['value_avg']:,.2f}
Ø Messwert
{stats['meter_max']:,.2f}
Max Zählerstand
"""
# Chart hinzufügen
result_html += f"""
Messwerte Verlauf ({CHART_TYPE.title()})
Zählerstände
Verfügbare Variablen:
"""
for var in available_vars:
result_html += f"- {var['variableName']} ({var['unitName']})
"
result_html += f"""
Anzahl Sensoren gefunden: {len(sensors)}
Measure Concept: {sensor['measureConcept']['name']}
"""
result = result_html
except Exception as e:
result = f"Allgemeiner Fehler: {str(e)}
"
print(f"Generated HTML dashboard with {len(chart_labels) if 'chart_labels' in locals() else 0} data points")