defmod EVU_Tibber_connect HTTPMOD https://api.tibber.com/v1-beta/gql 0
attr EVU_Tibber_connect userattr ws_homeId ws_minInterval ws_myId ws_token ws_websocketURL
attr EVU_Tibber_connect DbLogExclude .*
attr EVU_Tibber_connect DbLogInclude total_cost_.*,fc0_trigger.*
attr EVU_Tibber_connect comment Version 2024.01.22 14:00 \
https://developer.tibber.com/explorer\
\
In der FHEM Kommandozeile könnt Ihr das token und die homeID im KeyStore ablegen.\
Bitte lest dazu das Thema KeyStore im Wiki und legt die Funktion in Eure 99_myUtils.\
\
{KeyValue("store","EVU_Tibber_connect_token","5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE")}\
{KeyValue("store","EVU_Tibber_connect_homeID","96a14971-525a-4420-aae9-e5aedaa129ff")}\
\
Hierduch kann man einen wirtschaftlicheren trigger_price berechnen lassen:\
setreading EVU_Tibber compensation_grid <Eure Einspeisevergütung>\
\
# Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\
    (fc_avg - fc_min)  /2 + fc_min\
\
# Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\
# compensation_grid kann auch auf einen für Euch passenden Wert gesetzt werden\
    (fc_avg - compensation_grid) *0.85
