Seite 1 von 1

Abfrage von luftdaten.info mit Python

Verfasst: Donnerstag 21. März 2019, 23:18
von eagleflight
Der Noob lässt mal wieder grüßen :)
Diesmal mit einen JSON Problem

Über ein Nodemcu werden Daten eines Feinstaubsensors and die Website luftdaten.info übertragen und können dort mittels request wieder abgeholt werden. Die Daten werden als Json String bereitgestellt. Für die Daten gibt es zwei unterschiedliche Adressen. (siehe Skript).
Die Abfrage stammt aus dem Netz und wurde von mir angepasst.

Nachdem mein Skript seit ca. 3 Wochen permanent in einer 10 Min Schleife läuft, habe ich festgestellt, dass es öfter unregelmässig zu Falschauswertungen im Json.load kommt. Hier werden Werte vertauscht so daß der String nicht mehr sauber aufgelöst werden kann. Am Ende sind die Positionen von Temperatur und Humidity vertauscht. :/ Laut Betreiber der Website wäre der Json String immer gleich.

Gibt es eine Möglichkeit die Werte direkt aus den Json-String bzw. dem JSON Dictionary auszulesen und sich die Sucherrei im geparsten String zu ersparen ? Gestern lief es ohne Probleme, heute sind wieder die letzten Positionen vertauscht, damit kommt nur Müll raus :/.
Gibt es vielleicht so etwas wie einen Pointer o.ä. den man bei json.loads auf Anfang stellen muss ?

Hier der lauffähige Code Auszug mit den URL's.

Code: Alles auswählen


#!/usr/bin/python
# -*- coding: utf-8 -*-
# depends: python-requests
import time
import requests
import json

def pick_luftdaten_values(sensor):
    # Sensordaten für SDS011 und DHT11 abfragen
    # dazu die api von luftdaten.info nutzen
    
    r = requests.get(sensor)
    json_string = r.text
    parsed_json = json.loads(json_string)
 
    # print( json.dumps(parsed_json, sort_keys=True, indent=4, separators=(',',':')))
    
    l = len(parsed_json)-1
    a = len(parsed_json[l]['sensordatavalues'])
         
    if a == 1:
        result=(parsed_json[l]['sensordatavalues'][0]['value_type'])+": "+(parsed_json[l]['sensordatavalues'][0]['value'])
    if a == 2:
        result=(parsed_json[l]['sensordatavalues'][0]['value_type'])+": "+(parsed_json[l]['sensordatavalues'][0]['value'])
        result=result+" "+(parsed_json[l]['sensordatavalues'][1]['value_type'])+": "+(parsed_json[l]['sensordatavalues'][1]['value'])
    return(result)


#  Sensor Nummer 22451 und 22452
def luftdatenabfrage():
    try:
        url = 'http://api.luftdaten.info/static/v1/sensor/22451/'
        tweet = pick_luftdaten_values(url)
        
        #print(tweet)

        url = 'http://api.luftdaten.info/static/v1/sensor/22452/'
        tweet = tweet + " " + pick_luftdaten_values(url)
        
        #print(tweet)
        
        p1 = float(tweet[tweet.find('P1:') +3 : tweet.find("P2:")-1])
        p2 = float(tweet[tweet.find('P2:') +3 : tweet.find("humidity")-1])
        h1 = float(tweet[tweet.find('humidity:') + 10 : tweet.find("temperature")-1])
        t1 = float(tweet[tweet.find('temperature:') +13 : len(tweet)])               
        
    except:
        p1 = 0
        p2 = 0
        h1 = 0
        t1 = 0
        tweet = "no data available"
    
    finally:
        return(tweet, p1, p2, h1, t1)    
    

tweet, p1, p2, h1, t1 = luftdatenabfrage()

