Commit a203d7f3 authored by Peter van der meulen's avatar Peter van der meulen

Generate and send daily reports

parent 89abff56
......@@ -30,3 +30,4 @@ aurora_bot-*.tar
# Generated Public files
public/kp.txt
public/aurora_data.json
public/aurora_forecast.json
......@@ -6,10 +6,11 @@ config :aurora_bot,
darksky_api_key: System.get_env("DARKSKY_API_KEY"),
slack: [
token: System.get_env("SLACK_TOKEN"),
channel: System.get_env("SLACK_CHANNEL"),
channel: System.get_env("SLACK_CHANNEL")
]
config :aurora_bot, AuroraBot.Scheduler,
jobs: [
{"* * * * *", fn -> AuroraBot.Report.live_run!() end},
{"* * * * *", fn -> AuroraBot.Report.run_live!() end}
{"0 15 * * *", fn -> AuroraBot.Report.run_forecast!() end}
]
......@@ -11,6 +11,7 @@ defmodule AuroraBot.Forecast do
alias AuroraBot.Forecast.NOAAPlanetaryKForecast
alias __MODULE__
@derive {Jason.Encoder, only: [:datetime, :kp]}
defstruct datetime: nil, kp: nil
@doc """
......
defmodule AuroraBot.Report.ForecastReport do
@moduledoc """
Forecast reports
This module serves to create reports from collected forecasts from NOAA.
It warns who-ever reads it when the next auroral activities within the EU
happen.
"""
alias AuroraBot.Forecast
alias AuroraBot.Report.ToStore
alias AuroraBot.Report.ToSlack
alias __MODULE__
@derive {Jason.Encoder, only: [:next_events, :updated_at]}
defstruct next_events: [], updated_at: nil
@doc """
Creates a report including the next expected auroral events and the time at
which the report was generated.
## example
iex> new!()
%AuroraBot.Report.ForecastReport{
next_events: [
]
[%AuroraBot.Forecast{datetime: ~N[2018-11-17 21:00:00], kp: 6}]
}
"""
def new! do
%ForecastReport{next_events: Forecast.get!(), updated_at: Timex.now(:utc)}
end
@doc """
Generates a new report and saves it to a json api as well as a message to
Slack.
iex> run!
:ok
"""
def run! do
report = new!()
ToStore.forecast!(report)
send_slack_message(report)
end
defp send_slack_message(report) do
ToSlack.send!(
"*Daily Report.* \nLet's go over NOAA's expectations for the next few days." <>
"\nThe values used in this report are in the KP standard. You can read" <>
"more about that here: \n> https://bit.ly/more-about-kp",
[
Map.merge(
%{
"title" => "Aurora Events",
"pretext" => "Next expected auroral events:",
"title_link" => "https://aurora.picodevelopment.nl"
},
attachment_fields(report)
)
]
)
end
defp attachment_fields(report) do
case Enum.count(report.next_events) do
0 ->
%{
"color" => "danger",
"fields" => [
%{
"title" => "Nope",
"value" => "No Aurora's are expected in the next few days",
"short" => true
}
]
}
_ ->
fields = Enum.map(report.next_events, fn event -> create_event_field(event) end)
%{"color" => "good", "fields" => fields}
end
end
defp create_event_field(event) do
%{
"title" =>
event.datetime
|> Timex.Timezone.convert("Europe/Stockholm")
|> Timex.format!("%a %d %h at %H:%M Swedish time", :strftime),
"value" => "KP #{event.kp} expected",
"short" => true
}
end
end
defmodule AuroraBot.Report.Live do
defmodule AuroraBot.Report.LiveReport do
@moduledoc """
Live reports
......@@ -26,18 +26,18 @@ defmodule AuroraBot.Report.Live do
Generates a new report based on live data
## example:
iex> create_live!()
%AuroraBot.Report.Live{
iex> create!()
%AuroraBot.Report.LiveReport{
clouds: %{harnosand: 83, ostersund: 35, sundsvall: 68, umea: 90},
kp: 0,
updated_at: #DateTime<2018-11-12 20:41:47.931814Z>
}
"""
def create! do
def new! do
pkp_and_chances = LiveMetrics.get_kp_and_chances()
%Live{
%LiveReport{
updated_at: Timex.now(),
kp: pkp_and_chances.kp,
clouds: Weather.get_clouds(),
......@@ -55,7 +55,7 @@ defmodule AuroraBot.Report.Live do
"""
def run! do
report = create!()
report = new!()
ToStore.live!(report)
send_slack_message(report)
:ok
......@@ -86,7 +86,7 @@ defmodule AuroraBot.Report.Live do
true = Cachex.put!(:base, "slack-report", report.kp, ttl: :timer.hours(3))
ToSlack.send!(
"LIVE. \n New live data from IRF in Kiruna suggests that northern lights" <>
"*LIVE.* \n New live data from IRF in Kiruna suggests that northern lights" <>
" can be seen in Sweden.\n The calculated KP is #{report.kp}.",
[
message_attachments_probability(report.chances),
......
......@@ -7,34 +7,31 @@ defmodule AuroraBot.Report do
html file sitting on the disk.
"""
alias AuroraBot.Report.Live
alias AuroraBot.Report.LiveReport
alias AuroraBot.Report.ForecastReport
@doc """
Generates a new report based on live data
Generates a new report and safes it to different outlets like a JSON and
TXT end point as well as pings to Slack.
## example:
iex> create_live!()
%AuroraBot.Report.Live{
clouds: %{harnosand: 83, ostersund: 35, sundsvall: 68, umea: 90},
kp: 0,
updated_at: #DateTime<2018-11-12 20:41:47.931814Z>
}
iex> run_live!()
:ok
"""
def create_live! do
Live.create!()
def run_live! do
LiveReport.run!()
end
@doc """
Generates a new report and safes it to different outlets like a JSON and
TXT end point as well as pings to Slack.
Generates a new report and saves it to a json api as well as a message to
Slack.
## example:
iex> run_live!()
iex> run!
:ok
"""
def run_live! do
Live.run!()
def run_forecast! do
ForecastReport.run!()
end
end
defmodule AuroraBot.Report.ToStore do
def live!(report) do
json_report = Jason.encode!(report, pretty: true)
File.write!("public/aurora_data.json", json_report)
File.write!("public/aurora_data.json", to_json(report))
File.write!("public/kp.txt", Integer.to_string(report.kp))
end
def forecast!(report) do
File.write!("public/aurora_forecast.json", to_json(report))
end
defp to_json(input) do
Jason.encode!(input, pretty: true)
end
end
defmodule ReportSpec.ForecastReport do
use ESpec
alias AuroraBot.Report.ForecastReport
before do
mock_cache()
mock_noaa_requests()
end
describe "new!" do
it "creates a new report" do
%ForecastReport{next_events: next_events} = ForecastReport.new!()
forecast = [%AuroraBot.Forecast{datetime: ~N[2018-11-16 18:00:00], kp: 5}]
expect next_events |> to(eq forecast)
end
end
describe "run!" do
it "runs without issues" do
mock_slack_message()
expect ForecastReport.run!() |> to(eq :ok)
expect fn -> ForecastReport.run!() end |> to_not(raise_exception())
end
end
def mock_cache do
allow(AuroraBot.Cache |> to(accept(:fetch!, fn _, _, fallback, _ -> fallback.() end)))
end
def mock_noaa_requests() do
noaa_response = %HTTPoison.Response{status_code: 200, body: "[
[
\"time_tag\",
\"kp\",
\"observed\",
\"noaa_scale\"
],
[
\"2018-11-16 18:00:00\",
\"5\",
\"predicted\",
null
]]"}
allow HTTPoison
|> to(
accept(:get!, fn "https://services.swpc.noaa.gov" <> _ ->
noaa_response
end)
)
end
def mock_slack_message do
slack_response = %HTTPoison.Response{
status_code: 200,
body: "{\"ok\": true}"
}
allow HTTPoison
|> to(
accept(:get!, fn "https://slack.com/api/chat.postMessage" <> _, [], _ ->
slack_response
end)
)
end
end
defmodule ReportSpec do
defmodule ReportSpec.LiveReportSpec do
use ESpec
alias AuroraBot.Report
alias AuroraBot.Report.LiveReport
describe "run_live!" do
describe "run!" do
it "runs without issues" do
# Mock incoming data and caches
mock_cache()
......@@ -16,8 +16,8 @@ defmodule ReportSpec do
# Storing data to public
mock_file_store()
expect Report.run_live!() |> to(eq :ok)
expect fn -> Report.run_live!() end |> to_not(raise_exception())
expect LiveReport.run!() |> to(eq :ok)
expect fn -> LiveReport.run!() end |> to_not(raise_exception())
end
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment