13.Wio Terminalで天気(気象庁)2後編
13.Wio Terminalで天気(気象庁)2後編
気象庁のホームページ内で使用している非公開のjsonデータを使用します。前編の続きです。
・気象庁の天気発表時刻は、AM5時、AM11時、PM5時と急変時です。AM5時は予報が2日(明日まで)/7日(6日先まで)で、それ以外は3日/8日と予報日数が変わります。
・週間予報のjsonには"weathers"(天気名)が無いので天気コードから表示します。
・時刻により、降水確率のデータ数が少なくなります。フルでは今日と明日の8データですが、今日の00-06と06-12が"-"の時は、jsonでは6個のデータになっています。スケッチではデータ数からそれがいつのデータか判断しています。
・時刻により、気温のデータ数も少なくなります。スケッチではデータ数からそれがいつのデータか判断しています。
・今朝の最低気温で表示とjsonが異なる場合があります。jsonで "朝の最低気温" = "日中の最高気温" の場合は、表示では"朝の最低気温" = "-" となっています。
・SDのtxtファイルと"icon49.h"の天気マークとwifiを利用します。
・横浜の気象状況です。それ以外の場所は場所コードを検索し、3つのjsonのURLを変更します。
・内部時計で1分ごとに更新しているので、実際の時刻より0~1分遅れています。
・容量不足のため天気マークは大幅に統一したので、天気マークは参考程度にしてください。
・シリアルモニタには一部参考データも表示します。
課題
・下記jsonのG(県の注意報), H(県の早期注意), I(アメダスデータ)は今回使用していません。・日本語フォントと天気マークが容量を圧迫し、フラッシュメモリ512kbyteの残りが3%しかありません。外部フラッシュは4Mbyteあるらしいが。
・花粉の予報ができません。
必要ファイル
スケッチ以外に、・"icon49.h"
天気マークデータ 前編参照
・"GomiMon.txt", "GomiTue.txt", "GomiWed.txt", "GomiThu.txt", "GomiSat.txt"
今日のごみ収集品表示文として1画面分のtxtファイル
SDの"Gomi"ホルダに入れます。
金曜と日曜は他と同じなので削除しています。
操作
・バッテリパックを付け5weyボタンを右上にします。・5weyボタンを右へ押すと次を表示します。
・5weyボタンを左へ押すと前を表示します。
・ボタンを押すとクリック音がします。
・[8]の場合のみ、5weyボタンを下へ押すと次の頁を表示します。
・バッテリー残量%表示をします。
・充電中は、充電マークを表示します。
・内部時計で1分ごとに時刻を更新します。
起動時
・スケッチ内に書かれているwifiを使用して、NTP時刻と気象庁天気予報を1回読みます。[0]今日
・1行目 (令和年)西暦年月日(曜日) 充電マーク バッテリー残量・2行目 (am/pm)時:分(1分ごとに更新)
・3行目~ 気象データ ホームページ参照
・最下2行 備考
[1]明日
[2]明後日
[3]3日後
[4]4日後
[5]5日後
[6]6日後
[7]7日後
・データが無い時は表示しません。[8]県の概況文 明日まで
・5weyボタンを下へ押すと続きの頁を表示します。最大3頁。[9]関東の週間予報文 1週間
・最初の1頁分のみを表示します。[10]ごみ収集
・曜日ごとに収集品が変わります。今日のごみ収集品を表示します。(明日の分は表示しません。)・あらかじめSDに各曜日の表示文を1頁分保存しておきます。
jsonファイル
気象庁のホームページのソースで見つけたjsonファイルです。準備用の方には気象データは入っていません。また、G~Iは今回使用していません。準備用
▶A.場所コード(pathCode)http://www.jma.go.jp/bosai/common/const/area.json
▶B.アメダスコード
https://www.jma.go.jp/bosai/amedas/const/amedastable.json
▶C.コンテンツの種別
http://www.jma.go.jp/bosai/common/const/contents.json
気象データ例
▶D.横浜の天気予報 2日後・7日後までhttps://www.jma.go.jp/bosai/forecast/data/forecast/140000.json
▶E.神奈川県の天気概況 明日まで
https://www.jma.go.jp/bosai/forecast/data/overview_forecast/140000.json
▶F.関東甲信地方 週間天気予報
https://www.jma.go.jp/bosai/forecast/data/overview_week/130000.json
▶G.神奈川県の警報・注意報
https://www.jma.go.jp/bosai/warning/data/warning/140000.json
▶H.神奈川県の早期注意情報
https://www.jma.go.jp/bosai/probability/data/probability/140000.json
▶I.アメダスコードの気象データ
https://www.jma.go.jp/bosai/amedas/data/map/20220223150000.json
スケッチ
"icon49.h"(天気マーク)が同ホルダに必要です。SDの"Gomi"ホルダの下に"GomiMon.txt", "GomiTue.txt", "GomiWed.txt", "GomiThu.txt", "GomiSat.txt"が必要です。
2ケ所の*****は自分のwifiのssidとパスワードを記入してください。
// 天気情報 気象庁https://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=140000
// 気象庁ホームページからjsonデータを得てWio Terminalに表示
#include <SPI.h> // SDのためにSPI通信を使用
#include <Seeed_FS.h> // SDを使用
#include <SD/Seeed_SD.h> // SD追加分
#include "icon49.h" // 天気マーク 同一ホルダに置く 使うのは21個
#include <SparkFunBQ27441.h> // バッテリー残量IC BQ27441を使用
#include <rpcWiFi.h> // Wi-Fiを使用
#include <HTTPClient.h> // httpと通信
#include <WiFiClientSecure.h> // httpsと通信
#include <ArduinoJson.h> // json型式で抽出
#include <millisDelay.h> // ノンブロック遅延を使用。システムが停止しないタイマー
#include <RTC_SAMD51.h> // RTC(real-time clock)を使用
#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";
const char* timeURL = "ntp.nict.jp"; // 情報通信研究機構のNTPサーバー 時刻
DynamicJsonDocument weatherInfo(20000); //
int wDay = 0; // 0=今日,1=明日,2=明後日,・・・,7=7日先,8=神奈川県予報,9=関東予報,10ごみ収集
int bMid = 1, bMidN = 354; // bunDayの頁(1-3),1頁の文字数((12字x10行-2)x3?=354)
String myd; // 日付
String minTmpL, minTmp, minTmpH, maxTmpL, maxTmp, maxTmpH ;//最低気温,最高気温
String rain00_06, rain06_12, rain12_18, rain18_24; // 降水確率
String weather_d; // 天気名
String reliability; // 信頼度
String today; // json用文字列
String nenTmpMin, nenTmpMax; // 平年値 気温
String nenPreMin, nenPreMax; // 平年値 降水量
char buf1[50]; // 表示用文字列
String bunDay, bunWeek; // 天気2文
int hyou = 3; // 2:2日/6日, 3:3日/8日
WiFiClient client; // clientを定義
WiFiClientSecure clientS; // clientSを定義
WiFiUDP udp; // udpを定義
millisDelay updateDelay; // updateDelayを定義
RTC_SAMD51 rtc; // rtcを定義
static LGFX lcd; // LGFXのインスタンスを作成
DateTime now; // nowを定義
unsigned long devicetime; // 受信時刻
const int NTP_PACKET_SIZE = 48; // NTPタイムスタンプはメッセージの最初の48バイト
unsigned int localPort = 2390; // udpローカルポート番号
byte packetBuffer[NTP_PACKET_SIZE]; // パケットを保持するためのバッファ
char daysOfTheWeek[7][4] = {"日", "月", "火", "水", "木", "金", "土"}; // 曜日
String fname[] = {"Wed", "Mon", "Tue", "Wed", "Thu", "Mon", "Sat"}; //ファイル名一部
int youbiNo; // 0:日,・・・,6:土
const unsigned int BATTERY_CAPACITY = 650; // バッテリー設計容量650mAh
int yBikou = 299; // 備考欄のy (画面縦320,横240)
int wMark; // 表示用天気マーク番号
File myFile; // ファイルクラスを初期化し、myFileという名前を付ける
DynamicJsonDocument getJson() { //
DynamicJsonDocument doc(20000); //
if ((WiFi.status() == WL_CONNECTED)) { // wifiが接続されていたら
HTTPClient https; // 定義
/***** dayURL *****/
https.begin(clientS, dayURL); // dayURL アクセスするURLを登録
//Serial.print("dayULR = "); Serial.println(dayURL);//シリアルモニタに表示
int httpCodeD = https.GET();//登録URLに、GETリクエスト送信
if (httpCodeD > 0) { //HTTPのリターンコード。エラーの場合は負数。
String jsonString = createJson(https.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
bunDay = jsonString; // dayURLのjson文字列を保存しておく
Serial.print("dayURL→"); Serial.println(bunDay); // 読込みデータ表示
}
/***** weekURL *****/
https.begin(clientS, weekURL); // weekURL アクセスするURLを登録
//Serial.print("weekULR = "); Serial.println(dayURL);//シリアルモニタに表示
int httpCodeW = https.GET(); //登録URLに、GETリクエスト送信
if (httpCodeW > 0) { //HTTPのリターンコード。エラーの場合は負数。
String jsonStringW = createJson(https.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
bunWeek = jsonStringW; // weekURLのjson文字列を保存しておく
Serial.print("weekURL→"); Serial.println(bunWeek); // 読込みデータ表示
}
/***** weatherULR *****/
https.begin(clientS, weatherURL); // weatherULR アクセスするURLを登録
//Serial.print("weatherURL = "); Serial.println(weatherURL);//シリアルモニタに表示
int httpCode = https.GET(); // 登録URLに、GETリクエスト送信
if (httpCode > 0) { // HTTPのリターンコード。エラーの場合は負数。
String jsonString = createJson(https.getString());
//メッセージのボディ部,確保できなかった場合は空文字列,jsonオブジェクトの作成
Serial.print("weatherURL→"); Serial.println(jsonString); // 読込みデータ表示
deserializeJson(doc, jsonString);
// 直列化されたデータをDynamicJsonDocumentの形に変換
} else {
Serial.println("エラー HTTPリクエスト"); // シリアルモニタに表示
}
https.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("晴れ", "晴"); // 天気で使用
moji.replace("くもり", "曇"); // 天気で使用
moji.replace("曇り", "曇"); // 天気で使用
//moji.replace("のち", "/"); // 天気で使用
//moji.replace("時々", "I"); // 天気で使用
//moji.replace("一時", "II"); // 天気で使用
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; //
}
int mojiYoubiHenkan(String myd) {
//Serial.println(myd); // 表示
int y = myd.substring(0, 4).toInt(); // 予報年
int m = myd.substring(5, 7).toInt(); // 予報月
int d = myd.substring(8, 10).toInt(); // 予報日
//Serial.print(y); Serial.print(m); Serial.print(d);//表示
if (m <= 2) {
y = y - 1; m = m + 12; // ツェラーの公式のための準備
}
int C = (int)(y / 100); // 西暦上2桁
int Y = y % 100; // 西暦下2桁
int youbiNo = (d + (int)(2.6 * (m + 1)) + Y + (int)(Y / 4) +
5 * C + (int)(C / 4) + 6) % 7; // ツェラーの公式
//Serial.println(youbiNo);
return youbiNo; // 曜日番号を返す 0→日・・・
}
void printTime() { // 時刻画面表示関数 1分で更新
lcd.setCursor(2, 5); lcd.setTextSize(1.0); // 表示位置文字サイズ
lcd.printf("(R%d)%d", now.year() - 2018, now.year()); // 年表示
lcd.printf("/%d/%d(", now.month(), now.day()); // 月日表示
youbiNo = now.dayOfTheWeek(); // 曜日表示で使用
lcd.print(daysOfTheWeek[youbiNo]); // 曜日表示 0→日・・・
lcd.print(")"); // 表示
/***** AM/PM *****/
lcd.setCursor(55, 40); // 表示位置
int hourP = now.hour(); // 時刻
if (hourP > 12) { // 0-12時の場合
hourP = hourP - 12; // 12引く
lcd.print("PM"); // 表示
} else { // 13-23時の場合
lcd.print("AM"); // 表示
}
/***** 時分 *****/
lcd.setCursor(75, 30); lcd.setTextSize(2.0); // 表示位置,文字サイズ
lcd.printf(" %2d:%02d", hourP, now.minute()); // 時分表示
lcd.setTextSize(1.0); // 文字サイズ
lcd.setCursor(0, yBikou); lcd.print("■■■■■■■■■■■■"); // 表示
delay(500); // 0.5秒待つ
lcd.setCursor(0, yBikou); lcd.print("時刻更新 "); // 表示
}
void printWeather(String infoWeather) { // 天気表示関数
DynamicJsonDocument doc(20000); //
deserializeJson(doc, infoWeather);//直列化データをDynamicJsonDocumentに変換
Serial.println(); // 改行
lcd.drawFastHLine(1, 71, 238, TFT_WHITE); // 横線(x,y,w,色)
/***** 詳細予報表と週間予報表の日数判定 *****/
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) { // 天気マークの画面なら
/***** 天気文と天気マークを検索 *****/
if (wDay < 2 || (wDay == 2 && hyou == 3)) { // 今日or明日or(2日先でhyou=3)なら
String A = doc[0]["timeSeries"][0]["areas"][0]["weatherCodes"][wDay]; // ◆天気マークコード
weather_d = A; // 今は天気コード
} else { // 2日でhyou=2 or 3-7日先なら
String A = doc[1]["timeSeries"][0]["areas"][0]["weatherCodes"][wDay + 2 - hyou];//◆天気マークコード
weather_d = A; // 今は天気コード
}
if (weather_d == "100") { // 天気コード
wMark = 100; weather_d = "晴れ"; // 表示用天気マーク,天気名
} else if (weather_d == "101") {
wMark = 101; weather_d = "晴れ時々曇り";
} else if (weather_d == "102") {
wMark = 102; weather_d = "晴れ一時雨";
} else if (weather_d == "103") {
wMark = 102; weather_d = "晴れ時々雨";
} else if (weather_d == "104") {
wMark = 104; weather_d = "晴れ一時雪";
} else if (weather_d == "105") {
wMark = 104; weather_d = "晴れ時々雪";
} else if (weather_d == "106") {
wMark = 102; weather_d = "晴れ一時雨か雪";
} else if (weather_d == "107") {
wMark = 102; weather_d = "晴れ時々雨か雪";
} else if (weather_d == "108") {
wMark = 102; weather_d = "晴れ一時雨か雷雨";
} else if (weather_d == "110") {
wMark = 101; weather_d = "晴れのち時々曇り";
} else if (weather_d == "111") {
wMark = 111; weather_d = "晴れのち曇り";
} else if (weather_d == "112") {
wMark = 114; weather_d = "晴れのち一時雨";
} else if (weather_d == "113") {
wMark = 114; weather_d = "晴れのち時々雨";
} else if (weather_d == "114") {
wMark = 114; weather_d = "晴れのち雨";
} else if (weather_d == "115") {
wMark = 400; weather_d = "晴れのち一時雪";
} else if (weather_d == "116") {
wMark = 400; weather_d = "晴れのち時々雪";
} else if (weather_d == "117") {
wMark = 400; weather_d = "晴れのち雪";
} else if (weather_d == "118") {
wMark = 114; weather_d = "晴れのち雨か雪";
} else if (weather_d == "119") {
wMark = 114; weather_d = "晴れのち雨か雷雨";
} else if (weather_d == "120") {
wMark = 102; weather_d = "晴れ朝夕一時雨";
} else if (weather_d == "121") {
wMark = 102; weather_d = "晴れ朝の内一時雨";
} else if (weather_d == "122") {
wMark = 102; weather_d = "晴れ夕方一時雨";
} else if (weather_d == "123") {
wMark = 100; weather_d = "晴れ山沿い雷雨";
} else if (weather_d == "124") {
wMark = 100; weather_d = "晴れ山沿い雪";
} else if (weather_d == "125") {
wMark = 114; weather_d = "晴れ午後は雷雨";
} else if (weather_d == "126") {
wMark = 114; weather_d = "晴れ昼頃から雨";
} else if (weather_d == "127") {
wMark = 114; weather_d = "晴れ夕方から雨";
} else if (weather_d == "128") {
wMark = 114; weather_d = "晴れ夜は雨";
} else if (weather_d == "129") {
wMark = 114; weather_d = "晴れ夜半から雨";
} else if (weather_d == "130") {
wMark = 100; weather_d = "朝の内霧後晴れ";
} else if (weather_d == "131") {
wMark = 100; weather_d = "晴れ明け方霧";
} else if (weather_d == "132") {
wMark = 101; weather_d = "晴れ朝夕曇り";
} else if (weather_d == "140") {
wMark = 102; weather_d = "晴れ時々雨で雷を伴う";
} else if (weather_d == "160") {
wMark = 102; weather_d = "晴れ一時雪か雨";
} else if (weather_d == "170") {
wMark = 102; weather_d = "晴れ時々雪か雨";
} else if (weather_d == "181") {
wMark = 114; weather_d = "晴れのち雪か雨";
} else if (weather_d == "200") {
wMark = 200; weather_d = "曇り";
} else if (weather_d == "201") {
wMark = 201; weather_d = "曇り時々晴れ";
} else if (weather_d == "202") {
wMark = 202; weather_d = "曇り一時雨";
} else if (weather_d == "203") {
wMark = 202; weather_d = "曇り時々雨";
} else if (weather_d == "204") {
wMark = 204; weather_d = "曇り一時雪";
} else if (weather_d == "205") {
wMark = 204; weather_d = "曇り時々雪";
} else if (weather_d == "206") {
wMark = 202; weather_d = "曇り一時雨か雪";
} else if (weather_d == "207") {
wMark = 202; weather_d = "曇り時々雨か雪";
} else if (weather_d == "208") {
wMark = 202; weather_d = "曇り一時雨か雷雨";
} else if (weather_d == "209") {
wMark = 200; weather_d = "霧";
} else if (weather_d == "210") {
wMark = 130; weather_d = "曇りのち時々晴れ";
} else if (weather_d == "211") {
wMark = 130; weather_d = "曇りのち晴れ";
} else if (weather_d == "212") {
wMark = 214; weather_d = "曇りのち一時雨";
} else if (weather_d == "213") {
wMark = 214; weather_d = "曇りのち時々雨";
} else if (weather_d == "214") {
wMark = 214; weather_d = "曇りのち雨";
} else if (weather_d == "215") {
wMark = 400; weather_d = "曇りのち一時雪";
} else if (weather_d == "216") {
wMark = 400; weather_d = "曇りのち時々雪";
} else if (weather_d == "217") {
wMark = 400; weather_d = "曇りのち雪";
} else if (weather_d == "218") {
wMark = 214; weather_d = "曇りのち雨か雪";
} else if (weather_d == "219") {
wMark = 214; weather_d = "曇りのち雨か雷雨";
} else if (weather_d == "220") {
wMark = 202; weather_d = "曇り朝夕一時雨";
} else if (weather_d == "221") {
wMark = 202; weather_d = "曇り朝の内一時雨";
} else if (weather_d == "222") {
wMark = 202; weather_d = "曇り夕方一時雨";
} else if (weather_d == "223") {
wMark = 201; weather_d = "曇り日中時々晴れ";
} else if (weather_d == "224") {
wMark = 214; weather_d = "曇り昼頃から雨";
} else if (weather_d == "225") {
wMark = 214; weather_d = "曇り夕方から雨";
} else if (weather_d == "226") {
wMark = 214; weather_d = "曇り夜は雨";
} else if (weather_d == "227") {
wMark = 214; weather_d = "曇り夜半から雨";
} else if (weather_d == "228") {
wMark = 400; weather_d = "曇り昼頃から雪";
} else if (weather_d == "229") {
wMark = 400; weather_d = "曇り夕方から雪";
} else if (weather_d == "230") {
wMark = 400; weather_d = "曇り夜は雪";
} else if (weather_d == "231") {
wMark = 200; weather_d = "曇り海上海岸は霧か霧雨";
} else if (weather_d == "240") {
wMark = 202; weather_d = "曇り時々雨で雷を伴う";
} else if (weather_d == "250") {
wMark = 204; weather_d = "曇り時々雪で雷を伴う";
} else if (weather_d == "260") {
wMark = 202; weather_d = "曇り一時雪か雨";
} else if (weather_d == "270") {
wMark = 202; weather_d = "曇り時々雪か雨";
} else if (weather_d == "281") {
wMark = 214; weather_d = "曇りのち雪か雨";
} else if (weather_d == "300") {
wMark = 300; weather_d = "雨";
} else if (weather_d == "301") {
wMark = 301; weather_d = "雨時々晴れ";
} else if (weather_d == "302") {
wMark = 302; weather_d = "雨時々止む";
} else if (weather_d == "303") {
wMark = 300; weather_d = "雨時々雪";
} else if (weather_d == "304") {
wMark = 300; weather_d = "雨か雪";
} else if (weather_d == "306") {
wMark = 300; weather_d = "大雨";
} else if (weather_d == "307") {
wMark = 307; weather_d = "風雨共に強い";
} else if (weather_d == "308") {
wMark = 307; weather_d = "雨で暴風を伴う";
} else if (weather_d == "309") {
wMark = 300; weather_d = "雨一時雪";
} else if (weather_d == "311") {
wMark = 311; weather_d = "雨のち晴れ";
} else if (weather_d == "313") {
wMark = 313; weather_d = "雨のち曇り";
} else if (weather_d == "314") {
wMark = 300; weather_d = "雨のち時々雪";
} else if (weather_d == "315") {
wMark = 300; weather_d = "雨のち雪";
} else if (weather_d == "316") {
wMark = 311; weather_d = "雨か雪のち晴れ";
} else if (weather_d == "317") {
wMark = 313; weather_d = "雨か雪のち曇り";
} else if (weather_d == "320") {
wMark = 311; weather_d = "朝の内雨のち晴れ";
} else if (weather_d == "321") {
wMark = 313; weather_d = "朝の内雨のち曇り";
} else if (weather_d == "322") {
wMark = 300; weather_d = "雨朝晩一時雪";
} else if (weather_d == "323") {
wMark = 311; weather_d = "雨昼頃から晴れ";
} else if (weather_d == "324") {
wMark = 311; weather_d = "雨夕方から晴れ";
} else if (weather_d == "325") {
wMark = 311; weather_d = "雨夜は晴れ";
} else if (weather_d == "326") {
wMark = 300; weather_d = "雨夕方から雪";
} else if (weather_d == "327") {
wMark = 300; weather_d = "雨夜は雪";
} else if (weather_d == "328") {
wMark = 300; weather_d = "雨一時強く降る";
} else if (weather_d == "329") {
wMark = 300; weather_d = "雨一時みぞれ";
} else if (weather_d == "340") {
wMark = 300; weather_d = "雪か雨";
} else if (weather_d == "350") {
wMark = 300; weather_d = "雨で雷を伴う";
} else if (weather_d == "361") {
wMark = 311; weather_d = "雪か雨のち晴れ";
} else if (weather_d == "371") {
wMark = 313; weather_d = "雪か雨のち曇り";
} else if (weather_d == "400") {
wMark = 400; weather_d = "雪";
} else if (weather_d == "401") {
wMark = 400; weather_d = "雪時々晴れ";
} else if (weather_d == "402") {
wMark = 400; weather_d = "雪時々止む";
} else if (weather_d == "403") {
wMark = 403; weather_d = "雪時々雨";
} else if (weather_d == "405") {
wMark = 400; weather_d = "大雪";
} else if (weather_d == "406") {
wMark = 400; weather_d = "風雪強い";
} else if (weather_d == "407") {
wMark = 400; weather_d = "暴風雪";
} else if (weather_d == "409") {
wMark = 403; weather_d = "雪一時雨";
} else if (weather_d == "411") {
wMark = 400; weather_d = "雪のち晴れ";
} else if (weather_d == "413") {
wMark = 400; weather_d = "雪のち曇り";
} else if (weather_d == "414") {
wMark = 414; weather_d = "雪のち雨";
} else if (weather_d == "420") {
wMark = 400; weather_d = "朝の内雪のち晴れ";
} else if (weather_d == "421") {
wMark = 400; weather_d = "朝の内雪のち曇り";
} else if (weather_d == "422") {
wMark = 414; weather_d = "雪昼頃から雨";
} else if (weather_d == "423") {
wMark = 414; weather_d = "雪夕方から雨";
} else if (weather_d == "424") {
wMark = 414; weather_d = "雪夜半から雨";
} else if (weather_d == "425") {
wMark = 400; weather_d = "雪一時強く降る";
} else if (weather_d == "426") {
wMark = 414; weather_d = "雪のちみぞれ";
} else if (weather_d == "427") {
wMark = 403; weather_d = "雪一時みぞれ";
} else if (weather_d == "450") {
wMark = 400; weather_d = "雪で雷を伴う";
} else if (weather_d == "500") {
wMark = 100; weather_d = "月";
} else if (weather_d == "501") {
wMark = 101; weather_d = "月時々曇り";
} else if (weather_d == "502") {
wMark = 102; weather_d = "月時々雨";
} else if (weather_d == "510") {
wMark = 111; weather_d = "月のち曇り";
} else if (weather_d == "610") {
wMark = 130; weather_d = "曇りのち月";
} else {
wMark = 999; weather_d = "不明"; // あったら追加していく
}
weather_d = mojiHenkan(weather_d); // 文字変換
/***** 天気マーク *****/
int x = 140, y = 120, W = 72, H = 43; //天気マークの表示位置と大きさ
//Serial.print(wMark);
switch (wMark) {
case 100: lcd.pushImage(x, y, W, H, img100); break;
case 101: lcd.pushImage(x, y, W, H, img101); break;
case 102: lcd.pushImage(x, y, W, H, img102); break;
case 104: lcd.pushImage(x, y, W, H, img104); break;
//case 106: lcd.pushImage(x, y, W, H, img106); break;//容量不足で削除
//case 108: lcd.pushImage(x, y, W, H, img108); break;
case 111: lcd.pushImage(x, y, W, H, img111); break;
case 114: lcd.pushImage(x, y, W, H, img114); break;
//case 117: lcd.pushImage(x, y, W, H, img117); break;
//case 118: lcd.pushImage(x, y, W, H, img118); break;
//case 119: lcd.pushImage(x, y, W, H, img119); break;
case 130: lcd.pushImage(x, y, W, H, img130); break;
case 200: lcd.pushImage(x, y, W, H, img200); break;
case 201: lcd.pushImage(x, y, W, H, img201); break;
case 202: lcd.pushImage(x, y, W, H, img202); break;
case 204: lcd.pushImage(x, y, W, H, img204); break;
//case 206: lcd.pushImage(x, y, W, H, img206); break;
//case 208: lcd.pushImage(x, y, W, H, img208); break;
case 214: lcd.pushImage(x, y, W, H, img214); break;
//case 217: lcd.pushImage(x, y, W, H, img217); break;
//case 250: lcd.pushImage(x, y, W, H, img250); break;
//case 281: lcd.pushImage(x, y, W, H, img281); break;
case 300: lcd.pushImage(x, y, W, H, img300); break;
case 301: lcd.pushImage(x, y, W, H, img301); break;
case 302: lcd.pushImage(x, y, W, H, img302); break;
//case 303: lcd.pushImage(x, y, W, H, img303); break;
//case 304: lcd.pushImage(x, y, W, H, img304); break;
//case 306: lcd.pushImage(x, y, W, H, img306); break;
case 307: lcd.pushImage(x, y, W, H, img307); break;
case 311: lcd.pushImage(x, y, W, H, img311); break;
case 313: lcd.pushImage(x, y, W, H, img313); break;
//case 315: lcd.pushImage(x, y, W, H, img315); break;
//case 316: lcd.pushImage(x, y, W, H, img316); break;
//case 317: lcd.pushImage(x, y, W, H, img317); break;
//case 328: lcd.pushImage(x, y, W, H, img328); break;
//case 329: lcd.pushImage(x, y, W, H, img329); break;
//case 350: lcd.pushImage(x, y, W, H, img350); break;
case 400: lcd.pushImage(x, y, W, H, img400); break;
//case 401: lcd.pushImage(x, y, W, H, img401); break;
//case 402: lcd.pushImage(x, y, W, H, img402); break;
case 403: lcd.pushImage(x, y, W, H, img403); break;
//case 406: lcd.pushImage(x, y, W, H, img406); break;
//case 411: lcd.pushImage(x, y, W, H, img411); break;
//case 413: lcd.pushImage(x, y, W, H, img413); break;
case 414: lcd.pushImage(x, y, W, H, img414); break;
//case 425: lcd.pushImage(x, y, W, H, img425); break;
//case 426: lcd.pushImage(x, y, W, H, img426); break;
//case 427: lcd.pushImage(x, y, W, H, img427); break;
//case 450: lcd.pushImage(x, y, W, H, img450); break;
case 999: lcd.setCursor(x, y); lcd.println("無し");
}
/***** 日付 *****/
lcd.setCursor(0, 72); // 表示位置(x,y)
sprintf(buf1, "[%d] ", wDay); // 何日目 0:今日,1:明日・・・
lcd.print(buf1); Serial.print(buf1); // 表示
if (wDay == 0) { // 今日なら
String A = doc[0]["reportDatetime"]; // ◆発表月日時分
myd = A; myd = mojiHenkan(myd); //
int youbiNo = mojiYoubiHenkan(myd); // 曜日算出
if (youbiNo == 0) { // 日曜日は赤系色
lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // (文字色,背景色)
} else if (youbiNo == 6) { // 土曜日は青系色
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (文字色,背景色)
}
lcd.print(myd.substring(5, 10)); // 月日(a+1文字目からb文字目まで)
lcd.print("("); // 表示
lcd.print(daysOfTheWeek[youbiNo]); // 曜日表示 0→日・・・
lcd.print(")"); // 表示
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)戻す
lcd.print(myd.substring(11, 16)); // 時分
Serial.print(myd.substring(5, 16)); // 4+1文字目から16文字目までを表示
lcd.println("発表"); Serial.println("発表"); // 表示
} else { // 明日-7日先なら
String A = doc[1]["timeSeries"][0]["timeDefines"][wDay + 2 - hyou];//◆予報日
myd = A; myd = mojiHenkan(myd); // 文字変換
int youbiNo = mojiYoubiHenkan(myd); // 曜日算出
if (youbiNo == 0) { // 日曜日は赤系色
lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // (文字色,背景色)
} else if (youbiNo == 6) { // 土曜日は青系色
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (文字色,背景色)
}
lcd.print(myd.substring(0, 10)); // 年月日
Serial.println(myd.substring(0, 10)); // 0+1文字目から10文字目までを表示
lcd.print("("); // 表示
lcd.print(daysOfTheWeek[youbiNo]); // 曜日表示 0→日・・・
lcd.println(") "); Serial.println(); // 表示
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)戻す
}
/***** 天気文 *****/
if (wDay < 2 || (wDay == 2 && hyou == 3)) { // 今日or明日or(2日先でhyou=3)なら
String A = doc[0]["timeSeries"][0]["areas"][0]["weathers"][wDay];//◆詳細天気
weather_d = A; weather_d = mojiHenkan(weather_d); // 文字変換
}
lcd.print(weather_d); Serial.println(weather_d); // 表示
/***** 場所(横浜のみ) *****/
lcd.setCursor(0, 132); // 表示位置
String region = doc[0]["timeSeries"][2]["areas"][0]["area"]["name"];//◆横浜
lcd.print("("); lcd.print(region); lcd.println(")"); // 表示
Serial.println(region); // 表示
/***** 信頼度 *****/
if (wDay < 2 || (wDay == 2 && hyou == 3)) { // 今日 or 明日 or (2日でhyou=3)なら
reliability = "降水適中:--%"; //
} 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 = "降水適中:88%"; //
} else if (reliability == "B") { // 信頼度Bなら
reliability = "降水適中:73%"; //
} else { // 信頼度Cなら
reliability = "降水適中:58%"; //
}
}
lcd.println(reliability); Serial.println(reliability); // 表示
/***** 降水確率 *****/
if (wDay == 0) { // 今日なら
int i, count = 0; // 初期設定
rain00_06 = "-"; rain06_12 = "-"; // とりあえず
rain12_18 = "-"; rain18_24 = "-"; // とりあえず
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
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
rain12_18 = C; rain18_24 = D; //
} else if (count == 4) { // n=5の場合
String D = doc[0]["timeSeries"][1]["areas"][0]["pops"][0];//◆降水確率18_24
rain18_24 = D; //
}
lcd.print("(0)"); lcd.print(rain00_06); // 表示
lcd.print("(6)"); lcd.print(rain06_12); // 表示
lcd.print("(12)"); lcd.print(rain12_18); // 表示
lcd.print("(18)"); lcd.print(rain18_24); // 表示
lcd.println("%"); // 表示
} 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; //
lcd.print("(0)"); lcd.print(rain00_06); // 表示
lcd.print("(6)"); lcd.print(rain06_12); // 表示
lcd.print("(12)"); lcd.print(rain12_18); // 表示
lcd.print("(18)"); lcd.print(rain18_24); // 表示
lcd.println("%"); // 表示
} else { // 2-7日なら
String pop = doc[1]["timeSeries"][0]["areas"][0]["pops"][wDay + 2 - hyou];//◆降水確率
lcd.print("降水確率:"); lcd.print(pop); lcd.println("%"); // 表示
}
/***** 気温 *****/
if (wDay == 0) { // 今日なら
int i, count = 0; // 初期設定
minTmp = "--"; maxTmp = "--"; // とりあえず
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];//◆最高気温
maxTmp = B; // 最高気温
} else if (count == 1) { // n=2
}
if (minTmp == maxTmp) { // 今日の最低気温=最高気温の場合
minTmp = "--"; // 今日の最低気温
}
lcd.print("朝"); // 表示
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (文字色,背景色)
lcd.print(minTmp); // 最低温度
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
lcd.print("℃min 日中"); // 表示
lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // (文字色,背景色)
lcd.print(maxTmp); // 最高気温
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
lcd.println("℃max"); // 表示
} 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; //最低・最高気温
}
lcd.print("朝"); // 表示
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (文字色,背景色)
lcd.print(minTmp); // 最低気温
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
lcd.print("℃min 日中"); // 表示
lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // (文字色,背景色)
lcd.print(maxTmp); // 最高気温
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
lcd.println("℃max"); // 表示
} 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; // 最高気温
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (文字色,背景色)
lcd.printf("↓%d(%d-%d)", minTmp.toInt(), minTmpL.toInt(), minTmpH.toInt()); // 表示
lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // (文字色,背景色)
lcd.printf("↑%d℃(%d-%d)\n", maxTmp.toInt(), maxTmpL.toInt(), maxTmpH.toInt()); // 表示
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
}
/***** 風 *****/
if (wDay < 2 || (wDay == 2 && hyou == 3)) {//0-1日 or 2日でhyou=3なら,3日-は無し
String wind = doc[0]["timeSeries"][0]["areas"][0]["winds"][wDay]; // ◆風
wind = mojiHenkan(wind); wind = "風:" + wind; // 文字変換
lcd.print(wind); Serial.println(wind); // 表示
/***** 波 *****/
String wave = doc[0]["timeSeries"][0]["areas"][0]["waves"][wDay]; // ◆波
wave = mojiHenkan(wave); wave = "波:" + wave; // 文字変換
lcd.print(" "); lcd.println(wave); Serial.println(wave); // 表示
}
/***** 平年値 *****/
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, "平年最低%d℃", nenTmpMin.toInt()); // 変換
lcd.setTextColor(TFT_CYAN, TFT_BLACK); // (文字色,背景色)
lcd.print(buf1); Serial.print(buf1); // 表示
sprintf(buf1, " 最高%d℃", nenTmpMax.toInt()); // 変換
lcd.setTextColor(TFT_MAGENTA, TFT_BLACK); // (文字色,背景色)
lcd.println(buf1); Serial.println(buf1); // 表示
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
sprintf(buf1, "平年7日降水%2.0f-%2.0fmm",
nenPreMin.toFloat(), nenPreMax.toFloat()); // 変換
lcd.println(buf1); Serial.println(buf1); // 表示
}
/***** 神奈川県予報 *****/
} else if (wDay == 8) { // wDay=8なら
lcd.setCursor(0, 72); // 表示位置
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文字分
lcd.print(A); Serial.println(A); // 表示
/***** 関東予報 *****/
} else if (wDay == 9) { // wDay=9なら
lcd.setCursor(0, 72); // 表示位置
String A = doc[3]["headTitle"]; // ◆タイトル
String B = doc[3]["text"]; // ◆text
A = "[9] " + A + ": " + B; A = mojiHenkan(A); // 文字変換
A = A.substring(0, bMidN - 9) + "(略)"; // bMidN文字分-α表示
lcd.print(A); Serial.println(A); // 表示 一部のみ
} else { // ゴミ出し内容
lcd.fillScreen(TFT_BLACK); // 画面クリア
lcd.setCursor(0, 0); // 画面左上から開始
myFile = SD.open("Gomi/Gomi" + fname[youbiNo] + ".txt", FILE_READ);//SDのファイルを開く("f名",読込)
while (myFile.available()) { // ファイルから読取り可能なバイト数
lcd.write(myFile.read()); // ファイルから1バイト読取り、シリアルポートに1バイト出力
}
myFile.close(); // ファイルを閉じる
}
if (wDay != 10) { // ごみ収集で無ければ
lcd.drawFastHLine(1, 278, 238, TFT_WHITE); // 横線(x,y,w,色)
}
}
void printCharge() { // 充電マーク表示関数
int current = lipo.current(AVG); // 平均電流取得(mA) +充電,-放電
//Serial.printf("充電%dmA\n", current); // 電流値
int x = 190, y = 5, w = 4, h = 8, ww = 2; // W=幅/2,h=高さ/2,w=重なり/2
if (current > 0) { // 充電中なら
lcd.fillTriangle(x , y + h + ww, x + w + ww, y, x + w + ww, y + h + ww, TFT_RED); // 三角形
lcd.fillTriangle(x + w - ww , y + h - ww, x + w - ww, y + h + h, x + w + w, y + h - ww, TFT_RED);
} else { // 放電中なら
lcd.fillRect(x , y, w * 2 + 1, h * 2 + 1, TFT_BLACK); // 表示を消す
}
}
void printBT() { // バッテリー状態を読取り&表示関数
int x0 = 204, y0 = 2, W0 = 32, H0 = 22, W1 = 3; // 電池マーク大きさ 0:本体,1:+極
lcd.fillRect(x0, y0, W0, H0, TFT_SILVER); // 電池本体 四角形(x0,y0,W,H[,塗りつぶし色])
lcd.fillRect(x0 + W0, y0 + 3, W1, H0 - 6, TFT_SILVER); // 電池プラス極
unsigned int soc = lipo.soc(); // 充電率を取得(%) 満充電100% 完全放電0%
if (soc <= 10) { // 0-10%の時
lcd.setTextColor(TFT_BLACK, TFT_RED); // 赤地に黒文字
} else if (soc <= 25) { // 11-25%の時
lcd.setTextColor(TFT_BLACK, TFT_YELLOW); // 黄地に黒文字
} else { // 26-100%の時
lcd.setTextColor(TFT_WHITE, TFT_BLACK); // 黒地に白文字
}
lcd.setCursor(x0 + 1, y0 + 1); lcd.printf("%3d", soc); // 充電率
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // 文字色を戻す
}
unsigned long sendNTPpacket(const char* address) { // 指定アドレスにNTP要求送信関数
for (int i = 0; i < NTP_PACKET_SIZE; ++i) { // 0-47の48バイトについて
packetBuffer[i] = 0; // バッファ内の全バイトを0
} // 以下にNTP要求を形成するための値を設定
packetBuffer[0] = 0b11100011; // うるう年=同期無し,Ver4(通常),Mode=Client
packetBuffer[1] = 0; // 地層=原子時計???
packetBuffer[2] = 6; // 送出間隔 2^6=64秒
packetBuffer[3] = 0xEC; // 精度
// // packetBuffer[4]-[7]:ルート遅延は8バイトのゼロ
// // packetBuffer[8]-[11]:ルート拡散は8バイトのゼロ
packetBuffer[12] = 49; // [12]-[15]はIPアドレス[49,78,49,52]
packetBuffer[13] = 0x4E; // IPアドレス
packetBuffer[14] = 49; // IPアドレス
packetBuffer[15] = 52; // IPアドレス
udp.beginPacket(address, 123); // addressのポート123へ書込開始
udp.write(packetBuffer, NTP_PACKET_SIZE);// udpデータを書出す(送信バッファ,メッセージ長)
udp.endPacket(); // udpデータを書込んだ後に送信
}
void printAll() {
//lcd.clear(TFT_BLACK);
lcd.fillScreen(TFT_BLACK); // 画面クリア
if (wDay != 10) { // ごみ収集で無ければ時刻表示
printCharge(); // 充電マーク表示関数へ
printBT(); // 電池残量等表示関数へ
printTime(); // 時刻画面表示関数へ
}
printWeather(today); // 1画面設定関数へ
}
unsigned long getNTPtime() { // 時刻受信関数 UNIXの日本時間を返す
if (WiFi.status() == WL_CONNECTED) { // WiFiネットに接続したら
udp.begin(WiFi.localIP(), localPort);// udp(転送バッファ)を初期化 (IPアドレス,ポート番号)
sendNTPpacket(timeURL); // NTP要求送信関数へ
delay(1000); // 1秒待つ
if (udp.parsePacket()) { // 次に利用可能な着信パケットの処理を開始し、
// パケットの存在を確認。戻り値:パケットのサイズ(バイト)。udp.read()の前に必要
//lcd.setCursor(0, yBikou); lcd.print("時刻受信 "); // 表示
udp.read(packetBuffer, NTP_PACKET_SIZE); // パケットをバッファに読込む
// (格納バッファ(char or 配列byte), 読取バイト数(int))
// NTPサーバのパケットの送信時刻(1900/1/1 0:0:0からの秒数)は、41-48バイト目で整数部は41-44バイト目
// 1ワード=2バイト=16ビット
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);//値をwordデータ型に変換
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);//(上位(左)byte,下位(右)byte)
unsigned long secsSince1900 = highWord << 16 | lowWord; // 16bit左にシフトしbitごとにORする
const unsigned long seventyYears = 2208988800; // 70年=(70x365+閏日17)x24x60x60秒
unsigned long epoch = secsSince1900 - seventyYears; // UNIX=UTC-70年
long tzOffset = 32400; // 9H=9x60x60=32400S
unsigned long adjustedTime; // JST(日本時間)
return adjustedTime = epoch + tzOffset; // JST=UTC+9H
} else { // 利用可能なパケットがない場合
udp.stop(); // サーバーから切断し、udpセッション中に使用されていたリソースを解放
return 0; // 0は失敗、利用可能なパケットがない
}
udp.stop(); //ntp timeを頻繁に呼び出さないで、リソースのリリースを停止
} else {
return 0; // 0は失敗、ネットに接続できない
}
}
void setBQ27441() { // バッテリー残量IC(BQ27441-G1A)初期設定
if (!lipo.begin()) { // I2Cを初期化、通信確認出来ない時
lcd.setTextColor(TFT_RED); // 赤文字
lcd.setCursor(0, yBikou); lcd.println("バッテリー残量ICと通信できません"); // 表示
delay(500); // 0.5秒待つ
lcd.setCursor(0, yBikou); lcd.println("バッテリーを接続してください"); // 表示
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // 文字色を戻す
while (1); // 永久ループ
} // 通信出来たら
lcd.setCursor(0, yBikou); lcd.println("バッテリー残量ICに接続"); // 表示
lipo.setCapacity(BATTERY_CAPACITY); // バッテリー設計容量650mAhに設定
}
void setGamen() { // 画面初期設定関数
lcd.init(); // LCD初期化
lcd.setBrightness(64); // バックライト輝度(暗0-255明)
lcd.setRotation(2); // LCD表示向き
lcd.setFont(&lgfxJapanGothic_20); // ゴシック固定長 縦ドット(16,20,24,28,32)
//lcd.setTextScroll(true); // 画面下端に到達後スクロール
//lcd.setScrollRect(0, 0, lcd.width(), lcd.height());//スクロール範囲(X,Y,W,H)
lcd.setTextSize(1.0); // 文字サイズ(横縦幅倍数)
lcd.setTextColor(TFT_GREEN, TFT_BLACK); // (文字色,背景色)
//lcd.setCursor(0, 0); // 画面左上から開始
lcd.fillScreen(TFT_BLACK); // 画面クリア
}
void setWifi() { // Wifi設定関数
WiFi.mode(WIFI_STA); // 子機モード
lcd.setCursor(0, yBikou - 20); lcd.print("接続:" + String(ssid));//接続するSSID表示
WiFi.disconnect(); // Wi-Fiシールドをネットから切断
lcd.setCursor(0, yBikou); lcd.print("Wi - Fi接続待ち。 "); // 表示
WiFi.begin(ssid, password); // WiFiライブラリのネット設定を初期化し、接続開始
while (WiFi.status() != WL_CONNECTED) { // WiFiネットに接続していなかったら
WiFi.begin(ssid, password); // WiFiライブラリのネット設定を初期化し、接続開始
delay(500); // 0.5秒待つ
}
long rssi = WiFi.RSSI(); // 受信信号強度を取得
lcd.setCursor(0, yBikou); lcd.printf("受信:%3lddBm", rssi); // 受信信号強度を表示
Serial.printf("\n受信強度:%4lddBm\n", rssi); //
if (rssi <= -81) { // -81dBm以下の時
lcd.print("(使えない)"); // 表示
} else if (rssi <= -71) { // -71~-80dBmの時
lcd.print("(弱い)"); // 表示
} else if (rssi <= -68) { // -68~-70dBmの時
lcd.print("(強い)"); // 表示
} else if (rssi <= -31) { // -31~-67dBmの時
lcd.print("(とても強い)"); // 表示
} else { // 0~-30dBmの時
lcd.print("(非常に強い)"); // 表示
}
}
void setButton() { // ボタン設定関数
pinMode(WIO_KEY_A, INPUT_PULLUP); // 内側ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_KEY_B, INPUT_PULLUP); // 中間ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_KEY_C, INPUT_PULLUP); // 外側ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_5S_UP, INPUT_PULLUP); // 5wey上ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_5S_DOWN, INPUT_PULLUP); // 5wey下ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_5S_LEFT, INPUT_PULLUP); // 5wey左ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_5S_RIGHT, INPUT_PULLUP); // 5wey右ボタンをプルアップ抵抗入りデジタル入力に
pinMode(WIO_5S_PRESS, INPUT_PULLUP); // 5wey押ボタンをプルアップ抵抗入りデジタル入力に
}
void setBuzzer() { // ブザー設定関数
pinMode(WIO_BUZZER, OUTPUT); // ブザーpinを出力に
}
void click1() { // クリック音関数
int tone = 1900; //
for (long i = 0; i < 50000L; i += tone * 2) { // ループ
digitalWrite(WIO_BUZZER, HIGH); delayMicroseconds(tone); // ブサ―onで待つ
digitalWrite(WIO_BUZZER, LOW); delayMicroseconds(tone); // ブサ―offで待つ
}
tone = 900; //
for (long i = 0; i < 50000L; i += tone * 2) { // ループ
digitalWrite(WIO_BUZZER, HIGH); delayMicroseconds(tone); // ブサ―onで待つ
digitalWrite(WIO_BUZZER, LOW); delayMicroseconds(tone); // ブサ―offで待つ
}
}
void setup() {
setGamen(); // 画面設定の関数へ
setBQ27441(); // バッテリー残量設定関数へ
printCharge(); // 充電マーク表示関数へ
printBT(); // 電池残量等表示関数へ
setButton(); // ボタン設定の関数へ
setWifi(); // wifi設定の関数へ
setBuzzer(); // ブサ―設定関数へ
Serial.print("SD通信初期化"); // 表示 ファイルは消えない
if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) { // 通信初期化できなかったら
lcd.println(" 失敗"); // 表示
while (1); // 永久ループ
}
Serial.println(" 終了"); // 表示
devicetime = getNTPtime(); // 時刻受信関数へ
if (devicetime == 0) { // 時刻取得出来ない場合
lcd.setCursor(0, yBikou); lcd.print("時刻を受信できません。 "); // 表示
}
rtc.begin(); // 内部RTCを初期化
rtc.adjust(DateTime(devicetime)); // 受信時刻に更新
now = rtc.now(); // 更新後のWioのRTC時刻
printTime(); // 時刻画面表示関数へ
updateDelay.start(60 * 1000); // ノンブロック遅延開始 遅延1分
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); // シリアルモニタに表示
printWeather(today); // 1画面設定関数へ
}
void loop() {
if (digitalRead(WIO_5S_UP) == LOW) { // 5weyボタンを左へ押すと
click1(); // クリック音関数へ
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 = 10; // 最後の頁
}
printAll(); // 1画面設定関数へ
}
if (digitalRead(WIO_5S_DOWN) == LOW) { // 5weyボタンを右へ押すと
click1(); // クリック音関数へ
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; // 最初の頁
}
printAll(); // 1画面設定関数へ
}
if (digitalRead(WIO_5S_LEFT) == LOW) { // 5weyボタンを下へ押すと(8の時のみ使用)
if (wDay == 10) { // ごみ収集なら
click1(); // クリック音関数へ
printAll(); // 1画面設定関数へ
}
if (wDay == 8) { // 神奈川県天気概況なら
click1(); // クリック音関数へ
if (bMid < 3) { // 1頁か2頁なら
bMid++; // 次の頁へ
} else { // 3頁目なら
bMid = 1; // 1頁へ戻る
} // bMid=1→2→3→1→2→・・・
printAll(); // 1画面設定関数へ
}
}
if (wDay != 10)printCharge(); // ごみ収集で無ければ充電マーク表示関数へ
delay(200); // 0.2秒待つ
if (updateDelay.justFinished()) { // ノンブロック遅延が終了したら 1分ごとに更新
updateDelay.repeat(); // ノンブロック遅延を再開 定期更新
now = rtc.now(); // RTC時刻
if (wDay != 10) { // ごみ収集で無ければ時刻表示
printTime(); // 時刻画面表示関数へ
printBT(); // 残量等表示関数へ
}
}
}
* フラッシュメモリの97%を使用。