#はじめに
引越しを機に我が家にAlexaを導入しました。
定型アクションに含まれる「天気予報を読む」というアクションを利用し、毎朝9:00に今日の天気を教えてくれるよう設定しています。
今日の天気だけじゃなく、明日の天気を教えてくれる機能があったらいいな〜と思って開発しました。
#現状
アレクサに「明日の天気を教えて」と言えば天気、最高気温、最低気温を回答してもらえるのですが、こちらからの発言なしに定時実行することはできなさそうです。
定型アクションではスキルを発動することができるため、明日の天気を教えてくれるスキルを開発すれば設定した時刻に明日の天気を教えてくれるようになるはず!
※最終的に分かったのですが、現状のAlexaスキル開発では未公開のスキル(ステータスが開発中のスキル)は定型アクションで利用できないようです。定型アクションが設定できない
このページから投票できます。投票数が多ければ追加されるかもしれません!
スキルを公開する予定はないため、この記事では明日の天気を教えてくれる関数の作成方法のみを残しています。
#前提条件
初めてのスキル開発(amazon alexa公式)
#天気予報APIで天気情報を取得する
まずは明日の天気を取得するために利用する天気予報APIを決めます。今回はOpenWeatherMapAPIを利用しました。無料会員で登録します。
https://openweathermap.org
未来の天気を知りたいため、forecast
を利用します。
無料会員では3時間ごと5日分の天気しか取得できません。
下記のように郵便番号,国コード(jp)
を設定することで、地域を指定することができます。
緯度と経度で地域を指定する方法もありますが、今回は郵便番号で指定します。
zip=123-4567,jp
何も設定しない場合、気温は華氏で表記されます。今回は摂氏で表記して欲しいため下記の文言を入れておきます。
units=metric
appid
にOpenWeatherMapAPIに登録した際に付与されたAPPID
を入力します。
appid="APP ID"
よって今回は以下のURLを利用して、明日の天気情報を取得しようと思います。
http://api.openweathermap.org/data/2.5/forecast?zip={郵便番号},jp&units=metric&appid={APPID}
試しにWebブラウザ上でURLを叩いてみると、気温や気圧などの情報が取得できました。
この時にdt
やdt_txt
に入っている時刻は日本時間ではないため、後ほど変換する必要があります。
cod:200
message:0
cnt:40
list:[
0:{
dt:1607342400
main:{
temp:12.95
feels_like:10.44
temp_min:12.95
temp_max:13.12
pressure:1018
sea_level:1018
grnd_level:1017
humidity:55
temp_kf:-0.17
}
weather:[
0:{
id:801
main:Clouds
description:few clouds
icon:02n
}
]
clouds:{
all:24
}
wind:{
speed:1.74
deg:348
}
visibility:10000
pop:0
sys:{
pod:n
}
dt_txt:2020-12-07 12:00:00
}
1:{
"~~~~~~~以下略~~~~~~~"
#取得した情報を使って
3時間ごと5日分の天気を取得するURLは分かったため、次は上記の情報から必要な天気の情報を取得していきます。
明日の天気を知るにあたって最低限、最高気温と最低気温、雨の有無がわかれば良いと思ったので今回はそれを目標にします。
まずは、fetchでURLから情報を取得しresponseに結果を入力します。
(最初はfetchにawaitを入れておらずエラーが出ました。)
const fetchResponse = await fetch('http://api.openweathermap.org/data/2.5/forecast?zip="郵便番号",jp&units=metric&appid="APPID"');
const response = await fetchResponse.json();
つぎに明日の日付を取得します。
今回利用している環境では、現在の日時がUTC(協定世界時)で取得されるため、JST(日本標準時)に直す必要があります。
const jstOffset = 9 * 60;
const now = new Date();
const offset = now.getTimezoneOffset() + jstOffset;
//明日の日付を取得するため、取得した時間に24(時間)*60(分)*60(秒)*1000を追加する
now.setTime(now.getTime() + offset * 60 * 1000 + 24*60*60*1000);
const tomorrowDate = now.toLocaleDateString('ja-JP').replace(/\//g, '-');
これによってtomorrowDate
で明日の日付を取得することができました。
今度は天気予報APIから取得した情報から明日の天気を抜き出します。
let weather = [];
//天気予報APIで取得した時刻(response.list[i].dt)を、日本時間に変更しitemDateに格納する
for(let i = 0; i < response.list.length; i++){
const itemDtTxt = new Date(response.list[i].dt * 1000);
const itemOffset = itemDtTxt.getTimezoneOffset() + jstOffset;
itemDtTxt.setTime(itemDtTxt.getTime() + itemOffset * 60 * 1000);
const itemDate = itemDtTxt.toLocaleDateString('ja-JP').replace(/\//g, '-');
//itemDateが明日であれば、気温と天気の情報を取得しweatherに格納する
if (itemDate === tomorrowDate){
const item = {
temp: response.list[i].main.temp,
weather: response.list[i].weather[0].main
};
weather.push(item);
}
}
//最高気温と最低気温、天気にRainが含まれているかを判定する
const maxTemp = Math.max.apply(null, weather.map(_ => _.temp));
const minTemp = Math.min.apply(null, weather.map(_ => _.temp));
const rain = weather.some(_ => _.weather === "Rain");
let speakText = "";
speakText = "明日の最高気温は、" + maxTemp +"度、最低気温は、" + minTemp +"度です。";
if (rain === false){
speakText +="雨の予報はありません。";
}else{
speakText +="雨の予報があります。出かける時は傘を忘れずに。";
}
return speakText;
以上で、明日の最高気温、最低気温と雨が降るかどうかを教えてくれるようになりました。
#おわりに
今後やりたいこと
- 雨以外の天気も教えてほしい
- 日中の天気に絞って教えて欲しい
- 雨が降る時間を教えてくれるようにしたい