fritzbox-smarthome 0.1.3 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 782cdee20c938c01c4ee6f6560e05f7a7636d8b9315e6c63f577959e3df85f45
4
- data.tar.gz: a33ea016b04d0a710d13e0e1089850d74f1d16f14e9346683fac961640be2851
3
+ metadata.gz: 430136a0736fded1a9e2cf308cdeb00129e94514259915306146fc65be4fb04a
4
+ data.tar.gz: 8755e3f921c2c815b1e6d38d3372bcfff068e6a8aa7a47785d07213585e67101
5
5
  SHA512:
6
- metadata.gz: af9c5ed89753c194f8eefaf29dcf4893e9f68c99e7595cb95196b778b9bdbce2a7a6e2efa0b650ddf52f5fccab2e19f0bd065be68a4d805f1f94b96990a6fd61
7
- data.tar.gz: 4aabacf20397befaf87d069307e2bc525bfaee04ecae6563d63ee4b1c6487f62ede5f75d850257e63fecf87ade33c21b7ef85877a00de4fde861b763b0fb7137
6
+ metadata.gz: 94ac858e01f25649f9171df8cf685658b4a4e17f5c230a1394569c37d3052444ed1b155d8eb9a58d61fc056eb471347ee5c0c163b0a777651a8abceac4a3c76a
7
+ data.tar.gz: 198756b6e8a1d7d2cfcf886e26f5e2efd3d75eb655d2533e94074c936b42da531d58147ceba13e3a54b5e621f66fe99f56fe5652cbdd6c2b64294a095fa5e22e
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 3.1.2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.4.0
4
+
5
+ * Add support for Fritz!DECT lightbulbs
6
+
7
+ ## v0.3.0
8
+
9
+ * Use generic Actor class for unrecognised device
10
+ * Allow usage in rails up to 7.1.x
11
+ * Use ruby 3.1.x in development
12
+ * Update a other dependencies
13
+
14
+ ## v0.2.0
15
+
16
+ **Attention**: This release contains breaking changes! Check [README](README.md) for new interface.
17
+
18
+ * Add support for more actors types: switches and smoke detector
19
+ * Extract heater specific attributes and logic to own class
20
+
3
21
  ## v0.1.3
4
22
 
5
23
  * avoid nil error in actors:all smart devices request
data/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Ruby client library to interface with Smarthome features of your FritzBox.
4
4
 
5
+ Currently implemented actor types:
6
+
7
+ * Heater
8
+ * SmokeDetector
9
+ * Switch
10
+
5
11
  ## Installation
6
12
 
7
13
  Add this line to your application's Gemfile:
@@ -28,10 +34,12 @@ Fritzbox::Smarthome.configure do |config|
28
34
  config.verify_ssl = false
29
35
  end
30
36
 
37
+ # Get all actors of any type
31
38
  actors = Fritzbox::Smarthome::Actor.all
32
39
 
