はじめに
- 毎朝、私のNervesアプリ on Raspberry Pi 2がTwitterへ日本のどこかの地点の天気予報をつぶやくようにしていました
- 2020/8/1からは投稿ができていませんでした
- Livedoor Weather Web Serviceを利用させていただいておりましたが、こちらの通り、2020年7月31日(金)14:00 で終了となっておりました
- ■サービス終了のお知らせ
- いままでありがとうございました
- これは2020/8/16(日) NervesJP #10 ”やってみた”回 への私の報告です
OpenWeather
- こちらを使うことにしました
- いつ取得していたのかは忘れてしまいましたが、ユーザー登録とAPIキーの取得は済んでいたのでそれを使います
-
One Call APIを使います
-
"https://api.openweathermap.org/data/2.5/onecall?lat=#{lat}&lon=#{lon}&lang=ja&units=metric&exclude=current,minutely,hourly&appid=#{appid}"
にHTTP GETすると以下のようなJSONが返ってきます- 以下はJsonをMapに変換しています
-
%{
"daily" => [
%{
"clouds" => 75,
"dew_point" => 24.79,
"dt" => 1597629600,
"feels_like" => %{
"day" => 39.81,
"eve" => 37.77,
"morn" => 39.81,
"night" => 35
},
"humidity" => 56,
"pop" => 0.81,
"pressure" => 1008,
"rain" => 10.79,
"sunrise" => 1597607962,
"sunset" => 1597656497,
"temp" => %{
"day" => 34.88,
"eve" => 33.83,
"max" => 34.88,
"min" => 30.65,
"morn" => 34.88,
"night" => 30.65
},
"uvi" => 10.44,
"weather" => [
%{
"description" => "適度な雨",
"icon" => "10d",
"id" => 501,
"main" => "Rain"
}
],
"wind_deg" => 138,
"wind_speed" => 1.94
},
%{
"clouds" => 92,
"dew_point" => 20.43,
"dt" => 1597716000,
"feels_like" => %{
"day" => 35.26,
"eve" => 32.22,
"morn" => 31.63,
"night" => 31.69
},
"humidity" => 44,
"pop" => 0.88,
"pressure" => 1011,
"rain" => 2.69,
"sunrise" => 1597694411,
"sunset" => 1597742824,
"temp" => %{
"day" => 34.12,
"eve" => 31.05,
"max" => 34.12,
"min" => 28.23,
"morn" => 28.28,
"night" => 28.23
},
"uvi" => 11.12,
"weather" => [
%{
"description" => "小雨",
"icon" => "10d",
"id" => 500,
"main" => "Rain"
}
],
"wind_deg" => 94,
"wind_speed" => 3.72
},
%{
"clouds" => 76,
"dew_point" => 20.66,
"dt" => 1597802400,
"feels_like" => %{
"day" => 38.29,
"eve" => 34.73,
"morn" => 31.24,
"night" => 32.19
},
"humidity" => 43,
"pop" => 0,
"pressure" => 1011,
"sunrise" => 1597780859,
"sunset" => 1597829149,
"temp" => %{
"day" => 35.07,
"eve" => 33.76,
"max" => 37.26,
"min" => 27.42,
"morn" => 27.42,
"night" => 29.64
},
"uvi" => 9.9,
"weather" => [
%{
"description" => "曇りがち",
"icon" => "04d",
"id" => 803,
"main" => "Clouds"
}
],
"wind_deg" => 186,
"wind_speed" => 1.08
},
%{
"clouds" => 100,
"dew_point" => 19.46,
"dt" => 1597888800,
"feels_like" => %{
"day" => 38.65,
"eve" => 34.57,
"morn" => 32.67,
"night" => 33.34
},
"humidity" => 36,
"pop" => 0.04,
"pressure" => 1012,
"sunrise" => 1597867307,
"sunset" => 1597915474,
"temp" => %{
"day" => 36.96,
"eve" => 34.33,
"max" => 37.99,
"min" => 28.83,
"morn" => 28.83,
"night" => 30
},
"uvi" => 10.18,
"weather" => [
%{
"description" => "厚い雲",
"icon" => "04d",
"id" => 804,
"main" => "Clouds"
}
],
"wind_deg" => 199,
"wind_speed" => 2.46
},
%{
"clouds" => 0,
"dew_point" => 19.85,
"dt" => 1597975200,
"feels_like" => %{
"day" => 39.83,
"eve" => 35.75,
"morn" => 33.52,
"night" => 34.14
},
"humidity" => 35,
"pop" => 0.46,
"pressure" => 1013,
"rain" => 1.81,
"sunrise" => 1597953756,
"sunset" => 1598001798,
"temp" => %{
"day" => 37.8,
"eve" => 34.17,
"max" => 37.8,
"min" => 29.16,
"morn" => 29.16,
"night" => 29.86
},
"uvi" => 10.1,
"weather" => [
%{
"description" => "小雨",
"icon" => "10d",
"id" => 500,
"main" => "Rain"
}
],
"wind_deg" => 134,
"wind_speed" => 2.16
},
%{
"clouds" => 88,
"dew_point" => 20.9,
"dt" => 1598061600,
"feels_like" => %{
"day" => 36.82,
"eve" => 33.28,
"morn" => 32.27,
"night" => 33.27
},
"humidity" => 45,
"pop" => 0.73,
"pressure" => 1012,
"rain" => 4.02,
"sunrise" => 1598040204,
"sunset" => 1598088120,
"temp" => %{
"day" => 34.54,
"eve" => 31.43,
"max" => 34.54,
"min" => 28,
"morn" => 28,
"night" => 29.24
},
"uvi" => 9.1,
"weather" => [
%{
"description" => "適度な雨",
"icon" => "10d",
"id" => 501,
"main" => "Rain"
}
],
"wind_deg" => 88,
"wind_speed" => 2.62
},
%{
"clouds" => 94,
"dew_point" => 16.87,
"dt" => 1598148000,
"feels_like" => %{
"day" => 32.82,
"eve" => 33.91,
"morn" => 31.92,
"night" => 32.85
},
"humidity" => 37,
"pop" => 0.86,
"pressure" => 1009,
"rain" => 9.2,
"sunrise" => 1598126652,
"sunset" => 1598174442,
"temp" => %{
"day" => 33.14,
"eve" => 31.49,
"max" => 33.14,
"min" => 28.38,
"morn" => 28.38,
"night" => 29.02
},
"uvi" => 9.02,
"weather" => [
%{
"description" => "適度な雨",
"icon" => "10d",
"id" => 501,
"main" => "Rain"
}
],
"wind_deg" => 193,
"wind_speed" => 3.55
},
%{
"clouds" => 28,
"dew_point" => 18.94,
"dt" => 1598234400,
"feels_like" => %{
"day" => 40.32,
"eve" => 33.44,
"morn" => 31.95,
"night" => 32.95
},
"humidity" => 33,
"pop" => 0.51,
"pressure" => 1007,
"rain" => 1.01,
"sunrise" => 1598213099,
"sunset" => 1598260763,
"temp" => %{
"day" => 37.7,
"eve" => 32.03,
"max" => 37.7,
"min" => 28.18,
"morn" => 28.18,
"night" => 29.07
},
"uvi" => 10.05,
"weather" => [
%{
"description" => "小雨",
"icon" => "10d",
"id" => 500,
"main" => "Rain"
}
],
"wind_deg" => 164,
"wind_speed" => 0.65
}
],
"lat" => 36.2,
"lon" => 140.1,
"timezone" => "Asia/Tokyo",
"timezone_offset" => 32400
}
- lat, lonは、http://bulk.openweathermap.org/sample/ に圧縮されたJSONファイル(city.list.json)があるのでそれを解凍して使います
-
Nervesプロジェクトの
rootfs_overlay
配下にファイルを置いておくと、Nervesアプリから読み出すことができます- Overwriting Files in the Root Filesystem
-
NervesJPというワークスペース名のSlackにて、 @pojiro さんの書き込みから知った次第です
- ありがとうございます!
$ ls rootfs_overlay/usr/local/share
city.list.json
- たとえばこんな感じにプロジェクトに配置しておくと、Nervesアプリからは
/usr/local/share/city.list.json
というパスでアクセスできます
File.read!("/usr/local/share/city.list.json")
|> Jason.decode!()
|> Enum.filter(fn %{"country" => country} -> country == "JP" end)
キモのソースコード
lib/weather/forecast.ex
defmodule Weather.Forecast do
@api_key Application.get_env(:hello_nerves, :open_weather_api_key)
@city_list_json "/usr/local/share/city.list.json"
def run(%{"coord" => %{"lat" => lat, "lon" => lon}, "id" => city_id}) do
%{
"name" => name
} =
current(city_id)
|> HTTPoison.get!()
|> Map.get(:body)
|> Jason.decode!()
%{"daily" => dailies} =
onecall(lat, lon)
|> HTTPoison.get!()
|> Map.get(:body)
|> Jason.decode!()
description =
dailies |> Enum.at(0) |> Map.get("weather") |> Enum.at(0) |> Map.get("description")
temp_max = dailies |> Enum.at(0) |> Map.get("temp") |> Map.get("max")
temp_min = dailies |> Enum.at(0) |> Map.get("temp") |> Map.get("min")
"#{name}の天気は、#{description}です。\n最高気温は#{temp_max}℃です。最低気温は#{temp_min}℃です。\n\n#{i_use_nerves()}"
end
def run do
cities()
|> Enum.random()
|> run()
end
defp current(city_id) do
"http://api.openweathermap.org/data/2.5/weather?id=#{city_id}&lang=ja&units=metric&appid=#{
@api_key
}"
end
defp onecall(lat, lon) do
"https://api.openweathermap.org/data/2.5/onecall?lat=#{lat}&lon=#{lon}&lang=ja&units=metric&exclude=current,minutely,hourly&appid=#{
@api_key
}"
end
defp i_use_nerves do
if Application.get_env(:hello_nerves, :target) != :host do
"I use Nerves. I like it!"
else
""
end
end
defp cities do
path =
if Application.get_env(:hello_nerves, :target) != :host,
do: @city_list_json,
else: "rootfs_overlay/#{@city_list_json}"
File.read!(path)
|> Jason.decode!()
|> Enum.filter(fn %{"country" => country} -> country == "JP" end)
end
end