netatmo 0.1.0

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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +169 -0
  4. data/lib/netatmo.rb +20 -0
  5. data/lib/netatmo/administrative.rb +23 -0
  6. data/lib/netatmo/air_care/home_coach.rb +25 -0
  7. data/lib/netatmo/battery_status/battery_status.rb +34 -0
  8. data/lib/netatmo/battery_status/indoor_battery_status.rb +16 -0
  9. data/lib/netatmo/battery_status/outdoor_battery_status.rb +16 -0
  10. data/lib/netatmo/battery_status/wind_gauge_battery_status.rb +16 -0
  11. data/lib/netatmo/client.rb +98 -0
  12. data/lib/netatmo/dashboard_data/co2.rb +29 -0
  13. data/lib/netatmo/dashboard_data/health_index.rb +34 -0
  14. data/lib/netatmo/dashboard_data/humidity.rb +29 -0
  15. data/lib/netatmo/dashboard_data/noise.rb +29 -0
  16. data/lib/netatmo/dashboard_data/pressure.rb +43 -0
  17. data/lib/netatmo/dashboard_data/rain.rb +35 -0
  18. data/lib/netatmo/dashboard_data/temperature.rb +35 -0
  19. data/lib/netatmo/dashboard_data/wind.rb +33 -0
  20. data/lib/netatmo/place.rb +21 -0
  21. data/lib/netatmo/user.rb +13 -0
  22. data/lib/netatmo/util/battery_status.rb +9 -0
  23. data/lib/netatmo/util/device_type.rb +14 -0
  24. data/lib/netatmo/util/feel_like.rb +9 -0
  25. data/lib/netatmo/util/health_index.rb +9 -0
  26. data/lib/netatmo/util/pressureunit.rb +9 -0
  27. data/lib/netatmo/util/temp_trend.rb +9 -0
  28. data/lib/netatmo/util/unit.rb +9 -0
  29. data/lib/netatmo/util/wifi_status.rb +9 -0
  30. data/lib/netatmo/util/windunit.rb +9 -0
  31. data/lib/netatmo/version.rb +5 -0
  32. data/lib/netatmo/weather/base_station.rb +61 -0
  33. data/lib/netatmo/weather/battery_device.rb +24 -0
  34. data/lib/netatmo/weather/device.rb +121 -0
  35. data/lib/netatmo/weather/indoor_module.rb +20 -0
  36. data/lib/netatmo/weather/outdoor_module.rb +19 -0
  37. data/lib/netatmo/weather/rain_gauge.rb +15 -0
  38. data/lib/netatmo/weather/station_data.rb +19 -0
  39. data/lib/netatmo/weather/wifi_status.rb +34 -0
  40. data/lib/netatmo/weather/wind_gauge.rb +15 -0
  41. data/lib/netatmo_inflector.rb +24 -0
  42. metadata +224 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5afa0ba31f1da59d10c3b91a68679e21abef496ee5cd34ca0e235f5db43f948d
