Skrypty API i próbek do przesyłania danych

Pierwszym krokiem jest uzyskanie tokena ze strony platformy danych.

Gdy już posiadasz własny token, możesz użyć poniższego skryptu, aby przesłać swoje dane. Po przesłaniu danych pierwszej stacji przejdź na stronę aqicn.org/data-feed/verification/, aby skonfigurować stacje i zweryfikować przesłane dane.

Obsługiwane platformy oprogramowania:

Dostarczamy gotowe oprogramowanie na 3 platformy:

  • Arduino: Jeśli masz procesor Arduino, skorzystaj z gotowego do użycia oprogramowania dostępnego na github.com pod adresem aqicn/gaia-a08-arduino.
  • Python: Użyj poniższego fragmentu kodu
  • Wiersz poleceń (CURL): Użyj poniższego fragmentu kodu

Jeśli nie masz stacji monitorującej, a chciałbyś ją kupić, sprawdź nasze stacje monitorujące jakość powietrza GAIA.

Jeśli wolisz stację typu „zrób to sam”, sprawdź GAIA A08.


--

Przykładowy kod (python)

import requests  
 
# Sensor parameter   
sensorReadings = [   
	{'specie':'pm25', 'value': 393.3},  
	{'specie':'pm10', 'value': 109.3}  
] 
 
# Station parameter   
station = { 
	'id':		"station-001",  
	'location':  { 
		'latitude': 28.7501,  
		'longitude': 77.1177 
	} 
} 
 
# User parameter - get yours from https://aqicn.org/data-platform/token/ 
userToken = "dummy-token-for-test-purpose-only" 
 
# Then Upload the data  
params = {'station':station,'readings':sensorReadings,'token':userToken}  
request = requests.post( url = "https://aqicn.org/sensor/upload/",  json = params) 
#print(request.text) 
data = request.json()  
 
if data["status"]!="ok": 
	print("Something went wrong: %s" % data) 
else: 
	print("Data successfully posted: %s"%data) 

Przykładowy kod (curl)

curl -X POST https://aqicn.org/sensor/upload -H 'Content-Type: application/json' --data '{\ 
"token": "dummy-token-for-test-purpose-only",\ 
"station": { "id": "station-001" },\ 
"readings": [{"specie":"pm2.5", "value": 393.3}]\ 
}'

Przykładowy kod (arduino)

Check github.com/aqicn/gaia-a08-arduino for the full code.
#include <WiFi.h> 
#include <HTTPClient.h> 
#include <ArduinoJson.h> 
 
#define LATITUDE 28.7501 
#define LONGITUDE 77.1177 
 
void upload(float pm25_concentration, float pm10_concentration, const char * token) 
{ 
 
    static char stationID[32]; 
    uint64_t efuseMac = ESP.getEfuseMac(); 
    uint16_t chip = (uint16_t)(efuseMac >> 32); 
    snprintf(stationID, 32, "station-%x", chip); 
 
    doc["token"] = token; 
    doc["station"]["id"] = stationID; 
 
    doc["station"]["location"]["latitude"] = LATITUDE; 
    doc["station"]["location"]["longitude"] = LONGITUDE; 
 
    doc["readings"][0]["specie"] = "pm25"; 
    doc["readings"][0]["value"] = pm25_concentration; 
    doc["readings"][0]["unit"] = "µg/m3"; 
 
    doc["readings"][1]["specie"] = "pm10"; 
    doc["readings"][1]["value"] = pm10_concentration; 
    doc["readings"][1]["unit"] = "µg/m3"; 
 
    static char json_body[1024]; 
    serializeJson(doc, json_body); 
 
    HTTPClient http; 
    http.begin("https://aqicn.org/sensor/upload"); 
    http.addHeader("Content-Type", "application/json"); 
    int httpResponseCode = http.POST(json_body); 
 
    if (httpResponseCode > 0) 
    { 
 
        String response = http.getString(); 
        Serial.println(httpResponseCode); 
        Serial.println(response); 
    } 
    else 
    { 
 
        Serial.print("Error on sending POST: "); 
        Serial.println(httpResponseCode); 
    } 
 
    http.end(); 
}

Opcje interfejsu API

