ទិន្នន័យផ្ទុកឡើង API & ស្គ្រីបគំរូ

ជំហានដំបូងគឺដើម្បីទទួលបានសញ្ញាសម្ងាត់ពី ទំព័រទិន្នន័យវេទិកា ។

នៅពេលដែលអ្នកមានសញ្ញាសម្ងាត់ផ្ទាល់ខ្លួនរបស់អ្នក អ្នកអាចប្រើស្គ្រីបខាងក្រោមដើម្បីផ្ទុកទិន្នន័យរបស់អ្នក។ បន្ទាប់ពីអ្នកបង្ហោះទិន្នន័យស្ថានីយ៍ដំបូងរបស់អ្នក សូមចូលទៅកាន់ aqicn.org/data-feed/verification/ ដើម្បីកំណត់រចនាសម្ព័ន្ធស្ថានីយ៍របស់អ្នក និងផ្ទៀងផ្ទាត់ទិន្នន័យដែលបានផ្ទុកឡើង។

វេទិកាកម្មវិធីដែលគាំទ្រ៖

យើងផ្តល់ជូននូវកម្មវិធីដែលត្រៀមរួចជាស្រេចក្នុងការប្រើប្រាស់សម្រាប់វេទិកាទាំង 3 នោះ៖

  • Arduino ៖ ប្រសិនបើអ្នកមានស៊ីភីយូ Arduino សូមប្រើកម្មវិធីដែលត្រៀមរួចជាស្រេចក្នុងការប្រើប្រាស់ដែលមាននៅលើ github.com នៅ aqicn/gaia-a08-arduino ។
  • Python៖ ប្រើកូដ-snippet ខាងក្រោម
  • បន្ទាត់ពាក្យបញ្ជា (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 -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", ... សម្រាប់ឧបករណ៍ចាប់សញ្ញា gaz ប្រើ៖ "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 សម្រាប់មធ្យមម៉ោង។

ឧទាហរណ៍ ១

{ 
	"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-27T02:18:39+09:00","specie":"pm2.5", "value": 393.3, "unit":"mg/m3", "min":390.3, "max": 402.3, "stddev": 0.332},  
		{"time":"2026-09-27T02:18:39+09:00","specie":"pm10", "value": 109.3, "unit":"mg/m3"}, 
		{"time":"2026-09-27T02:18:39+09:00","specie":"co2", "value": 459.3, "unit":"ppb"}, 
		{"time":"2026-09-27T02:18:39+09:00","specie":"temp", "value": 26.8, "unit":"C"}, 
	] 
}

ឧទាហរណ៍ ២

{ 
	"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)Levels of Health Concern
0 - 50ល្អគុណភាពខ្យល់ត្រូវបានចាត់ទុកថាពេញចិត្តហើយការបំពុលបរិយាកាសបង្កឱ្យមានហានិភ័យតិចតួចឬគ្មាន
51 -100មធ្យមគុណភាពខ្យល់អាចទទួលយកបាន។ ទោះជាយ៉ាងណាក៏ដោយចំពោះការបំពុលមួយចំនួនវាអាចមានការព្រួយបារម្ភខាងសុខភាពក្នុងកម្រិតតិចតួចចំពោះមនុស្សតិចតួចដែលងាយទទួលរងការបំពុលខ្យល់។
101-150Unhealthy
for sensitive groups
សមាជិកនៃក្រុមរសើបអាចជួបប្រទះផលប៉ះពាល់សុខភាព។ សាធារណជន​ទូទៅ​មិន​ទំនង​ជា​រង​ផល​ប៉ះពាល់​ទេ។
151-200មិនល្អមនុស្សគ្រប់រូបអាចចាប់ផ្តើមមានផលប៉ះពាល់ដល់សុខភាព។ សមាជិកនៃក្រុមដែលប្រកាន់អក្សរតូចធំអាចមានផលប៉ះពាល់សុខភាពធ្ងន់ធ្ងរបន្ថែមទៀត
201-300មិនល្អខ្លាំងការព្រមានអំពីសុខភាពនៃស្ថានភាពគ្រាអាសន្ន។ ប្រជាជនទាំងមូលទំនងជារងផលប៉ះពាល់។
300+គ្រោះថ្នាក់ការប្រុងប្រយ័ត្នផ្នែកសុខភាព: មនុស្សគ្រប់រូបអាចមានផលប៉ះពាល់ធ្ងន់ធ្ងរលើសុខភាព

ដើម្បីដឹងបន្ថែមអំពីគុណភាពខ្យល់ និងការបំពុល សូមពិនិត្យមើល ប្រធានបទគុណភាពខ្យល់ wikipedia ឬ មគ្គុទ្ទេសក៍ airnow អំពីគុណភាពខ្យល់ និងសុខភាពរបស់អ្នក ។

សម្រាប់ដំបូន្មានសុខភាពដ៏មានប្រយោជន៍របស់វេជ្ជបណ្ឌិតទីក្រុងប៉េកាំង Richard Saint Cyr MD សូមពិនិត្យមើលប្លក់ www.myhealthbeijing.com ។


សេចក្តីជូនដំណឹងអំពីការប្រើប្រាស់: ទិន្នន័យគុណភាពខ្យល់ទាំងអស់មិនត្រូវបានគេប៉ាន់ស្មាននៅពេលបោះពុម្ភផ្សាយនោះទេហើយដោយសារតែការធានាគុណភាពនេះទិន្នន័យទាំងនេះអាចត្រូវបានកែប្រែដោយគ្មានការជូនដំណឹងគ្រប់ពេលវេលា។ គម្រោងសន្ទស្សន៍គុណភាពខ្យល់អាកាសពិភពលោកបានអនុវត្តនូវជំនាញនិងការថែទាំដែលសមស្របទាំងអស់ក្នុងការចងក្រងមាតិកានៃព័ត៌មាននេះហើយក្នុងករណីណាក៏ដោយក្រុមការងារគម្រោងសន្ទស្សន៍គុណភាពខ្យល់អាកាសពិភពលោកឬភ្នាក់ងាររបស់វាត្រូវទទួលខុសត្រូវលើកិច្ចសន្យាខូចខាតឬបើមិនដូច្នោះទេសម្រាប់ការបាត់បង់របួសឬខូចខាត ដែលកើតឡើងដោយផ្ទាល់ឬដោយប្រយោលពីការផ្គត់ផ្គង់ទិន្នន័យនេះ។