16.CoreInkで天気(気象庁)2
16.CoreInkで天気(気象庁)2
気象庁の天気予報を表示します。今年の春に気象庁のホームページがリニューアルし、Webの公開APIでは無いですが、気象庁のサイト内でJSONファイルが利用されています。このJSONファイルから表示します。
予報内容
0:今日, 1:明日, 2:明後日,・・・ 7:7日先No | 日後 | 01234567 |
1 | 日付 | 〇〇〇〇〇〇〇〇 |
2 | 降水確率 | 〇〇〇〇〇〇〇〇 |
3 | 天気マーク | 〇〇〇〇〇〇〇〇 |
4 | 詳細天気 | 〇〇〇----- |
5 | 簡易天気 | ---〇〇〇〇〇 |
6 | 最高温度 | 〇〇〇〇〇〇〇〇 |
7 | 最低温度 | 〇〇〇〇〇〇〇〇 |
8 | 風 | 〇〇〇----- |
9 | 波 | 〇〇〇----- |
10 | 信頼度 | ---〇〇〇〇〇 |
・平年の最高・最低気温,平年の7日合計降水量
・県内の明後日(or明日)までの予報文
・関東甲信地方の週間予報文
注)
No.2の0-1日は6Hごと「*/*/*/*%」,2-7日は1日「*%」。時刻により過去の表示が"-"になります。降水確率0-6は、AM8以前から。最低気温は、AM8以前から。降水確率6-12は、AM11から"-"。降水確率12-18と最高気温はPM5から"-"になります。降水確率18-24は、常時表示です。(一部推定)
No.6&7の0-1日は「*℃」、2-7日は範囲有り「*(*-*)℃」
No.7は、時刻により過去の表示が"-"になります。
No.9は、表示の無い地域もあります。
* 降水量(mm)の予報は有りません。
予報の資料
予報の更新時刻
・週間予報: AM11,PM5・明後日までの予報: 上記とAM5。これ以外もあり
・AM5時の更新では明日までと6日先まで、それ以外は、3日と7日先まで
注)時刻により表示数が異なります。AM0-5は、明日の項が当日です。
降水確率
明日までの予報は、0時から6/6から12/12から18/18から24の順上記以外は、1日
・降水確率は、予報区内で1mm以上の雨の降る確率です。6H毎に10%単位で発表されます。例)18-24時が20%は、その期間に1mm以上の雨の降る可能性が100回中20回あるという意味で、降水量と関係ありません。
最高・最低気温
・明日までは、日中の最高気温, 朝の最低気温・明後日以降は、1日の最高気温, 1日の最低気温。()範囲に入る確率はおよそ80%です。
信頼度
A (確度高い)・降水有無の適中率: 明日予報並み(88%)
・翌日に降水有無が変わる可能性: ほとんどない(1%)
B (やや高い)
・降水有無の適中率: 4日先の予報と同程度(73%)
・翌日に降水有無が変わる可能性:低い(6%)
C (やや低い)
・降水有無の適中率: Bより低い(58%)
もしくは
・翌日に降水有無が変わる可能性: Bより高い(16%)
* %値は、5年間の平均値
平年値
・降水量: 予報期間7日間(or 6日間)で合計したの平年並の範囲・最高・最低気温: 予報4日目の平年値
スケッチに必要な資料
エリアのコード
http://www.jma.go.jp/bosai/common/const/area.json1都3県のpathCodeは、
・埼玉県 110000 (南部,北部,秩父地方)
・千葉県 120000 (北西部,北東部,南部)
・東京都 130000 (東京地方,伊豆諸島北部,伊豆諸島南部,小笠原諸島)
・神奈川 140000 (東部,西部)
天気マーク
https://www.jma.go.jp/bosai/forecast/img/*.svg見つけたマークは、
100:晴, 101:晴時々曇, 102:晴一時雨, 110:晴後曇
200:曇, 201:曇時々晴, 202:曇一時雨, 210:曇後時々晴, 212:曇後一時雨
300:雨, 301:雨時々晴, 302:雨時々曇, 303:雨時々雪
400:雪, 401:雪時々晴, 402:雪時々曇, 403:雪時々雨
500:月, 501:月時々曇, 502:月時々雨, 510:月後曇, 610:曇後月
203:曇時々雨 ←ファイルは無いが予報で使用している。?
例)https://www.jma.go.jp/bosai/forecast/img/100.svg は、晴のマークです。
天気マークの決め方
気象庁の天気マークは20以上あるので、以下の方法で6つにまとめました。No | 条件 | yes | no |
---|---|---|---|
1 | 雨 | 2へ | 3へ |
2 | 曇 | 曇雨 | 雨 |
3 | 晴 | 4へ | 5へ |
4 | 曇 | 晴曇 | 晴 |
5 | 雪 | 雪 | 6へ |
6 | 曇 | 曇 | - |
HPで3日/8日の予報
https://www.jma.go.jp/bosai/forecast/data/forecast/140000.jsonJsonファイルに注釈はつけられません。字下げをし、注釈を付けました。
{["publishingOffice":"横浜地方気象台", // 気象台名
"reportDatetime":"2021-06-17T11:00:00+09:00", // 発表時刻
"timeSeries":[
{"timeDefines":["2021-06-17T11:00:00+09:00",
"2021-06-18T00:00:00+09:00",
"2021-06-19T00:00:00+09:00"],//今日から3日の日付
"areas":[
{"area":{"name":"東部",
"code":"140010"}, // 東部(横浜)
"weatherCodes":["200","200","212"], // 3日間の天気マーク 曇り,曇り,曇り後雨
"weathers":["くもり 所により 夜のはじめ頃 まで 雨 で 雷を伴う",
"くもり 明け方 まで 晴れ",
"くもり 後 一時 雨"], // 3日間の天気
"winds":["北東の風 後 北の風 海上 では 北東の風 やや強く",
"北の風 後 南の風",
"南の風 後 やや強く"], // 3日間の風
"waves":["1.5メートル 後 1メートル",
"1メートル",
"1メートル 後 1.5メートル"]}, // 3日間の波
{"area":{"name":"西部",
"code":"140020"}, // 西部(小田原) 上記と同様
"weatherCodes":["200","200","212"],
"weathers":["くもり 所により 夜のはじめ頃 まで 雨 で 雷を伴う",
"くもり",
"くもり 後 一時 雨"],
"winds":["北の風 海上 では 北東の風 やや強く",
"北の風 後 南の風",
"南の風 後 やや強く"],
"waves":["1.5メートル 後 1メートル",
"1メートル",
"1メートル 後 1.5メートル"]}]},
{"timeDefines":["2021-06-17T12:00:00+09:00",
"2021-06-17T18:00:00+09:00",
"2021-06-18T00:00:00+09:00",
"2021-06-18T06:00:00+09:00",
"2021-06-18T12:00:00+09:00",
"2021-06-18T18:00:00+09:00"], // 降水確率開始時刻6点
"areas":[
{"area":{"name":"東部",
"code":"140010"},
"pops":["30","20","0","0","10","10"]}, // 東部 降水確率6点
{"area":{"name":"西部",
"code":"140020"},
"pops":["30","20","10","10","10","10"]}]}, // 西部
{"timeDefines":["2021-06-17T09:00:00+09:00",
"2021-06-17T00:00:00+09:00",
"2021-06-18T00:00:00+09:00",
"2021-06-18T09:00:00+09:00"], // ?気温時刻4点
"areas":[
{"area":{"name":"横浜",
"code":"46106"},
"temps":["26","26","19","27"]}, // 横浜 最低気温 最高気温 明日まで
{"area":{"name":"小田原",
"code":"46166"},
"temps":["26","26","17","26"]}]}]}, // 小田原
{"publishingOffice":"横浜地方気象台", // 気象台名
"reportDatetime":"2021-06-17T11:00:00+09:00", // 発表時刻
"timeSeries":[
{"timeDefines":["2021-06-18T00:00:00+09:00",
"2021-06-19T00:00:00+09:00",
"2021-06-20T00:00:00+09:00",
"2021-06-21T00:00:00+09:00",
"2021-06-22T00:00:00+09:00",
"2021-06-23T00:00:00+09:00",
"2021-06-24T00:00:00+09:00"], // 明日から7日先の日付
"areas":[{
"area":{"name":"神奈川県","code":"140000"}, // 神奈川県
"weatherCodes":["200","212","202","200","202","202","202"],//明日から7日先の天気マーク
"pops":["","60","50","30","50","60","50"], // 明後日からの6日先の降水確率
"reliabilities":["","","C","A","C","B","C"]}]}, // 明々後日から5日先の信頼度
{"timeDefines":["2021-06-18T00:00:00+09:00",
"2021-06-19T00:00:00+09:00",
"2021-06-20T00:00:00+09:00",
"2021-06-21T00:00:00+09:00",
"2021-06-22T00:00:00+09:00",
"2021-06-23T00:00:00+09:00",
"2021-06-24T00:00:00+09:00"], // 明日から7日先の日付
"areas":[{
"area":{"name":"横浜",
"code":"46106"}, // 横浜
"tempsMin":["","21","21","21","18","17","18"], // 明後日から6日先の最低気温
"tempsMinUpper":["","23","23","22","20","19","20"], // その範囲H側
"tempsMinLower":["","19","20","19","15","15","16"], // その範囲L側
"tempsMax":["","27","29","27","22","21","23"], // 明後日から6日先の最高気温
"tempsMaxUpper":["","28","30","30","27","26","28"], // その範囲H側
"tempsMaxLower":["","25","26","24","21","19","21"]}]}], // その範囲L側
"tempAverage":{
"areas":[{
"area":{"name":"横浜",
"code":"46106"},
"min":"19.7",
"max":"25.9"}]}, // 明日から7日先までの最低気温 最高気温(℃)
"precipAverage":{
"areas":[{
"area":{"name":"横浜",
"code":"46106"},
"min":"27.0",
"max":"61.5"}]}}] // 明日から7日先までの降水量合計範囲(mm)
神奈川県の天気概況
https://www.jma.go.jp/bosai/forecast/data/overview_forecast/140000.json
{"publishingOffice":"横浜地方気象台",
"reportDatetime":"2021-06-17T10:57:00+09:00",
"targetArea":"神奈川県",
"headlineText":"東部では、17日夜のはじめ頃まで土砂災害に注意してください。神奈川県では、17日夜のはじめ頃まで落雷に注意してください。",
"text":" 前線が、華中から東シナ海を通って日本の南へのびています。また、前線上の伊豆諸島の南には低気圧があって、北東へ進んでいます。\n\n
神奈川県は、おおむね曇りとなっています。\n\n
17日は、上空の寒気や湿った空気の影響により、曇りで、夜のはじめ頃にかけて雨や雷雨となる所があるでしょう。\n\n
18日は、高気圧に緩やかに覆われますが、湿った空気の影響により、曇りで、東部では、明け方まで晴れる見込みです。\n\n
神奈川県の海上では、17日は波がやや高いでしょう。18日は多少波がある見込みです。"}
関東週間天気予報
https://www.jma.go.jp/bosai/forecast/data/overview_week/130000.json
{"publishingOffice":"気象庁",
"reportDatetime":"2021-06-17T10:35:00+09:00",
"headTitle":"関東甲信地方週間天気予報",
"text":"予報期間 6月18日から6月24日まで\n
向こう一週間は、前線や湿った空気の影響で曇りや雨の日が多いでしょう。\n
最高気温と最低気温はともに、平年並か平年より低い日が多いですが、期間の前半は平年より高い所もある見込みです。\n
降水量は、平年並か平年より多いでしょう。"}
概略天気
見つけられなかったので、天気マークから判断しています。表示内容
・横浜の予報です。・ボタンを下へ回すと下の項目へ、上へ回すと上の項目へ移動します。
・3秒押すと反応します。
・概略天気は天気マークから判断しているので、ホームページと少し違う場合があります。例)(HP)曇後一時雨 → (M5)曇後雨
[0] 今日の予報
[1] 明日の予報
[2] 明後日の予報
[3] 3日先の予報
[4] 4日先の予報
[5] 5日先の予報
[6] 6日先の予報
[7] 7日先の予報
無い場合は次へスキップします。
[8] 神奈川県の予報
1頁目
2頁目
3頁目
[9] 関東の予報
長くても最初の1頁のみ表示します。
[0]へ戻る。
[7]でデータが無い場合は次に移動します。 [8]は3頁あるのでボタンを押し込むと次の頁へ移動します。
[8]は、3頁で表示できる分のみ表示します。
[9]は、1頁分のみ表示します。
その時のホームページ
朝開いた時(2日/7日)
同日の昼に開いた時(3日/8日)
スケッチ
2ヶ所の*****は自分のwifiのSSIDとそのwifiのパスワードを記入してください。
// 天気情報 気象庁https://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=140000
// 気象庁ホームページからjsonデータを得てCoreInkに表示
#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 = "*****"; // 自分のwifiのSSID
const char* password = "*****"; // wifiのパスワード
const char* weatherURL = "https://www.jma.go.jp/bosai/forecast/data/forecast/140000.json";
// 気象庁 天気予報 神奈川県 横浜市
const char* dayURL = "https://www.jma.go.jp/bosai/forecast/data/overview_forecast/140000.json";
// 気象庁 神奈川県 天気概況
const char* weekURL = "https://www.jma.go.jp/bosai/forecast/data/overview_week/130000.json";
// 気象庁 関東甲信地方週間天気予報
DynamicJsonDocument weatherInfo(20000); //
Ink_Sprite InkPageSprite(&M5.M5Ink); // 定義
static LGFX_Sprite sprite; // 定義
int wDay = 0; // 0=今日,1=明日,2=明後日,・・・,7=7日先,8=神奈川県予報,9=関東予報
int bMid = 1, bMidN = 396; // bunDayの頁(1-3),1頁の文字数(12字x11行x3?=396)
String myd; // 日付
String minTmpL, minTmp, minTmpH, maxTmpL, maxTmp, maxTmpH ;//最低気温,最高気温
String rain00_06, rain06_12, rain12_18, rain18_24; // 降水確率
String weather_d; // 天気
String reliability; // 信頼度
String weatherCode; // 天気マーク
String today; // json用文字列
String nenTmpMin, nenTmpMax; // 平年値 気温
String nenPreMin, nenPreMax; // 平年値 降水量
char buf1[50]; // 表示用文字列
String bunDay, bunWeek; // 2文
int hyou = 3; // 2:2日/6日, 3:3日/7日
// 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(dayURL); // ◆dayURL アクセスするURLを登録
//Serial.print("dayULR = "); Serial.println(dayURL);//シリアルモニタに表示
int httpCodeD = http.GET();//登録URLに、GETリクエスト送信
if (httpCodeD > 0) { //HTTPのリターンコード。エラーの場合は負数。
String jsonStringD = createJson(http.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
Serial.println(jsonStringD); // 読込みデータ表示
bunDay = jsonStringD; // dayURLのjson文字列を保存しておく
}
http.begin(weekURL); // ◆weekURL アクセスするURLを登録
//Serial.print("weekULR = "); Serial.println(dayURL);//シリアルモニタに表示
int httpCodeW = http.GET();//登録URLに、GETリクエスト送信
if (httpCodeW > 0) {//HTTPのリターンコード。エラーの場合は負数。
String jsonStringW = createJson(http.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
Serial.println(jsonStringW); // 読込みデータ表示
bunWeek = jsonStringW; // weekURLのjson文字列を保存しておく
}
http.begin(weatherURL); // ◆weatherULR アクセスするURLを登録
//Serial.print("weatherULR = "); Serial.println(weatherURL);//シリアルモニタに表示
int httpCode = http.GET(); // 登録URLに、GETリクエスト送信
if (httpCode > 0) { // HTTPのリターンコード。エラーの場合は負数。
String jsonString = createJson(http.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
Serial.println(jsonString); // 読込みデータ表示
deserializeJson(doc, jsonString);
// 直列化されたデータをDynamicJsonDocumentの形に変換
} else {
Serial.println("エラー HTTPリクエスト"); // シリアルモニタに表示
}
http.end(); // TCPコネクションを切断しHTTP通信を終了
}
return doc;
}
// JSONP形式をJSON形式に getJsonから1回呼ばれる
String createJson(String jsonString) {
return jsonString.substring(0, jsonString.length() - 2);
}
String mojiHenkan(String moji) { // 文字変換
moji.replace(" ", ""); // 全角空白を削除
moji.replace("メートル", "m"); // 波で使用
moji.replace("0", "0"); // 半角変換 波で使用
moji.replace("1", "1"); //
moji.replace("2", "2"); //
moji.replace("3", "3"); //
moji.replace("4", "4"); //
moji.replace("5", "5"); //
moji.replace("6", "6"); //
moji.replace("7", "7"); //
moji.replace("8", "8"); //
moji.replace("9", "9"); //
moji.replace(".", "."); //
moji.replace("-", "/"); // "-" → "/" 時刻で使用
moji.replace("T", " "); // "T" → " " 時刻で使用
moji.replace("\n", ""); // 予報文で使用
return moji;
}
void drawWeather(String infoWeather) { // 1画面セットする
DynamicJsonDocument doc(20000); //
deserializeJson(doc, infoWeather); // 直列化されたデータを
// DynamicJsonDocumentの形に変換
sprite.clear(TFT_WHITE); // 全体の背景色を白
Serial.println(); // 改行
// 詳細予報表と週間予報表の日数判定
int i, count = 0; // 初期設定
String timeDefine = doc[0]["timeSeries"][0]["timeDefines"]; //詳細日配列
for (i = 0; timeDefine[i] != '\0'; i++) { // 文字列の最初から最後まで
if (timeDefine[i] == ',') { // ','の数をカウント
count++; // 1カウントする
}
}
hyou = count + 1; // 2:詳細2日/週間7日,3:3日/8日
if (wDay < 8) { // 天気マーク付画面の場合
// 日付
sprite.setCursor(0, 1); // 表示位置(x,y)
sprintf(buf1, "[%d] ", wDay); // 何日目
sprite.print(buf1); Serial.print(buf1); // 表示
if (wDay == 0) { // ◆日付 今日
String A = doc[0]["reportDatetime"]; // 発表月日時分
myd = A; myd = mojiHenkan(myd); // 文字変換
sprite.print(myd.substring(5, 16)); // 月日時分
Serial.println(myd.substring(5, 16)); //4+1文字目から16文字目までを表示
} else { // ◆日付 明日-7日先
String A = doc[1]["timeSeries"][0]["timeDefines"][wDay + 2 - hyou]; //予報日
myd = A; myd = mojiHenkan(myd); // 文字変換
sprite.print(myd.substring(0, 10)); // 年月日
Serial.println(myd.substring(0, 10)); // 0+1文字目から10文字目までを表示
}
// 信頼度
sprite.setCursor(140, 1); // 表示位置
if (wDay < 2 || (wDay == 2 && hyou == 3)) { // ◆信頼度 今日,明日,2日でhyou=3の時
Serial.println("信頼:-"); // シリアルモニタへ表示 画面表示無し
} else { // 2日でhyou=2 or 3-7日先
String A = doc[1]["timeSeries"][0]["areas"][0]["reliabilities"][wDay + 2 - hyou]; //信頼度
reliability = A;
if (reliability == "A") { // A→高とした
reliability = "信頼:高";
} else if (reliability == "B") { // B→中とした
reliability = "信頼:中";
} else { // C→低とした
reliability = "信頼:低";
}
sprite.print(reliability); Serial.println(reliability); // 表示
}
// 天気マーク(天気文に少し消される)
int x = 64, y = 50, W = 72, H = 72; // 天気マークの表示位置と大きさ
int wNo; // 天気マークNo.
if (wDay < 2) { // ◆マーク 今日と明日
String A = doc[0]["timeSeries"][0]["areas"][0]["weatherCodes"][wDay];//天気コード
weatherCode = A; // 天気マーク
} else { // ◆マーク 2-7日先
String A = doc[1]["timeSeries"][0]["areas"][0]["weatherCodes"][wDay + 2 - hyou];//天気コード
weatherCode = A; // 天気マーク
}
wNo = weatherCode.toInt(); // String→整数 に変換
switch (wNo) {
case 302: // 雨時々曇
case 301: // 雨時々晴
case 202: // 曇一時雨
case 203: // 曇時々雨
case 102: // 晴時々雨
case 112: // 晴後雨
case 502: // 月時々雨
case 212: // 曇後雨
case 214: // 曇昼過ぎから雨
sprite.pushImage(x, y, W, H, imgKumoriAme); // くもり雨
break;
case 300: // 雨
sprite.pushImage(x, y, W, H, imgAme); // 雨
break;
case 101: // 晴時々曇
case 501: // 月時々曇
case 201: // 曇時々晴
case 110: // 晴後曇
case 510: // 月後曇
case 210: // 曇後晴
case 610: // 曇後月
sprite.pushImage(x, y, W, H, imgHareKumori); // 晴れくもり
break;
case 100: // 晴
case 500: // 月
sprite.pushImage(x, y, W, H, imgHare); // 晴れ
break;
case 400: // 雪
case 401: // 雪時々晴
case 402: // 雪時々曇
case 403: // 雪時々雨
case 303: // 雨時々雪
sprite.pushImage(x, y, W, H, imgYuki); // 雪
break;
case 200: // 曇
sprite.pushImage(x, y, W, H, imgKumori); // くもり
break;
}
// 天気文
sprite.setCursor(0, 20); // 表示位置
if (wDay < 2 || (wDay == 2 && hyou == 3)) { // ◆天気文 今日,明日,2日でhyou=3の時
String A = doc[0]["timeSeries"][0]["areas"][0]["weathers"][wDay]; // 詳細天気
weather_d = A; weather_d = mojiHenkan(weather_d); // 文字変換
sprite.print(weather_d); Serial.println(weather_d); // 表示
} else { // ◆天気文 2日でhyou=2の時,3-7日先
String A = doc[1]["timeSeries"][0]["areas"][0]["weatherCodes"][wDay + 2 - hyou];//詳細天気
weather_d = A;
if (weather_d == "100") {
weather_d = "晴";
} else if (weather_d == "101") {
weather_d = "晴時々曇";
} else if (weather_d == "102") {
weather_d = "晴一時雨";
} else if (weather_d == "110") {
weather_d = "晴後曇";
} else if (weather_d == "112") {
weather_d = "晴後雨";
} else if (weather_d == "200") {
weather_d = "曇";
} else if (weather_d == "201") {
weather_d = "曇時々晴";
} else if (weather_d == "202") {
weather_d = "曇一時雨";
} else if (weather_d == "203") {
weather_d = "曇時々雨";
} else if (weather_d == "210") {
weather_d = "曇後晴";
} else if (weather_d == "212") {
weather_d = "曇後雨";
} else if (weather_d == "300") {
weather_d = "雨";
} else if (weather_d == "301") {
weather_d = "雨時々晴";
} else if (weather_d == "302") {
weather_d = "雨時々曇";
} else if (weather_d == "303") {
weather_d = "雨時々雪";
} else if (weather_d == "400") {
weather_d = "雪";
} else if (weather_d == "401") {
weather_d = "雪時々晴";
} else if (weather_d == "402") {
weather_d = "雪時々曇";
} else if (weather_d == "403") {
weather_d = "雪時々雨";
} else if (weather_d == "500") {
weather_d = "月";
} else if (weather_d == "501") {
weather_d = "月時々曇";
} else if (weather_d == "502") {
weather_d = "月時々雨";
} else if (weather_d == "510") {
weather_d = "月後曇";
} else if (weather_d == "610") {
weather_d = "曇後月";
} else {
weather_d = "不明"; // あったら追加していく
}
sprite.print(weather_d); Serial.println(weather_d); // 表示
}
// ◆場所 (横浜のみ)
sprite.setCursor(1, 100); // 表示位置
String region = doc[0]["timeSeries"][2]["areas"][0]["area"]["name"]; //横浜
sprite.printf("(%s)", region); Serial.println(region); // 表示
// 降水確率
sprite.setCursor(0, 120); // 表示位置
if (wDay == 0) { // ◆降水確率 今日
int i, count = 0; // 初期設定
String pop = doc[0]["timeSeries"][1]["areas"][0]["pops"]; // 降水確率配列
for (i = 0; pop[i] != '\0'; i++) { // 文字列の最初から最後まで
if (pop[i] == ',') { // ','の数をカウント
count++; // 1カウントする
}
}
if (count == 7) { // n=8の場合
String A = doc[0]["timeSeries"][1]["areas"][0]["pops"][0]; // 降水確率00_06
String B = doc[0]["timeSeries"][1]["areas"][0]["pops"][1]; // 降水確率06_12
String C = doc[0]["timeSeries"][1]["areas"][0]["pops"][2]; // 降水確率12_18
String D = doc[0]["timeSeries"][1]["areas"][0]["pops"][3]; // 降水確率18_24
rain00_06 = A; rain06_12 = B;
rain12_18 = C; rain18_24 = D;
} else if (count == 6) { // n=7の場合
String B = doc[0]["timeSeries"][1]["areas"][0]["pops"][0]; // 降水確率06_12
String C = doc[0]["timeSeries"][1]["areas"][0]["pops"][1]; // 降水確率12_18
String D = doc[0]["timeSeries"][1]["areas"][0]["pops"][2]; // 降水確率18_24
rain00_06 = "--"; rain06_12 = B;
rain12_18 = C; rain18_24 = D;
} else if (count == 5) { // n=6の場合
String C = doc[0]["timeSeries"][1]["areas"][0]["pops"][0]; // 降水確率12_18
String D = doc[0]["timeSeries"][1]["areas"][0]["pops"][1]; // 降水確率18_24
rain00_06 = "--"; rain06_12 = "--";
rain12_18 = C; rain18_24 = D;
} else if (count == 4) { // n=5の場合
String D = doc[0]["timeSeries"][1]["areas"][0]["pops"][0]; // 降水確率18_24
rain00_06 = "--"; rain06_12 = "--";
rain12_18 = "--"; rain18_24 = D;
}
sprintf(buf1, "(0-)%02s(6)%02s(12)%02s(18)%02s%%",
rain00_06, rain06_12, rain12_18, rain18_24);//
sprite.print(buf1); Serial.print("降水確率:"); Serial.println(buf1); // 表示
} else if (wDay == 1) { // ◆降水確率 明日
int i, count = 0; // 初期設定
String pop = doc[0]["timeSeries"][1]["areas"][0]["pops"]; // 降水確率配列
for (i = 0; pop[i] != '\0'; i++) { // 文字列の最初から最後まで
if (pop[i] == ',') { // ','の数をカウント
count++; // count=7(n=8)-4(n=5)を想定
}
}
String A = doc[0]["timeSeries"][1]["areas"][0]["pops"][count - 3];//降水確率00_06
String B = doc[0]["timeSeries"][1]["areas"][0]["pops"][count - 2];//降水確率06_12
String C = doc[0]["timeSeries"][1]["areas"][0]["pops"][count - 1];//降水確率12_18
String D = doc[0]["timeSeries"][1]["areas"][0]["pops"][count]; //降水確率18_24
rain00_06 = A; rain06_12 = B; rain12_18 = C; rain18_24 = D;
sprintf(buf1, "(0-)%02s(6)%02s(12)%02s(18)%02s%%",
rain00_06, rain06_12, rain12_18, rain18_24); //
sprite.print(buf1); Serial.print("降水確率:"); Serial.println(buf1); // 表示
} else { // ◆降水確率 2-7日
String pop = doc[1]["timeSeries"][0]["areas"][0]["pops"][wDay + 2 - hyou]; // 降水確率
sprintf(buf1, "降水確率:%02s%%", pop); //
sprite.print(buf1); Serial.println(buf1); // 表示
}
// 気温
sprite.setCursor(1, 136); // 表示位置
if (wDay == 0) { // ◆気温 今日
int i, count = 0; // 初期設定
String hairetu = doc[0]["timeSeries"][2]["areas"][0]["temps"]; // 気温配列
for (i = 0; hairetu[i] != '\0'; i++) { // 文字列の最初から最後まで
if (hairetu[i] == ',') { // ','の数をカウント
count++; // 1カウントする
}
}
if (count == 3) { // n=4
String A = doc[0]["timeSeries"][2]["areas"][0]["temps"][0]; // 最低気温
String B = doc[0]["timeSeries"][2]["areas"][0]["temps"][1]; // 最高気温
minTmp = A; maxTmp = B; // 最低・最高気温
} else if (count == 2) { // n=3
String B = doc[0]["timeSeries"][2]["areas"][0]["temps"][0]; // 最高気温
minTmp = "--"; maxTmp = B; // 最低・最高気温
} else if (count == 1) { // n=2
minTmp = "--"; maxTmp = "--"; // 最低・最高気温
}
if (minTmp == maxTmp) { // 今日の最低気温=最高気温の場合
minTmp = "--"; // 今日の最低気温
}
sprintf(buf1, "朝の最低%02s 日中の最高%02s℃", minTmp, maxTmp); //
sprite.printf(buf1); Serial.println(buf1); // 表示
} else if (wDay == 1) { // ◆気温 明日
int i, count = 0; // 初期設定
String hairetu = doc[0]["timeSeries"][2]["areas"][0]["temps"]; //気温配列
for (i = 0; hairetu[i] != '\0'; i++) { // 文字列の最初から最後まで
if (hairetu[i] == ',') { // ','の数をカウント
count++; // 1カウントする
}
}
if (count == 3) { // n=4
String A = doc[0]["timeSeries"][2]["areas"][0]["temps"][2]; // 最低気温
String B = doc[0]["timeSeries"][2]["areas"][0]["temps"][3]; // 最高気温
minTmp = A; maxTmp = B; // 最低・最高気温
} else if (count == 2) { // n=3
String A = doc[0]["timeSeries"][2]["areas"][0]["temps"][1]; // 最低気温
String B = doc[0]["timeSeries"][2]["areas"][0]["temps"][2]; // 最高気温
minTmp = A; maxTmp = B; // 最低・最高気温
} else if (count == 1) { // n=2
String A = doc[0]["timeSeries"][2]["areas"][0]["temps"][0]; // 最低気温
String B = doc[0]["timeSeries"][2]["areas"][0]["temps"][1]; // 最高気温
minTmp = A; maxTmp = B; // 最低・最高気温
}
sprintf(buf1, "朝の最低%02s 日中の最高%02s℃", minTmp, maxTmp); //
sprite.printf(buf1); Serial.println(buf1); // 表示
} else { // ◆気温 2-7日
String A = doc[1]["timeSeries"][1]["areas"][0]["tempsMin"][wDay + 2 - hyou]; //最低typ
String B = doc[1]["timeSeries"][1]["areas"][0]["tempsMinUpper"][wDay + 2 - hyou]; //最低H
String C = doc[1]["timeSeries"][1]["areas"][0]["tempsMinLower"][wDay + 2 - hyou]; //最低L
minTmp = A; minTmpH = B; minTmpL = C; // 最低気温
String D = doc[1]["timeSeries"][1]["areas"][0]["tempsMax"][wDay + 2 - hyou]; //最高typ
String E = doc[1]["timeSeries"][1]["areas"][0]["tempsMaxUpper"][wDay + 2 - hyou]; //最高H
String F = doc[1]["timeSeries"][1]["areas"][0]["tempsMaxLower"][wDay + 2 - hyou]; //最高L
maxTmp = D; maxTmpH = E; maxTmpL = F; // 最高気温
sprintf(buf1, "↓%02s℃(%02s-%02s) ↑%02s℃(%02s-%02s)",
minTmp, minTmpL, minTmpH, maxTmp, maxTmpL, maxTmpH);
sprite.print(buf1); Serial.println(buf1); // 表示
}
// 風と波
sprite.setCursor(1, 152); // 表示位置
if (wDay < 2 || (wDay == 2 && hyou == 3)) {//◆風 0-1日,2日でhyou=3の時,3日-は無し
String wind = doc[0]["timeSeries"][0]["areas"][0]["winds"][wDay]; // 風
wind = mojiHenkan(wind); wind = "風:" + wind; // 文字変換
sprite.print(wind); Serial.println(wind); // 表示
String wave = doc[0]["timeSeries"][0]["areas"][0]["waves"][wDay]; // 波
wave = mojiHenkan(wave); wave = "波:" + wave; // 文字変換
sprite.print(" "); sprite.print(wave); Serial.println(wave); // 表示
}
//平年値
sprite.setCursor(1, 160); // 表示位置
if (wDay > 2 || (wDay == 2 && hyou == 2)) { // 風と波の表示が無い時
String A = doc[1]["tempAverage"]["areas"][0]["min"]; // ◆平年 最低温度
String B = doc[1]["tempAverage"]["areas"][0]["max"]; // ◆平年 最高温度
String C = doc[1]["precipAverage"]["areas"][0]["min"];//◆平年 降水min
String D = doc[1]["precipAverage"]["areas"][0]["max"];//◆平年 降水max
nenTmpMin = A; nenTmpMax = B; nenPreMin = C; nenPreMax = D;
sprintf(buf1, "平年最低%02.0f℃ 最高%02.0f℃",
nenTmpMin.toFloat(), nenTmpMax.toFloat());
sprite.print(buf1); Serial.println(buf1); // 表示
sprite.setCursor(1, 180); // 表示位置
sprintf(buf1, "平年7日間合計降水%02.0f-%02.0fmm",
nenPreMin.toFloat(), nenPreMax.toFloat());
sprite.print(buf1); Serial.println(buf1); // 表示
}
} else if (wDay == 8) { // ◆神奈川県予報
sprite.setCursor(0, 0); // 表示位置
String A = doc[2]["headlineText"]; // ヘッドライン
String B = doc[2]["text"]; // text
A = "[8] " + A + B; A = mojiHenkan(A); // 文字変換
A = A.substring((bMid - 1) * bMidN, bMid * bMidN);//bMidN文字分表示
sprite.print(A); Serial.println(A); // 表示
} else { // ◆関東予報 wDay=9
sprite.setCursor(0, 0); // 表示位置
String A = doc[3]["headTitle"]; // タイトル
String B = doc[3]["text"]; // text
A = "[9] " + A + ":" + B; A = mojiHenkan(A); // 文字変換
sprite.print(A); Serial.println(A); // 表示 144文字のみ
}
}
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[0] + weatherInfo[1];
String A = weatherInfo[0]; // 明後日まで
String B = weatherInfo[1]; // 7日先まで
today = "[" + A + "," + B + "," + bunDay + "\"}," + bunWeek + "\"}]";
Serial.println("today = "); Serial.println(today); //シリアルモニタに表示
drawWeather(today); // 1画面設定関数へ
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
void loop() {
if (M5.BtnUP.wasPressed()) { // ボタンを上に回したら
if (wDay > 0) { // 最初の頁でなければ
wDay--; // 前の頁へ
if (wDay == 8) { // 8へ戻ったら
bMid = 1; // 1頁目(を表示)
} else if (hyou == 2 && wDay == 7) { // hyou=2でwDay=7は無いので
wDay--; // 1つ前へスキップ
}
} else { // 最初の頁だったら
wDay = 9; // 最後の頁
}
drawWeather(today); // 1画面設定関数へ
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
if (M5.BtnDOWN.wasPressed()) { // ボタンを下に回したら
if (wDay < 10) { // 最後の頁でなければ
wDay++; // 次の頁へ
if (wDay == 8) { // 8へ戻ったら
bMid = 1; // 1頁目(を表示)
} else if (hyou == 2 && wDay == 7) { // hyou=2でwDay=7は無いので
wDay++; // 1つ次へスキップ
}
} else { // 最後の頁だったら
wDay = 0; // 最初の頁
}
drawWeather(today); // 1画面設定関数へ
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
if (M5.BtnMID.wasPressed()) { // ボタンを押し込んだら(8の時のみ使用)
if (bMid < 3) { // 1頁か2頁なら
bMid++; // 次の頁へ
} else { // 3頁目なら
bMid = 1; // 1頁へ戻る
} // bMid=1→2→3→1→2→・・・
drawWeather(today); // 1画面設定関数へ
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
//if (M5.BtnUP.pressedFor(2000)) { // ボタンを2秒間上に回したら
//if (M5.BtnDOWN.pressedFor(2000)) { // ボタンを2秒間下に回したら
//if (M5.BtnEXT.wasPressed()) { // 上面ボタンを押したら
//if (M5.BtnPWR.wasPressed()) { // 電源ボタンを押したら(電源off)
M5.update(); // ボタンとブザーを更新
delay(500); // 0.5秒待つ
}