Parameter Type Optional/Mandatory Explanations
token string mandatory

Zdobądź własny token z aqicn.org/data-platform/token.

station
station.id string mandatory

Unikalny identyfikator stacji - możesz wybrać dowolną nazwę zawierającą maksymalnie 128 znaków.
Ta nazwa będzie używana wyłącznie wewnętrznie w Twoim przypadku. Nikt inny nie zobaczy tego identyfikatora

station.name string optional

Nazwa stacji – może to być na przykład nazwa Twojego budynku, nazwa ulicy, nazwa wydziału uniwersyteckiego, kod Twojej osobistej stacji pogodowej.
Ta nazwa będzie używana jako przyrostek adresu URL Twojej stacji.

station.latitude float optional

Długość geograficzna Twojej stacji

station.longitude float optional

Długość geograficzna Twojej stacji

organization
org.website string optional

Jeśli masz stronę internetową zawierającą więcej informacji o Twojej stacji/czujniku, dodamy ten link na naszej mapie, gdy z niej skorzystasz. Zobacz swoją stację

org.name string optional

Jeśli określisz witrynę internetową, ta „nazwa organizacji” zostanie powiązana z witryną internetową.

readings
readings[*].specie string mandatory

Nazwa substancji zanieczyszczającej, którą zgłaszasz. Dla czujników gazu użyj: „pm2,5”, „pm10”, „pm1,0”, ... Dla czujnika gazu użyj: „co2”, „no2”, „o3”, ... Dla czujnika pogodowego, użyj: „temp”, „wilgotność”, „ciśnienie”, „prędkość wiatru”, „podmuch wiatru”, „kierunek wiatru”, ..
Właściwie możesz użyć dowolnej nazwy gatunku. Po zatwierdzeniu stacji nazwy zostaną znormalizowane w naszym systemie.

readings[*].value float mandatory

Jeśli Twój czujnik generuje wartości co sekundę, a przesyłasz dane tylko co minutę, wartość ta powinna być średnią wszystkich wartości odczytanych w ciągu ostatniej minuty.

readings[*].unit string optional

Jednostka wartości. Np. „mg/m3” dla czujnika pyłu, ppb dla czujników gazu, C dla czujnika temperatury.

readings[*].time string optional

Data i godzina odczytu w formacie ISO 8601

readings[*].min float optional

Jeśli wartości odczytu opierają się na uśrednieniu kilku wartości, wówczas odpowiada to wartości minimalnej wszystkich wartości użytych do uśrednienia.

readings[*].max float optional

Jeśli wartości odczytu opierają się na uśrednieniu kilku wartości, wówczas odpowiada to maksymalnej wartości wszystkich wartości użytych do uśrednienia.

readings[*].median float optional

Jeśli wartości odczytu opierają się na uśrednieniu kilku wartości, wówczas odpowiada to medianie wszystkich wartości użytych do uśrednienia.

readings[*].stddev float optional

Jeżeli wartości odczytu opierają się na uśrednieniu kilku wartości, wówczas odpowiada to odchyleniu standardowemu wszystkich wartości użytych do uśrednienia.

readings[*].averaging float optional

Jeżeli powyższe wartości opierają się na uśrednieniu kilku wartości, wówczas odpowiada to czasowi trwania okresu uśredniania w sekundach.
Na przykład użyj 60 dla średnich danych minutowych i 3600 dla średnich godzinowych.

Przykład 1

{ 
	"token": "......", 
	"station": { 
		"id": "station-001", 
		"name": "HCPA Santa Cecília", 
		"latitude": 103.37893, 
		"longitude": 43.17108, 
	}, 
	"org": { 
		"website":"https://pacto.upsensor.com/", 
		"name":"Porto Ar Alegre", 
	}, 
	"readings": [ 
		{"time":"2024-05-04T21:14:38+09:00","specie":"pm2.5", "value": 393.3, "unit":"mg/m3", "min":390.3, "max": 402.3, "stddev": 0.332},  
		{"time":"2024-05-04T21:14:38+09:00","specie":"pm10", "value": 109.3, "unit":"mg/m3"}, 
		{"time":"2024-05-04T21:14:38+09:00","specie":"co2", "value": 459.3, "unit":"ppb"}, 
		{"time":"2024-05-04T21:14:38+09:00","specie":"temp", "value": 26.8, "unit":"C"}, 
	] 
}