print(tweet)
print(p1)
print(p2)
print(h1)
print(t1)


Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 01:18
von __blackjack__
@eagleflight: Könntest Du das Problem etwas genauer beschreiben? Was passiert genau und was erwartest Du stattdessen? Und warum verbastelst Du das erst so völlig unübersichtlich in eine Zeichenkette um danach dann wieder irgendwelche Werte aus dieser Zeichenkette heraus zu kratzen?

Falls die Elemente zu 'sensordatavalues' nicht immer die gleiche Reihenfolge haben sollten: Das macht ja nichts weil die durch den 'valuetype'-Wert ja identifiziert werden können.

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 08:07
von sparrow
Der Code schießt sich selbst in dem Fuß.
Ist das irgendwelcher umgebauter Beispielcode für einen Twitter-Client? Oder warum heißen da Variablen "tweet"?

Wenn doch schon json zurück kommt, dann sollte man das auch sauber verarbeiten.

Hier mal die Ausgabe der Website formatiert. Das hilft ja manchmal den Überblick zu behalten:

Code: Alles auswählen

[  
   {  
      "id":3166869294,
      "sensordatavalues":[  
         {  
            "value":"59.70",
            "id":6721847928,
            "value_type":"humidity"
         },
         {  
            "value":"9.50",
            "id":6721847927,
            "value_type":"temperature"
         }
      ],
      "timestamp":"2019-03-22 06:59:44",
      "sensor":{  
         "id":22452,
         "pin":"7",
         "sensor_type":{  
            "manufacturer":"various",
            "name":"DHT22",
            "id":9
         }
      },
      "sampling_rate":null,
      "location":{  
         "altitude":"135.2",
         "id":11393,
         "country":"DE",
         "longitude":"8.8600",
         "latitude":"49.9480"
      }
   },
   {  
      "id":3166883398,
      "sensordatavalues":[  
         {  
            "value":"60.30",
            "id":6721877603,
            "value_type":"humidity"
         },
         {  
            "value":"9.60",
            "id":6721877602,
            "value_type":"temperature"
         }
      ],
      "timestamp":"2019-03-22 07:02:11",
      "sensor":{  
         "id":22452,
         "pin":"7",
         "sensor_type":{  
            "manufacturer":"various",
            "name":"DHT22",
            "id":9
         }
      },
      "sampling_rate":null,
      "location":{  
         "altitude":"135.2",
         "id":11393,
         "country":"DE",
         "longitude":"8.8600",
         "latitude":"49.9480"
      }
   }
]

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 08:20
von eagleflight
Guten Morgen
Es gibt 2 URL#s die abgefragt werden müssen. Einmal die Feinstaubwerte und zum Zweiten die Temperatur und Feuchtewerte. Die setzte ich beide zusammen und daraus entsteht folgender Json String aus dem die Sektionen "sensordatavalues - P1, P2" und "sensordatavalues - humidity und temperature" herausgeholt werden müssen. Aber irgendwie scheint sich bei meiner Version der Sting zu ändern, jedenfalls ging es gestern Abend nicht und heute früh kommt wieder das richtige Ergebnis :roll: Ich suche jetzt den Weg wie man direkt auf die Values zugreifen kann ohne diese Stringfummelei.

Code: Alles auswählen

