09.CoreInkで天気(気象庁)
9.CoreInkで天気(気象庁)修正待ち
気象庁のデータを表示させます。
日本語表示があるのでLovyanGFXモジュール。wifi接続、jsonデータ取得の必要があります。
ライブラリのインストール
Arduino IDE > スケッチ > ライブラリをインクルード > ライブラリを管理にて ArduinoJson by Benoit Blanchon (Ver6.17.3でした)を検索してインストール > 閉じる(Arduino_JSON by Arduino ではありません)
説明
気象庁の横浜地方気象台のページは、https://www.jma.go.jp/bosai/forecast/#area_type=class20s&area_code=1410000
で、気象庁の天気予報情報をXMLやJSONP形式で配信してくれている
https://www.drk7.jp/weather/
のサービスを利用します。1日1回AM6:00ごろ更新
しかし、気象庁のホームページがリニューアルしてdrk7.jpの更新待ちなので古いデータで確認します。2021/4更新予定だそうです。そこで、テストとして古いデータで1日のみ表示させてみます。
(4/24更新) https://www.drk7.jp/weather/ を見に行くと、「4月22日現在、一部要素の欠損、確認不足ではありますが、仮対応中です。」となっています。天気,天気マーク,波,最高・最低温度,6H毎の降水確率が7日分見れるようです。更新はもう少し待ってみます。
* 降水確率は、予報区内で一定時間内(ここでは6H)に降水量にして1mm以上の雨or雪の降る確率の平均値で、四捨五入して10%単位で表現しています。
* もし、1時間に1mm以上の雨が降ると、普通に傘が必要です。降水確率30%以上は外出時傘を持った方が良いらしいです。
drk7.jpで出力しているXMLデータ(実際使用するのはjsonデータ)で、一部を抜出すと以下が得られます。
<pref id="神奈川県">
<area id="東部"> // 横浜
<geo><long>139.5479</long><lat>35.5142</lat></geo>
<info date="2021/02/24">
<weather>くもり時々晴れ</weather>
<img>http://www.drk7.jp/MT/images/MTWeather/201.gif</img>
<weather_detail>北の風 海上 では 北の風 やや強く くもり 昼過ぎ から 夕方 晴れ</weather_detail>
<wave>波 1メートル</wave>
<temperature unit="摂氏">
<range centigrade="max">11</range>
<range centigrade="min">4</range>
</temperature>
<rainfallchance unit="%">
<period hour="00-06">0</period>
<period hour="06-12">0</period>
<period hour="12-18">10</period>
<period hour="18-24">10</period>
</rainfallchance>
</info>
<info date="2021/02/25"> // 2日目
・・・(略)
</info>
<info date="2021/02/26"> // 3日目
・・・(略)
</info>
<info date="2021/02/27"> // 4日目
・・・(略)
</info>
<info date="2021/02/28"> // 5日目
・・・(略)
</info>
<info date="2021/03/01"> // 6日目
・・・(略)
</info>
<info date="2021/03/02"> // 7日目
・・・(略)
</info>
</area>
<area id="西部"> // 小田原
・・・(略)
</area>
</pref>
予報項目
全ての日(7日間)にある項目- 年月日
- 概略の天気
- 降水確率(0-6,6-12,12-18,18-24時の1日4回x7日)
- 最高温度・最低温度
- 天気マーク(gif)
- 詳細な天気
- 波の高さ
画像の設定方法
6つの画像は以下の方法で上から順に決めました。- "雨" + "くもり" → "imgKumoriAme[]"
- "雨" → "imgAme[]"
- "晴" + "くもり" → "imgHareKumori[]"
- "晴" → "imgHare[]"
- "雪" → "imgYuki[]"
- "曇り" → "imgKumori[]"
- ""
年/月/日 ↑最高気温|↓最低気温℃
概略天気
天気マーク
詳細天気
降水確率(0-6時)0 (6-12)0 (12-18)10 (18-24)10%
波の高さ
* 以上が1日に得られるすべてです。
スケッチ
xxxxxは、接続するwifiのSSIDとパスワードを記入します。前回作った天気マークの"icon6.h"も必要です。
// 天気情報 気象庁
// www.drk7.jpからjsonデータを得る。2021/4再開
// 関数一覧
// pushSprite // LovyanGFXの1画面表示お決まり
// getJson // jsonを得る
// createJson // JSONP形式をJSON形式に変換
// drawWeather // 1画面セットする
// inkSet // coreInkを使う時お決まり
// wifiSet // wifiを使う時お決まり
// nihonSet // 日本語を表示する時お決まり
// setup //
// loop // 何もしない
#include "icon6.h" // 天気マーク 同一ホルダに置く
#include <M5CoreInk.h> // M5Stack CoreInk使用
#include <WiFi.h> // wifi使用
#include <HTTPClient.h> // httpと通信
#include <ArduinoJson.h> // json型式で抽出
#include <efontEnableJaMini.h> // フォント 日本語ミニ
#include <efontFontData.h> // efontのフォントデータ
#define LGFX_AUTODETECT // init時に対応機種を自動認識
#include <LovyanGFX.hpp> // 描画ライブラリ
const char* ssid = "xxxxx"; // 自分のwifiのSSID
const char* password = "xxxxx"; // wifiのパスワード
const char* weatherURL = "https://www.drk7.jp/weather/json/14.js"; //神奈川県
const char* region = "東部"; // 横浜
DynamicJsonDocument weatherInfo(20000); //
Ink_Sprite InkPageSprite(&M5.M5Ink); // 定義
static LGFX_Sprite sprite; // 定義
// LovyanGFXの1画面表示関数
void pushSprite(Ink_Sprite *coreinkSprite, LGFX_Sprite *lgfxSprite) {
coreinkSprite->clear();
for (int y = 0; y < 200; y++) { // 縦方向0-199
for (int x = 0; x < 200; x++) { // 横方向0-199
uint16_t c = lgfxSprite->readPixel(x, y);
if (c == 0x0000) {
coreinkSprite->drawPix(x, y, 0);
}
}
}
coreinkSprite->pushSprite(); // アロー演算子
}
DynamicJsonDocument getJson() { //
DynamicJsonDocument doc(20000); //
if ((WiFi.status() == WL_CONNECTED)) { // wifiが接続されていたら
HTTPClient http; // 定義
http.begin(weatherURL); // アクセスするURLを登録
Serial.println(weatherURL); // シリアルモニタに表示
int httpCode = http.GET();//登録URLに、GETリクエスト送信
if (httpCode > 0) {//HTTPのリターンコード。エラーの場合は負数。
String jsonString = createJson(http.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
deserializeJson(doc, jsonString);
// 直列化されたデータをDynamicJsonDocumentの形に変換
} else {
Serial.println("エラー HTTPリクエスト"); // シリアルモニタに表示
}
http.end(); // TCPコネクションを切断しHTTP通信を終了
}
return doc;
}
// JSONP形式をJSON形式に getJsonから1回呼ばれる
String createJson(String jsonString) {
jsonString.replace("drk7jpweather.callback(", "");
return jsonString.substring(0, jsonString.length() - 2);
}
void drawWeather(String infoWeather) { // 1画面セットする
DynamicJsonDocument doc(20000); //
deserializeJson(doc, infoWeather); //
String myd = doc["date"]; // 年月日
sprite.setCursor(0, 1); sprite.print(myd); //
Serial.println(myd); // シリアルモニタへ表示
String maxTmp = doc["temperature"]["range"][0]["content"]; // 最高気温
Serial.print("最高気温"); Serial.print(maxTmp); // シリアルモニタへ表示
String minTmp = doc["temperature"]["range"][1]["content"]; // 最低気温
Serial.print("/最低気温"); Serial.println(minTmp); // シリアルモニタへ表示
sprite.setCursor(130, 1); sprite.printf("↑%02s|↓%02s℃", maxTmp, minTmp);
String weather = doc["weather"]; // 概略天気
sprite.setCursor(0, 21); sprite.print(weather); //
Serial.println(weather); // シリアルモニタへ表示
int x = 64, y = 35, W = 72, H = 72; // 天気マークの表示位置と大きさ
if (weather.indexOf("雨") != -1) {
if (weather.indexOf("くもり") != -1) {
sprite.pushImage(x, y, W, H, imgKumoriAme); // くもり雨
} else { //(x, y, W, H, imgデータ)
sprite.pushImage(x, y, W, H, imgAme); // 雨
}
} else if (weather.indexOf("晴") != -1) {
if (weather.indexOf("くもり") != -1) {
sprite.pushImage(x, y, W, H, imgHareKumori); // 晴れくもり
} else {
sprite.pushImage(x, y, W, H, imgHare); // 晴れ
}
} else if (weather.indexOf("雪") != -1) {
sprite.pushImage(x, y, W, H, imgYuki); // 雪
} else if (weather.indexOf("くもり") != -1) {
sprite.pushImage(x, y, W, H, imgKumori); // くもり
}
String weather_d = doc["weather_detail"]; // 詳細天気
sprite.setCursor(0, 105); sprite.print(weather_d); //
Serial.println(weather_d); // シリアルモニタへ表示
String rain0_6 = doc["rainfallchance"]["period"][0]["content"]; // 降水量0-6時
Serial.print("降水確率:"); Serial.print(rain0_6); // シリアルモニタへ表示
String rain6_12 = doc["rainfallchance"]["period"][1]["content"]; // 6-12時
Serial.print(" "); Serial.print(rain6_12); // シリアルモニタへ表示
String rain12_18 = doc["rainfallchance"]["period"][2]["content"];// 12-18時
Serial.print(" "); Serial.print(rain12_18); // シリアルモニタへ表示
String rain18_24 = doc["rainfallchance"]["period"][3]["content"]; // 18-24時
Serial.print(" "); Serial.println(rain18_24); // シリアルモニタへ表示
//sprite.setCursor(0, 140); sprite.print("(0-)(6-)(12)(18)");
sprite.setCursor(0, 160);
sprite.printf("(0-)%02s(6)%02s(12)%02s(18)%02s%%"
, rain0_6, rain6_12, rain12_18, rain18_24);
String wave = doc["wave"]; // 波
sprite.setCursor(0, 180); sprite.print(wave); //
Serial.println(wave); // シリアルモニタへ表示
}
void inkSet() { // お決まり
M5.begin(); // E-Ink,RTC,I2C,ブザーを初期化
if (!M5.M5Ink.isInit()) { // 初期化出来なければ
Serial.println("エラー Ink Init"); // シリアルモニタに表示
while (1) delay(100); // ずっと待つ
}
M5.M5Ink.clear(); // 画像クリア
delay(1000); // 1秒待つ
InkPageSprite.creatSprite(0, 0, 200, 200, false);
// 画像領域を作成し、画面ドライバーから画像データバフを取得しない
}
void wifiSet() { // お決まり
Serial.print(ssid); // シリアルモニタに表示
Serial.print("に接続中"); // シリアルモニタに表示
WiFi.begin(ssid, password); // ネット設定を初期化
while (WiFi.status() != WL_CONNECTED) { // 接続状態が接続完でない時
delay(500); // 0.5秒待つ
Serial.print("."); // シリアルモニタに表示
}
Serial.println("ok"); // シリアルモニタに表示
}
void nihonSet() { // efont日本語16太 お決まり(16or24)
sprite.setColorDepth(2); // 2ビットパレットモードに設定
sprite.createPalette(); // パレットモードにする?
sprite.createSprite(200, 200); // 200x200でスプライトを作成
sprite.clear(TFT_WHITE); // 全体の背景色を白
sprite.setFont(&fonts::efontJA_16_b); // efont日本語16ドット太字
sprite.setTextColor(TFT_BLACK, TFT_WHITE); // 白地に黒字
}
void setup() {
inkSet(); // CoreInkの設定
wifiSet(); // wifiの設定
nihonSet(); // 日本語設定(efont16太)
weatherInfo = getJson(); // 関数へ
WiFi.disconnect(true); // ネットワークから切断
WiFi.mode(WIFI_OFF); // wifiの動作モード
Serial.print("wifi offか="); // シリアルモニタに表示
Serial.println(WiFi.status()); // wifiの接続状態
// 0(WiFi.beginが呼出され3or4になるまで),1(使用可能なSSIDがない)
// 2(スキャン完了),3(WiFi接続),4(すべての試行で接続失敗)
// 5(接続が失われた),255(WiFiシールドがない)
String today = weatherInfo["pref"]["area"][region]["info"][0];
// 神奈川県 area = 東部 info = 今日
drawWeather(today); // 1画面設定関数へ
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
void loop() {
delay(15000); // 15秒待つ
}