NetAtmo Wetterdaten HOWTO

Problemlösungen und Hinweise von allgemeinem Interesse zur Haussteuerung mit HomeMatic

Moderator: Co-Administratoren

Steffen B.
Beiträge: 5
Registriert: 07.09.2024, 20:06
System: CCU

Re: NetAtmo Wetterdaten HOWTO

Beitrag von Steffen B. » 11.09.2025, 19:47

Hallo zusammen.

Mich hat die Domain-Umstellung von Netatmo ganz schön ins Grübeln gebracht. Nix ging mehr. Heute bin ich der Sache auf den Grund gegangen und dabei auf diesen Text gestoßen: We will be retiring the domain api.netatmo.net and consolidating all API traffic under the existing domain api.netatmo.com on September 8, 2025.
Die Domain-Änderung ist in dieser Version der netatmo.tcl eingearbeitet. Zudem habe ich auf meiner CCU3 das Problem, dass die im tmp-Verzeichnis abgelegte netatmo.dat nach einem Neustart der CCU gelöscht war. Ich habe sie daher nach /usr/local/addons/netatmo/ verschoben. Diese Pfadänderung ist ebenfalls eingearbeitet.

Code: Alles auswählen

# Ausführung in der WinSCP-Terminal: tclsh netatmo.tcl oder tclsh netatmo.tcl -cfginfo 
#!/bin/tclsh

