@ -1,9 +1,10 @@
import httpx
import html
import json
from datetime import datetime
from datetime import datetime
# GraphQL Query für alle Sensoren
import httpx
query = '''
QUERY = """
query GetAllSensors {
query GetAllSensors {
sensors {
sensors {
id
id
@ -17,47 +18,65 @@ query GetAllSensors {
}
}
}
}
}
}
'''
""" .strip()
def escape_text ( value , default = " " ) :
text = default if value is None else str ( value )
return html . escape ( text , quote = True )
# API Aufruf
with httpx . Client ( ) as client :
def build_error ( message ) :
return (
" <div style= ' color: var(--color-danger, #dc3545); "
" font-family: Segoe UI, Tahoma, Geneva, Verdana, sans-serif; ' > "
f " { escape_text ( message ) } "
" </div> "
)
def build_report ( ) :
with httpx . Client ( ) as client :
response = client . post (
response = client . post (
f " { EXTERNAL_BASE_URL } /graphql " ,
f " { EXTERNAL_BASE_URL } /graphql " ,
json = { " query " : query } ,
json = { " query " : QUERY } ,
headers = AUTH_HEADERS ,
headers = AUTH_HEADERS ,
timeout = 30.0
timeout = 30.0 ,
)
)
if response . status_code != 200 :
if response . status_code != 200 :
result = f " <div style= ' color: var(--color-danger); ' >Fehler beim Abrufen der Sensoren: { response . status_code } </div> "
return build_error ( f " Fehler beim Abrufen der Sensoren: { response . status_code } ")
else :
data = response . json ( )
data = response . json ( )
sensors = data . get ( ' data ' , { } ) . get ( ' sensors ' , [ ] )
sensors = data . get ( " data " , { } ) . get ( " sensors " , [ ] )
# Sortiere Sensoren nach MeasureConcept Name
sensors . sort (
sensors . sort ( key = lambda s : ( s [ ' measureConcept ' ] [ ' name ' ] . strip ( ) if s [ ' measureConcept ' ] [ ' name ' ] else ' ' , s [ ' name ' ] . strip ( ) ) )
key = lambda s : (
( s . get ( " measureConcept " ) or { } ) . get ( " name " , " " ) . strip ( ) ,
( s . get ( " name " ) or " " ) . strip ( ) ,
)
)
# Gruppiere nach MeasureConcept
measure_concepts = { }
measure_concepts = { }
for sensor in sensors :
for sensor in sensors :
mc_id = sensor [ ' measureConcept ' ] [ ' id ' ]
measure_concept = sensor . get ( " measureConcept " ) or { }
mc_name = sensor [ ' measureConcept ' ] [ ' name ' ] . strip ( ) if sensor [ ' measureConcept ' ] [ ' name ' ] else ' Unbekannt '
mc_id = str ( measure_concept . get ( " id " ) or " unknown " )
mc_desc = sensor [ ' measureConcept ' ] [ ' description ' ] or ' '
mc_name = ( measure_concept . get ( " name " ) or " Unbekannt " ) . strip ( )
mc_desc = measure_concept . get ( " description " ) or " "
if mc_id not in measure_concepts :
if mc_id not in measure_concepts :
measure_concepts [ mc_id ] = {
measure_concepts [ mc_id ] = {
' name ' : mc_name ,
" name " : mc_name ,
' description ' : mc_desc ,
" description " : mc_desc ,
' sensors ' : [ ]
" sensors " : [ ] ,
}
}
measure_concepts [ mc_id ] [ ' sensors ' ] . append ( sensor )
# Statistiken
measure_concepts [ mc_id ] [ " sensors " ] . append ( sensor )
total_sensors = len ( sensors )
total_sensors = len ( sensors )
total_concepts = len ( measure_concepts )
total_concepts = len ( measure_concepts )
# HTML generieren
html_output = f """
html = f '''
< ! DOCTYPE html >
< ! DOCTYPE html >
< html >
< html >
< head >
< head >
@ -257,7 +276,7 @@ with httpx.Client() as client:
< body >
< body >
< div class = " container " >
< div class = " container " >
< div class = " header " >
< div class = " header " >
< h1 > 🔧 Sensor Ü bersicht< / h1 >
< h1 > Sensor Ue bersicht< / h1 >
< div class = " stats " >
< div class = " stats " >
< div class = " stat-card " >
< div class = " stat-card " >
< div class = " number " > { total_sensors } < / div >
< div class = " number " > { total_sensors } < / div >
@ -272,115 +291,115 @@ with httpx.Client() as client:
< div class = " filters " >
< div class = " filters " >
< div class = " filter-group " >
< div class = " filter-group " >
< label for = " searchInput " > 🔍 Sensor suchen : < / label >
< label for = " searchInput " > Sensor suchen : < / label >
< input type = " text " id = " searchInput " placeholder = " Sensor-Name, ID oder Beschreibung... " onkeyup = " filterSensors() " >
< input type = " text " id = " searchInput " placeholder = " Sensor-Name, ID oder Beschreibung... " onkeyup = " filterSensors() " >
< / div >
< / div >
< div class = " filter-group " >
< div class = " filter-group " >
< label for = " conceptFilter " > 📊 MeasureConcept filtern : < / label >
< label for = " conceptFilter " > MeasureConcept filtern : < / label >
< select id = " conceptFilter " onchange = " filterSensors() " >
< select id = " conceptFilter " onchange = " filterSensors() " >
< option value = " " > Alle MeasureConcepts anzeigen < / option >
< option value = " " > Alle MeasureConcepts anzeigen < / option >
'''
"""
# MeasureConcept Options für Filter
for mc_id , mc_data in sorted ( measure_concepts . items ( ) , key = lambda item : item [ 1 ] [ " name " ] ) :
for mc_id , mc_data in sorted ( measure_concepts . items ( ) , key = lambda x : x [ 1 ] [ ' name ' ] ) :
mc_name = escape_text ( mc_data [ " name " ] , " Unbekannt " )
mc_name = mc_data [ ' name ' ]
sensor_count = len ( mc_data [ " sensors " ] )
sensor_count = len ( mc_data [ ' sensors ' ] )
html_output + = (
html + = f ' <option value= " { mc_id } " > { mc_name } ( { sensor_count } Sensoren)</option> \n '
f ' <option value= " { escape_text ( mc_id ) } " > '
f " { mc_name } ( { sensor_count } Sensoren)</option> \n "
)
html + = '''
html_output + = """
< / select >
< / select >
< / div >
< / div >
< / div >
< / div >
< div id = " sensorsContent " >
< div id = " sensorsContent " >
'''
"""
# MeasureConcepts und Sensoren ausgeben
for mc_id , mc_data in sorted ( measure_concepts . items ( ) , key = lambda item : item [ 1 ] [ " name " ] ) :
for mc_id , mc_data in sorted ( measure_concepts . items ( ) , key = lambda x : x [ 1 ] [ ' name ' ] ) :
safe_mc_id = escape_text ( mc_id )
mc_name = mc_data [ ' name ' ]
mc_name = escape_text ( mc_data [ " name " ] , " Unbekannt " )
mc_desc = mc_data [ ' description ' ]
mc_desc = escape_text ( mc_data [ " description " ] )
sensors_in_concept = mc_data [ ' sensors ' ]
sensors_in_concept = mc_data [ " sensors " ]
html + = f '''
html_output + = f """
< div class = " measure-concept " data - concept - id = " { mc_id}" >
< div class = " measure-concept " data - concept - id = " { safe_ mc_id}" >
< div class = " concept-header " onclick = " toggleConcept( ' { mc_id}' ) " >
< div class = " concept-header " onclick = " toggleConcept( ' { safe_ mc_id}' ) " >
< div >
< div >
< h3 >
< h3 >
📊 { mc_name }
{ mc_name }
< span class = " sensor-count " > { len ( sensors_in_concept ) } Sensoren < / span >
< span class = " sensor-count " > { len ( sensors_in_concept ) } Sensoren < / span >
< / h3 >
< / h3 >
'''
"""
if mc_desc :
if mc_desc :
html + = f ' <div class= " concept-description " > { mc_desc } </div> \n '
html _output + = f ' <div class= " concept-description " > { mc_desc } </div> \n '
html + = '''
html_output + = f """
< / div >
< / div >
< / div >
< / div >
< div class = " sensors-container " id = " sensors- { mc_id}" >
< div class = " sensors-container " id = " sensors- { safe_ mc_id}" >
< div class = " sensor-grid " >
< div class = " sensor-grid " >
'''
"""
for sensor in sensors_in_concept :
for sensor in sensors_in_concept :
sensor_id = sensor [ ' id ' ]
sensor_id = escape_text ( sensor . get ( " id " ) , " Unbekannt " )
sensor_name = sensor [ ' name ' ] . strip ( ) if sensor [ ' name ' ] else ' Unbekannter Name '
sensor_name = escape_text ( ( sensor . get ( " name " ) or " " ) . strip ( ) , " Unbekannter Name " )
sensor_extern = sensor . get ( ' nameExtern ' , ' ' ) or ' '
sensor_extern = escape_text ( sensor . get ( " nameExtern " ) or " " )
sensor_desc = sensor . get ( ' description ' , ' ' ) or ' '
sensor_desc = escape_text ( sensor . get ( " description " ) or " " )
html + = f '''
html_output + = f """
< div class = " sensor-card " data - sensor - name = " {sensor_name} " data - sensor - id = " {sensor_id} " data - sensor - desc = " {sensor_desc} " >
< div class = " sensor-card " data - sensor - name = " {sensor_name} " data - sensor - id = " {sensor_id} " data - sensor - desc = " {sensor_desc} " >
< div class = " sensor-id " > ID : { sensor_id } < / div >
< div class = " sensor-id " > ID : { sensor_id } < / div >
< div class = " sensor-name " > { sensor_name } < / div >
< div class = " sensor-name " > { sensor_name } < / div >
'''
"""
if sensor_extern and sensor_extern . strip ( ) != ' - ' :
if sensor_extern and sensor_extern != " - " :
html + = f ' <div class= " sensor-extern " >Extern: { sensor_extern } </div> \n '
html _output + = f ' <div class= " sensor-extern " >Extern: { sensor_extern } </div> \n '
if sensor_desc :
if sensor_desc :
html + = f ' <div class= " sensor-description " > { sensor_desc } </div> \n '
html _output + = f ' <div class= " sensor-description " > { sensor_desc } </div> \n '
else :
else :
html + = ' <div class= " sensor-description no-data " >Keine Beschreibung verf ü gbar</div>\n '
html _output + = ' <div class= " sensor-description no-data " >Keine Beschreibung verf ue gbar</div>\n '
html + = ' </div> \n '
html_output + = " </div> \n "
html + = '''
html_output + = """
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
'''
"""
# Timestamp und JavaScript
current_time = datetime . now ( ) . strftime ( " %d . % m. % Y um % H: % M: % S " )
current_time = datetime . now ( ) . strftime ( ' %d . % m. % Y um % H: % M: % S ' )
html_output + = f """
html + = f '''
< / div >
< / div >
< div class = " timestamp " >
< div class = " timestamp " >
📅 Erstellt am { current_time }
Erstellt am { current_time }
< / div >
< / div >
< / div >
< / div >
< script >
< script >
function toggleConcept ( conceptId ) { {
function toggleConcept ( conceptId ) { {
const container = document . getElementById ( ' sensors- ' + conceptId ) ;
const container = document . getElementById ( ' sensors- ' + conceptId ) ;
if ( container ) { {
container . classList . toggle ( ' active ' ) ;
container . classList . toggle ( ' active ' ) ;
} }
} }
} }
function filterSensors ( ) { {
function filterSensors ( ) { {
const searchTerm = document . getElementById ( ' searchInput ' ) . value . toLowerCase ( ) ;
const searchTerm = document . getElementById ( ' searchInput ' ) . value . toLowerCase ( ) ;
const conceptFilter = document . getElementById ( ' conceptFilter ' ) . value ;
const conceptFilter = document . getElementById ( ' conceptFilter ' ) . value ;
const concepts = document . querySelectorAll ( ' .measure-concept ' ) ;
const concepts = document . querySelectorAll ( ' .measure-concept ' ) ;
concepts . forEach ( concept = > { {
concepts . forEach ( concept = > { {
const conceptId = concept . getAttribute ( ' data-concept-id ' ) ;
const conceptId = concept . getAttribute ( ' data-concept-id ' ) ;
let showConcept = false ;
let showConcept = false ;
/ / Concept Filter prüfen
if ( conceptFilter & & conceptFilter != = conceptId ) { {
if ( conceptFilter & & conceptFilter != = conceptId ) { {
concept . style . display = ' none ' ;
concept . style . display = ' none ' ;
return ;
return ;
} }
} }
/ / Sensor Cards filtern
const sensorCards = concept . querySelectorAll ( ' .sensor-card ' ) ;
const sensorCards = concept . querySelectorAll ( ' .sensor-card ' ) ;
sensorCards . forEach ( card = > { {
sensorCards . forEach ( card = > { {
const sensorName = card . getAttribute ( ' data-sensor-name ' ) . toLowerCase ( ) ;
const sensorName = card . getAttribute ( ' data-sensor-name ' ) . toLowerCase ( ) ;
@ -402,13 +421,16 @@ with httpx.Client() as client:
} } ) ;
} } ) ;
} }
} }
/ / Alle Concepts initial zuklappen
document . querySelectorAll ( ' .sensors-container ' ) . forEach ( container = > { {
document . querySelectorAll ( ' .sensors-container ' ) . forEach ( container = > { {
container . classList . remove ( ' active ' ) ;
container . classList . remove ( ' active ' ) ;
} } ) ;
} } ) ;
< / script >
< / script >
< / body >
< / body >
< / html >
< / html >
'''
"""
return html_output
result = html
result = build_report ( )
print ( result )