- 實現 D1 mini 抓取中央氣象局資料
- 實現 D1 mini 與 BLYNK 連結
承前文
NodeMCU 教學 - 06:使用 WeMos D1 mini NodeMCU 網路爬蟲 抓取 JSON 天氣資訊
我們已經完成用 D1 mini 來從網路上取得氣溫資訊,最後就只要結合
NodeMCU 教學 - 02:WeMos D1 mini NodeMCU 與 BLYNK
就能完成最後一浬路了 !!!!
#define BLYNK_PRINT Serial
#include "ESP8266WiFi.h"
#include "ArduinoJson.h"
#include "BlynkSimpleEsp8266.h"
#include "SimpleTimer.h"
void get_Weather();
bool showWeather(char *json);
// ===== Wifi setup =====
const char *ssid = "WIFI帳號";
const char *pass = "wifi密碼";
// ===== Temp. setup =====
const char *host = "opendata.cwb.gov.tw";
const char *dataid = "O-A0003-001";
const char *locationName = "新竹";
const char *privateKey = "你的識別碼";
const char *elementName = "TEMP";//可用逗號隔開來取得多筆資料,詳細請見 CWB_Opendata_API.pdf
static char respBuf[4096];
// ==== BLYNK ====
char auth[] = "BLYNK 的 Auth";
// ===== Hardware setup =====
const int ledPin = D4; // the number of the LED pin
SimpleTimer timer;
volatile float temp1 = 0;
volatile int flag = 1;
void timer_1260000(){
flag = 0;
Serial.println("timerInterrupt START!");
get_Weather();
Serial.println("Send Temp. data to BLYNK !!");
Blynk.virtualWrite(V1, temp1); //一定要寫在 showWeather 的 Function 主體以外
Serial.println("timerInterrupt END!\n");
flag = 1;
}
void setup()
{
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
delay(10);
digitalWrite(ledPin,LOW);
Blynk.begin(auth, ssid, pass);
timer.setInterval(1260000L, timer_1260000);
digitalWrite(ledPin,HIGH);
}
void loop()
{
if(flag) {
Blynk.run();
timer.run();
}
delay(20);
}
/* =====================*/
// ===== get_Weather ====
/* =====================*/
void get_Weather()
{
digitalWrite(ledPin, HIGH);
Serial.print("Connecting to ");
Serial.println(host);
WiFiClient client;
const int Port = 80;
if (!client.connect(host, Port)) {
Serial.println("Connection failed");
return;
}
// Create a URI for the request
String url = "/api/v1/rest/datastore/";
url += dataid;
url += "?Authorization=";
url += privateKey;
url += "&locationName=";
url += locationName;
url += "&elementName=";
url += elementName;
Serial.print("Requesting URL: ");
Serial.println(url);
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
client.flush();
int respLen = 0;
bool skip_headers = true;
while (client.connected() || client.available()) {
if (skip_headers) {
String aLine = client.readStringUntil('\n');
if (aLine.length() <= 1) {
skip_headers = false;
}
}
else {
int bytesIn;
bytesIn = client.read((uint8_t *)&respBuf[respLen], sizeof(respBuf) - respLen);
Serial.print(F("bytesIn ")); Serial.println(bytesIn);
if (bytesIn > 0) {
respLen += bytesIn;
if (respLen > sizeof(respBuf)) respLen = sizeof(respBuf);
}
else if (bytesIn < 0) {
Serial.print(F("read error "));
Serial.println(bytesIn);
}
}
delay(1);
}
Serial.println();
Serial.println("closing connection");
Serial.println();
client.stop();
if (respLen >= sizeof(respBuf)) {
Serial.print(F("respBuf overflow "));
Serial.println(respLen);
return;
}
respBuf[respLen++] = '\0';
Serial.print(F("respLen "));
Serial.println(respLen);
Serial.println("");
if(showWeather(respBuf)) {
Serial.println("Get Temp. data");
}
digitalWrite(ledPin, LOW);
}
/* =====================*/
// ===== showWeather ====
/* =====================*/
bool showWeather(char *json){
StaticJsonBuffer<3072> jsonBuffer;
// Skip characters until first '{' found
// Ignore chunked length, if present
char *jsonstart = strchr(json, '{');
Serial.println("jsonstart");
Serial.println(jsonstart);
Serial.println("");
if (jsonstart == NULL) {
Serial.println(F("JSON data missing"));
return false;
}
json = jsonstart;
// Parse JSON
JsonObject& root = jsonBuffer.parseObject(json);
if (!root.success()) {
Serial.println(F("jsonBuffer.parseObject() failed"));
return false;
}
// Extract weather info from parsed JSON
int stationId = root["records"]["location"][0]["stationId"];
Serial.print("stationId = ");
Serial.println(stationId);
float temp = root["records"]["location"][0]["weatherElement"][0]["elementValue"];
Serial.print("Temp. = ");
Serial.println(temp);
//Blynk.virtualWrite(V1, temp); 直接寫成這樣讓 temp 傳上雲端不行
temp1 = temp; // 用一個全域變數供 get_Weather 調用
//Blynk.virtualWrite(V1, temp1); 寫成這樣也不行
return true;
}
3072>
程式碼的部分有點長,BLYNK 部分的介面就簡單的顯示就好
最後的結果如上方兩張圖,注意在顯示元件的地方我們選擇用 PUSH ,並在程式碼中利用 timer 來定時進行推送數據到雲端的功能。
在實現的過程中也出現一些狀況如下圖所示
我本來是將 Blynk.virtualWrite(V1, temp); 寫在 showWeather 函數末端,結果微控器會一直出現上圖中的錯誤,之後是將 temp 存到全域變數 temp1 ,並且挪到 showWeather 函數之外才免除這個錯誤
網路上查詢可能的成因之後發現要根治此問題有點麻煩,暫時將此問題擱置