netatmo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +169 -0
- data/lib/netatmo.rb +20 -0
- data/lib/netatmo/administrative.rb +23 -0
- data/lib/netatmo/air_care/home_coach.rb +25 -0
- data/lib/netatmo/battery_status/battery_status.rb +34 -0
- data/lib/netatmo/battery_status/indoor_battery_status.rb +16 -0
- data/lib/netatmo/battery_status/outdoor_battery_status.rb +16 -0
- data/lib/netatmo/battery_status/wind_gauge_battery_status.rb +16 -0
- data/lib/netatmo/client.rb +98 -0
- data/lib/netatmo/dashboard_data/co2.rb +29 -0
- data/lib/netatmo/dashboard_data/health_index.rb +34 -0
- data/lib/netatmo/dashboard_data/humidity.rb +29 -0
- data/lib/netatmo/dashboard_data/noise.rb +29 -0
- data/lib/netatmo/dashboard_data/pressure.rb +43 -0
- data/lib/netatmo/dashboard_data/rain.rb +35 -0
- data/lib/netatmo/dashboard_data/temperature.rb +35 -0
- data/lib/netatmo/dashboard_data/wind.rb +33 -0
- data/lib/netatmo/place.rb +21 -0
- data/lib/netatmo/user.rb +13 -0
- data/lib/netatmo/util/battery_status.rb +9 -0
- data/lib/netatmo/util/device_type.rb +14 -0
- data/lib/netatmo/util/feel_like.rb +9 -0
- data/lib/netatmo/util/health_index.rb +9 -0
- data/lib/netatmo/util/pressureunit.rb +9 -0
- data/lib/netatmo/util/temp_trend.rb +9 -0
- data/lib/netatmo/util/unit.rb +9 -0
- data/lib/netatmo/util/wifi_status.rb +9 -0
- data/lib/netatmo/util/windunit.rb +9 -0
- data/lib/netatmo/version.rb +5 -0
- data/lib/netatmo/weather/base_station.rb +61 -0
- data/lib/netatmo/weather/battery_device.rb +24 -0
- data/lib/netatmo/weather/device.rb +121 -0
- data/lib/netatmo/weather/indoor_module.rb +20 -0
- data/lib/netatmo/weather/outdoor_module.rb +19 -0
- data/lib/netatmo/weather/rain_gauge.rb +15 -0
- data/lib/netatmo/weather/station_data.rb +19 -0
- data/lib/netatmo/weather/wifi_status.rb +34 -0
- data/lib/netatmo/weather/wind_gauge.rb +15 -0
- data/lib/netatmo_inflector.rb +24 -0
- metadata +224 -0
checksums.yaml
ADDED
@@ -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
|
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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).
|
data/lib/netatmo.rb
ADDED
@@ -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
|