API завантаження даних і зразки сценаріїв

Перший крок — отримати маркер зі сторінки платформи даних .

Отримавши власний маркер, ви можете використовувати наступний сценарій для завантаження даних. Після того, як ви завантажите свої перші дані станції, перейдіть на aqicn.org/data-feed/verification/, щоб налаштувати свої станції та перевірити завантажені дані.

Підтримувані програмні платформи:

Ми надаємо готове до використання програмне забезпечення для цих 3 платформ:

  • Arduino : якщо у вас є процесор Arduino, використовуйте готове до використання програмне забезпечення, доступне на github.com за адресою aqicn/gaia-a08-arduino .
  • Python: використовуйте наведений нижче фрагмент коду
  • Командний рядок (CURL): використовуйте наведений нижче фрагмент коду

Якщо у вас немає жодної станції моніторингу, але ви хочете її отримати, перевірте наші станції моніторингу якості повітря GAIA .

Якщо ви віддаєте перевагу станції DIY, перевірте GAIA A08 .

Режим роботи

Під час завантаження даних бажано обчислювати середнє значення даних за останню хвилину (що зазвичай становить близько 60 зразків на забруднювач) та надсилати усереднені дані на наш сервер щохвилини.

Якщо ви не впевнені, як завантажити дані, або якщо ви хочете використовувати власний скрипт, просто надішліть нам повідомлення за допомогою форми нижче, і ми зробимо все можливе, щоб допомогти вам.


- -

Приклад коду (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) 

Зразок коду (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}]\ 
}'

Приклад коду (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(); 
}

Параметри API

Parameter Type Optional/Mandatory Explanations
token string mandatory

Отримайте власний маркер на сайті aqicn.org/data-platform/token .

station
station.id string mandatory

Унікальний ідентифікатор станції - ви можете вибрати будь-яку назву з максимум 128 символів.
Це ім’я використовується для вас лише внутрішньо. Ніхто більше не побачить цей ідентифікатор

station.name string optional

Назва станції - це може бути, наприклад, назва вашого будинку, назва вулиці, назва факультету університету, код вашої особистої метеостанції.
Ця назва використовуватиметься як суфікс для URL-адреси вашої станції.

station.location.latitude float optional

Довгота вашої станції

station.location.longitude float optional

Довгота вашої станції

organization
org.website string optional

Якщо у вас є веб-сайт із додатковою інформацією про вашу станцію/датчик, ми додамо це посилання на нашу карту, коли буде використано переглянути вашу станцію

org.name string optional

Якщо ви вкажете веб-сайт, ця «назва організації» буде пов’язана з веб-сайтом.

readings
readings[*].specie string mandatory

Назва забруднювача, про який ви повідомляєте. Для датчиків газу використовуйте: "pm2.5", "pm10", "pm1.0", ... Для датчика газу використовуйте: "co2", "no2", "o3", ... Для датчика погоди, використовувати: "температура", "вологість", "тиск", "швидкість вітру", "пориви вітру", "напрямок вітру", ..
Насправді ви можете використовувати будь-яку назву виду. Коли ваша станція буде перевірена, імена будуть нормалізовані в нашій системі.

readings[*].value float mandatory

Якщо ваш датчик видає значення щосекунди, а ви завантажуєте лише щохвилини, це значення має бути середнім для всіх значень, зчитаних за останню хвилину.

readings[*].unit string optional

Одиниця величини. Наприклад, "mg/m3" для датчика пилу, ppb для датчиків газу, C для датчика температури.

readings[*].time string optional

Дата та час зчитування у форматі ISO 8601

readings[*].min float optional

Якщо значення показань базуються на усередненні кількох значень, то це відповідає мінімальному значенню всіх значень, використаних для усереднення.

readings[*].max float optional

Якщо значення показань базуються на усередненні кількох значень, то це відповідає максимальному значенню всіх значень, використаних для усереднення.

readings[*].median float optional

Якщо значення показань базуються на усередненні кількох значень, то це відповідає медіанному значенню всіх значень, використаних для усереднення.

readings[*].stddev float optional

Якщо значення показань базуються на усередненні кількох значень, то це відповідає стандартному відхиленню всіх значень, використаних для усереднення.

readings[*].averaging float optional

Якщо наведені вище значення базуються на усередненні кількох значень, то це відповідає тривалості періоду усереднення в секундах.
Наприклад, використовуйте 60 для середніх даних за хвилину та 3600 для середніх за годину.

Приклад 1

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

Приклад 2

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

Повний приклад коду

Ви можете використовувати цей код для постійного зчитування з датчика SDS і завантаження щохвилини: (сценарій також доступний на 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) 
 

Do you know of any Air Quality stations in your area?
why not participate to the map with your own air quality station?

Наші монітори якості повітря GAIA дуже легко налаштувати: вам потрібна лише точка доступу WIFI і USB-сумісне джерело живлення.

Після підключення рівень забруднення повітря в реальному часі миттєво стає доступним на картах і через API.

Станція поставляється з 10-метровим водонепроникним кабелем живлення, блоком живлення USB, монтажним обладнанням і додатковою сонячною панеллю.

Про якість повітря та вимірювання забруднення:

Про рівень якості повітря

-Значення індексу якості повітря (AQI).Рівні занепокоєння здоров'ям
0 - 50ДобреЯкість повітря вважається задовільною і забруднення повітря становить незначний ризик або не становить ризику взагалі
51 -100ПомірнийЯкість повітря є прийнятною; однак, для деяких забруднюючих речовин може спостерігатися помірна загроза здоров'ю для дуже невеликої кількості людей, що незвично чутливі до забруднення повітря.
101-150Нездоровий для чутливих групЛюди з чутливими органами дихання можуть відчувати дискомфорт. Здорові люди скоріше за все не відчують впливу.
151-200НездоровийКожен може почати зазнавати впливу на здоров'я; члени чутливих груп можуть мати серйозніші наслідки для здоров'я
201-300Дуже, нездоровийПопередження про небезпеку для здоров'я, надзвичайна ситуація. Все населення, швидше за все, зазнає впливу.
300+НебезпечнийНебезпека: будь-хто може зазнати більш серйозних наслідків для здоров'я

Щоб дізнатися більше про якість повітря та забруднення, перегляньте тему «Якість повітря» у Вікіпедії або посібник airnow «Якість повітря та ваше здоров’я» .

Щоб отримати дуже корисні поради щодо здоров’я пекінського лікаря Річарда Сен-Сіра, відвідайте блог www.myhealthbeijing.com .


Повідомлення про використання: Всі дані за якістю повітря є неперевіреними на момент публікації, і в зв'язку з забезпеченням якості цих даних, вони можуть бути змінені в будь-який час та без попереднього повідомлення. Проект Світового індексу якості повітря доклав усіх розумних навичок та обережності щодо збирання цієї інформації, і ні за яких обставин проектна команда Світового індексу якості повітря , або її агенти, не будуть нести відповідальність за договором, правопорушенням чи іншим чином за будь-які втрати, пошкодження або збитки, що виникають безпосередньо чи опосередковано від надання цих даних.