[
    {
        "id":3166925901,
        "location":{
            "altitude":"135.2",
            "country":"DE",
            "id":11393,
            "latitude":"49.9480",
            "longitude":"8.8600"
        },
        "sampling_rate":null,
        "sensor":{
            "id":22451,
            "pin":"1",
            "sensor_type":{
                "id":14,
                "manufacturer":"Nova Fitness",
                "name":"SDS011"
            }
        },
        "sensordatavalues":[
            {
                "id":6721966975,
                "value":"27.80",
                "value_type":"P1"
            },
            {
                "id":6721966977,
                "value":"4.62",
                "value_type":"P2"
            }
        ],
        "timestamp":"2019-03-22 07:09:35"
    },
    {
        "id":3166940390,
        "location":{
            "altitude":"135.2",
            "country":"DE",
            "id":11393,
            "latitude":"49.9480",
            "longitude":"8.8600"
        },
        "sampling_rate":null,
        "sensor":{
            "id":22451,
            "pin":"1",
            "sensor_type":{
                "id":14,
                "manufacturer":"Nova Fitness",
                "name":"SDS011"
            }
        },
        "sensordatavalues":[
            {
                "id":6721997451,
                "value":"19.98",
                "value_type":"P1"
            },
            {
                "id":6721997452,
                "value":"3.72",
                "value_type":"P2"
            }
        ],
        "timestamp":"2019-03-22 07:12:07"
    }
]
[
    {
        "id":3166926200,
        "location":{
            "altitude":"135.2",
            "country":"DE",
            "id":11393,
            "latitude":"49.9480",
            "longitude":"8.8600"
        },
        "sampling_rate":null,
        "sensor":{
            "id":22452,
            "pin":"7",
            "sensor_type":{
                "id":9,
                "manufacturer":"various",
                "name":"DHT22"
            }
        },
        "sensordatavalues":[
            {
                "id":6721967612,
                "value":"57.60",
                "value_type":"humidity"
            },
            {
                "id":6721967611,
                "value":"10.80",
                "value_type":"temperature"
            }
        ],
        "timestamp":"2019-03-22 07:09:39"
    },
    {
        "id":3166940454,
        "location":{
            "altitude":"135.2",
            "country":"DE",
            "id":11393,
            "latitude":"49.9480",
            "longitude":"8.8600"
        },
        "sampling_rate":null,
        "sensor":{
            "id":22452,
            "pin":"7",
            "sensor_type":{
                "id":9,
                "manufacturer":"various",
                "name":"DHT22"
            }
        },
        "sensordatavalues":[
            {
                "id":6721997587,
                "value":"57.00",
                "value_type":"humidity"
            },
            {
                "id":6721997586,
                "value":"11.40",
                "value_type":"temperature"
            }
        ],
        "timestamp":"2019-03-22 07:12:08"
    }
]
P1: 19.98 P2: 3.72 humidity: 57.00 temperature: 11.40
19.98
3.72
57.0
11.4

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 08:26
von eagleflight
Ja, der Code kommt von einer Website die einen Tweet für Twitter erzeugt. Ich habe den einfach übernommen, weil er auf Anhieb ein brauchbares Ergebnis geliefert hat. Jetzt, nach einiger Zeit stellt sich aber heraus, das wohl irgendwo ein Bug drinnen ist. Ab und zu sind am Ende des Strings die Werte temperature und humidity vertauscht.

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 08:53
von kbr
Was heißt vertauscht? Ist nur die Ausgabe vertauscht oder sind die Werte selbst vertauscht? Interpretierst Du die Daten als String oder liest Du sie (hoffentlich) per json.loads ein?

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 08:55
von Sirius3
@eagleflight: requests kann auch direkt json als Ergebnis liefern.
`l` und `a` sind schlechte Variablennamen. Wenn man das letzte Element einer Liste will, kann man auch mit negativen Indices arbeiten.
Es ist schlecht, innerhalbe eines Programms mit formatierten Strings zu arbeiten (wobei wenn es gebraucht wird format besser ist als Strings mit + zusammenzustückeln). Das einfachste wäre, ein Wörterbuch zu benutzen.
`return` ist keine Funktion, die Klammern also überflüssig.

Nakte `except` sollte man nicht benutzten, weil die auch viele Programmierfehler abfangen. Immer so konkret wie möglich die Exception angeben, und auch nur dann, wenn der Fehler sinnvoll behandelt werden kann. Eine Exception in einen String "no data available" umzuwandeln, ist z.B. hier nicht sinnvoll.

Wenn Du mit Wörterbüchern arbeitest, brauchst Du auch keine Stringsuchfunktionen.
Du benutzt Python2 (besser auf Python3 umsteigen!) und dort ist `print` keine Funktion, die Klammern gehören also weg.

Code: Alles auswählen