Przykład 2

{ 
	"token": "......", 
	"station": { 
		"id": "station-001", 
	}, 
	"readings": [ 
		{"specie":"pm2.5", "value": 393.3} 
	] 
}

Kompletny przykład kodu

Możesz użyć tego kodu do ciągłego odczytu z czujnika SDS i przesyłania co minutę: (skrypt dostępny również na https://github .com/aqicn/sds-sensor-reader).

import requests 
import random 
import time 
import math 
import json 
import sys 
from serial import Serial 
 
LOCATION = {'latitude': 28.7501, 'longitude': 77.1177} 
TOKEN    = "dummy-token-for-test-purpose-only" 
SENSORID = "station-001" 
USBPORT  = "/dev/ttyUSB0" 
 
class SensorDataUploader: 
 
    def __init__(self, station, token): 
        self.token = token 
        self.station = station 
 
 
    def send(self,readings): 
 
        params = {'station':self.station,'readings':readings,'token':self.token}  
        print("Uploading: %s"%json.dumps(params, indent=4)) 
 
        request = requests.post( url = "https://aqicn.org/sensor/upload/",  json = params) 
        data = request.json()  
        if data["status"]!="ok": 
            print("Something went wrong: %s" % data) 
        else: 
            print("Data successfully posted: %s"%data) 
 
 
 
 
class Accumulator: 
 
    def __init__(self, name): 
        self.name = name 
        self.values = [] 
 
    def add(self,val): 
        self.values.append(val) 
 
    def count(self): 
        return len(self.values) 
 
    def reset(self): 
        self.values=[] 
 
    def min(self): 
        return self.values[0] 
 
    def max(self): 
        return self.values[len(self.values)-1] 
 
    def median(self): 
        return self.values[len(self.values)/2] 
 
    def mean(self): 
        return float(sum(self.values)) / len(self.values) 
 
    def stddev(self): 
        l = len(self.values) 
        mean = self.mean() 
        return math.sqrt(float(reduce(lambda x, y: x + y, map(lambda x: (x - mean) ** 2, self.values))) / l) 
 
 
    def summary(self): 
        self.values.sort() 
        return {"specie":self.name,'value':self.mean(),'min':self.min(),'max':self.max(),'median':self.median(), 'stddev':self.stddev()}  
 
 
 
class DummyReader: 
 
    def read( self ): 
 
        time.sleep(1.1) 
        return {"pm2.5":random.random()*10,"pm10":random.random()*10} 
 
 
class SDS011Reader: 
 
    def __init__(self, inport): 
        self.serial = Serial(port=inport,baudrate=9600) 
        self.values = [] 
        self.step = 0 
 
    def read( self ): 
 
        # time.sleep(1) 
        # return {"pm2.5":random.random()*100,"pm10":random.random()*100} 
 
        while self.serial.inWaiting()!=0: 
            v=ord(self.serial.read()) 
 
            if self.step ==0: 
                if v==170: 
                    self.step=1 
 
            elif self.step==1: 
                if v==192: 
                    self.values = [0,0,0,0,0,0,0] 
                    self.step=2 
                else: 
                    self.step=0 
 
            elif self.step>8: 
                self.step =0 
                pm25 = (self.values[0]+self.values[1]*256)/10 
                pm10 = (self.values[2]+self.values[3]*256)/10 
                return {"pm2.5":pm25,"pm10":pm10} 
 
            elif self.step>=2: 
                self.values[self.step-2]=v 
                self.step= self.step+1 
 
        return None 
 
 
 
def readAndUpload(sensor, uploader): 
 
    try: 
 
        while True: 
            accumulators = {} 
            startTime = time.time() 
 
            while time.time() < startTime+60: 
                values = sensor.read() 
                if values==None: 
                    continue 
 
                print("Reading [%2d]: %s"%(int(time.time()-startTime),values)) 
                for specie, value in values.items(): 
                    if not (specie in accumulators): 
                        accumulators[specie]=Accumulator(specie) 
                    accumulators[specie].add(value) 
 
 
            readings = [] 
            for specie, accumulator in accumulators.items(): 
                readings.append(accumulator.summary()) 
 
            if len(readings)>0: 
                uploader.send(readings) 
            else: 
                print("No value read from the sensor...") 
 
 
    except KeyboardInterrupt: 
        print "Bye" 
        sys.exit() 
 
 
 
print("Starting reading sensor "+SENSORID+" on port "+USBPORT) 
 
# Station parameter   
station = {'id':SENSORID, 'location':LOCATION} 
uploader = SensorDataUploader(station, TOKEN) 
 
sensor = SDS011Reader(USBPORT) 
# sensor = DummyReader() 
readAndUpload(sensor,uploader) 
 

Zmierz jakość powietrza w swojej okolicy
Weź udział i stwórz własną stację monitorowania jakości powietrza

Monitor jakości powietrza GAIA wykorzystuje laserowe czujniki cząstek do pomiaru w czasie rzeczywistym zanieczyszczenia cząstkami PM2,5 i PM10, które są jedną z najbardziej szkodliwych substancji zanieczyszczających powietrze.

Jest bardzo łatwy w konfiguracji: wymaga jedynie punktu dostępu WIFI i zasilacza kompatybilnego z USB. Po nawiązaniu połączenia informacje o poziomie zanieczyszczenia powietrza w czasie rzeczywistym są natychmiast dostępne na naszych mapach.

Stacja jest dostarczana z 10-metrowymi wodoodpornymi kablami zasilającymi, zasilaczem, elementami montażowymi i opcjonalnym panelem słonecznym.

O pomiarach jakości powietrza i zanieczyszczeń:

O Poziomach Jakości Powietrza

- Wartości Indeksu Jakości Powietrza (AQI)Poziomy zagrożenia zdrowia
0 - 50 Dobra 0-50: Dobra - Jakość powietrza jest uznawana za zadowalającą, a zanieczyszczenie powietrza stanowi niewielkie ryzyko lub jego brak.
51 -100 Średnia 50-100: Średnia - Jakość powietrza jest dopuszczalna; jednak niektóre zanieczyszczenia mogą być umiarkowanie szkodliwe dla bardzo małej liczby osób, które są niezwykle wrażliwe na zanieczyszczenie powietrza.
101-150 Niezdrowa dla osób wrażliwych 100-150: Niezdrowe dla wrażliwych osób - u osób wrażliwych mogą wystąpić negatywne skutki dla zdrowia. Większość populacji może nie odczuwać negatywnych objawów.
151-200 Niezdrowa 150-200: Niezdrowe - Każdy może zacząć doświadczać negatywnych skutków zdrowotnych; U osób wrażliwych mogą wystąpić poważniejsze skutki zdrowotne.
201-300 Bardzo niezdrowa 200-300: Bardzo niezdrowe - Ostrzeżenie zdrowotne, poziom alarmowy. Bardzo prawdopodobny negatywny wpływ na całą populację.
300+ Zagrożenie dla życia 300 : Niebezpieczny - Alarm Zdrowotny: każdy może doświadczyć poważniejszych skutków zdrowotnych.

Aby dowiedzieć się więcej na temat jakości powietrza i zanieczyszczenia, sprawdź w wikipedii temat "jakość powietrza" lub nasz poradnik o jakości powietrza i jego wpływie na Twoje zdrowie.

Więcej przydatnych informacji zdrowotnych na blogu doktora Richarda Sainta z Pekinu: www.myhealthbeijing.com .


Uwaga dotycząca użytkowania: Wszystkie dane dotyczące jakości powietrza mogą być nieważne w chwili publikacji, a w celu zapewnienia jakości dane te mogą być w dowolnym momencie zmieniane bez powiadomienia. Projekt World Air Quality Index wykorzystuje wszystkie przydatne umiejętności, dba o rzetelność przy kompilowaniu treści tych informacji, ale w żadnym wypadku zespół projektowy World Air Quality Index lub jego agenci nie są odpowiedzialni za umowę, delikt lub w inny sposób za jakiekolwiek straty, obrażenia lub szkody wynikające bezpośrednio lub pośrednio z dostarczania tych danych.



Ustawienia


Ustawienia Języka:


Temperature unit:
Celcius