4
+ data.tar.gz: 572df5b1e1fced24e36023d4cf9a210ce057df459942917193dad8331c32bc0c
5
+ SHA512:
6
+ metadata.gz: f762ee09437e403a2ec4737a31f933c8c8980b3db8d167383b552f26b6ad26db083565ac1f697b60b7db65a8a7740445f7d12875123df0df7943c9d0f670b4b3
7
+ data.tar.gz: 3a1cb2e6420c2b2ba96428d1064f8f3354d77405a88b6452dfcf45a5358bdebf778048a1acf9fbf39c96677b959622b8ce43321b461e46152cb1b2899afb309c
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Marco Roth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,169 @@
1
+ # Netatmo
2
+
3
+ Ruby API Wrapper for the [Netatmo API](https://dev.netatmo.com/apidocumentation/).
4
+
5
+ ![Build Status](https://github.com/marcoroth/netatmo-ruby/workflows/Build/badge.svg)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'netatmo'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install netatmo
22
+
23
+ ## Usage
24
+
25
+ ### Environment variables
26
+
27
+ | Name | Description |
28
+ |---------------------------|------------------------|
29
+ | `NETATMO_CLIENT_ID` | Your app client_id |
30
+ | `NETATMO_CLIENT_SECRET` | Your app client_secret |
31
+ | `NETATMO_CLIENT_USERNAME` | User address email |
32
+ | `NETATMO_CLIENT_PASSWORD` | User password |
33
+
34
+ ### Creating a client
35
+
36
+ To create a Netatmo client you can either set the required environment variables or pass the credentials via a config block to the initialize method.
37
+
38
+ ```ruby
39
+ # if you configured the required ENV variables
40
+ client = Netatmo::Client.new
41
+
42
+ # or if you want to provide the required credentials
43
+ client = Netatmo::Client.new do |config|
44
+ config.client_id = '10acb39bc818e5789'
45
+ config.client_secret = '10dsfxyzbkzva'
46
+ config.username = 'user@email.address'
47
+ config.password = 'UserPassword'
48
+ end
49
+
50
+ ```
51
+
52
+ ### Endpoint `/getstationdata`
53
+
54
+ `get_station_data` Returns all weather stations you have read access to.
55
+
56
+ ```ruby
57
+ station_data = client.get_station_data
58
+ # => #<Netatmo::Weather::StationData @devices=[...] @user=#<Netatmo::User> ...>
59
+
60
+ ```
61
+
62
+ #### Devices
63
+
64
+ You can access the base stations in the `devices` array.
65
+
66
+ ```ruby
67
+ station_data.devices
68
+
69
+ # => [
70
+ # #<Netatmo::Weather::BaseStation @id="00:11:22:00:11:22", @modules=[...] ...>,
71
+ # #<Netatmo::Weather::BaseStation @id="12:23:34:45:56:67", @modules=[...] ...>
72
+ # ]
73
+
74
+ ```
75
+
76
+
77
+
78
+ ```ruby
79
+ base_station = station_data.devices.first
80
+ # => #<Netatmo::Weather::BaseStation @id="00:11:22:00:11:22", @code="NAMain", @data_types=["Temperature", "CO2", "Humidity", "Noise", "Pressure"], @modules=[...]>
81
+
82
+ ```
83
+
84
+ #### Modules
85
+
86
+ All to this base station connected modules are accessible in the `modules` array.
87
+
88
+ ```ruby
89
+ base_station.modules
90
+ # => [
91
+ # #<Netatmo::Weather::OutdoorModule @code="NAModule1", @data_types=["Temperature", "Humidity"], ...>,
92
+ # #<Netatmo::Weather::WindGauge @code="NAModule2", @data_types=["Wind"], ...>,
93
+ # #<Netatmo::Weather::IndoorModule @code="NAModule4", @data_types=["Temperature", "CO2", "Humidity"], ...>,
94
+ # #<Netatmo::Weather::RainGauge @code="NAModule3", @data_types=["Rain"], ...>
95
+ # ]
96
+ ```
97
+
98
+ ```ruby
99
+ outdoor = base_station.modules.first
100
+
101
+ # => #<Netatmo::Weather::OutdoorModule
102
+ # @id="11:22:33:44:55:66",
103
+ # @code="NAModule1",
104
+ # @data_types=["Temperature", "Humidity"],
105
+ # @module_name="Module",
106
+ # @reachable=true,
107
+ # @firmware=44,
108
+ # @last_setup=2014-12-24 21:57:28 +0100,
109
+ # @last_message=2020-02-11 10:49:33 +0100,
110
+ # @last_seen=2020-02-11 10:49:27 +0100,
111
+ # @rf_status=66,
112
+ # @battery_vp=5440,
113
+ # @battery_percent=77,
114
+ # @battery_status=#<Netatmo::BatteryStatus::OutdoorBatteryStatus @value=5440>,
115
+ # @humidity=#<Netatmo::DashboardData::Humidity @time=2020-02-11 10:48:36 +0100, @value=62.0, @unit="%">,
116
+ # @temperature=#<Netatmo::DashboardData::Temperature @time=2020-02-11 10:48:36 +0100, @value=13.6, @min=7.6,
117
+ # @max=13.6, @min_date=2020-02-11 07:12:25 +0100, @max_date=2020-02-11 10:48:36 +0100,
118
+ # @trend=#<Netatmo::Util::TempTrend @value=1>,
119
+ # @unit="°C">
120
+ # >
121
+ ```
122
+
123
+ #### Data Types
124
+
125
+ You can ask the module if it provides certain data types.
126
+
127
+ ```ruby
128
+ outdoor.temperature?
129
+ # => true
130
+ ```
131
+
132
+ ```ruby
133
+ outdoor.noise?
134
+ # => false
135
+ ```
136
+
137
+ If the data type is supported you can access the values.
138
+
139
+ ```ruby
140
+ outdoor.temperature
141
+ # => #<Netatmo::DashboardData::Temperature @value=13.6, @min=7.6, @max=13.6, @unit="°C", @time=2020-02-11 10:48:36 +0100, @trend=#<Netatmo::Util::TempTrend @value=1>, ...>
142
+ ```
143
+
144
+ #### Values
145
+
146
+ If you want to get a hash of all the available data types on the module you use the `values` method.
147
+
148
+ ```ruby
149
+ outdoor.values
150
+ # => {
151
+ # :humidity=>#<Netatmo::DashboardData::Humidity ...>,
152
+ # :temperature=>#<Netatmo::DashboardData::Temperature ...
153
+ # }
154
+
155
+ ```
156
+
157
+ ## Development
158
+
159
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
160
+
161
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
162
+
163
+ ## Contributing
164
+
165
+ Bug reports and pull requests are welcome on GitHub at https://github.com/marcoroth/netatmo-ruby.
166
+
167
+ ## License
168
+
169
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'netatmo/version'
4
+ require 'netatmo_inflector'
5
+
6
+ require 'zeitwerk'
7
+ require 'byebug'
8
+ require 'dotenv'
9
+ require 'easy_enum'
10
+
11
+ Dotenv.load
12
+
13
+ @loader = Zeitwerk::Loader.for_gem
14
+ @loader.inflector = NetatmoInflector.new
15
+ @loader.enable_reloading
16
+ @loader.setup
17
+
18
+ module Netatmo
19
+ class Error < StandardError; end
20
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Netatmo
4
+ class Administrative
5
+ attr_accessor :unit
6
+ attr_accessor :windunit
7
+ attr_accessor :pressureunit
8
+ attr_accessor :lang
9
+ attr_accessor :reg_locale
10
+ attr_accessor :country
11
+ attr_accessor :feel_like
12
+
13
+ def initialize(data)
14
+ self.unit = Netatmo::Util::Unit.value(data['unit'])
15
+ self.windunit = Netatmo::Util::Windunit.value(data['windunit'])
16
+ self.pressureunit = Netatmo::Util::Pressureunit.value(data['pressureunit'])
17
+ self.feel_like = Netatmo::Util::FeelLike.value(data['feel_like_algo'])
18
+ self.lang = data['lang']
19
+ self.reg_locale = data['reg_locale']
20
+ self.country = data['country']
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Netatmo
4
+ module AirCare
5
+ class HomeCoach < Netatmo::Weather::BaseStation
6
+ attr_accessor :health_index
7
+
8
+ # DeviceType: NHC
9
+ def initialize(data)
10
+ super(data)
11
+
12
+ self.health_index = Netatmo::DashboardData::HealthIndex.new(data['dashboard_data'])
13
+ end
14
+
15
+ def name
16
+ module_name
17
+ end
18
+
19
+ def data
20
+ d = super
21
+ d << health_index if health_index?
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Netatmo
6
+ module BatteryStatus
7
+ class BatteryStatus
8
+ extend Forwardable
9
+
10
+ attr_accessor :type
11
+ attr_accessor :value
12
+
13
+ class << self
14
+ attr_accessor :status_values
15
+ end
16
+
17
+ self.status_values = {}
18
+
19
+ def initialize(value)
20
+ self.value = value
21
+ end
22
+
23
+ def status
24
+ self.class.status_values.each do |key, range|
25
+ return Netatmo::Util::BatteryStatus.key(key) if range.cover? value
26
+ end
27
+
28
+ nil
29
+ end
30
+
31
+ def_delegators :status, :max?, :full?, :high?, :medium?, :low?, :very_low?
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Netatmo
4
+ module BatteryStatus
5
+ class IndoorBatteryStatus < BatteryStatus
6
+ self.status_values = {
7
+ very_low: 0..4559,
8
+ low: 4560..4919,
9
+ medium: 4920..5279,
10
+ high: 5280..5639,
11
+ full: 5640..5999,
12
+ max: 6000..6000
13
+ }.freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Netatmo
4
+ module BatteryStatus
5
+ class OutdoorBatteryStatus < BatteryStatus
6
+ self.status_values = {
7
+ very_low: 0..3999,
8
+ low: 4000..4499,
9
+ medium: 4500..4999,
10
+ high: 5000..5499,
11
+ full: 5500..5999,
12
+ max: 6000..6000
13
+ }.freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Netatmo
4
+ module BatteryStatus
5
+ class WindGaugeBatteryStatus < BatteryStatus
6
+ self.status_values = {
7
+ very_low: 0..4359,
8
+ low: 4360..4769,
9
+ medium: 4770..5179,
10
+ high: 5180..5589,
11
+ full: 5590..5999,
12
+ max: 6000..6000
13
+ }.freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ module Netatmo
7
+ class Client
8
+ BASE_URL = 'https://api.netatmo.net'
9
+ attr_accessor :access_token, :refresh_token, :expires_at
10
+ Config = Struct.new(:client_id, :client_secret, :username, :password, :base_url)
11
+
12
+ def initialize(&config_block)
13
+ if block_given?
14
+ config_block.call config
15
+ else
16
+ config
17
+ end
18
+
19
+ authenticate
20
+ end
21
+
22
+ def configure(&config_block)
23
+ config_block.call config if block_given?
24
+ config
25
+ end
26
+
27
+ def config
28
+ @config ||= Config.new(
29
+ ENV['NETATMO_CLIENT_ID'],
30
+ ENV['NETATMO_CLIENT_SECRET'],
31
+ ENV['NETATMO_USERNAME'],
32
+ ENV['NETATMO_PASSWORD'],
33
+ BASE_URL
34
+ )
35
+ end
36
+
37
+ def authenticate
38
+ if @access_token && @expires_at > Time.now
39
+ true
40
+ else
41
+ fetch_token
42
+ end
43
+ end
44
+
45
+ def fetch_token
46
+ response = if @refresh_token
47
+ connection.post '/oauth2/token' do |request|
48
+ request.body = {
49
+ grant_type: :refresh_token,
50
+ refresh_token: @refresh_token,
51
+ client_id: config.client_id,
52
+ client_secret: config.client_secret
53
+ }
54
+ end
55
+ else
56
+ connection.post '/oauth2/token' do |request|
57
+ request.body = {
58
+ grant_type: :password,
59
+ client_id: config.client_id,
60
+ client_secret: config.client_secret,
61
+ username: config.username,
62
+ password: config.password,
63
+ scope: 'read_station'
64
+ }
65
+ end
66
+ end
67
+ store_token(response)
68
+ end
69
+
70
+ # rubocop:disable Naming/AccessorMethodName
71
+ def get_station_data
72
+ response = connection.get('/api/getstationsdata', access_token: @access_token)
73
+
74
+ raise 'Unauthenticated' unless response.status == 200
75
+
76
+ Netatmo::Weather::StationData.new(JSON.parse(response.body)['body'])
77
+ end
78
+ # rubocop:enable Naming/AccessorMethodName
79
+
80
+ private
81
+
82
+ def connection
83
+ @connection ||= Faraday::Connection.new(url: config.base_url) do |builder|
84
+ builder.request :url_encoded
85
+ builder.adapter :net_http
86
+ end
87
+ end
88
+
89
+ def store_token(response)
90
+ return unless response.status == 200
91
+
92
+ data = JSON.parse(response.body)
93
+ @access_token = data['access_token']
94
+ @refresh_token = data['refresh_token']
95
+ @expires_at = Time.now + data['expires_in']
96
+ end
97
+ end
98
+ end