# Steffen B. 11.09.2025   auf Basis von Indigo aus 2015

    load tclrega.so

    #---------------------------------------------------------------------------------------------------------------#
    #                                                   CONFIG                                                      #
    #---------------------------------------------------------------------------------------------------------------#
    #  to obtain your own client ID and API key please register a new app here: http://dev.netatmo.com/dev/listapps
    #set clientId "xxxxxxxxxxxxxxxxxxxxxxxx"                     
    #set clientSecret "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    #  the following are MAC addresses of your indoor station and the outside module and rain module
    #set deviceid "XX:XX:XX:XX:XX:XX"
    #set moduleid "XX:XX:XX:XX:XX:XX"
    #set rainid "XX:XX:XX:XX:XX:XX"
    set windid "XX:XX:XX:XX:XX:XX"
    
    set ::env(LD_LIBRARY_PATH) "/usr/local/addons/cuxd"
    #set cfgfile "/tmp/netatmo.dat" Pfad geändert 10.09.2025
    set cfgfile "/usr/local/addons/netatmo/netatmo.dat" 
    set logtag "netatmo.tcl"
    set logfacility "local1"
    # 0=panic, 1=alert 2=crit 3=err 4=warn 5=notice 6=info 7=debug
    set loglevel 6
    #---------------------------------------------------------------------------------------------------------------#

    #---------------------------------------------------------------------------------------------------------------#
    #                                              GLOBAL VARIABLES                                                 #
    #---------------------------------------------------------------------------------------------------------------#
    set startprm ""
    set accesstoken ""
    set refreshtoken ""
    set tokenexpireU 0
    #---------------------------------------------------------------------------------------------------------------#


    set loglevels {panic alert crit err warn notice info debug}

    proc log {lvl msg} {
        global logtag
        global logfacility
        global loglevel
        global loglevels
       
        set lvlnum [lsearch $loglevels $lvl]
       
        if {$lvlnum <= $loglevel} {
            if {$lvlnum <= 3} {
                catch {exec logger -s -t $logtag -p $logfacility.$lvl $msg}
            } else {
                puts "$lvl: $msg"
                catch {exec logger -t $logtag -p $logfacility.$lvl $msg}
            }
           
        }
       
    }

    proc loadAccessToken {} {
        global accesstoken
        global refreshtoken
        global tokenexpireU
        global cfgfile
        global startprm
       
        log info "loading file content from $cfgfile."
       
        set fp [open $cfgfile r]
        set file_data [read $fp]
        close $fp
       
        log debug "file content is:\n$file_data"
       
        set data [split $file_data "\n"]   
       
        set accesstoken  [lindex $data 0]
        set refreshtoken [lindex $data 1]
        set tokenexpireU [lindex $data 2]
        set tokenexpireN [lindex $data 3]
        set tokenscope   [lindex $data 4]
        #set tokenexpireN [clock format $tokenexpireU -format "%H:%M:%S"]
        
        log info "accesstoken  is: $accesstoken"
        log info "refreshtoken is: $refreshtoken"
        log info "tokenexpireU is: $tokenexpireU"
        log info "tokenexpireN is: $tokenexpireN"
        log info "tokenscope   is: $tokenscope"
        
        if {$startprm == "-cfginfo"} {
            log info "script has been terminated."        
            exit 0
        } 
    }
    
    proc refreshToken {rt ci cs} {
        log debug "refreshing token."
        set url "https://api.netatmo.com/oauth2/token"
        set header "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
        set parameter "grant_type=refresh_token&refresh_token=$rt&client_id=$ci&client_secret=$cs"

        catch {exec /usr/local/addons/cuxd/curl -k -i -H $header -X POST -d $parameter $url} response
        log debug "response was $response"
       
        return $response

    }      

    proc parseOAuthResponse {input} {
        log debug "parsing authentication result."
        global accesstoken
        global refreshtoken
       
        regexp {HTTP/1.1\s(\d*)} $input dummy returncode
        regexp {\"access_token\":\"(.*?)\"} $input dummy accesstoken
        regexp {\"refresh_token\":\"(.*?)\"} $input dummy refreshtoken
        regexp {\"expires_in\":(.*?)\,} $input dummy expiresin
        regexp {\"scope\":\s*(\[[^\]]*\])} $input dummy scope

        log debug "returncode is $returncode"
        log debug "accesstoken is $accesstoken"
        log debug "refreshtoken is $refreshtoken"
        log debug "expires in $expiresin"
        log debug "scope is $scope"
       
        if {[expr $returncode]!=200} {
            log error "Authentication failed with code $returncode and response $input."
            exit 1
        }

        return "$expiresin $scope"
    }

    proc saveAccessToken {input} {
        global accesstoken
        global refreshtoken
        global tokenexpireU
        global cfgfile
        
        set input [split $input " "]
        set expin [lindex $input 0]
        set scope [lindex $input 1]
       
        set now [clock seconds]
        set tokenexpireU [expr $now + $expin]
                
        # Umwandlung der Unix-Zeit in Normal-Zeit
        set tokenexpireN [clock format $tokenexpireU -format "%H:%M:%S"]
        log notice "new accesstoken expires at $tokenexpireN."
        
        log debug "saving new token to $cfgfile."
       
        set fileId [open $cfgfile "w"]
       
        puts $fileId $accesstoken
        puts $fileId $refreshtoken
        puts $fileId $tokenexpireU
        puts $fileId $tokenexpireN
        puts $fileId $scope
        
        close $fileId
    }
   
log debug "Script has been started."

set startprm [lindex $argv 0]

if { [file exists $cfgfile] == 1} {
    log info "cfgfile $cfgfile found."
        loadAccessToken
        set now [clock seconds]
        log debug "current time is [clock format $now -format "%Y-%m-%dT%H:%M:%S"], accesstoken expires at [clock format $tokenexpireU -format "%Y-%m-%dT%H:%M:%S"]"
        if {[expr $now >= $tokenexpireU] == 1} {
            log notice "token has already expired."
            saveAccessToken [parseOAuthResponse [refreshToken $refreshtoken $clientId $clientSecret]]
            log notice "oauth token successfully refreshed."
        } else {
            log info "token is still valid."
        }
    } else {
        log info "cfgfile $cfgfile not found."
        log info "create a new file with PC cmd: python NetatmoInitialRequest.py."
        log info "copy the new file from PC %tmp%/netatmo.dat to CCU $cfgfile."
    }
    
# Info for Weather Station:
# max -> Temperature, CO2, Humidity, Pressure, Noise, Rain (if module_id is a rain sensor)
# 30min, 1hour, 3hours -> Temperature, CO2, Humidity, Pressure, Noise, min_temp, max_temp, min_hum, max_hum, min_pressure, max_pressure, min_noise, max_noise, sum_rain (if module_id is a rain sensor)
# 1day, 1week, 1month -> Temperature, Co2, Humidity, Pressure, Noise, min_temp, date_min_temp, max_temp, date_max_temp, min_hum, date_min_hum, max_hum, date_max_hum, min_pressure, date_min_pressure, max_pressure, date_max_pressure, min_noise, date_min_noise, max_noise, date_max_noise, date_min_co2, date_max_co2, sum_rain (if module_id is a rain sensor)    
    
if {$deviceid != "XX:XX:XX:XX:XX:XX"} {
    log debug "polling main module..."
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&scale=max&type=Temperature,Humidity,CO2,Pressure,Noise&date_end=last"
    log debug "querying $url"
    catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
    log debug "response is: $response"

    regexp {\"value\":\[\[(.*?),(.*?),(.*?),(.*?),(.*?)\]} $response dummy itemp ihum ico2 ipressure inoise
    
    log debug "LogI is $response"              
    log info "Inside temperature is $itemp"
    log info "Inside humidity is $ihum"
    log info "Inside CO2 level $ico2"
    log info "Inside pressure is $ipressure"
    log info "Inside noise level is $inoise"
}

if {$moduleid != "XX:XX:XX:XX:XX:XX"} {
    log debug "polling outdoor module..."
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&module_id=$moduleid&scale=max&type=Temperature,Humidity&date_end=last"
    log debug "querying $url"
    catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
    log debug "response is: $response"

    regexp {\"value\":\[\[(.*?),(.*?)\]} $response dummy otemp ohum

    log info "Outside temperature is $otemp"
    log info "Outside humidity is $ohum"
}

if {$rainid != "XX:XX:XX:XX:XX:XX"} {

    log debug "polling regensensor module...30min"
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&module_id=$rainid&scale=30min&type=Rain,sum_rain&date_end=last"
    log debug "querying $url"
    catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
    log debug "response is: $response"

    regexp {\"value\":\[\[(.*?),(.*?)\]} $response dummy rainNow rain30min
    
    log debug "LogR is $response"                
    log info "Outside rainNow is $rainNow"
    log info "Outside rain30min is $rain30min"

    log debug "polling regensensor module...1h"
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&module_id=$rainid&scale=1hour&type=Rain,sum_rain&date_end=last"
    log debug "querying $url"
    catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
    log debug "response is: $response"

    regexp {\"value\":\[\[(.*?),(.*?)\]} $response dummy dummy rain1h
    
    log debug "LogR is $response"                
    log info "Outside rain1h is $rain1h"
    
    log debug "polling regensensor module...1d"
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&module_id=$rainid&scale=1day&type=sum_rain&date_end=last"
    log debug "querying $url"
    catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
    log debug "response is: $response"

    regexp {\"value\":\[\[(.*?)\]} $response dummy rain1d
    
    log debug "LogR is $response"                
    log info "Outside rain1d is $rain1d"
    
    log debug "polling regensensor module...1w"
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&module_id=$rainid&scale=1week&type=sum_rain&date_end=last"
    log debug "querying $url"
    catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
    log debug "response is: $response"

    regexp {\"value\":\[\[(.*?)\]} $response dummy rain1w
    
    log debug "LogR is $response"                
    log info "Outside rain1w is $rain1w"

  }

if { $windid != "XX:XX:XX:XX:XX:XX"} {
    log debug "polling wind module..."
    set url "https://api.netatmo.com/api/getmeasure?access_token=$accesstoken&device_id=$deviceid&module_id=$windid&scale=max&type=WindAngle,WindStrength,GustAngle,GustStrength&date_end=last"
   log debug "quering $url"
   catch {exec /usr/local/addons/cuxd/curl -k -# $url} response
   log debug "respnose is $response"

   regexp {\"value\":\[\[(.*?),(.*?),(.*?),(.*?)\]} $response dummy windangle windstrength gustangle guststrength
   log info "WindAngle is $windangle"
   log info "Windstrength is $windstrength"
   log info "GustAngle is $gustangle"
   log info "Guststrength is $guststrength"
}

# set ReGaHss variables

set rega_cmd ""

append rega_cmd "var ITemp = dom.GetObject('CUxD.CUX9002001:1.SET_TEMPERATURE');"
append rega_cmd "var IHumi = dom.GetObject('CUxD.CUX9002001:1.SET_HUMIDITY');"

if {$moduleid != "XX:XX:XX:XX:XX:XX"} {
    append rega_cmd "var OTemp = dom.GetObject('CUxD.CUX9002002:1.SET_TEMPERATURE');"
    append rega_cmd "var OHumi = dom.GetObject('CUxD.CUX9002002:1.SET_HUMIDITY');"
}

if {$rainid != "XX:XX:XX:XX:XX:XX"} {
    append rega_cmd "var Rain1 = dom.GetObject('Regenmenge_aktuell');"
    append rega_cmd "var Rain2 = dom.GetObject('Regenmenge_30min');"
    append rega_cmd "var Rain3 = dom.GetObject('Regenmenge_1h');"
    append rega_cmd "var Rain4 = dom.GetObject('Regenmenge_1d');"
    append rega_cmd "var Rain5 = dom.GetObject('Regenmenge_1w');"
}

append rega_cmd "var IPress = dom.GetObject('Luftdruck');"
append rega_cmd "var ICO2 = dom.GetObject('CO2');"
append rega_cmd "var INoise = dom.GetObject('Sonometer');"

if {$windid != "XX:XX:XX:XX:XX:XX"} {
    append rega_cmd "var windA = dom.GetObject('Windrichtung');"
    append rega_cmd "var windS = dom.GetObject('Windstaerke');"
    append rega_cmd "var gustA = dom.GetObject('Gustangle');"
    append rega_cmd "var gustS = dom.GetObject('Guststaerke');"
}

if {$moduleid != "XX:XX:XX:XX:XX:XX"} {
    append rega_cmd "OTemp.State('$otemp');"
    append rega_cmd "OHumi.State('$ohum');"
}

append rega_cmd "ITemp.State('$itemp');"
append rega_cmd "IHumi.State('$ihum');"
append rega_cmd "IPress.State('$ipressure');"
append rega_cmd "ICO2.State('$ico2');"
append rega_cmd "INoise.State('$inoise');"

if {$rainid != "XX:XX:XX:XX:XX:XX"} {
    append rega_cmd "Rain1.State('$rainNow');"
    append rega_cmd "Rain2.State('$rain30min');"    
    append rega_cmd "Rain3.State('$rain1h');"
    append rega_cmd "Rain4.State('$rain1d');"
    append rega_cmd "Rain5.State('$rain1w');"
}

if {$windid != "XX:XX:XX:XX:XX:XX"} {
    append rega_cmd "windA.State('$windangle');"
    append rega_cmd "windS.State('$windstrength');"
    append rega_cmd "gustA.State('$gustangle');"
    append rega_cmd "gustS.State('$guststrength');"
}

append rega_cmd "var sdatetime = system.Date('%d.%m.%Y %H:%M:%S');"
append rega_cmd "var netatmosynctime = dom.GetObject('SyncTime');"
append rega_cmd "netatmosynctime.Variable(sdatetime.ToString());"

rega_script $rega_cmd

log debug "rega_cmd is $rega_cmd"

log info "script has been terminated."
CCU3, HmIP-MOD-OC8 + ELV-SH-GVI + 8x Hunter Magnetventil PGV-101-G-B, TinyMatic-App

klausi0812
Beiträge: 9
Registriert: 15.05.2018, 21:51
System: CCU
Wohnort: Orth an der Donau / NÖ
Hat sich bedankt: 3 Mal
Danksagung erhalten: 1 Mal

Re: NetAtmo Wetterdaten HOWTO

Beitrag von klausi0812 » 05.05.2026, 10:39

FYI, offenbar sind die API Services von Netatmo aktuell unterbrochen:
https://helpcenter.netatmo.com/hc/en-us ... 03-05-2026
Zumindest bei mir klappen die API Abrufe über OAuth seit 03.05.2026 ca 17 Uhr nicht mehr.

Germa
Beiträge: 187
Registriert: 15.12.2019, 12:26
System: CCU
Hat sich bedankt: 36 Mal
Danksagung erhalten: 25 Mal

Re: NetAtmo Wetterdaten HOWTO

Beitrag von Germa » 05.05.2026, 10:52

die hatten einen Serverausfall ca. ab 1 Uhr Sonntag, bis ca. 15 Uhr. Seit dem geht aber alles wieder
wenn wir uns alle gegenseitig helfen, ist allen geholfen :wink:
_______________________________________________
CCU3 seit 2018, 103 Geräte, 202 Programme, 222 sysvar
Projekte: Wettersensor viewtopic.php?t=65631

klausi0812
Beiträge: 9
Registriert: 15.05.2018, 21:51
System: CCU
Wohnort: Orth an der Donau / NÖ
Hat sich bedankt: 3 Mal
Danksagung erhalten: 1 Mal

Re: NetAtmo Wetterdaten HOWTO

Beitrag von klausi0812 » 05.05.2026, 18:27

Bei mir läuft es wieder. Ich habe die Codes auf dem NAS gelöscht, beim nächsten Aufruf wurden die neu generiert und der Zugriff + Auth. klappt wieder. Netatmo's API braucht eindeutig immer wieder Aufmerksamkeit.

Antworten

Zurück zu „HomeMatic Tipps & Tricks - keine Fragen!“