-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreport.rb
112 lines (95 loc) · 3.66 KB
/
report.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# frozen_string_literal: true
class Report < ApplicationRecord
after_save :scrape
has_many :forecasts, -> { order(created_at: :asc) }
default_scope { includes(:forecasts) }
scope :today, lambda {
where(created_at: (Time.current.beginning_of_day..Time.current.end_of_day))
}
def self.latest
order(created_at: :asc).last
end
def actual_forecast
forecasts.where(projection: false).first
end
def scrape
wg_forecasts = weather_gov_forecasts
# weather.gov forecasts have two per day: daytime and nighttime
# Get highest temp from either forecast
high_temp = [wg_forecasts[0][0]['temperature'], wg_forecasts[1][0]['temperature']].max
dew_point = wg_forecasts[0][0].key?('dewpoint') ? wg_forecasts[0][0]['dewpoint']['value'] * 9 / 5 + 32 : nil # convert C to F
humidity = wg_forecasts[0][0].key?('relativeHumidity') ? ['relativeHumidity']['value'] : nil
forecast = forecasts.create(
projection: false,
high_temp: high_temp,
dew_point: dew_point,
humidity: humidity,
peak_hour: DateTime.parse(peak_load['BeginDate']),
peak_load: peak_load['LoadMw'].to_i,
actual_peak_hour: Time.parse(morning_report['PeakLoadYesterdayHour']).hour,
actual_peak_load: morning_report['PeakLoadYesterdayMw'],
date: Date.current
)
sd_forecast = seven_day_forecast.first['MarketDay']
wg_forecasts[0][0...-1].each.with_index() do |day, index|
high_temp = [day['temperature'], wg_forecasts[1][index]['temperature']].max
dew_point = day.key?('dewpoint') ? day['dewpoint']['value'] * 9 / 5 + 32 : nil # convert C to F
humidity = day.key?('relativeHumidity') ? ['relativeHumidity']['value'] : nil
forecasts.create(projection: true,
high_temp: high_temp,
dew_point: dew_point,
humidity: humidity,
peak_load: sd_forecast[index]['PeakLoadMw'],
date: Date.parse(sd_forecast[index]['MarketDate']))
end
end
def peak_load
current_hourly_load.max_by { |hour| hour['LoadMw'] }
end
def morning_report
url = 'https://webservices.iso-ne.com/api/v1.1/morningreport/current.json'
request_json(url)['MorningReports']['MorningReport'].first
end
def weather_gov_forecasts
Retriable.retriable(tries: 5, base_interval: 10) do
resp = RestClient.get 'https://api.weather.gov/gridpoints/BOX/68,82/forecast'
response_json = JSON.parse resp
response_json['properties']['periods'].partition.with_index { |_, i| i.even? }
end
end
def current_hourly_load
date = Time.current.strftime('%Y%m%d')
url = "https://webservices.iso-ne.com/api/v1.1/hourlyloadforecast/day/#{date}.json"
request_json(url)['HourlyLoadForecasts']['HourlyLoadForecast']
end
def seven_day_forecast
url = 'https://webservices.iso-ne.com/api/v1.1/sevendayforecast/current.json'
request_json(url)['SevenDayForecasts']['SevenDayForecast']
end
def request_json(url)
Retriable.retriable(tries: 5, base_interval: 10) do
resp = RestClient::Request.execute request_params.merge({ url: url })
JSON.parse resp
end
end
def as_json(options={})
{
likely: actual_forecast.risk == :likely ? 'true' : nil,
possible: actual_forecast.risk == :possible ? 'true' : nil,
unlikely: actual_forecast.risk == :unlikely ? 'true' : nil,
forecasts: forecasts[0..7].as_json
}
end
def to_json(*options)
as_json(*options).to_json(*options)
end
private
def request_params
{
method: :get,
user: ENV.fetch('ISO_USER'),
password: ENV.fetch('ISO_PASS'),
verify_ssl: OpenSSL::SSL::VERIFY_NONE
}
end
end