meteoalarm 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +44 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -0
- data/Rakefile +14 -0
- data/countries/austria.json +116122 -0
- data/countries/belgium.json +369 -0
- data/countries/bosnia-herzegovina.json +474 -0
- data/countries/bulgeria.json +1084 -0
- data/countries/croatia.json +129694 -0
- data/countries/cyprus.json +67 -0
- data/countries/czechia.json +839 -0
- data/countries/denmark.json +2359 -0
- data/countries/estonia.json +838 -0
- data/countries/finland.json +3546 -0
- data/countries/france.json +4601 -0
- data/countries/germany.json +13918 -0
- data/countries/greece.json +1958 -0
- data/countries/hungary.json +545 -0
- data/countries/iceland.json +653 -0
- data/countries/ireland.json +1949 -0
- data/countries/israel.json +1733 -0
- data/countries/italy.json +3192 -0
- data/countries/latvia.json +164392 -0
- data/countries/lithuania.json +556 -0
- data/countries/luxembourg.json +52 -0
- data/countries/malta.json +47 -0
- data/countries/moldova.json +1609 -0
- data/countries/montenegro.json +193 -0
- data/countries/netherlands.json +956 -0
- data/countries/norway.json +7295 -0
- data/countries/poland.json +16858 -0
- data/countries/portugal.json +5923 -0
- data/countries/republic-of-north-macedonia.json +908 -0
- data/countries/romania.json +2122 -0
- data/countries/serbia.json +881 -0
- data/countries/slovenia.json +256 -0
- data/countries/slovkia.json +2628 -0
- data/countries/spain.json +14032 -0
- data/countries/sweden.json +3660 -0
- data/countries/switzerland.json +30511 -0
- data/countries/united-kingdom.json +98131 -0
- data/lib/meteoalarm/country_mapping.rb +41 -0
- data/lib/meteoalarm/tasks/areas.rake +17 -0
- data/lib/meteoalarm/tasks/countries.rake +10 -0
- data/lib/meteoalarm/version.rb +5 -0
- data/lib/meteoalarm.rb +185 -0
- metadata +93 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Meteoalarm
|
4
|
+
COUNTRY_MAPPING = { 'AT' => 'austria',
|
5
|
+
'BA' => 'bosnia-herzegovina',
|
6
|
+
'BE' => 'belgium',
|
7
|
+
'BG' => 'bulgeria',
|
8
|
+
'CH' => 'switzerland',
|
9
|
+
'CY' => 'cyprus',
|
10
|
+
'CZ' => 'czechia',
|
11
|
+
'DE' => 'germany',
|
12
|
+
'DK' => 'denmark',
|
13
|
+
'EE' => 'estonia',
|
14
|
+
'ES' => 'spain',
|
15
|
+
'FI' => 'finland',
|
16
|
+
'FR' => 'france',
|
17
|
+
'GR' => 'greece',
|
18
|
+
'HR' => 'croatia',
|
19
|
+
'HU' => 'hungary',
|
20
|
+
'IE' => 'ireland',
|
21
|
+
'IL' => 'israel',
|
22
|
+
'IS' => 'iceland',
|
23
|
+
'IT' => 'italy',
|
24
|
+
'LT' => 'lithuania',
|
25
|
+
'LU' => 'luxembourg',
|
26
|
+
'LV' => 'latvia',
|
27
|
+
'MD' => 'moldova',
|
28
|
+
'ME' => 'montenegro',
|
29
|
+
'MK' => 'republic-of-north-macedonia',
|
30
|
+
'MT' => 'malta',
|
31
|
+
'NL' => 'netherlands',
|
32
|
+
'NO' => 'norway',
|
33
|
+
'PL' => 'poland',
|
34
|
+
'PT' => 'portugal',
|
35
|
+
'RO' => 'romania',
|
36
|
+
'RS' => 'serbia',
|
37
|
+
'SE' => 'sweden',
|
38
|
+
'SI' => 'slovenia',
|
39
|
+
'SK' => 'slovkia',
|
40
|
+
'UK' => 'united-kingdom' }.freeze
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative '../country_mapping'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
namespace :meteoalarm do
|
5
|
+
desc 'List all areas of given COUNTRY_CODE in Meteoalarm system'
|
6
|
+
task :areas do
|
7
|
+
country = Meteoalarm::COUNTRY_MAPPING[ENV['COUNTRY_CODE']&.upcase]
|
8
|
+
if country
|
9
|
+
path = File.expand_path(__dir__)
|
10
|
+
data = File.read("#{path}/../../../countries/#{country}.json")
|
11
|
+
spec = JSON.parse(data)
|
12
|
+
spec.each { |s| p s["area"] }
|
13
|
+
else
|
14
|
+
p 'Error: Invalid country code'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/meteoalarm.rb
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
require 'time'
|
6
|
+
require_relative 'meteoalarm/version'
|
7
|
+
require_relative 'meteoalarm/country_mapping'
|
8
|
+
|
9
|
+
module Meteoalarm
|
10
|
+
class Error < StandardError; end
|
11
|
+
class ArgumentError < Error; end
|
12
|
+
class APIError < Error; end
|
13
|
+
|
14
|
+
class Client
|
15
|
+
BASE_URL = 'https://feeds.meteoalarm.org/api/v1/warnings/'
|
16
|
+
|
17
|
+
# Use this class to retrieve meteo alarms for a specific country.
|
18
|
+
#
|
19
|
+
# Example:
|
20
|
+
# >> Meteoalarm::Client.alarms('FR')
|
21
|
+
#
|
22
|
+
# Arguments:
|
23
|
+
# country_code: (String) - ISO 3166-1 A-2 code representing the country
|
24
|
+
# options: (Hash) - Additional search options
|
25
|
+
# latitude:, longitude: (Float) - Coordinates for location-based alarm search
|
26
|
+
# area: (String) - Area to filter alarms (ignored if coordinates are provided)
|
27
|
+
# active_now: (Boolean) - Search for currently active alarms
|
28
|
+
# expired: (Boolean) - List alarms that have expired
|
29
|
+
# date: (Date) - Search alarms by a specified future date
|
30
|
+
#
|
31
|
+
# Returns an array of weather alarms based on the provided criteria.
|
32
|
+
|
33
|
+
def self.alarms(country_code, options = {})
|
34
|
+
country = Meteoalarm::COUNTRY_MAPPING[country_code.upcase]
|
35
|
+
raise Meteoalarm::ArgumentError, "The provided country code is not supported. Refer to the rake tasks to view a list of available country codes." unless country
|
36
|
+
raise Meteoalarm::ArgumentError, "Both latitude and longitude must be provided." if (options[:latitude] && !options[:longitude]) || (!options[:latitude] && options[:longitude])
|
37
|
+
raise Meteoalarm::ArgumentError, "Incorrect date format provided." if options[:date] && !options[:date].is_a?(Date)
|
38
|
+
raise Meteoalarm::ArgumentError, "The date must be set in the future." if options[:date] && options[:date] < Date.today
|
39
|
+
warn "Provided coordinates will override the specified area." if (options[:latitude] && options[:area])
|
40
|
+
|
41
|
+
new.send(:alarms, country, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def alarms(country, options = {})
|
47
|
+
endpoint = "#{ BASE_URL }feeds-#{ country }"
|
48
|
+
response = send_http_request(endpoint)
|
49
|
+
check_status_code(response.code)
|
50
|
+
|
51
|
+
warnings = JSON.parse(response.body, symbolize_names: true)[:warnings]
|
52
|
+
reject_expired_warnings(warnings) unless options[:expired]
|
53
|
+
|
54
|
+
if options[:latitude] && options[:longitude]
|
55
|
+
warnings = check_warnings_in_coordinates(warnings, country, options[:latitude], options[:longitude])
|
56
|
+
elsif options[:area]
|
57
|
+
warnings = find_warnings_in_area(warnings, options[:area].downcase)
|
58
|
+
check_area(country, options[:area]) if warnings == []
|
59
|
+
end
|
60
|
+
|
61
|
+
warnings = future_alarms(warnings) if options[:future_alarms]
|
62
|
+
warnings = currently_active_alarms(warnings) if options[:active_now]
|
63
|
+
warnings = alarms_filter_by_date(warnings, options[:date]) if options[:date]
|
64
|
+
|
65
|
+
warnings
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_area(country, area)
|
69
|
+
path = File.expand_path(__dir__)
|
70
|
+
data = File.read("#{path}/../countries/#{country}.json")
|
71
|
+
spec = JSON.parse(data)
|
72
|
+
unless spec.find { |s| s["area"].downcase == area.downcase }
|
73
|
+
raise Meteoalarm::ArgumentError, 'The provided area name is not supported. Refer to the rake tasks to view a list of available area names.'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def send_http_request(endpoint)
|
78
|
+
uri = URI.parse(endpoint)
|
79
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
80
|
+
http.use_ssl = true
|
81
|
+
request = Net::HTTP::Get.new(uri.path)
|
82
|
+
http.request(request)
|
83
|
+
end
|
84
|
+
|
85
|
+
def check_status_code(status_code)
|
86
|
+
if status_code == '404'
|
87
|
+
raise Meteoalarm::APIError, "The requested page could not be found. Please consider upgrading the Meteoalarm gem or opening an issue."
|
88
|
+
elsif status_code.to_i >= 500
|
89
|
+
raise Meteoalarm::APIError, "Server error - status code: #{status_code}"
|
90
|
+
elsif status_code.to_i != 200
|
91
|
+
raise Meteoalarm::APIError, "Server returned unexpected status code: #{status_code}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def reject_expired_warnings(warnings)
|
96
|
+
warnings.reject! do |warning|
|
97
|
+
Time.parse(warning.dig(:alert, :info, 0, :expires)) < Time.now
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def check_warnings_in_coordinates(warnings, country, latitude, longitude)
|
102
|
+
path = File.expand_path(__dir__)
|
103
|
+
country_spec = File.read("#{path}/../countries/#{country}.json")
|
104
|
+
parsed_data = JSON.parse(country_spec)
|
105
|
+
|
106
|
+
alerts = []
|
107
|
+
parsed_data.each do |area|
|
108
|
+
if area['type'] == 'MultiPolygon'
|
109
|
+
multipolygon = area['coordinates'].first
|
110
|
+
if point_in_multipolygon(longitude, latitude, multipolygon)
|
111
|
+
alerts << find_warnings_in_code(warnings, area['code'])
|
112
|
+
end
|
113
|
+
else
|
114
|
+
polygon = area['coordinates'].first
|
115
|
+
if point_in_polygon(longitude, latitude, polygon)
|
116
|
+
alerts << find_warnings_in_code(warnings, area['code'])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
alerts.flatten
|
121
|
+
end
|
122
|
+
|
123
|
+
def point_in_polygon(long, lat, polygon)
|
124
|
+
odd_nodes = false
|
125
|
+
j = polygon.length - 1
|
126
|
+
|
127
|
+
(0...polygon.length).each do |i|
|
128
|
+
if (polygon[i][1] < lat && polygon[j][1] >= lat) || (polygon[j][1] < lat && polygon[i][1] >= lat)
|
129
|
+
if (polygon[i][0] + (lat - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) * (polygon[j][0] - polygon[i][0]) < long)
|
130
|
+
odd_nodes = !odd_nodes
|
131
|
+
end
|
132
|
+
end
|
133
|
+
j = i
|
134
|
+
end
|
135
|
+
|
136
|
+
odd_nodes
|
137
|
+
end
|
138
|
+
|
139
|
+
def point_in_multipolygon(long, lat, multipolygon)
|
140
|
+
multipolygon.each do |polygon|
|
141
|
+
return true if point_in_polygon(long, lat, polygon)
|
142
|
+
end
|
143
|
+
|
144
|
+
false
|
145
|
+
end
|
146
|
+
|
147
|
+
def find_warnings_in_code(warnings, code)
|
148
|
+
warnings.each_with_object([]) do |alert, area_alerts|
|
149
|
+
alert.dig(:alert, :info, 0, :area).each do |area|
|
150
|
+
area_alerts << alert if area[:geocode].any? { |geocode| geocode[:value] == code }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def find_warnings_in_area(warnings, area)
|
156
|
+
warnings.select do |alert|
|
157
|
+
alert.dig(:alert, :info, 0, :area).any? { |alert_area| alert_area[:areaDesc].downcase == area }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def currently_active_alarms(warnings)
|
162
|
+
warnings.select do |alert|
|
163
|
+
onset_time = Time.parse(alert.dig(:alert, :info, 0, :onset))
|
164
|
+
expires_time = Time.parse(alert.dig(:alert, :info, 0, :expires))
|
165
|
+
|
166
|
+
onset_time <= Time.now && expires_time > Time.now
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def future_alarms(warnings)
|
171
|
+
warnings.select do |alert|
|
172
|
+
onset_time = Time.parse(alert.dig(:alert, :info, 0, :onset))
|
173
|
+
expires_time = Time.parse(alert.dig(:alert, :info, 0, :expires))
|
174
|
+
|
175
|
+
onset_time > Time.now
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def alarms_filter_by_date(warnings, date)
|
180
|
+
warnings.select do |alert|
|
181
|
+
Time.parse(alert.dig(:alert, :info, 0, :onset)).to_date == date
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meteoalarm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Em Jov
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: API wrapper for meteoalarm.org.
|
14
|
+
email:
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- CHANGELOG.md
|
20
|
+
- Gemfile
|
21
|
+
- Gemfile.lock
|
22
|
+
- LICENSE.txt
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- countries/austria.json
|
26
|
+
- countries/belgium.json
|
27
|
+
- countries/bosnia-herzegovina.json
|
28
|
+
- countries/bulgeria.json
|
29
|
+
- countries/croatia.json
|
30
|
+
- countries/cyprus.json
|
31
|
+
- countries/czechia.json
|
32
|
+
- countries/denmark.json
|
33
|
+
- countries/estonia.json
|
34
|
+
- countries/finland.json
|
35
|
+
- countries/france.json
|
36
|
+
- countries/germany.json
|
37
|
+
- countries/greece.json
|
38
|
+
- countries/hungary.json
|
39
|
+
- countries/iceland.json
|
40
|
+
- countries/ireland.json
|
41
|
+
- countries/israel.json
|
42
|
+
- countries/italy.json
|
43
|
+
- countries/latvia.json
|
44
|
+
- countries/lithuania.json
|
45
|
+
- countries/luxembourg.json
|
46
|
+
- countries/malta.json
|
47
|
+
- countries/moldova.json
|
48
|
+
- countries/montenegro.json
|
49
|
+
- countries/netherlands.json
|
50
|
+
- countries/norway.json
|
51
|
+
- countries/poland.json
|
52
|
+
- countries/portugal.json
|
53
|
+
- countries/republic-of-north-macedonia.json
|
54
|
+
- countries/romania.json
|
55
|
+
- countries/serbia.json
|
56
|
+
- countries/slovenia.json
|
57
|
+
- countries/slovkia.json
|
58
|
+
- countries/spain.json
|
59
|
+
- countries/sweden.json
|
60
|
+
- countries/switzerland.json
|
61
|
+
- countries/united-kingdom.json
|
62
|
+
- lib/meteoalarm.rb
|
63
|
+
- lib/meteoalarm/country_mapping.rb
|
64
|
+
- lib/meteoalarm/tasks/areas.rake
|
65
|
+
- lib/meteoalarm/tasks/countries.rake
|
66
|
+
- lib/meteoalarm/version.rb
|
67
|
+
homepage: https://github.com/em-jov/meteoalarm
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata:
|
71
|
+
homepage_uri: https://github.com/em-jov/meteoalarm
|
72
|
+
source_code_uri: https://github.com/em-jov/meteoalarm
|
73
|
+
changelog_uri: https://github.com/em-jov/meteoalarm/blob/main/CHANGELOG.md
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.6.0
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubygems_version: 3.4.10
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: API wrapper for meteoalarm.org.
|
93
|
+
test_files: []
|