14.CoreInkでOpenWeatherMap(5)
>14.CoreInkでOpenWeatherMap(5)
説明
無料のワンコールAPI(https://openweathermap.org/api/one-call-api)で- 現在の天気
- 1Hの分毎の降水量予報
- 48Hの時間予報
- 7日間の毎日の天気予報
- 全国気象警報
- 過去5日間の過去の気象データ
[1]現在の気象
ボタンを2秒間上に回したら | 何もしない |
ボタンを上に回したら | |
ボタンを2秒間下に回したら | [2]へ |
ボタンを下に回したら | |
ボタンを押し込んだら | |
上面ボタンを押したら | 何もしない |
[2]1H後までの降水予報量
ボタンを2秒間上に回したら | [1]へ |
ボタンを上に回したら | |
ボタンを2秒間下に回したら | [3]へ |
ボタンを下に回したら | |
ボタンを押し込んだら | |
上面ボタンを押したら | [1]へ |
[3]48H後までの気象予報のmenu
月/日は一番左の時刻の日付です。48データあります。
ボタンを2秒間上に回したら | 時刻を1行上へ |
ボタンを上に回したら | 前の時刻へ |
ボタンを2秒間下に回したら | 時刻を1行下へ |
ボタンを下に回したら | 次の時刻へ |
ボタンを押し込んだら | [4]へ |
上面ボタンを押したら | [1]へ |
[4]48H後までの気象予報
ボタンを2秒間上に回したら | 1H前の予報へ |
ボタンを上に回したら | |
ボタンを2秒間下に回したら | 1H後の予報へ |
ボタンを下に回したら | |
ボタンを押し込んだら | [5]へ |
上面ボタンを押したら | [1]へ |
[5]7日後までの気象予報
ボタンを2秒間上に回したら | 1日前の予報へ |
ボタンを上に回したら | |
ボタンを2秒間下に回したら | 1日後の予報へ |
ボタンを下に回したら | |
ボタンを押し込んだら | 何もせず |
上面ボタンを押したら | [1]へ |
スケッチ
xxxxxは、自分のwifiのSSID、wifiのパスワード、APIキーを入力します。自分で作った天気のアイコン"icon48-9.h"も必要です。
// 天気情報 OpenWeatherMap
// 確認は、https://openweathermap.org/city/1848354
// 関数一覧
// pushSprite LovyanGFXの1画面表示お決まり
// getJson jsonを得る
// houi wind_degからwind_houi算出
// drawCcurrent 現在の天気 1画面をセット
// drawMinutely 1H後までの降水量 1画面セット
// drawHourlymenu 48H後までの予報のmenu 1画面セット
// drawHourly 48H後までの予報 1画面セット
// drawDaily 7日後までの予報 1画面セット
// inkSet coreInkを使う時お決まり
// wifiSet wifiを使う時お決まり
// nihonSet 日本語を表示する時お決まり
// setup
// loop
#include "icon48-9.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> // 描画ライブラリ
#include <time.h> // 時間表示
const char* ssid = "xxxxx"; // 自分のwifiのSSID
const char* password = "xxxxx"; // wifiのパスワード
const char* weatherURL = "https://api.openweathermap.org/data/2.5/onecall?lat=35.447781&lon=139.642502&units=metric&lang=ja&appid=xxxxx";
// 神奈川県 横浜 ワンコールAPI
DynamicJsonDocument weatherInfo(35000); //
Ink_Sprite InkPageSprite(&M5.M5Ink); // 定義
static LGFX_Sprite sprite; // 定義
time_t t; // システム時刻 time()関数によって得られる,<time.h>で定義,数値
struct tm *tm; // 構造体の型を宣言,タグ名,構造体変数名
static const char *wd[7] = {"(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)"};
int dy = 17, upy; // 行刻み,上の行
int sheet; // 1:現在(current) 2:1H後までの降水量(minutely)
// 3:48H後までの予報のmenu(hourly) 4:48H後までの予報(hourly)
// 5:7日後までの予報(daily)
int hanten = 0; // sheet=3にて選択時刻0-47
// 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(35000); //
if ((WiFi.status() == WL_CONNECTED)) { // wifiが接続されていたら
HTTPClient http; // 定義
http.begin(weatherURL); // アクセスするURLを登録
Serial.println(weatherURL); // シリアルモニタに表示
int httpCode = http.GET(); //登録URLに、GETリクエスト送信
if (httpCode > 0) { //HTTPのリターンコード。エラーの場合は負数
String jsonString = http.getString(); //
Serial.print("HTTPコード="); Serial.println(httpCode);//シリアルモニタに表示
Serial.println(jsonString); // json用文字列 長い
deserializeJson(doc, jsonString);
// 直列化されたデータをDynamicJsonDocumentの形に変換
} else {
Serial.println("エラー HTTPリクエスト"); // シリアルモニタに表示
}
http.end(); // TCPコネクションを切断しHTTP通信を終了
}
return doc;
}
String houi(int wind_degInt) { // wind_degIntからwind_houi算出
String wind_houi; // 8方位
if (wind_degInt < 22.5) {
wind_houi = "北 ";
} else if (wind_degInt < 67.5) {
wind_houi = "北東";
} else if (wind_degInt < 112.5) {
wind_houi = "東 ";
} else if (wind_degInt < 157.5) {
wind_houi = "南東";
} else if (wind_degInt < 202.5) {
wind_houi = "南 ";
} else if (wind_degInt < 247.5) {
wind_houi = "南西";
} else if (wind_degInt < 292.5) {
wind_houi = "西 ";
} else if (wind_degInt < 337.5) {
wind_houi = "北西";
} else {
wind_houi = "北 ";
}
return wind_houi;
}
void drawCcurrent() { // 現在の気象 1画面セットする
sheet = 1; // 画面1
upy = 2; // 表示用y
sprite.clear(TFT_WHITE); // 全体の背景色を白
String today = weatherInfo["current"]; // 現在(current)
DynamicJsonDocument doc(35000); //
deserializeJson(doc, today); //
//
String dt = doc["dt"]; // 現在の時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.setCursor(5, upy); // 表示位置
sprite.printf("%04d/%02d/%02d%s %02d:%02d現在", // 画面表示
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, wd[tm->tm_wday],
tm->tm_hour, tm->tm_min);
Serial.printf("現在%04d/%02d/%02d%s %02d:%02d", // シリアルモニタに表示
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, wd[tm->tm_wday],
tm->tm_hour, tm->tm_min);
//
String sunrise = doc["sunrise"]; // 日の出時刻(Unix,UTC)
t = sunrise.toInt() + 9 * 3600; tm = localtime(&t); //
upy = upy + dy + 1; sprite.setCursor(10, upy); // 表示位置
sprite.printf("日の出%01d:%02d", tm->tm_hour, tm->tm_min); // 画面表示
Serial.printf(" 日の出%01d:%02d", tm->tm_hour, tm->tm_min);//シリアルモニタに表示
//
String sunset = doc["sunset"]; // 日没時間(Unix,UTC)
t = sunset.toInt() + 9 * 3600 ; tm = localtime(&t); //
sprite.printf(" 日没%02d:%02d", tm->tm_hour, tm->tm_min);// 画面表示
Serial.printf(" 日没%02d:%02d\n", tm->tm_hour, tm->tm_min);//シリアルモニタに表示
//
String icon = doc["weather"][0]["icon"]; // 天気アイコンID
upy = upy + dy + 1; sprite.setCursor(10, upy); // 表示位置
Serial.printf("天気(%s)", icon); // シリアルモニタに表示
int x = 70, y = 52, W = 48, H = 48; // 天気マークの表示位置と大きさ
if (icon == "01d" || icon == "01n") { // or
sprite.pushImage(x, y, W, H, img48hare); // 晴天(晴れ)
} else if (icon == "02d" || icon == "02n") {
sprite.pushImage(x, y, W, H, img48hareKumori);// いくつかの雲:11-25%(晴曇り)
} else if (icon == "03d" || icon == "03n") {
sprite.pushImage(x, y, W, H, img48kumori); // 散在する雲25-50%(曇り)
} else if (icon == "04d" || icon == "04n") {
sprite.pushImage(x, y, W, H, img48donyori); // 壊れた雲51-100%(どんより)
} else if (icon == "09d" || icon == "09n") {
sprite.pushImage(x, y, W, H, img48kumoriAme); // にわか雨(曇雨)
} else if (icon == "10d" || icon == "10n") {
sprite.pushImage(x, y, W, H, img48ame); // 雨(雨)
} else if (icon == "11d" || icon == "11n") {
sprite.pushImage(x, y, W, H, img48kaminari); // 雷雨(雷)
} else if (icon == "13d" || icon == "13n") {
sprite.pushImage(x, y, W, H, img48yuki); // 雪(雪)
} else if (icon == "50d" || icon == "50n") {
sprite.pushImage(x, y, W, H, img48moya); // 靄(もや)
}
//
String main = doc["weather"][0]["main"]; // 概略気象
Serial.printf("%s\n", main); // シリアルモニタに表示
//
String id = doc["weather"][0]["id"]; // 詳細気象ID
Serial.printf("詳細(%s)", id); // シリアルモニタに表示
//
char buf[100]; // char用buf
String description = doc["weather"][0]["description"]; // 詳細気象 日本語
int len = description.length(); // 文字列長さ
description.toCharArray(buf, len); // string → char
for (int i = 0; i < len; i++) {
sprite.printf("%c", description[i]); // 日本語変数表示
}
Serial.printf("%s\n", description); // シリアルモニタに表示
//
String temp = doc["temp"]; // 温度
upy = upy + dy; sprite.setCursor(130, upy); // 表示位置
sprite.printf("温度%2.0f℃", temp.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp.toFloat()); // シリアルモニタに表示
//
String feels_like = doc["feels_like"]; // 体感温度
upy = upy + dy + 1; sprite.setCursor(130, upy); // 表示位置
sprite.printf("体感%2.0f℃", feels_like.toFloat()); // 画面表示
Serial.printf(" 体感%2.0f℃", feels_like.toFloat()); // シリアルモニタに表示
//
String dew_point = doc["dew_point"]; // 結露気温
upy = upy + dy + 1; sprite.setCursor(130, upy); // 表示位置
sprite.printf("結露%2.0f℃", dew_point.toFloat()); // 画面表示
Serial.printf(" 結露%2.0f℃", dew_point.toFloat()); // シリアルモニタに表示
//
sprite.setCursor(10, upy); // 表示位置
sprite.print("(横浜)"); // 場所を画面表示
//
String humidity = doc["humidity"]; // 湿度(%)
upy = upy + dy + 1; sprite.setCursor(10, upy); // 表示位置
sprite.printf("湿度%2.0f%%", humidity.toFloat()); // 画面表示
Serial.printf(" 湿度%2.0f%%", humidity.toFloat()); // シリアルモニタに表示
//
String pressure = doc["pressure"]; // 海面気圧(hPa)
sprite.printf(" 海面%4.0fhPa", pressure.toFloat()); // 画面表示
Serial.printf(" 海面%4.0fhPa\n", pressure.toFloat()); // シリアルモニタに表示
//
String wind_speed = doc["wind_speed"]; // 風速(m/s)
upy = upy + dy + 1; sprite.setCursor(10, upy); // 表示位置
sprite.printf("風%2.0fm/s", wind_speed.toFloat()); // 画面表示
Serial.printf("風%2.0fm/s", wind_speed.toFloat()); // シリアルモニタに表示
//
String wind_deg = doc["wind_deg"]; // 風向(方位角)
int wind_degInt = wind_deg.toInt(); //
String wind_houi = houi(wind_degInt); // wind_degからwind_houi算出
sprite.printf("(%s%3d°)", wind_houi, wind_degInt); // 画面表示
Serial.printf("(%s%3d°)", wind_houi, wind_degInt); // シリアルモニタに表示
//
String clouds = doc["clouds"]; // 曇量(%)
sprite.setCursor(150, upy); // 表示位置
sprite.printf("曇%2d%%", clouds.toInt()); // 画面表示
Serial.printf(" 曇量%2d%%\n", clouds.toInt()); // シリアルモニタに表示
//
String uvi = doc["uvi"]; // UV指数
upy = upy + dy + 1; sprite.setCursor(10, upy); // 表示位置
sprite.printf("UV指数%4.1f", uvi.toFloat()); // 画面表示
Serial.printf("UV指数%4.1f", uvi.toFloat()); // シリアルモニタに表示
//
String visibility = doc["visibility"]; // 可視性(m)
sprite.printf(" 可視%4.1fkm", visibility.toFloat() / 1000); // 画面表示
Serial.printf(" 可視性%4.1fkm", visibility.toFloat() / 1000); // シリアルモニタに表示
//
String rain_1h = doc["hourly"][0]["rain"][0]["1h"];
//利用可能な場合、過去1Hの降水量(mm)
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
if (rain_1h = "") {
sprite.printf("降水なし"); // 画面表示
Serial.printf("降水なし"); // シリアルモニタに表示
} else {
sprite.printf("1H雨%.0dmm", rain_1h.toInt()); // 画面表示
Serial.printf("1H降水%.0dmm", rain_1h.toInt()); // シリアルモニタに表示
}
//
String snow_1h = doc["hourly"][0]["snow"][0]["1h"];
//利用可能な場合、1H前からの積雪量(mm)
if (snow_1h = "") {
sprite.printf(" 積雪なし"); // 画面表示
Serial.printf(" 積雪なし\n"); // シリアルモニタに表示
} else {
sprite.printf(" 1H雪%.0dmm", snow_1h.toInt()); // 画面表示
Serial.printf(" 1H前からの積雪%.0dmm\n", snow_1h.toInt()); // シリアルモニタに表示
}
//
String wind_gust = doc["wind_gust"]; // 利用可能な場合、突風(m/s)
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
if (wind_gust = "") {
sprite.printf("突風なし"); // 画面表示
Serial.printf(" 突風なし\n"); // シリアルモニタに表示
} else {
sprite.printf("突風%2.0fm/s", wind_gust.toFloat()); // 画面表示
Serial.printf(" 突風%2.0fm/s\n", wind_gust.toFloat()); // シリアルモニタに表示
}
}
void drawMinutely() { // 1H後までの降水量 1画面セットする
sheet = 2; // 画面2
sprite.clear(TFT_WHITE); // 全体の背景色を白
String minutely = weatherInfo["minutely"]; //
DynamicJsonDocument doc(35000); //
deserializeJson(doc, minutely); //
//
String dt = doc[0]["dt"]; // 時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.setCursor(0, 0); // 1行目
sprite.printf("%02d:%02dから60分後までの", // 画面表示
tm->tm_hour, tm->tm_min);
sprite.setCursor(70, dy); sprite.print("降水予測量(mm/H)"); // 2行目
//
int x = 20, y = 20; // 表示位置
for (int i = 0; i <= 60; i++) { // 61データ
String dt = doc[i]["dt"]; // 時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; //
tm = localtime(&t); //
Serial.printf("%04d/%02d/%02d%s %02d:%02d", // シリアルモニタに表示
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, wd[tm->tm_wday],
tm->tm_hour, tm->tm_min);
//
String precipitation = doc[i]["precipitation"]; // 降水予測量(mm)
sprite.setCursor(x, y); // 表示位置
y = y + (dy - 2); // 下へ
if (y > 180) { // 次の列へ
y = 35; // yの最上位置へ
x = x + 30; // 右へ
}
sprite.printf("%3d", precipitation.toInt()); // 画面表示
Serial.printf(" %dmm\n", precipitation.toInt());// シリアルモニタに表示
}
int i = 0; // 分
for (y = 21; y <= 180; y = y + dy - 2) { // 11文字表示
sprite.setTextColor(TFT_WHITE, TFT_BLACK); // 黒地に白字
sprite.setCursor(0, y); // 表示位置
sprite.printf("%2d", i); // 最左列の縦軸値
i = i + 1; // 次の分
}
i = 1; // 分
for (x = 20; x <= 180; x = x + 30) { // 6文字表示
sprite.setCursor(x, 185); // 表示位置
sprite.printf("%3d", i * 10); // 最下行の横軸値
i = i + 1; // 次の分
}
sprite.setTextColor(TFT_BLACK, TFT_WHITE); // 白地に黒字
for (x = 17; x <= 180; x = x + 30) { // 6本引く
sprite.drawFastVLine(x, 35, 165, TFT_BLACK); // 縦線(x,y,L,色)
}
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
void drawHourlymenu() { // 48H後までの予報menu 1画面セットする
sheet = 3; // 画面3
sprite.clear(TFT_WHITE); // 全体の背景色を白
String hourly = weatherInfo["hourly"]; //
DynamicJsonDocument doc(35000); //
deserializeJson(doc, hourly); //
upy = 5; sprite.setCursor(15, upy); // 表示位置
sprite.print("予報の時刻選択メニュー"); // 画面表示
String dt = doc[0]["dt"]; // 予報時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
upy = upy + dy + 5; sprite.setCursor(10, upy); // 表示位置
sprite.printf("%02d/%02d %02d時 ~ ", // 画面表示
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour);
String dt1 = doc[47]["dt"]; // 予報時刻(Unix,UTC)
t = dt1.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.printf("%02d/%02d %02d時", // 画面表示
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour);
int i = 0;
sprite.drawFastHLine(0, 49, 199, TFT_BLACK); // 横線(x,y,L,色)
for (int y = 50; y < 180; y = y + dy) {
String dt = doc[i]["dt"]; // 予報時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.setCursor(5, y); // 表示位置
sprite.setTextColor(TFT_BLACK, TFT_WHITE); // 白地に黒字
sprite.printf("%02d/%02d|", tm->tm_mon + 1, tm->tm_mday); // 画面表示
for (int x = 55; x < 180; x = x + 24) {
String dt = doc[i]["dt"]; // 予報時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
if (hanten == i) {
sprite.setTextColor(TFT_WHITE, TFT_BLACK); // 黒地に白字
} else {
sprite.setTextColor(TFT_BLACK, TFT_WHITE); // 白地に黒字
}
sprite.setCursor(x, y); // 表示位置
sprite.printf("%02d", tm->tm_hour); // 画面表示
i = i + 1; // 次の時刻
}
sprite.drawFastHLine(0, y + 16, 199, TFT_BLACK);//横線(x,y,L,色)
}
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
}
void drawHourly() { // 48H後までの予報 1画面セットする
sheet = 4; // 画面4
upy = 2; // 表示用y
sprite.clear(TFT_WHITE); // 全体の背景色を白
String hourly = weatherInfo["hourly"]; //
DynamicJsonDocument doc(35000); //
deserializeJson(doc, hourly); //
String dt = doc[hanten]["dt"]; // 予報時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.setCursor(20, upy); // 表示位置
sprite.printf("%04d/%02d/%02d%s %02d:%02d", // 画面表示
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, wd[tm->tm_wday],
tm->tm_hour, tm->tm_min);
Serial.printf("%02d/%02d%s%02d", // シリアルモニタに表示
tm->tm_mon + 1, tm->tm_mday,
wd[tm->tm_wday], tm->tm_hour);
//
String icon = doc[hanten]["weather"][0]["icon"]; // 天気アイコンID
upy = upy + dy + 2; sprite.setCursor(10, upy); // 表示位置
Serial.printf(" 天気(%s)", icon); // シリアルモニタに表示
int x = 70, y = 33, W = 48, H = 48; // 天気マークの表示位置と大きさ
if (icon == "01d" || icon == "01n") {
sprite.pushImage(x, y, W, H, img48hare); // 晴天(晴れ)
} else if (icon == "02d" || icon == "02n") { // or
sprite.pushImage(x, y, W, H, img48hareKumori); // いくつかの雲:11-25%(晴曇り)
} else if (icon == "03d" || icon == "03n") {
sprite.pushImage(x, y, W, H, img48kumori); // 散在する雲25-50%(曇り)
} else if (icon == "04d" || icon == "04n") {
sprite.pushImage(x, y, W, H, img48donyori); // 壊れた雲51-100%(どんより)
} else if (icon == "09d" || icon == "09n") {
sprite.pushImage(x, y, W, H, img48kumoriAme); // にわか雨(曇雨)
} else if (icon == "10d" || icon == "10n") {
sprite.pushImage(x, y, W, H, img48ame); // 雨(雨)
} else if (icon == "11d" || icon == "11n") {
sprite.pushImage(x, y, W, H, img48kaminari); // 雷雨(雷)
} else if (icon == "13d" || icon == "13n") {
sprite.pushImage(x, y, W, H, img48yuki); // 雪(雪)
} else if (icon == "50d" || icon == "50n") {
sprite.pushImage(x, y, W, H, img48moya); // 靄(もや)
}
//
String main = doc[hanten]["weather"][0]["main"]; // 概略気象
Serial.printf(" %s", main); // シリアルモニタに表示
//
String id = doc[hanten]["weather"][0]["id"]; // 詳細気象ID
Serial.printf(" 詳細(%s)", id); // シリアルモニタに表示
//
char buf[100]; //
String description = doc[hanten]["weather"][0]["description"]; //詳細気象 日本語
int len = description.length(); // 文字列長さ
description.toCharArray(buf, len); // string → char
for (int i = 0; i < len; i++) {
sprite.printf("%c", description[i]); // 日本語変数表示
}
Serial.printf(" %s", description); // シリアルモニタに表示
//
String temp = doc[hanten]["temp"]; // 温度
upy = upy + dy + 2; sprite.setCursor(130, upy); // 表示位置
sprite.printf("温度%2.0f℃", temp.toFloat()); // 文字列→単精度浮動小数点
Serial.printf(" 温度%2.0f℃", temp.toFloat()); // シリアルモニタに表示
//
String feels_like = doc[hanten]["feels_like"]; // 体感温度
upy = upy + dy + 2; sprite.setCursor(130, upy); // 表示位置
sprite.printf("体感%2.0f℃", feels_like.toFloat()); // 画面表示
Serial.printf(" 体感%2.0f℃", feels_like.toFloat()); // シリアルモニタに表示
//
String dew_point = doc[hanten]["dew_point"]; // 結露気温
upy = upy + dy + 2; sprite.setCursor(130, upy); // 表示位置
sprite.printf("結露%2.0f℃", dew_point.toFloat()); // 画面表示
Serial.printf(" 結露%2.0f℃", dew_point.toFloat()); // シリアルモニタに表示
//
sprite.setCursor(10, upy); // 表示位置
sprite.print("(横浜)"); // 場所
//
String humidity = doc[hanten]["humidity"]; // 湿度(%)
upy = upy + dy + 2; sprite.setCursor(10, upy); // 表示位置
sprite.printf("湿度%2.0f%%", humidity.toFloat()); // 画面表示
Serial.printf(" %2.0f%%", humidity.toFloat()); // シリアルモニタに表示
//
String pressure = doc[hanten]["pressure"]; // 海面気圧(hPa)
sprite.printf(" 海面%4.0fhPa", pressure.toFloat()); // 画面表示
Serial.printf(" %4.0fhPa", pressure.toFloat()); // シリアルモニタに表示
//
String wind_speed = doc[hanten]["wind_speed"]; // 風速(m/s)
upy = upy + dy + 2; sprite.setCursor(10, upy); // 表示位置
sprite.printf("風%2.0fm/s", wind_speed.toFloat()); // 画面表示
Serial.printf(" 風%2.0fm/s", wind_speed.toFloat()); // シリアルモニタに表示
//
String wind_deg = doc[hanten]["wind_deg"]; // 風向(方位角)
int wind_degInt = wind_deg.toInt(); // stringからintに変換
String wind_houi = houi(wind_degInt); // wind_degからwind_houi算出
sprite.printf("(%s%3d°)", wind_houi, wind_degInt); // 画面表示
Serial.printf("(%s%3d°)", wind_houi, wind_degInt); // シリアルモニタに表示
//
String clouds = doc[hanten]["clouds"]; // 曇量(%)
sprite.setCursor(150, upy); // 表示位置
sprite.printf("曇%2d%%", clouds.toInt()); // 画面表示
Serial.printf(" 曇%2d%%", clouds.toInt()); // シリアルモニタに表示
//
String uvi = doc[hanten]["uvi"]; // UV指数
upy = upy + dy + 2; sprite.setCursor(10, upy); // 表示位置
sprite.printf("UV指数%4.1f", uvi.toFloat()); // 画面表示
Serial.printf(" UV%4.1f", uvi.toFloat()); // シリアルモニタに表示
//
String visibility = doc[hanten]["visibility"]; // 可視性(m)
sprite.printf(" 可視%4.1fkm", visibility.toFloat() / 1000); // 画面表示
Serial.printf(" 可視性%4.1fkm", visibility.toFloat() / 1000); // シリアルモニタに表示
//
String pop = doc[hanten]["pop"]; // 降水確率(%)
upy = upy + dy + 2; sprite.setCursor(10, upy); // 表示位置
sprite.printf("降水%2.0f%%", pop.toInt()); // 画面表示
Serial.printf(" 降水%2.0f%%", pop.toInt()); // シリアルモニタに表示
//
String snow_1h = doc[hanten]["snow"][0]["1h"];
//利用可能な場合、1H前からの積雪量(mm)
if (snow_1h = "") {
sprite.printf(" 積雪なし"); // 画面表示
Serial.printf(" 積雪なし"); // シリアルモニタに表示
} else {
sprite.printf(" 1H雪%.0dmm", snow_1h.toInt()); // 画面表示
Serial.printf(" 1H前からの積雪%.0dmm", snow_1h.toInt()); // シリアルモニタに表示
}
//
String wind_gust = doc[hanten]["wind_gust"]; // 利用可能な場合、突風(m/s)
upy = upy + dy + 2; sprite.setCursor(10, upy); // 表示位置
if (wind_gust = "") {
sprite.printf("突風なし"); // 画面表示
Serial.printf(" 突風なし"); // シリアルモニタに表示
} else {
sprite.printf("突風%2.0fm/s", wind_gust.toFloat()); // 画面表示
Serial.printf(" 突風%2.0fm/s", wind_gust.toFloat()); // シリアルモニタに表示
}
Serial.println("");
}
void drawDaily() { // 7日後までの予報(daily) 1画面セット
sheet = 5; // 画面5
upy = 0; // 表示用y
sprite.clear(TFT_WHITE); // 全体の背景色を白
String daily = weatherInfo["daily"]; //
DynamicJsonDocument doc(35000); //
deserializeJson(doc, daily); //
String dt = doc[hanten]["dt"]; // 予報時刻(Unix,UTC)
t = dt.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.setCursor(20, upy); // 表示位置
sprite.printf("%04d/%02d/%02d%s %02d:%02d", // 画面表示
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, wd[tm->tm_wday],
tm->tm_hour, tm->tm_min);
Serial.printf("現在%04d/%02d/%02d%s %02d:%02d", // シリアルモニタに表示
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, wd[tm->tm_wday],
tm->tm_hour, tm->tm_min);
String sunrise = doc[hanten]["sunrise"]; // 日の出時刻(Unix,UTC)
t = sunrise.toInt() + 9 * 3600; tm = localtime(&t); //
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
sprite.printf("日の出%01d:%02d", tm->tm_hour, tm->tm_min); // 画面表示
Serial.printf(" 日の出%01d:%02d", tm->tm_hour, tm->tm_min);//シリアルモニタに表示
String sunset = doc[hanten]["sunset"]; // 日没時刻(Unix,UTC)
t = sunset.toInt() + 9 * 3600; tm = localtime(&t); //
sprite.printf(" 日没%02d:%02d", tm->tm_hour, tm->tm_min);// 画面表示
Serial.printf(" 日没%02d:%02d\n", tm->tm_hour, tm->tm_min);//シリアルモニタに表示
String icon = doc[hanten]["weather"][0]["icon"]; // 天気アイコンID
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
Serial.printf("天気(%s)", icon); // シリアルモニタに表示
int x = 70, y = 52, W = 48, H = 48; // 天気マークの表示位置と大きさ
if (icon == "01d" || icon == "01n") { // or
sprite.pushImage(x, y, W, H, img48hare); // 晴天(晴れ)
} else if (icon == "02d" || icon == "02n") {
sprite.pushImage(x, y, W, H, img48hareKumori);// いくつかの雲:11-25%(晴曇り)
} else if (icon == "03d" || icon == "03n") {
sprite.pushImage(x, y, W, H, img48kumori); // 散在する雲25-50%(曇り)
} else if (icon == "04d" || icon == "04n") {
sprite.pushImage(x, y, W, H, img48donyori); // 壊れた雲51-100%(どんより)
} else if (icon == "09d" || icon == "09n") {
sprite.pushImage(x, y, W, H, img48kumoriAme); // にわか雨(曇雨)
} else if (icon == "10d" || icon == "10n") {
sprite.pushImage(x, y, W, H, img48ame); // 雨(雨)
} else if (icon == "11d" || icon == "11n") {
sprite.pushImage(x, y, W, H, img48kaminari); // 雷雨(雷)
} else if (icon == "13d" || icon == "13n") {
sprite.pushImage(x, y, W, H, img48yuki); // 雪(雪)
} else if (icon == "50d" || icon == "50n") {
sprite.pushImage(x, y, W, H, img48moya); // 靄(もや)
}
String main = doc[hanten]["weather"][0]["main"]; // 概略気象
Serial.printf("%s\n", main); // シリアルモニタに表示
String id = doc[hanten]["weather"][0]["id"]; // 詳細気象ID
Serial.printf("詳細(%s)", id); // シリアルモニタに表示
char buf[100]; // char用buf
String description = doc[hanten]["weather"][0]["description"];//詳細気象 日本語
int len = description.length(); // 文字列長さ
description.toCharArray(buf, len); // string → char
for (int i = 0; i < len; i++) {
sprite.printf("%c", description[i]); // 日本語変数表示
}
Serial.printf("%s\n", description); // シリアルモニタに表示
String pop = doc[hanten]["pop"]; // 降水確率(%)
upy = upy + dy - 2; sprite.setCursor(130, upy); // 表示位置
sprite.printf("降水%2.0f%%", pop.toInt()); // 画面表示
Serial.printf(" 降水%2.0f%%", pop.toInt()); // シリアルモニタに表示
String uvi = doc[hanten]["uvi"]; // UV指数
upy = upy + dy; sprite.setCursor(130, upy); // 表示位置
sprite.printf("UV %4.1f", uvi.toFloat()); // 画面表示
Serial.printf("UV指数%4.1f", uvi.toFloat()); // シリアルモニタに表示
String dew_point = doc[hanten]["dew_point"]; // 結露温度
upy = upy + dy; sprite.setCursor(130, upy); // 表示位置
sprite.printf("結露%2.0f℃", dew_point.toFloat()); // 画面表示
Serial.printf(" 結露%2.0f℃", dew_point.toFloat()); // シリアルモニタに表示
sprite.setCursor(10, upy); // 表示位置
sprite.print("(横浜)"); // 場所を画面表示
String temp_max = doc[hanten]["temp"]["max"]; // 最高温度
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
sprite.printf("H%2.0f", temp_max.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp_max.toFloat()); // シリアルモニタに表示
String temp_min = doc[hanten]["temp"]["min"]; // 最低温度
sprite.printf("L%2.0f", temp_min.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp_min.toFloat()); // シリアルモニタに表示
String temp_morn = doc[hanten]["temp"]["morn"]; // 朝の温度
sprite.printf("朝%2.0f", temp_morn.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp_morn.toFloat()); // シリアルモニタに表示
String temp_day = doc[hanten]["temp"]["day"]; // 日中温度
sprite.printf("昼%2.0f", temp_day.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp_day.toFloat()); // シリアルモニタに表示
String temp_eve = doc[hanten]["temp"]["eve"]; // 夕方の温度
//upy = upy + dy; sprite.setCursor(130, upy); // 表示位置
sprite.printf("夕%2.0f", temp_eve.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp_eve.toFloat()); // シリアルモニタに表示
String temp_night = doc[hanten]["temp"]["night"]; // 夜の温度
sprite.printf("夜%2.0f℃", temp_night.toFloat()); // 文字列→単精度浮動小数点
Serial.printf("温度%2.0f℃", temp_night.toFloat()); // シリアルモニタに表示
String feels_morn = doc[hanten]["feels_like"]["morn"]; // 朝の体感温度
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
sprite.printf(" 体感:朝%2.0f", feels_morn.toFloat()); // 画面表示
Serial.printf(" 体感%2.0f℃", feels_morn.toFloat()); // シリアルモニタに表示
String feels_day = doc[hanten]["feels_like"]["day"];//日中の体感温度
sprite.printf("昼%2.0f", feels_day.toFloat()); // 画面表示
Serial.printf(" 体感%2.0f℃", feels_day.toFloat()); // シリアルモニタに表示
String feels_eve = doc[hanten]["feels_like"]["eve"]; // 夕方の体感温度
sprite.printf("夕%2.0f", feels_eve.toFloat()); // 画面表示
Serial.printf(" 体感%2.0f℃", feels_eve.toFloat()); // シリアルモニタに表示
String feels_night = doc[hanten]["feels_like"]["night"]; // 夜の体感温度
sprite.printf("夜%2.0f℃", feels_night.toFloat()); // 画面表示
Serial.printf(" 体感%2.0f℃", feels_night.toFloat()); // シリアルモニタに表示
String humidity = doc[hanten]["humidity"]; // 湿度(%)
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
sprite.printf("湿度%2.0f%%", humidity.toFloat()); // 画面表示
Serial.printf(" 湿度%2.0f%%", humidity.toFloat()); // シリアルモニタに表示
String pressure = doc[hanten]["pressure"]; // 海面気圧(hPa)
sprite.printf(" 海面%4.0fhPa", pressure.toFloat()); // 画面表示
Serial.printf(" 海面%4.0fhPa\n", pressure.toFloat());//シリアルモニタに表示
String wind_speed = doc[hanten]["wind_speed"]; // 風速(m/s)
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
sprite.printf("風%2.0fm/s", wind_speed.toFloat()); // 画面表示
Serial.printf("風%2.0fm/s", wind_speed.toFloat()); // シリアルモニタに表示
//
String wind_deg = doc[hanten]["wind_deg"]; // 風向(方位角)
int wind_degInt = wind_deg.toInt(); //
String wind_houi = houi(wind_degInt); // wind_degからwind_houi算出
sprite.printf("(%s%3d°)", wind_houi, wind_degInt); // 画面表示
Serial.printf("(%s%3d°)", wind_houi, wind_degInt); // シリアルモニタに表示
String clouds = doc[hanten]["clouds"]; // 曇量(%)
sprite.setCursor(150, upy); // 表示位置
sprite.printf("曇%2d%%", clouds.toInt()); // 画面表示
Serial.printf(" 曇量%2d%%\n", clouds.toInt()); // シリアルモニタに表示
String rain = doc[hanten]["hourly"][0]["rain"]; //利用可能な場合、降水量(mm)
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
if (rain = "") {
sprite.printf("降水なし"); // 画面表示
Serial.printf("降水なし"); // シリアルモニタに表示
} else {
sprite.printf("1H雨%.0dmm", rain.toInt()); // 画面表示
Serial.printf("1H降水%.0dmm", rain.toInt()); // シリアルモニタに表示
}
String snow = doc[hanten]["snow"]; //利用可能な場合、積雪量(mm)
if (snow = "") {
sprite.printf(" 積雪なし"); // 画面表示
Serial.printf(" 積雪なし\n"); // シリアルモニタに表示
} else {
sprite.printf(" 雪%.0dmm", snow.toInt()); // 画面表示
Serial.printf(" 積雪%.0dmm\n", snow.toInt()); // シリアルモニタに表示
}
String wind_gust = doc[hanten]["wind_gust"]; // 利用可能な場合、突風(m/s)
upy = upy + dy; sprite.setCursor(10, upy); // 表示位置
if (wind_gust = "") {
sprite.printf("突風なし"); // 画面表示
Serial.printf(" 突風なし\n"); // シリアルモニタに表示
} else {
sprite.printf("突風%2.0fm/s", wind_gust.toFloat()); // 画面表示
Serial.printf(" 突風%2.0fm/s\n", wind_gust.toFloat()); // シリアルモニタに表示
}
}
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(); // json取得関数へ
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シールドがない)
drawCcurrent(); // 現在の気象表示関数へ
}
void loop() {
if (M5.BtnUP.pressedFor(2000)) { // ボタンを2秒間上に回したら
switch (sheet) {
case 1: break; // 現在の気象時
case 2: // 1H後までの降水量時
drawCcurrent(); break; // 現在の気象表示へ
case 3: // 48H後までの予報menu時
if (hanten > 5) {
hanten = hanten - 6; // 選択時刻を1行上へ
drawHourlymenu(); // 48H後までの予報menu表示へ
}
break;
case 4: // 48H後までの予報時
if (hanten > 0) {
hanten--; // 1H前の予報へ
drawHourly(); // 48H後までの予報表示へ
}
break;
case 5: // 7日後までの予報時
if (hanten > 0) {
hanten--; // 1日前の予報へ
drawDaily(); // 48H後までの予報表示へ
}
break;
}
M5.update(); // ボタンとブザーを更新
}
if (M5.BtnDOWN.pressedFor(2000)) { // ボタンを2秒間下に回したら
switch (sheet) {
case 1: // 現在の気象時
drawMinutely(); break; // 1H後までの降水量表示へ
case 2: // 1H後までの降水量時
drawHourlymenu(); break; // 48H後までの予報menu表示へ
case 3: // 48H後までの予報menu時
if (hanten < 42) {
hanten = hanten + 6; // 選択時刻を1行下へ
drawHourlymenu(); // 48H後までの予報menu表示へ
}
break;
case 4: // 48H後までの予報時
if (hanten < 47) {
hanten++; // 1H後の予報へ
drawHourly(); // 48H後までの予報表示へ
}
break;
case 5: // 7日後までの予報時
if (hanten < 6) {
hanten++; // 1日後の予報へ
drawDaily(); // 48H後までの予報表示へ
}
break;
}
M5.update(); // ボタンとブザーを更新
}
if (M5.BtnUP.wasPressed()) { // ボタンを上に回したら
switch (sheet) {
case 1: break; // 現在の気象時
case 2: // 1H後までの降水量時
drawCcurrent(); break; // 現在の気象表示へ
case 3: // 48H後までの予報menu時
if (hanten > 0) {
hanten--; // 選択時刻を-1
drawHourlymenu(); // 48H後までの予報menu表示へ
}
break;
case 4: // 48H後までの予報時
if (hanten > 0) {
hanten--; // 1日前の予報へ
drawHourly(); // 48H後までの予報表示へ
}
break;
case 5: // 7日後までの予報時
if (hanten > 0) {
hanten--; // 1日前の予報へ
drawDaily(); // 48H後までの予報表示へ
}
break;
}
}
if (M5.BtnDOWN.wasPressed()) { // ボタンを下に回したら
switch (sheet) {
case 1: // 現在の気象時
drawMinutely(); break; // 1H後までの降水量表示へ
case 2: // 1H後までの降水量時
drawHourlymenu(); break; // 48H後までの予報menu表示へ
case 3: // 48H後までの予報menu時
if (hanten < 47) {
hanten++; // 選択時刻を+1
drawHourlymenu(); // 48H後までの予報menu表示へ
}
break;
case 4: // 48H後までの予報時
if (hanten < 47) {
hanten++; // 1H前の予報へ
drawHourly(); // 48H後までの予報表示へ
}
break;
case 5: // 7日後までの予報時
if (hanten < 6) {
hanten++; // 1H前の予報へ
drawDaily(); // 48H後までの予報表示へ
}
break;
}
}
if (M5.BtnMID.wasPressed()) { // ボタンを押し込んだら
switch (sheet) {
case 1: // 現在の気象時
drawMinutely(); break; // 1H後までの降水量表示へ
case 2: // 1H後までの降水量時
drawHourlymenu(); break; // 48H後までの予報menu表示へ
case 3: // 48H後までの予報menu時
drawHourly(); break; // 48H後までの予報表示へ
case 4: // 48H後までの予報時
hanten = 1; drawDaily(); break; // 7日後までの予報表示へ
case 5: // 7日後までの予報時
break;
}
}
if (M5.BtnEXT.wasPressed()) { // 上面ボタンを押したら
switch (sheet) {
case 1: break; // 現在の気象時
case 2: // 1H後までの降水量時
case 3: // 48H後までの予報menu時
case 4: // 48H後までの予報時
case 5: // 7日後までの予報時
drawCcurrent(); break; // 現在の気象表示へ
}
}
if (M5.BtnPWR.wasPressed()) { // 電源ボタンを押したら(電源off)
M5.PowerDown();//しばらくすると上面緑LED消灯。電源onは電源ボタンを押す
}
pushSprite(&InkPageSprite, &sprite); // 1画面表示関数へ
M5.update(); // ボタンとブザーを更新
}