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%を使用。