33
- actor = actors.last
34
- actor.update_hkr_temp_set(BigDecimal.new('21.5'))
40
+ # Get all actors of type Heater
41
+ heaters = Fritzbox::Smarthome::Heater.all
42
+ heaters.last.update_hkr_temp_set(BigDecimal('21.5'))
35
43
  ```
36
44
 
37
45
  ## Development
@@ -20,14 +20,14 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_dependency 'activesupport', '>= 5.1', '< 6.2'
24
- spec.add_dependency 'activemodel', '>= 5.1', '< 6.2'
25
- spec.add_dependency 'httparty', '~> 0.16'
23
+ spec.add_dependency 'activesupport', '>= 5.1', '<= 7.1'
24
+ spec.add_dependency 'activemodel', '>= 5.1', '<= 7.1'
25
+ spec.add_dependency 'httparty', '~> 0.20'
26
26
  spec.add_dependency 'nori', '~> 2.6'
27
- spec.add_dependency 'nokogiri', '~> 1.8'
27
+ spec.add_dependency 'nokogiri', '~> 1.13'
28
28
 
29
29
  spec.add_development_dependency 'rake', '~> 13.0'
30
- spec.add_development_dependency 'rspec', '~> 3.0'
31
- spec.add_development_dependency 'webmock', '~> 3.3'
32
- spec.add_development_dependency 'byebug', '~> 11.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.11'
31
+ spec.add_development_dependency 'webmock', '~> 3.14'
32
+ spec.add_development_dependency 'byebug', '~> 11.1'
33
33
  end
@@ -9,49 +9,31 @@ module Fritzbox
9
9
  :ain,
10
10
  :present,
11
11
  :name,
12
- :hkr_temp_is,
13
- :hkr_temp_set,
14
- :hkr_next_change_period,
15
- :hkr_next_change_temp,
12
+ :manufacturer,
16
13
  :group_members
17
14
 
18
15
  class << self
19
16
  def all(types: ['group', 'device'])
20
17
  response = get(command: 'getdevicelistinfos')
21
18
  xml = nori.parse(response.body)
22
-
23
19
  Array.wrap(types.map { |type| xml.dig('devicelist', type) }.flatten).compact.map do |data|
24
- new_from_api(data)
25
- end
26
- end
27
-
28
- def only_heaters
29
- all.select { |record| record.hkr_temp_is.present? }
20
+ klass = Actor.descendants.find { |k| k.match?(data) } || Actor
21
+ self.in?([klass, Actor]) ? klass.new_from_api(data) : nil
22
+ end.compact
30
23
  end
31
24
 
32
25
  def new_from_api(data)
33
26
  new(
34
- id: data.dig('@id').to_s,
35
- type: data.dig('groupinfo').present? ? :group : :device,
36
- ain: data.dig('@identifier').to_s,
37
- present: data.dig('present') == '1',
38
- name: data.dig('name').to_s,
39
- hkr_temp_is: data.dig('hkr', 'tist').to_i * 0.5,
40
- hkr_temp_set: data.dig('hkr', 'tsoll').to_i * 0.5,
41
- hkr_next_change_period: Time.at(data.dig('hkr', 'nextchange', 'endperiod').to_i),
42
- hkr_next_change_temp: data.dig('hkr', 'nextchange', 'tchange').to_i * 0.5,
43
- group_members: data.dig('groupinfo', 'members').to_s.split(',').presence
27
+ id: data.dig('@id').to_s,
28
+ type: data.dig('groupinfo').present? ? :group : :device,
29
+ ain: data.dig('@identifier').to_s,
30
+ present: data.dig('present') == '1',
31
+ name: (data.dig('name') || data.dig('@productname')).to_s,
32
+ manufacturer: (data.dig('manufacturer') || data.dig('@manufacturer')).to_s,
33
+ group_members: data.dig('groupinfo', 'members').to_s.split(',').presence
44
34
  )
45
35
  end
46
36
  end
47
-
48
- def update_hkr_temp_set(value)
49
- raise ArgumentError unless value.is_a? BigDecimal
50
- value = (value / 0.5).to_i
51
- response = self.class.get(command: 'sethkrtsoll', ain: ain, param: value)
52
- raise 'Could not set temperature' unless response.body == "#{value}\n"
53
- true
54
- end
55
37
  end
56
38
  end
57
39
  end
@@ -0,0 +1,41 @@
1
+ module Fritzbox
2
+ module Smarthome
3
+ class Heater < Actor
4
+
5
+ attr_accessor \
6
+ :battery,
7
+ :batterylow,
8
+ :hkr_temp_is,
9
+ :hkr_temp_set,
10
+ :hkr_next_change_period,
11
+ :hkr_next_change_temp
12
+
13
+ class << self
14
+ def match?(data)
15
+ data.key?('hkr')
16
+ end
17
+
18
+ def new_from_api(data)
19
+ instance = super
20
+ instance.assign_attributes(
21
+ battery: data.dig('battery').to_i,
22
+ batterylow: data.dig('batterylow').to_i,
23
+ hkr_temp_is: data.dig('hkr', 'tist').to_i * 0.5,
24
+ hkr_temp_set: data.dig('hkr', 'tsoll').to_i * 0.5,
25
+ hkr_next_change_period: Time.at(data.dig('hkr', 'nextchange', 'endperiod').to_i),
26
+ hkr_next_change_temp: data.dig('hkr', 'nextchange', 'tchange').to_i * 0.5
27
+ )
28
+ instance
29
+ end
30
+ end
31
+
32
+ def update_hkr_temp_set(value)
33
+ raise ArgumentError unless value.is_a? BigDecimal
34
+ value = (value / 0.5).to_i
35
+ response = self.class.get(command: 'sethkrtsoll', ain: ain, param: value)
36
+ raise 'Could not set temperature' unless response.body == "#{value}\n"
37
+ true
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fritzbox
4
+ module Smarthome
5
+ class Lightbulb < Actor
6
+
7
+ attr_accessor \
8
+ :simpleonoff_state
9
+
10
+ class << self
11
+ def match?(data)
12
+ data.fetch('@productname', '') =~ /FRITZ!DECT 5\d{2}/i
13
+ end
14
+
15
+ def new_from_api(data)
16
+ instance = super
17
+ instance.assign_attributes(
18
+ simpleonoff_state: data.dig('simpleonoff', 'state').to_i,
19
+ )
20
+ instance
21
+ end
22
+ end
23
+
24
+ def active?
25
+ simpleonoff_state == 1
26
+ end
27
+
28
+ def toggle!
29
+ value = active? ? 0 : 1
30
+ response = self.class.get(command: 'setsimpleonoff', ain: ain, onoff: value)
31
+
32
+ response.ok? && @simpleonoff_state = value
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fritzbox
4
+ module Smarthome
5
+ class NullLogger < Logger
6
+ def initialize(*_args)
7
+ super(File::NULL)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,11 +2,18 @@ module Fritzbox
2
2
  module Smarthome
3
3
  class Resource
4
4
  class << self
5
- def get(command:, ain: nil, param: nil)
5
+ # @param params [Hash] key/value pairs that will be appended to the switchcmd query string
6
+ def get(command:, ain: nil, param: nil, **params)
6
7
  url = "#{config.endpoint}/webservices/homeautoswitch.lua?switchcmd=#{command}&sid=#{authenticate}"
7
8
  url = "#{url}&ain=#{ain}" if ain.present?
8
9
  url = "#{url}&param=#{param}" if param.present?
9
10
 
11
+ params.each_with_object(url) do |(key, value)|
12
+ url = "#{url}&#{key}=#{value}"
13
+ end
14
+
15
+ config.logger.debug(url)
16
+
10
17
  HTTParty.get(url, **httparty_options)
11
18
  end
12
19
 
@@ -0,0 +1,25 @@
1
+ module Fritzbox
2
+ module Smarthome
3
+ class SmokeDetector < Actor
4
+
5
+ attr_accessor \
6
+ :alert_state,
7
+ :last_alert
8
+
9
+ class << self
10
+ def match?(data)
11
+ data.key?('alert')
12
+ end
13
+
14
+ def new_from_api(data)
15
+ instance = super
16
+ instance.assign_attributes(
17
+ alert_state: data.dig('alert', 'state').to_i,
18
+ last_alert: Time.at(data.dig('alert', 'lastalertchgtimestamp').to_i)
19
+ )
20
+ instance
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ module Fritzbox
2
+ module Smarthome
3
+ class Switch < Actor
4
+
5
+ attr_accessor \
6
+ :switch_state,
7
+ :switch_mode,
8
+ :switch_lock,
9
+ :switch_devicelock,
10
+ :simpleonoff_state,
11
+ :powermeter_voltage,
12
+ :powermeter_power,
13
+ :powermeter_energy,
14
+ :temperature_celsius,
15
+ :temperature_offset
16
+
17
+ class << self
18
+ def match?(data)
19
+ data.key?('switch')
20
+ end
21
+
22
+ def new_from_api(data)
23
+ instance = super
24
+ instance.assign_attributes(
25
+ switch_state: data.dig('switch', 'state').to_i,
26
+ switch_mode: data.dig('switch', 'mode').to_s,
27
+ switch_lock: data.dig('switch', 'lock').to_i,
28
+ switch_devicelock: data.dig('switch', 'devicelock').to_i,
29
+ simpleonoff_state: data.dig('simpleonoff', 'state').to_i,
30
+ powermeter_voltage: data.dig('powermeter', 'voltage').to_i,
31
+ powermeter_power: data.dig('powermeter', 'power').to_i,
32
+ powermeter_energy: data.dig('powermeter', 'energy').to_i,
33
+ temperature_celsius: data.dig('temperature', 'celsius').to_i,
34
+ temperature_offset: data.dig('temperature', 'offset').to_i
35
+ )
36
+ instance
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  module Fritzbox
2
2
  module Smarthome
3
- VERSION = '0.1.3'.freeze
3
+ VERSION = '0.4.0'.freeze
4
4
  end
5
5
  end
@@ -4,8 +4,13 @@ require 'httparty'
4
4
  require 'nori'
5
5
 
6
6
  require 'fritzbox/smarthome/version'
7
- require "fritzbox/smarthome/resource"
7
+ require 'fritzbox/smarthome/null_logger'
8
+ require 'fritzbox/smarthome/resource'
8
9
  require 'fritzbox/smarthome/actor'
10
+ require 'fritzbox/smarthome/heater'
11
+ require 'fritzbox/smarthome/switch'
12
+ require 'fritzbox/smarthome/smoke_detector'
13
+ require 'fritzbox/smarthome/lightbulb'
9
14
 
10
15
  module Fritzbox
11
16
  module Smarthome
@@ -25,7 +30,7 @@ module Fritzbox
25
30
  defaults.username = 'smarthome'
26
31
  defaults.password = 'verysmart'
27
32
  defaults.verify_ssl = true
28
- defaults.logger = nil
33
+ defaults.logger = NullLogger.new
29
34
  end
30
35
 
31
36
  class << self
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fritzbox-smarthome
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Klaus Meyer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-01 00:00:00.000000000 Z
11
+ date: 2022-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -17,9 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '5.1'
20
- - - "<"
20
+ - - "<="
21
21
  - !ruby/object:Gem::Version
22
- version: '6.2'
22
+ version: '7.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,9 +27,9 @@ dependencies:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
29
  version: '5.1'
30
- - - "<"
30
+ - - "<="
31
31
  - !ruby/object:Gem::Version
32
- version: '6.2'
32
+ version: '7.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activemodel
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -37,9 +37,9 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '5.1'
40
- - - "<"
40
+ - - "<="
41
41
  - !ruby/object:Gem::Version
42
- version: '6.2'
42
+ version: '7.1'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -47,23 +47,23 @@ dependencies:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
49
  version: '5.1'
50
- - - "<"
50
+ - - "<="
51
51
  - !ruby/object:Gem::Version
52
- version: '6.2'
52
+ version: '7.1'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: httparty
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '0.16'
59
+ version: '0.20'
60
60
  type: :runtime
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '0.16'
66
+ version: '0.20'
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: nori
69
69
  requirement: !ruby/object:Gem::Requirement
@@ -84,14 +84,14 @@ dependencies:
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '1.8'
87
+ version: '1.13'
88
88
  type: :runtime
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
- version: '1.8'
94
+ version: '1.13'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: rake
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -112,42 +112,42 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '3.0'
115
+ version: '3.11'
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '3.0'
122
+ version: '3.11'
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: webmock
125
125
  requirement: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - "~>"
128
128
  - !ruby/object:Gem::Version
129
- version: '3.3'
129
+ version: '3.14'
130
130
  type: :development
131
131
  prerelease: false
132
132
  version_requirements: !ruby/object:Gem::Requirement
133
133
  requirements:
134
134
  - - "~>"
135
135
  - !ruby/object:Gem::Version
136
- version: '3.3'
136
+ version: '3.14'
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: byebug
139
139
  requirement: !ruby/object:Gem::Requirement
140
140
  requirements:
141
141
  - - "~>"
142
142
  - !ruby/object:Gem::Version
143
- version: '11.0'
143
+ version: '11.1'
144
144
  type: :development
145
145
  prerelease: false
146
146
  version_requirements: !ruby/object:Gem::Requirement
147
147
  requirements:
148
148
  - - "~>"
149
149
  - !ruby/object:Gem::Version
150
- version: '11.0'
150
+ version: '11.1'
151
151
  description: ''
152
152
  email:
153
153
  - spam@klaus-meyer.net
@@ -170,7 +170,12 @@ files:
170
170
  - fritzbox-smarthome.gemspec
171
171
  - lib/fritzbox/smarthome.rb
172
172
  - lib/fritzbox/smarthome/actor.rb
173
+ - lib/fritzbox/smarthome/heater.rb
174
+ - lib/fritzbox/smarthome/lightbulb.rb
175
+ - lib/fritzbox/smarthome/null_logger.rb
173
176
  - lib/fritzbox/smarthome/resource.rb
177
+ - lib/fritzbox/smarthome/smoke_detector.rb
178
+ - lib/fritzbox/smarthome/switch.rb
174
179
  - lib/fritzbox/smarthome/version.rb
175
180
  homepage: https://github.com/klausmeyer/fritzbox-smarthome
176
181
  licenses:
@@ -191,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
196
  - !ruby/object:Gem::Version
192
197
  version: '0'
193
198
  requirements: []
194
- rubygems_version: 3.1.2
199
+ rubygems_version: 3.3.7
195
200
  signing_key:
196
201
  specification_version: 4
197
202
  summary: Client library to interface with Smarthome features of your FritzBox