attr EVU_Tibber_connect disable 0
attr EVU_Tibber_connect enableControlSet 1
attr EVU_Tibber_connect get01-1Name current_currency
attr EVU_Tibber_connect get01-2Name current_level
attr EVU_Tibber_connect get01-3Name current_date
attr EVU_Tibber_connect get01-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get01-4Name current_price
attr EVU_Tibber_connect get01-4OExpr $val *100
attr EVU_Tibber_connect get01Data { "query": "{viewer {home(id:\"%%homeID%%\") {currentSubscription {priceInfo {current {total startsAt currency level}}}}}}" }
attr EVU_Tibber_connect get01Header01 Content-Type: application/json
attr EVU_Tibber_connect get01Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get01JSON data_viewer_home_currentSubscription_priceInfo_current
attr EVU_Tibber_connect get01Name 01_priceInfo
attr EVU_Tibber_connect get01URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get02-10Name fc0_03_total
attr EVU_Tibber_connect get02-11Name fc0_04_startsAt
attr EVU_Tibber_connect get02-11OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-12Name fc0_04_total
attr EVU_Tibber_connect get02-13Name fc0_05_startsAt
attr EVU_Tibber_connect get02-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-14Name fc0_05_total
attr EVU_Tibber_connect get02-15Name fc0_06_startsAt
attr EVU_Tibber_connect get02-15OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-16Name fc0_06_total
attr EVU_Tibber_connect get02-17Name fc0_07_startsAt
attr EVU_Tibber_connect get02-17OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-18Name fc0_07_total
attr EVU_Tibber_connect get02-19Name fc0_08_startsAt
attr EVU_Tibber_connect get02-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-1Name current_date
attr EVU_Tibber_connect get02-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-20Name fc0_08_total
attr EVU_Tibber_connect get02-21Name fc0_09_startsAt
attr EVU_Tibber_connect get02-21OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-22Name fc0_09_total
attr EVU_Tibber_connect get02-23Name fc0_10_startsAt
attr EVU_Tibber_connect get02-23OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-24Name fc0_10_total
attr EVU_Tibber_connect get02-25Name fc0_11_startsAt
attr EVU_Tibber_connect get02-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-26Name fc0_11_total
attr EVU_Tibber_connect get02-27Name fc0_12_startsAt
attr EVU_Tibber_connect get02-27OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-28Name fc0_12_total
attr EVU_Tibber_connect get02-29Name fc0_13_startsAt
attr EVU_Tibber_connect get02-29OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-2Name current_price
attr EVU_Tibber_connect get02-2OExpr $val *100
attr EVU_Tibber_connect get02-30Name fc0_13_total
attr EVU_Tibber_connect get02-31Name fc0_14_startsAt
attr EVU_Tibber_connect get02-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-32Name fc0_14_total
attr EVU_Tibber_connect get02-33Name fc0_15_startsAt
attr EVU_Tibber_connect get02-33OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-34Name fc0_15_total
attr EVU_Tibber_connect get02-35Name fc0_16_startsAt
attr EVU_Tibber_connect get02-35OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-36Name fc0_16_total
attr EVU_Tibber_connect get02-37Name fc0_17_startsAt
attr EVU_Tibber_connect get02-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-38Name fc0_17_total
attr EVU_Tibber_connect get02-39Name fc0_18_startsAt
attr EVU_Tibber_connect get02-39OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-3Name fc0_00_startsAt
attr EVU_Tibber_connect get02-3OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-40Name fc0_18_total
attr EVU_Tibber_connect get02-41Name fc0_19_startsAt
attr EVU_Tibber_connect get02-41OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-42Name fc0_19_total
attr EVU_Tibber_connect get02-43Name fc0_20_startsAt
attr EVU_Tibber_connect get02-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-44Name fc0_20_total
attr EVU_Tibber_connect get02-45Name fc0_21_startsAt
attr EVU_Tibber_connect get02-45OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-46Name fc0_21_total
attr EVU_Tibber_connect get02-47Name fc0_22_startsAt
attr EVU_Tibber_connect get02-47OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-48Name fc0_22_total
attr EVU_Tibber_connect get02-49Name fc0_23_startsAt
attr EVU_Tibber_connect get02-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-4Name fc0_00_total
attr EVU_Tibber_connect get02-50Name fc0_23_total
attr EVU_Tibber_connect get02-51Name fc1_00_startsAt
attr EVU_Tibber_connect get02-51OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-52Name fc1_00_total
attr EVU_Tibber_connect get02-53Name fc1_01_startsAt
attr EVU_Tibber_connect get02-53OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-54Name fc1_01_total
attr EVU_Tibber_connect get02-55Name fc1_02_startsAt
attr EVU_Tibber_connect get02-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-56Name fc1_02_total
attr EVU_Tibber_connect get02-57Name fc1_03_startsAt
attr EVU_Tibber_connect get02-57OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-58Name fc1_03_total
attr EVU_Tibber_connect get02-59Name fc1_04_startsAt
attr EVU_Tibber_connect get02-59OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-5Name fc0_01_startsAt
attr EVU_Tibber_connect get02-5OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-60Name fc1_04_total
attr EVU_Tibber_connect get02-61Name fc1_05_startsAt
attr EVU_Tibber_connect get02-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-62Name fc1_05_total
attr EVU_Tibber_connect get02-63Name fc1_06_startsAt
attr EVU_Tibber_connect get02-63OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-64Name fc1_06_total
attr EVU_Tibber_connect get02-65Name fc1_07_startsAt
attr EVU_Tibber_connect get02-65OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-66Name fc1_07_total
attr EVU_Tibber_connect get02-67Name fc1_08_startsAt
attr EVU_Tibber_connect get02-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-68Name fc1_08_total
attr EVU_Tibber_connect get02-69Name fc1_09_startsAt
attr EVU_Tibber_connect get02-69OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-6Name fc0_01_total
attr EVU_Tibber_connect get02-70Name fc1_09_total
attr EVU_Tibber_connect get02-71Name fc1_10_startsAt
attr EVU_Tibber_connect get02-71OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-72Name fc1_10_total
attr EVU_Tibber_connect get02-73Name fc1_11_startsAt
attr EVU_Tibber_connect get02-73OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-74Name fc1_11_total
attr EVU_Tibber_connect get02-75Name fc1_12_startsAt
attr EVU_Tibber_connect get02-75OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-76Name fc1_12_total
attr EVU_Tibber_connect get02-77Name fc1_13_startsAt
attr EVU_Tibber_connect get02-77OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-78Name fc1_13_total
attr EVU_Tibber_connect get02-79Name fc1_14_startsAt
attr EVU_Tibber_connect get02-79OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-7Name fc0_02_startsAt
attr EVU_Tibber_connect get02-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-80Name fc1_14_total
attr EVU_Tibber_connect get02-81Name fc1_15_startsAt
attr EVU_Tibber_connect get02-81OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-82Name fc1_15_total
attr EVU_Tibber_connect get02-83Name fc1_16_startsAt
attr EVU_Tibber_connect get02-83OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-84Name fc1_16_total
attr EVU_Tibber_connect get02-85Name fc1_17_startsAt
attr EVU_Tibber_connect get02-85OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-86Name fc1_17_total
attr EVU_Tibber_connect get02-87Name fc1_18_startsAt
attr EVU_Tibber_connect get02-87OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-88Name fc1_18_total
attr EVU_Tibber_connect get02-89Name fc1_19_startsAt
attr EVU_Tibber_connect get02-89OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-8Name fc0_02_total
attr EVU_Tibber_connect get02-90Name fc1_19_total
attr EVU_Tibber_connect get02-91Name fc1_20_startsAt
attr EVU_Tibber_connect get02-91OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-92Name fc1_20_total
attr EVU_Tibber_connect get02-93Name fc1_21_startsAt
attr EVU_Tibber_connect get02-93OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-94Name fc1_21_total
attr EVU_Tibber_connect get02-95Name fc1_22_startsAt
attr EVU_Tibber_connect get02-95OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-96Name fc1_22_total
attr EVU_Tibber_connect get02-97Name fc1_23_startsAt
attr EVU_Tibber_connect get02-97OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02-98Name fc1_23_total
attr EVU_Tibber_connect get02-9Name fc0_03_startsAt
attr EVU_Tibber_connect get02-9OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get02Data { "query": "{viewer {home(id:\"%%homeID%%\") {currentSubscription {priceInfo {current {total startsAt} today {total startsAt} tomorrow {total startsAt}}}}}}" }
attr EVU_Tibber_connect get02Header01 Content-Type: application/json
attr EVU_Tibber_connect get02Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get02JSON data_viewer_home_currentSubscription_priceInfo
attr EVU_Tibber_connect get02Name 02_priceAll
attr EVU_Tibber_connect get02URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get03-1Name nodes_00_00_from
attr EVU_Tibber_connect get03-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get03-2Name nodes_00_00_cost
attr EVU_Tibber_connect get03-2OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-3Name nodes_00_00_consumption
attr EVU_Tibber_connect get03-4Name nodes_00_01_from
attr EVU_Tibber_connect get03-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get03-50Name nodes_00_01_cost
attr EVU_Tibber_connect get03-50OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-5Name nodes_00_01_cost
attr EVU_Tibber_connect get03-5OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-6Name nodes_00_01_consumption
attr EVU_Tibber_connect get03-7Name nodes_00_02_from
attr EVU_Tibber_connect get03-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get03-8Name nodes_00_02_cost
attr EVU_Tibber_connect get03-8OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get03-9Name nodes_00_02_consumption
attr EVU_Tibber_connect get03Data { "query": "{viewer {home(id:\"%%homeID%%\") {consumption(resolution: HOURLY, last: 3) {nodes {from cost consumption }}}}}"}
attr EVU_Tibber_connect get03Header01 Content-Type: application/json
attr EVU_Tibber_connect get03Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get03Name 03_consumption_hour
attr EVU_Tibber_connect get03RegOpt g
attr EVU_Tibber_connect get03Regex \{"from":"([\d+-]+T[\d+:]+\.000[+-][\d+:]+)","cost":(null|\d+\.\d+|0),"consumption":(null|\d+\.\d+|0)\}
attr EVU_Tibber_connect get03URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get04-10Name nodes_24_03_from
attr EVU_Tibber_connect get04-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-11Name nodes_24_03_cost
attr EVU_Tibber_connect get04-11OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-12Name nodes_24_03_consumption
attr EVU_Tibber_connect get04-13Name nodes_24_04_from
attr EVU_Tibber_connect get04-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-14Name nodes_24_04_cost
attr EVU_Tibber_connect get04-14OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-15Name nodes_24_04_consumption
attr EVU_Tibber_connect get04-16Name nodes_24_05_from
attr EVU_Tibber_connect get04-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-17Name nodes_24_05_cost
attr EVU_Tibber_connect get04-17OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-18Name nodes_24_05_consumption
attr EVU_Tibber_connect get04-19Name nodes_24_06_from
attr EVU_Tibber_connect get04-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-1Name nodes_24_00_from
attr EVU_Tibber_connect get04-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-20Name nodes_24_06_cost
attr EVU_Tibber_connect get04-20OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-21Name nodes_24_06_consumption
attr EVU_Tibber_connect get04-22Name nodes_24_07_from
attr EVU_Tibber_connect get04-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-23Name nodes_24_07_cost
attr EVU_Tibber_connect get04-23OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-24Name nodes_24_07_consumption
attr EVU_Tibber_connect get04-25Name nodes_24_08_from
attr EVU_Tibber_connect get04-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-26Name nodes_24_08_cost
attr EVU_Tibber_connect get04-26OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-27Name nodes_24_08_consumption
attr EVU_Tibber_connect get04-28Name nodes_24_09_from
attr EVU_Tibber_connect get04-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-29Name nodes_24_09_cost
attr EVU_Tibber_connect get04-29OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-2Name nodes_24_00_cost
attr EVU_Tibber_connect get04-2OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-30Name nodes_24_09_consumption
attr EVU_Tibber_connect get04-31Name nodes_24_10_from
attr EVU_Tibber_connect get04-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-32Name nodes_24_10_cost
attr EVU_Tibber_connect get04-32OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-33Name nodes_24_10_consumption
attr EVU_Tibber_connect get04-34Name nodes_24_11_from
attr EVU_Tibber_connect get04-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-35Name nodes_24_11_cost
attr EVU_Tibber_connect get04-35OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-36Name nodes_24_11_consumption
attr EVU_Tibber_connect get04-37Name nodes_24_12_from
attr EVU_Tibber_connect get04-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-38Name nodes_24_12_cost
attr EVU_Tibber_connect get04-38OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-39Name nodes_24_12_consumption
attr EVU_Tibber_connect get04-3Name nodes_24_00_consumption
attr EVU_Tibber_connect get04-40Name nodes_24_13_from
attr EVU_Tibber_connect get04-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-41Name nodes_24_13_cost
attr EVU_Tibber_connect get04-41OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-42Name nodes_24_13_consumption
attr EVU_Tibber_connect get04-43Name nodes_24_14_from
attr EVU_Tibber_connect get04-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-44Name nodes_24_14_cost
attr EVU_Tibber_connect get04-44OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-45Name nodes_24_14_consumption
attr EVU_Tibber_connect get04-46Name nodes_24_15_from
attr EVU_Tibber_connect get04-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-47Name nodes_24_15_cost
attr EVU_Tibber_connect get04-47OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-48Name nodes_24_15_consumption
attr EVU_Tibber_connect get04-49Name nodes_24_16_from
attr EVU_Tibber_connect get04-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-4Name nodes_24_01_from
attr EVU_Tibber_connect get04-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-50Name nodes_24_16_cost
attr EVU_Tibber_connect get04-50OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-51Name nodes_24_16_consumption
attr EVU_Tibber_connect get04-52Name nodes_24_17_from
attr EVU_Tibber_connect get04-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-53Name nodes_24_17_cost
attr EVU_Tibber_connect get04-53OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-54Name nodes_24_17_consumption
attr EVU_Tibber_connect get04-55Name nodes_24_18_from
attr EVU_Tibber_connect get04-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-56Name nodes_24_18_cost
attr EVU_Tibber_connect get04-56OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-57Name nodes_24_18_consumption
attr EVU_Tibber_connect get04-58Name nodes_24_19_from
attr EVU_Tibber_connect get04-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-59Name nodes_24_19_cost
attr EVU_Tibber_connect get04-59OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-5Name nodes_24_01_cost
attr EVU_Tibber_connect get04-5OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-60Name nodes_24_19_consumption
attr EVU_Tibber_connect get04-61Name nodes_24_20_from
attr EVU_Tibber_connect get04-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-62Name nodes_24_20_cost
attr EVU_Tibber_connect get04-62OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-63Name nodes_24_20_consumption
attr EVU_Tibber_connect get04-64Name nodes_24_21_from
attr EVU_Tibber_connect get04-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-65Name nodes_24_21_cost
attr EVU_Tibber_connect get04-65OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-66Name nodes_24_21_consumption
attr EVU_Tibber_connect get04-67Name nodes_24_22_from
attr EVU_Tibber_connect get04-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-68Name nodes_24_22_cost
attr EVU_Tibber_connect get04-68OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-69Name nodes_24_22_consumption
attr EVU_Tibber_connect get04-6Name nodes_24_01_consumption
attr EVU_Tibber_connect get04-70Name nodes_24_23_from
attr EVU_Tibber_connect get04-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-71Name nodes_24_23_cost
attr EVU_Tibber_connect get04-71OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-72Name nodes_24_23_consumption
attr EVU_Tibber_connect get04-7Name nodes_24_02_from
attr EVU_Tibber_connect get04-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get04-8Name nodes_24_02_cost
attr EVU_Tibber_connect get04-8OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get04-9Name nodes_24_02_consumption
attr EVU_Tibber_connect get04Data { "query": "{viewer {home(id:\"%%homeID%%\") {consumption(resolution: HOURLY, last: 24) {nodes {from cost consumption}}}}}"}
attr EVU_Tibber_connect get04Header01 Content-Type: application/json
attr EVU_Tibber_connect get04Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get04Name 04_consumption_hour_24
attr EVU_Tibber_connect get04RegOpt g
attr EVU_Tibber_connect get04Regex \{"from":"([\d+-]+T[\d+:]+\.000[+-][\d+:]+)","cost":(null|\d+\.\d+|0),"consumption":(null|\d+\.\d+|0)\}
attr EVU_Tibber_connect get04URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get05AutoNumLen 4
attr EVU_Tibber_connect get05Data { "query": "{viewer {home(id:\"%%homeID%%\") {consumption(resolution: HOURLY, last: 100) {nodes {from cost consumption}}}}}"}
attr EVU_Tibber_connect get05Header01 Content-Type: application/json
attr EVU_Tibber_connect get05Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get05JSON data_viewer_home
attr EVU_Tibber_connect get05Name 05_consumption_hourly_100
attr EVU_Tibber_connect get05URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get06-10Name Adresse_07_Telefon
attr EVU_Tibber_connect get06-11Name Adresse_01_Vorname
attr EVU_Tibber_connect get06-12Name Adresse_02_Nachname
attr EVU_Tibber_connect get06-1Name Adresse_03_Strasse
attr EVU_Tibber_connect get06-2Name Adresse_05_Ort
attr EVU_Tibber_connect get06-3Name Adresse_06_Land
attr EVU_Tibber_connect get06-4Name Adresse_05_Ort
attr EVU_Tibber_connect get06-5Name Adresse_06_Land
attr EVU_Tibber_connect get06-6Name Adresse_09_latitude
attr EVU_Tibber_connect get06-7Name Adresse_10_longitude
attr EVU_Tibber_connect get06-8Name Adresse_04_Plz
attr EVU_Tibber_connect get06-9Name Adresse_08_eMail
attr EVU_Tibber_connect get06Data { "query": "{viewer {home(id:\"%%homeID%%\") {address {address1 address2 address3 postalCode city country latitude longitude} owner {firstName lastName contactInfo {email mobile}}}}}" }
attr EVU_Tibber_connect get06Header01 Content-Type: application/json
attr EVU_Tibber_connect get06Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get06JSON data_viewer_home
attr EVU_Tibber_connect get06Name 06_address
attr EVU_Tibber_connect get06URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect get07-10Name nodes_24_03_from
attr EVU_Tibber_connect get07-10OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-11Name nodes_24_03_cost
attr EVU_Tibber_connect get07-11OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-12Name nodes_24_03_consumption
attr EVU_Tibber_connect get07-13Name nodes_24_04_from
attr EVU_Tibber_connect get07-13OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-14Name nodes_24_04_cost
attr EVU_Tibber_connect get07-14OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-15Name nodes_24_04_consumption
attr EVU_Tibber_connect get07-16Name nodes_24_05_from
attr EVU_Tibber_connect get07-16OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-17Name nodes_24_05_cost
attr EVU_Tibber_connect get07-17OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-18Name nodes_24_05_consumption
attr EVU_Tibber_connect get07-19Name nodes_24_06_from
attr EVU_Tibber_connect get07-19OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-1Name features_realTimeConsumptionEnabled
attr EVU_Tibber_connect get07-1OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-20Name nodes_24_06_cost
attr EVU_Tibber_connect get07-20OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-21Name nodes_24_06_consumption
attr EVU_Tibber_connect get07-22Name nodes_24_07_from
attr EVU_Tibber_connect get07-22OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-23Name nodes_24_07_cost
attr EVU_Tibber_connect get07-23OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-24Name nodes_24_07_consumption
attr EVU_Tibber_connect get07-25Name nodes_24_08_from
attr EVU_Tibber_connect get07-25OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-26Name nodes_24_08_cost
attr EVU_Tibber_connect get07-26OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-27Name nodes_24_08_consumption
attr EVU_Tibber_connect get07-28Name nodes_24_09_from
attr EVU_Tibber_connect get07-28OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-29Name nodes_24_09_cost
attr EVU_Tibber_connect get07-29OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-2Name features_id
attr EVU_Tibber_connect get07-2OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-30Name nodes_24_09_consumption
attr EVU_Tibber_connect get07-31Name nodes_24_10_from
attr EVU_Tibber_connect get07-31OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-32Name nodes_24_10_cost
attr EVU_Tibber_connect get07-32OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-33Name nodes_24_10_consumption
attr EVU_Tibber_connect get07-34Name nodes_24_11_from
attr EVU_Tibber_connect get07-34OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-35Name nodes_24_11_cost
attr EVU_Tibber_connect get07-35OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-36Name nodes_24_11_consumption
attr EVU_Tibber_connect get07-37Name nodes_24_12_from
attr EVU_Tibber_connect get07-37OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-38Name nodes_24_12_cost
attr EVU_Tibber_connect get07-38OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-39Name nodes_24_12_consumption
attr EVU_Tibber_connect get07-3Name nodes_24_00_consumption
attr EVU_Tibber_connect get07-40Name nodes_24_13_from
attr EVU_Tibber_connect get07-40OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-41Name nodes_24_13_cost
attr EVU_Tibber_connect get07-41OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-42Name nodes_24_13_consumption
attr EVU_Tibber_connect get07-43Name nodes_24_14_from
attr EVU_Tibber_connect get07-43OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-44Name nodes_24_14_cost
attr EVU_Tibber_connect get07-44OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-45Name nodes_24_14_consumption
attr EVU_Tibber_connect get07-46Name nodes_24_15_from
attr EVU_Tibber_connect get07-46OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-47Name nodes_24_15_cost
attr EVU_Tibber_connect get07-47OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-48Name nodes_24_15_consumption
attr EVU_Tibber_connect get07-49Name nodes_24_16_from
attr EVU_Tibber_connect get07-49OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-4Name nodes_24_01_from
attr EVU_Tibber_connect get07-4OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-50Name nodes_24_16_cost
attr EVU_Tibber_connect get07-50OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-51Name nodes_24_16_consumption
attr EVU_Tibber_connect get07-52Name nodes_24_17_from
attr EVU_Tibber_connect get07-52OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-53Name nodes_24_17_cost
attr EVU_Tibber_connect get07-53OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-54Name nodes_24_17_consumption
attr EVU_Tibber_connect get07-55Name nodes_24_18_from
attr EVU_Tibber_connect get07-55OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-56Name nodes_24_18_cost
attr EVU_Tibber_connect get07-56OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-57Name nodes_24_18_consumption
attr EVU_Tibber_connect get07-58Name nodes_24_19_from
attr EVU_Tibber_connect get07-58OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-59Name nodes_24_19_cost
attr EVU_Tibber_connect get07-59OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-5Name nodes_24_01_cost
attr EVU_Tibber_connect get07-5OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-60Name nodes_24_19_consumption
attr EVU_Tibber_connect get07-61Name nodes_24_20_from
attr EVU_Tibber_connect get07-61OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-62Name nodes_24_20_cost
attr EVU_Tibber_connect get07-62OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-63Name nodes_24_20_consumption
attr EVU_Tibber_connect get07-64Name nodes_24_21_from
attr EVU_Tibber_connect get07-64OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-65Name nodes_24_21_cost
attr EVU_Tibber_connect get07-65OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-66Name nodes_24_21_consumption
attr EVU_Tibber_connect get07-67Name nodes_24_22_from
attr EVU_Tibber_connect get07-67OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-68Name nodes_24_22_cost
attr EVU_Tibber_connect get07-68OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-69Name nodes_24_22_consumption
attr EVU_Tibber_connect get07-6Name nodes_24_01_consumption
attr EVU_Tibber_connect get07-70Name nodes_24_23_from
attr EVU_Tibber_connect get07-70OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-71Name nodes_24_23_cost
attr EVU_Tibber_connect get07-71OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-72Name nodes_24_23_consumption
attr EVU_Tibber_connect get07-7Name nodes_24_02_from
attr EVU_Tibber_connect get07-7OExpr $val =~ s/T/ /g ;; substr($val,0,19)
attr EVU_Tibber_connect get07-8Name nodes_24_02_cost
attr EVU_Tibber_connect get07-8OExpr ($val ne "0" and $val ne "null")? round($val,4) : $val
attr EVU_Tibber_connect get07-9Name nodes_24_02_consumption
attr EVU_Tibber_connect get07Data { "query": "{viewer {home(id:\"%%homeID%%\") {id features{realTimeConsumptionEnabled} } } }" }
attr EVU_Tibber_connect get07Header01 Content-Type: application/json
attr EVU_Tibber_connect get07Header02 Authorization: Bearer %%token%%
attr EVU_Tibber_connect get07JSON data_viewer_home
attr EVU_Tibber_connect get07Name 07_realTimeConsumptionEnabled
attr EVU_Tibber_connect get07RegOpt g
attr EVU_Tibber_connect get07Regex \{"from":"([\d+-]+T[\d+:]+\.000[+-][\d+:]+)","cost":(null|\d+\.\d+|0),"consumption":(null|\d+\.\d+|0)\}
attr EVU_Tibber_connect get07URL https://api.tibber.com/v1-beta/gql
attr EVU_Tibber_connect group PV Steuerung EVU
attr EVU_Tibber_connect icon stromzaehler_icon
attr EVU_Tibber_connect replacement01Mode expression
attr EVU_Tibber_connect replacement01Regex %%token%%
attr EVU_Tibber_connect replacement01Value {KeyValue("read","EVU_Tibber_connect_token")}
attr EVU_Tibber_connect replacement02Mode expression
attr EVU_Tibber_connect replacement02Regex %%homeID%%
attr EVU_Tibber_connect replacement02Value {KeyValue("read","EVU_Tibber_connect_homeID")}
attr EVU_Tibber_connect requestData { "query": "{viewer {home(id:\"%%homeID%%\") {currentSubscription {priceInfo {current {total energy tax startsAt }}}}}}" }
attr EVU_Tibber_connect requestHeader1 Content-Type: application/json
attr EVU_Tibber_connect requestHeader2 Authorization: Bearer %%token%%
attr EVU_Tibber_connect room Strom->Boerse
attr EVU_Tibber_connect showBody 1
attr EVU_Tibber_connect showError 1
attr EVU_Tibber_connect sortby 313
attr EVU_Tibber_connect timeout 30
attr EVU_Tibber_connect userReadings ws_connect:ws_cmd:.connect {\
    my $hash = $defs{$name};;\
    my $devState = DevIo_IsOpen($hash);;\
    return "Device already open" if (defined($devState));;\
    \
    # establish connection to websocket\
    # format must also include portnumber if a path is to be specified\
    $hash->{DeviceName} = AttrVal($name, "ws_websocketURL", "wss:echo.websocket.org:443");;\
    \
    # special headers needed for Tibber, see also Developer Tools in Browser\
    $hash->{header}{'Sec-WebSocket-Protocol'} = 'graphql-transport-ws';;\
    $hash->{header}{'Host'} = 'websocket-api.tibber.com';;\
    $hash->{header}{'Origin'} = 'https://developer.tibber.com';;\
    \
    # callback function when "select()" signals data for us\
    # websocket Ping/Pongs are treated in DevIo but still call this function\
    $hash->{directReadFn} = sub () {\
        my $hash = $defs{$name};;\
        \
        # we can read without closing the DevIo, because select() signalled data\
        my $buf = DevIo_SimpleRead($hash);;\
        \
        # if read fails, close device\
        if(!defined($buf)) {\
            DevIo_CloseDev($hash);;\
            $buf = "not_connected";;\
        }\
        \
        #Log(3, "$name:$reading: websocket data: >>>$buf<<<");;\
        \
        # only update our reading if buffer is not empty and if last update is older than minInterval\
        if ($buf ne "") {\
            my $websocketDataAge = ReadingsAge($name, "ws_websocketData", 3600);;\
            my $minInterval = AttrVal($name, "ws_minInterval", 0);;\
            my $isNext = ($buf =~ /.*id.*type.*next.*payload.*data.*liveMeasurement.*/s);;\
            \
            readingsBeginUpdate($hash);;\
            readingsBulkUpdate($hash, "ws_websocketData", "$buf") if ($isNext && $websocketDataAge > $minInterval);;\
            readingsBulkUpdate($hash, "ws_websocketData", "$buf") if (!$isNext);;\
            readingsEndUpdate($hash, 1);;\
            #Log(3, "$name:$reading: websocket data written to reading");;\
        }\
    };;\
    \
    # open DevIo websocket\
    DevIo_OpenDev($hash, 0, undef, sub(){\
        my ($hash, $error) = @_;;\
        return "$error" if ($error);;\
        \
        my $token = AttrVal($name, "ws_token", "???");;\
           $token = KeyValue("read","EVU_Tibber_connect_token") if ($token eq "???");;\
\
        DevIo_SimpleWrite($hash, '{"type":"connection_init","payload":{"token":"'.$token.'"}}', 2);;\
    });;\
    readingsBulkUpdate($hash, "ws_websocketData", "");;\
    #Log(3, "$name:$reading: websocket data cleared in reading");;\
      \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
\
ws_disconnect:ws_cmd:.disconnect {\
    Log(3, "$name: disconnect");;\
    my $hash = $defs{$name};;\
    RemoveInternalTimer($hash);;\
    DevIo_SimpleRead($hash);;\
    DevIo_CloseDev($hash);;\
\
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
\
ws_onDisconnect {\
    my $myState = ReadingsVal($name, "state", "???");;\
    my $myData = ReadingsVal($name, "ws_websocketData", "???");;\
    return if ($myState ne "disconnected" and $myData ne "not_connected");;\
    \
	## timer callback function, called after a few seconds to initiate a reconnect\
	my $timerFunction = sub() {\
		my ($arg) = @_;;\
		my $hash = $defs{$name};;\
		my $devState = DevIo_IsOpen($hash);;\
		\
		# only re-connect if device is not connected\
		readingsSingleUpdate($hash, "ws_cmd", "connect", 1) if (!defined($devState));;\
	};;\
	RemoveInternalTimer($name.$reading.'Timer');;\
	\
	# wait a random time before reconnect (exponential backoff TBD):\
	my $rwait = int(rand(200)) + 30;;\
	InternalTimer(gettimeofday() + $rwait, $timerFunction, $name.$reading.'Timer');;\
	\
	#set cmd to a new value, informs user and allows to retrigger when timer expires\
	my $hash = $defs{$name};;\
	readingsBulkUpdate($hash, "ws_cmd", "reconnect attempt in $rwait seconds");;\
	\
	return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
\
ws_onTimeout:ws_websocketData:.* {\
	#re-establish websocket connection if no data received in the past ten minutes\
	#but only if our reading "ws_cmd" was not set to the value "disconnect"\
\
        #Log(3, "$name:$reading: websocket data triggert ws_onTimeout");;\
\
	#timeout in seconds when the connection is considered dead\
	my $timeoutTime = 600;;\
	\
	# function to execute when timeout expired\
	# defining the function here in the userReading, allows us to insert variables directly\
	my $timerFunction = sub() {\
		my ($arg) = @_;;\
		my $hash = $defs{$name};;\
		my $rCmd = ReadingsVal($name, "ws_cmd", "???");;\
		my $age  = ReadingsAge($name, "ws_websocketData", 0);;\
		\
		Log(3, "$name: onTimeoutTimer triggered >>$arg<<");;\
		\
		#do not do anything further if disconnect is on purpose\
		if ( $rCmd eq "disconnect" ) {\
			Log(3, "$name: ws_cmd was set to disconnect");;\
			return;;\
		}\
		\
		# for whatever reason, we triggered to soon (80%)\
		if ( $age < $timeoutTime*0.8 ) {\
			Log(3, "$name: ws_websocketData is not outdated");;\
			return;;\
		}\
		\
		DevIo_CloseDev($hash);;\
		Log(3, "$name: onTimeoutTimer closed DevIo...");;\
		\
		readingsSingleUpdate($hash, "ws_cmd", "connect", 1);;\
		Log(3, "$name: onTimeoutTimer set ws_cmd to value 'connect'");;\
	};;\
\
        #Log(3, "$name:$reading: onTimeout function defined");;\
\
	#remove/cancel previous timers, because we got fresh data and countdown starts again\
	RemoveInternalTimer($name.$reading.'Timer');;\
	\
	#set timer to expire and execute function defined above, give special arg as identifier\
	InternalTimer(gettimeofday() + $timeoutTime, $timerFunction, $name.$reading.'Timer');;\
	\
	return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
\
ws_onConnectionAck:ws_websocketData:.*connection_ack.* {\
    #ws_websocketData contains the string "connection_ack"\
    Log(3, "$name:$reading: got connection ack");;\
    \
    # do not proceed if connection is lost\
    my $hash = $defs{$name};;\
    my $devState = DevIo_IsOpen($hash);;\
    return "Device not open" if (!defined($devState));;\
\
    readingsBulkUpdate($hash, "ws_cmd", "got connection ack");;\
    \
    my $homeId = AttrVal($name, "ws_homeId", "???");;\
       $homeId = KeyValue("read","EVU_Tibber_connect_homeID") if ($homeId eq "???");;\
\
    my $myId = AttrVal($name, "ws_myId", "???");;\
       $myId = KeyValue("read","EVU_Tibber_connect_homeID") if ($myId eq "???");;\
    \
    # build the query, do it in pieces, the comma at the end caused perl errors\
    # so we put it together in this not very elegant way\
    my $json = '{ "id":"'. $myId .'", "type":"subscribe"'.", ";;\
    $json .= '"payload":{';;\
    $json .= '"variables":{}'.", ";;\
    $json .= '"extensions":{}'.", ";;\
    $json .= '"query":"subscription { liveMeasurement( homeId: \"'.$homeId.'\" ) ';;\
    #$json .= '{ timestamp power accumulatedConsumption accumulatedCost currency minPower averagePower maxPower signalStrength }}"';;\
    $json .= '{ timestamp power lastMeterConsumption accumulatedConsumption accumulatedProduction ';;\
    $json .= 'accumulatedProductionLastHour accumulatedCost accumulatedReward currency minPower averagePower maxPower ';;\
    $json .= 'powerProduction powerReactive powerProductionReactive minPowerProduction maxPowerProduction lastMeterProduction ';;\
    $json .= 'powerFactor voltagePhase1 voltagePhase2 voltagePhase3 signalStrength }}"';;\
    $json .= '}}';;\
    \
    #send the string via websocket as ASCII\
    Log(3, "$name:$reading: sending JSON: >>>$json<<<");;\
    DevIo_SimpleWrite($hash, $json, 2);;\
        \
    return POSIX::strftime("%H:%M:%S",localtime(time()));;\
},\
\
ws_onNextLiveMeasurement:ws_websocketData:.*next.*payload.*data.*liveMeasurement.* {\
    #websocketData contains next-live-measurement-data\
    my $val = ReadingsVal($name, "ws_websocketData", "{}");;\
    my %res = %{json2nameValue($val, undef, undef, "payload_data_liveMeasurement.*")};;\
    \
    my $ret = "got values for:\n";;\
    foreach my $k (sort keys %res) {\
        $ret .= "$k\n";;\
        readingsBulkUpdate($hash, makeReadingName($k), $res{$k});;\
    }\
    return $ret;;\
},\
\
nodes_TIMESTAMP:nodes_00_00_cost.* {\
my ($timestamp,$value) = 2x0;;\
my $tmp = 0;;\
\
for (my $loop_last = 0;; $loop_last <= 2;; $loop_last++) {\
  $timestamp = ReadingsVal("$NAME","nodes_00_".sprintf("%02d",$loop_last)."_from","null");;\
  $value = ReadingsVal("$NAME","nodes_00_".sprintf("%02d",$loop_last)."_cost","null");;\
\
  if ( $value ne "null" ) {\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","nodes_00_".sprintf("%02d",$loop_last)."_consumption","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  } else {\
    $tmp = "null";;\
  }\
} # end for\
if ($tmp eq "null") {\
  $timestamp = $tmp\
}\
$timestamp;;\
},\
\
nodes_TIMESTAMP:nodes_24_00_cost.* {\
my ($timestamp,$value) = 2x0;;\
my $tmp = 0;;\
\
for (my $loop_last = 0;; $loop_last <= 23;; $loop_last++) {\
  $timestamp = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_from","null");;\
  $value = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_cost","null");;\
\
  if ( $value ne "null" ) {\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","nodes_24_".sprintf("%02d",$loop_last)."_consumption","null");;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  } else {\
    $tmp = "null";;\
  }\
} # end for\
if ($tmp eq "null") {\
  $timestamp = $tmp\
}\
$timestamp;;\
},\
\
nodes_TIMESTAMP:05_consumption_hourly_100-0001.* {\
my ($timestamp,$value) = 2x0;;\
\
for (my $loop_last = 1;; $loop_last <= 300;; $loop_last += 3) {\
\
  $timestamp =  ReadingsVal("$NAME","05_consumption_hourly_100-".sprintf("%04d",$loop_last+2),"null");; # timestamp\
  $timestamp =~ s/T/ /g ;;\
  $timestamp =  substr($timestamp,0,19);;\
  $value = ReadingsVal("$NAME","05_consumption_hourly_100-".sprintf("%04d",$loop_last+1),"null");;  # cost\
\
  if ( $value ne "" ) {\
    $value = round($value,4);;\
# print $timestamp." ".$value."\n";;\
\
    # Eintragen der Kosten für die Stunde\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_cost','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
    # Eintragen des Verbrauchs für die Stunde\
    $value = ReadingsVal("$NAME","05_consumption_hourly_100-".sprintf("%04d",$loop_last),"null");;  # consumption\
    $value = round($value,4);;\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
              INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                VALUES('".$timestamp."','$NAME','Tibber','nodes_consumption','".$value."')\
              ON DUPLICATE KEY UPDATE\
                VALUE='".$value."';;") ;;\
  }\
} # end for\
\
$timestamp;;\
},\
\
nodes_cost_avg:nodes_TIMESTAMP.* {\
## Berechnung des Tages Wertes\
  if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(avg(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
  } else {\
    ReadingsVal("$NAME","nodes_cost_avg","null")\
  }\
},\
\
nodes_cost_min:nodes_TIMESTAMP.* {\
##  Ermittlung des minimal Wertes\
if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
  ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(min(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
} else {\
  ReadingsVal("$NAME","nodes_cost_min","null")\
}\
},\
\
nodes_cost_max:nodes_TIMESTAMP.* {\
## Ermittlung des maximal Wertes\
  if ( ReadingsVal("$NAME","nodes_TIMESTAMP","null") ne "null" ) {\
    ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(max(VALUE)*100 AS DECIMAL(4,2)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND TIMESTAMP >= curdate() ;;") ;;\
  } else {\
    ReadingsVal("$NAME","nodes_cost_max","null")\
  }\
},\
\
nodes_consumption_day:nodes_TIMESTAMP.* {\
## Berechnung des Tages Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
nodes_consumption_month:nodes_TIMESTAMP.* {\
## Berechnung des Monats Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND YEAR(TIMESTAMP) = YEAR(curdate())\
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;") ;;\
},\
\
nodes_consumption_year:nodes_TIMESTAMP.* {\
## Berechnung des Jahres Verbrauches\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT cast(sum(VALUE) AS DECIMAL(10,4)) FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_consumption'\
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;") ;;\
},\
\
fc_avg:current_price.* {\
## Berechnung des durchschnitt Wertes\
  my $fc_avg = 0;;\
  my $fc = 0;;\
\
  if (ReadingsVal("$NAME","fc1_00_startsAt","null") ne "null") {       ## Der nächste Tag ist bereits da\
    if (AttrVal("$NAME","verbose",0) >=3) {\
      Log 3, "$NAME cmd_1  : Tibber Daten für fc1 sind bereits da";;\
    }\
    $fc = 1;;\
  } # end if\
\
    for (my $j=0;;$j<=$fc;;$j++){\
      for (my $k=0;;$k<=23;;$k++) {                                          ## Summe  berechnen\
        $fc_avg += ReadingsVal("$NAME",sprintf("fc%d_%02d_total",$j,$k),0);;\
        } # end $k\
    } # end $j\
\
    return round($fc_avg / (24 *(1+$fc)) *100 ,2);;                     ## Durchschnitt berechnen\
},\
\
fc_med:current_price.* {\
## Berechnung des median Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT\
             cast( (   (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), ',', floor(1+((count(VALUE)-1) / 2)))  , ',', -1))\
                       + (SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(VALUE order by VALUE), ',', ceiling(1+((count(VALUE)-1) / 2))), ',', -1))\
                     )/2 *100\
             AS DECIMAL(4,2))\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND (   READING='fc0_total' AND TIMESTAMP >= DATE_FORMAT(NOW(), '%Y-%m-%d 00:00:00')\
                     OR READING='fc1_total' AND TIMESTAMP >= DATE_FORMAT(NOW() + INTERVAL 1 DAY, '%Y-%m-%d 00:00:00') ) ;;") ;;\
},\
\
fc_min:current_price.* {\
##  Ermittlung des minimal Wertes\
  my $fc_min = 0;;\
  my $fc_tmp = 0;;\
  my $fc = 0;;\
\
  if (ReadingsVal("$NAME","fc1_00_startsAt","null") ne "null") {       ## Der nächste Tag ist bereits da\
    $fc = 1;;\
  } # end if\
\
    for (my $j=0;;$j<=$fc;;$j++){\
      for (my $k=0;;$k<=23;;$k++) {\
        $fc_tmp = ReadingsVal("$NAME",sprintf("fc%d_%02d_total",$j,$k),0);;\
  \
        if (($fc_tmp < $fc_min) or ($j == 0 and $k == 0)) {\
          $fc_min = $fc_tmp;;\
        }\
      } # end $k\
    } # end $j\
\
    return round($fc_min *100 ,2);;                             ## Von Euro auf Cent umrechnen\
},\
\
fc_max:current_price.* {\
##  Ermittlung des minimal Wertes\
  my $fc_max = 0;;\
  my $fc_tmp = 0;;\
  my $fc = 0;;\
\
  if (ReadingsVal("$NAME","fc1_00_startsAt","null") ne "null") {       ## Der nächste Tag ist bereits da\
    $fc = 1;;\
  } # end if\
\
    for (my $j=0;;$j<=$fc;;$j++){\
      for (my $k=0;;$k<=23;;$k++) {\
        $fc_tmp = ReadingsVal("$NAME",sprintf("fc%d_%02d_total",$j,$k),0);;\
  \
        if (($fc_tmp > $fc_max) or ($j == 0 and $k == 0)) {\
          $fc_max = $fc_tmp;;\
        }\
      } # end $k\
    } # end $j\
\
    return round($fc_max *100 ,2);;                             ## Von Euro auf Cent umrechnen\
},\
\
fc_trigger_price:fc_avg.* {\
## fc_trigger_price:[fc_avg|compensation_grid].* {\
  my $fc_avg = ReadingsVal("$NAME","fc_avg",0);;\
  my $fc_min = ReadingsVal("$NAME","fc_min",0);;\
\
  # Berechnung eines Default Schwellwertes als täglicher Niedrigpreis\
  my $price_level = round( ($fc_avg - $fc_min)/2 + $fc_min , 1);;\
  \
  # Abschätzung von Wirtschaftlichkeit beim Speicher Laden, falls Tibber zu teuer wird\
  if ( ReadingsVal("$NAME","compensation_grid",0) != 0 ) {\
    my $price_level_battery = round( ($fc_avg - ReadingsVal("$NAME","compensation_grid",0)) *0.85 , 1) ;;\
    if ( $price_level > $price_level_battery ) {\
      $price_level = $price_level_battery;;\
    }\
  }\
$price_level;;\
},\
\
fc0_trigger_start:fc_trigger_price.* {\
  my $fc_trigger_price = ReadingsVal("$NAME","fc_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
  my $fc_total = 0;;\
\
    for (my $loop_hour = $hour;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc0_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        return(sprintf("%02d:00",$loop_hour)) ;;\
      }\
    } # end  for loop_hour\
\
  return("null");;\
},\
\
fc0_trigger_stop:fc0_trigger_start.* {\
  my $fc = 0;;\
  my $loop_hour = 0;;\
  my $fc_trigger_price = ReadingsVal("$NAME","fc_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my $fc_trigger_start = ReadingsVal("$NAME","fc0_trigger_start","null");;\
  my $fc_trigger_stop = $fc_trigger_start;;\
\
  if ( $fc_trigger_start ne "null" ) {\
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\
    my $fc_total = 0;;\
\
    for ($loop_hour = $fc_trigger_start;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        $fc_trigger_stop = sprintf("%02d:00",$loop_hour) ;;\
      } else {\
        return(sprintf("%02d:00",$loop_hour));;\
      }\
\
     # wechsel zum nächsten Tag\
     if ( $loop_hour == 23 and $fc == 0 ) {\
       $fc = 1;;\
       $loop_hour = -1;;\
     }\
\
    } # end for loop_hour\
  }\
 \
  return($fc_trigger_stop);;\
},\
\
fc0_trigger:fc0_trigger_stop.* {\
\
  # Setzen des Triggers für die aktuelle Stunde\
  if ( ReadingsVal("$NAME","current_price",100)  < ReadingsVal("$NAME","fc_trigger_price",0) ) {\
    return("on")\
  } else {\
    return("off")\
  }\
},\
\
fc1_trigger_start:fc_trigger_price.* {\
  if (ReadingsVal("$NAME","fc1_00_startsAt","null") ne "null") {\
    my $fc_trigger_price = ReadingsVal("$NAME","fc_trigger_price",0) /100;;\
\
    # Ermitteln des nächsten Trigger Fensters\
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
    my $fc_total = 0;;\
\
    for (my $loop_hour = 0;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc1_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        return(sprintf("%02d:00",$loop_hour)) ;;\
      }\
    } # end  for loop_hour\
  }\
  return("null");;\
},\
\
fc1_trigger_stop:fc0_trigger_start.* {\
  my $loop_hour = 0;;\
  my $fc_trigger_price = ReadingsVal("$NAME","fc_trigger_price",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my $fc_trigger_start = ReadingsVal("$NAME","fc1_trigger_start","null");;\
  my $fc_trigger_stop = $fc_trigger_start;;\
\
  if ( $fc_trigger_start ne "null" ) {\
    $fc_trigger_start =~ /(\d\d):/;; $fc_trigger_start = $1 ;;\
    my $fc_total = 0;;\
\
    for ($loop_hour = $fc_trigger_start;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc1_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total < $fc_trigger_price ) {\
        $fc_trigger_stop = sprintf("%02d:00",$loop_hour) ;;\
      } else {\
        return(sprintf("%02d:00",$loop_hour));;\
      }\
\
    } # end for loop_hour\
  }\
 \
  return($fc_trigger_stop);;\
},\
\
fc_trigger_max:fc_avg.* {\
  my $fc_avg = ReadingsVal("$NAME","fc_avg",0);;\
  my $fc_max = ReadingsVal("$NAME","fc_max",0);;\
\
  # Berechnung eines Schwellwertes als täglichen Maximalpreises\
  my $price_level = round( ($fc_max - $fc_avg)/2 + $fc_avg , 0);;\
  \
$price_level;;\
},\
\
fc0_trigger_max_start:fc_trigger_max.* {\
  my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;;\
\
  # Ermitteln des nächsten Trigger_max Fensters\
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
  my $fc_total = 0;;\
\
    for (my $loop_hour = $hour;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc0_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total > $fc_trigger_max ) {\
        return(sprintf("%02d:00",$loop_hour)) ;;\
      }\
    } # end  for loop_hour\