import requests

SENSOR_URL = "http://api.luftdaten.info/static/v1/sensor/{}"

def pick_luftdaten_values(sensor_id):
    # Sensordaten für SDS011 und DHT11 abfragen
    # dazu die api von luftdaten.info nutzen
    result = requests.get(SENSOR_URL.format(sensor_id))
    data = result.json()
    return {d['value_type']: d['value'] for d in data[-1]['sensordatavalues']}


#  Sensor Nummer 22451 und 22452
def luftdatenabfrage():
    sensor_p = pick_luftdaten_values(22451)
    sensor_h = pick_luftdaten_values(22452)
    return sensor_p['P1'], snesor_p['P2'], sensor_h['humidity'], sensor_h['temperature']

p1, p2, h1, t1 = luftdatenabfrage()
print p1
print p2
print h1
print t1

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 09:30
von sparrow
Wenn ich das richtig sehe, befindet sich in den Daten ja auch mehr als eine Messung.
Vielleicht wäre es auch sinnvoll zu schauen, ob die Daten bereits vorliegen.

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 11:22
von eagleflight
@ Sirius

Du iritierst mich etwas mit Deinen Aussagen bezgl. print :shock:
Ich benutze sicher Python3 und bekomme einen Fehler, wenn ich print ohne Klammer benutze :?

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/pi/python/feinstaubsensor_abfragen_02.py", line 10
    print sys.version_info[0]
            ^
SyntaxError: Missing parentheses in call to 'print'
mit Klammer geht es und liefert brav Version 3

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 11:44
von eagleflight
So geht es, Danke.
War noch ein fehlender "/" in der url und in sensor_h ein Buchstabendreher, also nichts tragisches.

Die Klammer für print brauche ich leider immer noch :/

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
# depends: python-requests
import requests
import json

SENSOR_URL = "http://api.luftdaten.info/static/v1/sensor/{}/"

def pick_luftdaten_values(sensor_id):
    # Sensordaten für Luftdaten (p1/p2=Feinstaubwerte, DHT für Temp und Luftfeuchte) abfragen
    # dazu die api von luftdaten.info nutzen
    result = requests.get(SENSOR_URL.format(sensor_id))
    data = result.json()
    return {d['value_type']: d['value'] for d in data[-1]['sensordatavalues']}

#  Sensor Nummer 22451 und 22452
def luftdatenabfrage():
    sensor_p = pick_luftdaten_values(22451)
    sensor_h = pick_luftdaten_values(22452)
    return sensor_p['P1'], sensor_p['P2'], sensor_h['humidity'], sensor_h['temperature']

p1, p2, h1, t1 = luftdatenabfrage()
print (p1)
print (p2)
print (h1)
print (t1)

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 12:07
von __deets__
Ich bin mir nicht sicher warum Sirius3 auf Python 2 kam, aber er scheint sich geirrt zu haben, womit die Klammer um das print auch voellig ok geht. Und er das ja eh empfohlen hat.

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 12:30
von __blackjack__
@__deets__: Das scheint ein Raspi zu sein, und in der ersten Zeile steht ganz deutlich dass das mit Python 2 ausgeführt werden soll. Also sind entweder die Klammern bei `print` falsch oder die erste Zeile. Und auch die zweite Zeile deutet eher auf Python 2 hin, weil sie bei 3 überflüssig wäre.

Re: Abfrage von luftdaten.info mit Python

Verfasst: Freitag 22. März 2019, 12:37
von __deets__
@__blackjack__ das mag drauf hindeuten, die erzwungene Klammern deuten in die andere Richtung und sind ein bisschen deutlicher beim deuten ;)
Und da encoding-tags ja etwas sind, dass aehnlich wie sudo und Salz reichlich verwandt wird in der Hoffnung es hilft etwas, ist auch das nicht aussagekraeftig.

Mir ging es ja nur darum dem TE klar zu machen, dass es kein Fehler ist, wenn er Klammern braucht.