精選文章
LASS - 1
LASS
此範例使用實驗版 SDK, 實驗版方式,
在偏好設定的 板子管理員網址 (Additional Board Manager) 輸入:
https://github.com/neojou/arduino-ameba/raw/master/release/package_njiot.com_ameba_index.json
在做這個 LASS 範例之前, 請先做底下幾個範例
1. PM2.5 sensor
2. Wifi NTP 讀取時間
3. MQTT example
如同 MQTT 範例, 我們先用 Google 的 MQTTLens 來連接 LASS server
gpssensor.ddns.net
看看
如果有顯示 connected, 表示目前網路環境是可以連線的.
LASS PM2.5 arduino program
https://github.com/neojou/arduino-ameba/blob/master/example/lass-pm25/lass-pm25.ino
程式說明 :
1. 時間
如先前 NTP 範例, 我們只有在一開始時 setup() , 用 NTP 抓時間.
之後用 系統 millis() 和 NTP 時間 相加 計算. getCurrentTime()
將來如果搭配省電, 可以外接 RTC 定時喚醒/或重開主系統
2. LASS MQTT 資料格式
https://lass.hackpad.com/LASS-Data-specification-1dYpwINtH8R
程式是在 sendMQTTMessage() ,
用 sprinf 把資料按格式寫到 payload 後,
用 MQTT publish() 將 payload 送出
mqttclient.publish((char*)outTopic,payload);
3. 溫度
之後 用 DHT sensor 把溫度補上
4. GPS 位置.
目前先用 google map 把 GPS 位置手寫填到 gps_lat 和 gps_lon 變數中
之後接 GPS 把資料補上
5. device ID
會拿這片卡的 MAC 最後兩碼來組合
sprintf(clientId, "FT2_0%02X%02X", mac[4], mac[5]);
執行結果 :
從log 可以看到
MQTT client id:FT2_0F0EC
可以從底下這個 link 看到
http://nrl.iis.sinica.edu.tw/LASS/show.php?device_id=FT2_0F0EC
之後來變成長期觀測站時, 可以來研究修改一下. 讓底下這個站顯示
http://iot.sparkfuture.io/pm25
此範例使用實驗版 SDK, 實驗版方式,
在偏好設定的 板子管理員網址 (Additional Board Manager) 輸入:
https://github.com/neojou/arduino-ameba/raw/master/release/package_njiot.com_ameba_index.json
在做這個 LASS 範例之前, 請先做底下幾個範例
1. PM2.5 sensor
2. Wifi NTP 讀取時間
3. MQTT example
如同 MQTT 範例, 我們先用 Google 的 MQTTLens 來連接 LASS server
gpssensor.ddns.net
看看
如果有顯示 connected, 表示目前網路環境是可以連線的.
LASS PM2.5 arduino program
https://github.com/neojou/arduino-ameba/blob/master/example/lass-pm25/lass-pm25.ino
| /* | |
| This example demonstrate how to upload sensor data to MQTT server of LASS. | |
| It include features: | |
| (1) Connect to WiFi | |
| (2) Retrieve NTP time with WiFiUDP | |
| (3) Get PM 2.5 value from PMS3003 air condition sensor with UART | |
| (4) Optional DHT support ,comment #define USE_DHT | |
| (5) Connect to MQTT server and try reconnect when disconnect | |
| https://github.com/LinkItONEDevGroup/LASS | |
| */ | |
| #include <WiFi.h> | |
| #include <PubSubClient.h> | |
| #include <WiFiUdp.h> | |
| //#define USE_DHT | |
| #ifdef USE_DHT | |
| #include "DHT.h" | |
| #endif | |
| char ssid[] = "YourWiFiAPName"; // your network SSID (name) | |
| char pass[] = "YourWiFiAPPass"; // your network password | |
| char gps_lat[] = "24.7805647"; // device's gps latitude | |
| char gps_lon[] = "120.9933177"; // device's gps longitude | |
| #ifdef USE_DHT | |
| #define DHTPIN 2 // what digital pin we're connected to | |
| #define DHTTYPE DHT11 // DHT 22 (AM2302), AM2321 | |
| //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 | |
| DHT dht(DHTPIN, DHTTYPE); | |
| #endif | |
| const char server[] = "gpssensor.ddns.net"; // the MQTT server of LASS | |
| const char ntpServer[] = "pool.ntp.org"; | |
| #define MAX_CLIENT_ID_LEN 10 | |
| #define MAX_TOPIC_LEN 50 | |
| char clientId[MAX_CLIENT_ID_LEN]; | |
| char outTopic[MAX_TOPIC_LEN]; | |
| void MQTTcallback(char* topic, byte* payload, unsigned int length) | |
| { | |
| Serial.print(F("Message arrived [")); | |
| Serial.print(topic); | |
| Serial.print(F("] ")); | |
| for (int i=0;i<length;i++) { | |
| Serial.print((char)payload[i]); | |
| } | |
| Serial.println(); | |
| } | |
| WiFiClient wifiClient; | |
| PubSubClient mqttclient((char*)server, 1883, MQTTcallback, wifiClient); | |
| WiFiUDP Udp; | |
| void initializeWiFi() | |
| { | |
| int status = WL_IDLE_STATUS; | |
| // attempt to connect to Wifi network: | |
| while (status != WL_CONNECTED) { | |
| Serial.print("Attempting to connect to SSID: "); | |
| Serial.println(ssid); | |
| // Connect to WPA/WPA2 network. Change this line if using open or WEP network: | |
| status = WiFi.begin(ssid, pass); | |
| // wait 10 seconds for connection: | |
| Serial.println("WiFi connected , wait for 10 sec to get IP"); | |
| delay(10000); | |
| } | |
| // DHCP IP | |
| Serial.println(F("IP address: ")); | |
| Serial.println(WiFi.localIP()); | |
| // local port to listen for UDP packets | |
| Udp.begin(2390); | |
| } | |
| //NTP | |
| unsigned int localPort = 2390; // local port to listen for UDP packets | |
| const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message | |
| const byte nptSendPacket[ NTP_PACKET_SIZE] = { | |
| 0xE3, 0x00, 0x06, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x4E, 0x31, 0x34, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
| }; | |
| byte ntpRecvBuffer[ NTP_PACKET_SIZE ]; | |
| uint32_t epochSystem = 0; // timestamp of system boot up | |
| #define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) | |
| static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 | |
| void retrieveNtpTime(){ | |
| Serial.println("Send NTP packet"); | |
| Udp.beginPacket(ntpServer, 123); //NTP requests are to port 123 | |
| Udp.write(nptSendPacket, NTP_PACKET_SIZE); | |
| Udp.endPacket(); | |
| if(Udp.parsePacket()) { | |
| Serial.println("NTP packet received"); | |
| Udp.read(ntpRecvBuffer, NTP_PACKET_SIZE); // read the packet into the buffer | |
| unsigned long highWord = word(ntpRecvBuffer[40], ntpRecvBuffer[41]); | |
| unsigned long lowWord = word(ntpRecvBuffer[42], ntpRecvBuffer[43]); | |
| unsigned long secsSince1900 = highWord << 16 | lowWord; | |
| const unsigned long seventyYears = 2208988800UL; | |
| unsigned long epoch = secsSince1900 - seventyYears; | |
| epochSystem = epoch - millis() / 1000; | |
| } | |
| } | |
| //Sensor | |
| long pmcf10=0; | |
| long pmcf25=0; | |
| long pmcf100=0; | |
| long pmat10=0; | |
| long pmat25=0; | |
| long pmat100=0; | |
| void retrievePM25Value() | |
| { | |
| int count; | |
| unsigned char c; | |
| unsigned char high; | |
| count=0; | |
| while (Serial1.available()) { | |
| c = Serial1.read(); | |
| if((count==0 && c!=0x42) || (count==1 && c!=0x4d)){ | |
| Serial.println(F("#[G3-ERROR-CHECKSUM]")); | |
| break; | |
| } | |
| if(count > 15){ | |
| Serial.println("G3 complete"); | |
| break; | |
| } | |
| else if(count == 4 || count == 6 || count == 8 || count == 10 || count == 12 || count == 14) { | |
| high = c; | |
| } | |
| else if(count == 5){ | |
| pmcf10 = 256*high + c; | |
| Serial.print("CF=1, PM1.0="); | |
| Serial.print(pmcf10); | |
| Serial.println(" ug/m3"); | |
| } | |
| else if(count == 7){ | |
| pmcf25 = 256*high + c; | |
| Serial.print("CF=1, PM2.5="); | |
| Serial.print(pmcf25); | |
| Serial.println(" ug/m3"); | |
| } | |
| else if(count == 9){ | |
| pmcf100 = 256*high + c; | |
| Serial.print("CF=1, PM10="); | |
| Serial.print(pmcf100); | |
| Serial.println(" ug/m3"); | |
| } | |
| else if(count == 11){ | |
| pmat10 = 256*high + c; | |
| Serial.print("atmosphere, PM1.0="); | |
| Serial.print(pmat10); | |
| Serial.println(" ug/m3"); | |
| } | |
| else if(count == 13){ | |
| pmat25 = 256*high + c; | |
| Serial.print("atmosphere, PM2.5="); | |
| Serial.print(pmat25); | |
| Serial.println(" ug/m3"); | |
| } | |
| else if(count == 15){ | |
| pmat100 = 256*high + c; | |
| Serial.print("atmosphere, PM10="); | |
| Serial.print(pmat100); | |
| Serial.println(" ug/m3"); | |
| } | |
| count++; | |
| } | |
| while(Serial1.available()) Serial1.read(); | |
| } | |
| void initializeMQTT() { | |
| byte mac[6]; | |
| WiFi.macAddress(mac); | |
| memset(clientId, 0, MAX_CLIENT_ID_LEN); | |
| sprintf(clientId, "FT2_0%02X%02X", mac[4], mac[5]); | |
| sprintf(outTopic, "LASS/Test/Pm25Ameba/%s", clientId); | |
| Serial.print("MQTT client id:"); | |
| Serial.println(clientId); | |
| Serial.print("MQTT topic:"); | |
| Serial.println(outTopic); | |
| } | |
| void reconnectMQTT() { | |
| // Loop until we're reconnected | |
| while (!mqttclient.connected()) { | |
| Serial.print(F("Attempting MQTT connection...")); | |
| // Attempt to connect | |
| if (mqttclient.connect(clientId)) { | |
| Serial.println(F("connected")); | |
| mqttclient.subscribe(outTopic); | |
| } else { | |
| Serial.println(F("Failed... try again in 5 seconds")); | |
| // Wait 5 seconds before retrying | |
| delay(5000); | |
| } | |
| } | |
| } | |
| void getCurrentTime(unsigned long epoch, int *year, int *month, int *day, int *hour, int *minute, int *second) { | |
| int tempDay = 0; | |
| *hour = (epoch % 86400L) / 3600; | |
| *minute = (epoch % 3600) / 60; | |
| *second = epoch % 60; | |
| *year = 1970; | |
| *month = 0; | |
| *day = epoch / 86400; | |
| for (*year = 1970; ; (*year)++) { | |
| if (tempDay + (LEAP_YEAR(*year) ? 366 : 365) > *day) { | |
| break; | |
| } else { | |
| tempDay += (LEAP_YEAR(*year) ? 366 : 365); | |
| } | |
| } | |
| tempDay = *day - tempDay; // the days left in a year | |
| for ((*month) = 0; (*month) < 12; (*month)++) { | |
| if ((*month) == 1) { | |
| if (LEAP_YEAR(*year)) { | |
| if (tempDay - 29 < 0) { | |
| break; | |
| } else { | |
| tempDay -= 29; | |
| } | |
| } else { | |
| if (tempDay - 28 < 0) { | |
| break; | |
| } else { | |
| tempDay -= 28; | |
| } | |
| } | |
| } else { | |
| if (tempDay - monthDays[(*month)] < 0) { | |
| break; | |
| } else { | |
| tempDay -= monthDays[(*month)]; | |
| } | |
| } | |
| } | |
| (*month)++; | |
| *day = tempDay+2; // one for base 1, one for current day | |
| } | |
| char payload[300]; | |
| void sendMQTTMessage(){ | |
| unsigned long epoch = epochSystem + millis() / 1000; | |
| int year, month, day, hour, minute, second; | |
| getCurrentTime(epoch, &year, &month, &day, &hour, &minute, &second); | |
| sprintf(payload, "|ver_format=3|fmt_opt=1|app=Pm25Ameba|ver_app=0.0.1|device_id=%s|tick=%d|date=%4d-%02d-%02d|time=%02d:%02d:%02d|device=Ameba|s_d0=%d|gps_lat=%s|gps_lon=%s|gps_fix=1|gps_num=9|gps_alt=2", | |
| clientId, | |
| millis(), | |
| year, month, day, | |
| hour, minute, second, | |
| pmat25, | |
| gps_lat, gps_lon | |
| ); | |
| // Once connected, publish an announcement... | |
| mqttclient.publish((char*)outTopic,payload); | |
| Serial.print(outTopic); | |
| Serial.println(payload); | |
| } | |
| void setup() | |
| { | |
| Serial.begin(9600); | |
| delay(10); | |
| initializeWiFi(); | |
| retrieveNtpTime(); | |
| initializeMQTT(); | |
| #ifdef USE_DHT | |
| dht.begin(); | |
| #endif | |
| Serial1.begin(9600); // PMS 3003 UART has baud rate 9600 | |
| } | |
| void loop() | |
| { | |
| #ifdef USE_DHT | |
| h = dht.readHumidity(); | |
| t = dht.readTemperature(); | |
| if(isnan(h) || isnan(t)) { h=-1;t=-1;} | |
| #endif | |
| retrievePM25Value(); | |
| if (pmat25 == 0 ) { | |
| Serial.println("try to read PM25 sensor later"); | |
| delay(5000); | |
| return; | |
| } | |
| //Process Filter or any logic control below | |
| if(mqttclient.connected()){ | |
| sendMQTTMessage(); | |
| mqttclient.loop(); | |
| delay(60000); | |
| } else { | |
| reconnectMQTT(); | |
| delay(1000); | |
| return; | |
| } | |
| } |
程式說明 :
1. 時間
如先前 NTP 範例, 我們只有在一開始時 setup() , 用 NTP 抓時間.
之後用 系統 millis() 和 NTP 時間 相加 計算. getCurrentTime()
將來如果搭配省電, 可以外接 RTC 定時喚醒/或重開主系統
2. LASS MQTT 資料格式
https://lass.hackpad.com/LASS-Data-specification-1dYpwINtH8R
程式是在 sendMQTTMessage() ,
用 sprinf 把資料按格式寫到 payload 後,
用 MQTT publish() 將 payload 送出
mqttclient.publish((char*)outTopic,payload);
3. 溫度
之後 用 DHT sensor 把溫度補上
4. GPS 位置.
目前先用 google map 把 GPS 位置手寫填到 gps_lat 和 gps_lon 變數中
| char gps_lat[] = "24.7805647"; // device's gps latitude | |
| char gps_lon[] = "120.9933177"; // device's gps longitude |
5. device ID
會拿這片卡的 MAC 最後兩碼來組合
sprintf(clientId, "FT2_0%02X%02X", mac[4], mac[5]);
執行結果 :
從log 可以看到
MQTT client id:FT2_0F0EC
可以從底下這個 link 看到
http://nrl.iis.sinica.edu.tw/LASS/show.php?device_id=FT2_0F0EC
之後來變成長期觀測站時, 可以來研究修改一下. 讓底下這個站顯示
http://iot.sparkfuture.io/pm25



留言
張貼留言