\
  return("null");;\
},\
\
fc0_trigger_max_stop:fc0_trigger_max_start.* {\
  my $fc = 0;;\
  my $loop_hour = 0;;\
  my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my $fc_trigger_max_start = ReadingsVal("$NAME","fc0_trigger_max_start","null");;\
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\
\
  if ( $fc_trigger_max_start ne "null" ) {\
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\
    my $fc_total = 0;;\
\
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc".$fc."_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total > $fc_trigger_max ) {\
        $fc_trigger_max_stop = sprintf("%02d:00",$loop_hour) ;;\
      } else {\
        return(sprintf("%02d:00",$loop_hour));;\
      }\
\
     # wechsel zum nächsten Tag\
     if ( $loop_hour == 23 and $fc == 0 ) {\
       $fc = 1;;\
       $loop_hour = -1;;\
     }\
\
    } # end for loop_hour\
  }\
 \
  return($fc_trigger_max_stop);;\
},\
\
fc0_trigger_max:fc0_trigger_max_stop.* {\
\
  # Setzen des maximum Triggers für die aktuelle Stunde\
  if ( ReadingsVal("$NAME","current_price",0)  > ReadingsVal("$NAME","fc_trigger_max",0) ) {\
    return("on")\
  } else {\
    return("off")\
  }\
},\
\
fc1_trigger_max_start:fc_trigger_max.* {\
  if (ReadingsVal("$NAME","fc1_00_startsAt","null") ne "null") {\
    my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;;\
\
    # Ermitteln des nächsten Trigger Fensters\
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);; $year += 1900;; $mon += 1 ;;\
    my $fc_total = 0;;\
\
    for (my $loop_hour = 0;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc1_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total > $fc_trigger_max ) {\
        return(sprintf("%02d:00",$loop_hour)) ;;\
      }\
    } # end  for loop_hour\
  }\
  return("null");;\
},\
\
fc1_trigger_max_stop:fc0_trigger_max_start.* {\
  my $loop_hour = 0;;\
  my $fc_trigger_max = ReadingsVal("$NAME","fc_trigger_max",0) /100;;\
\
  # Ermitteln des nächsten Trigger Fensters\
  my $fc_trigger_max_start = ReadingsVal("$NAME","fc1_trigger_max_start","null");;\
  my $fc_trigger_max_stop = $fc_trigger_max_start;;\
\
  if ( $fc_trigger_max_start ne "null" ) {\
    $fc_trigger_max_start =~ /(\d\d):/;; $fc_trigger_max_start = $1 ;;\
    my $fc_total = 0;;\
\
    for ($loop_hour = $fc_trigger_max_start;; $loop_hour <= 23;; $loop_hour++) {\
      $fc_total = ReadingsVal("$NAME","fc1_".sprintf("%02d",$loop_hour)."_total",0);;\
      if ( $fc_total > $fc_trigger_max ) {\
        $fc_trigger_max_stop = sprintf("%02d:00",$loop_hour) ;;\
      } else {\
        return(sprintf("%02d:00",$loop_hour));;\
      }\
\
    } # end for loop_hour\
  }\
 \
  return($fc_trigger_max_stop);;\
},\
\
total_cost_day:nodes_TIMESTAMP.* {\
## Berechnung des Tages Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND date(TIMESTAMP) = curdate() ;;") ;;\
},\
\
total_cost_month:nodes_TIMESTAMP.* {\
## Berechnung des monats Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND YEAR(TIMESTAMP) = YEAR(curdate())\
             AND MONTH(TIMESTAMP) = MONTH(curdate()) ;;") ;;\
},\
\
total_cost_year:nodes_TIMESTAMP.* {\
## Berechnung des Jahres Wertes\
::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
           SELECT CAST(SUM(VALUE) AS DECIMAL(8,2)) AS VALUE\
           FROM history\
           WHERE DEVICE='".$NAME."'\
             AND READING='nodes_cost'\
             AND YEAR(TIMESTAMP) = YEAR(curdate()) ;;") ;;\
},\
\
fc_DbLog:fc0_00_total.* {\
my ($timestamp,$date,$hour,$value,$loop_fc_next) = 5x0;;\
\
for (my $loop_fc = 0;; $loop_fc <= 1;; $loop_fc++) {\
  $loop_fc_next = $loop_fc +1;;\
  $date = ReadingsVal("$NAME","fc".$loop_fc."_00_startsAt","null");;\
  if ($date ne "null") {\
    $date =~ /([\d+-]+)/;; $date = $1 ;;\
    for (my $loop_hour = 0;; $loop_hour <= 23;; $loop_hour++) {\
      $hour = sprintf("%02d",$loop_hour);;\
      $timestamp = $date." ".$hour.":00:00";;\
      $value = ReadingsVal("$NAME","fc".$loop_fc."_".$hour."_total","null");;\
      ::CommandGet(undef, "LogDBRep_".$NAME."_SQL sqlCmdBlocking\
                        INSERT INTO history (TIMESTAMP,DEVICE,TYPE,READING,VALUE)\
                          VALUES('".$timestamp."','$NAME','Tibber','fc".$loop_fc."_total','".$value."')\
                        ON DUPLICATE KEY UPDATE\
                          VALUE='".$value."';;") ;;\
    }\
    if (ReadingsVal("$NAME","fc".$loop_fc."_00_startsAt","null") eq ReadingsVal("$NAME","fc".$loop_fc_next."_00_startsAt","null")) {\
      fhem("deletereading $NAME fc".$loop_fc_next."_.*");;\
    }\
  } else {\
      fhem("deletereading $NAME fc1_.*");;\
  }\
}\
ReadingsTimestamp("$NAME","fc0_00_startsAt","null");;\
}
attr EVU_Tibber_connect verbose 0
attr EVU_Tibber_connect ws_minInterval 54
attr EVU_Tibber_connect ws_websocketURL wss:websocket-api.tibber.com:443/v1-beta/gql/subscriptions