fritzbox-smarthome 0.4.0 → 0.6.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 +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +11 -0
- data/README.md +7 -0
- data/fritzbox-smarthome.gemspec +1 -1
- data/lib/fritzbox/smarthome/actor.rb +45 -18
- data/lib/fritzbox/smarthome/heater.rb +12 -12
- data/lib/fritzbox/smarthome/lightbulb.rb +1 -21
- data/lib/fritzbox/smarthome/properties/simple_on_off.rb +54 -0
- data/lib/fritzbox/smarthome/properties.rb +10 -0
- data/lib/fritzbox/smarthome/resource.rb +6 -0
- data/lib/fritzbox/smarthome/smoke_detector.rb +8 -8
- data/lib/fritzbox/smarthome/switch.rb +17 -17
- data/lib/fritzbox/smarthome/version.rb +1 -1
- data/lib/fritzbox/smarthome.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87ca99bd2b9c7f0ab8cc157255593d9211b16e168f838e3a7b643dd273b541e2
|
4
|
+
data.tar.gz: c9d862aa7dfae2b02cb16694e2caf8595397fbdc990e84fb0539159b1a5dfee6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de120146d37f15a50a43c0ba89c19cee46f91131a4765a01d518cedf897ecaa053269c6cae7bb5a6ccbdd35bd48904571722c6bafcd475d28e92ce4ff636d63c
|
7
|
+
data.tar.gz: 62629678cefbef554aa83ff465a3086661c0100075375723fdefe0ab655816b441da4c17aabba5c8d9462172cd559d6d64461ca584ed496c4c4769f5e815f9ea
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## v0.6.0
|
4
|
+
|
5
|
+
* Add support for `Actor.find_by!(ain:)` and `Actor#reload`
|
6
|
+
|
7
|
+
## v0.5.0
|
8
|
+
|
9
|
+
* Unify on/off interface
|
10
|
+
* Provides `#active?` and `#toggle!` methods
|
11
|
+
* Adds new functionality to `Switch`
|
12
|
+
* Replacing own implementation in `Lightbulb`
|
13
|
+
|
3
14
|
## v0.4.0
|
4
15
|
|
5
16
|
* Add support for Fritz!DECT lightbulbs
|
data/README.md
CHANGED
@@ -5,6 +5,7 @@ Ruby client library to interface with Smarthome features of your FritzBox.
|
|
5
5
|
Currently implemented actor types:
|
6
6
|
|
7
7
|
* Heater
|
8
|
+
* Lightbulb
|
8
9
|
* SmokeDetector
|
9
10
|
* Switch
|
10
11
|
|
@@ -40,6 +41,12 @@ actors = Fritzbox::Smarthome::Actor.all
|
|
40
41
|
# Get all actors of type Heater
|
41
42
|
heaters = Fritzbox::Smarthome::Heater.all
|
42
43
|
heaters.last.update_hkr_temp_set(BigDecimal('21.5'))
|
44
|
+
|
45
|
+
# Get a specific actor via it's AIN
|
46
|
+
actor = Fritzbox::Smarthome::Actor.find_by!(ain: '0815 4711')
|
47
|
+
|
48
|
+
# Reload the data of an already fetched actor
|
49
|
+
actor.reload
|
43
50
|
```
|
44
51
|
|
45
52
|
## Development
|
data/fritzbox-smarthome.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
-
f.match(%r{^(test|spec|features)/})
|
17
|
+
f.match(%r{^(test|spec|features|examples)/})
|
18
18
|
end
|
19
19
|
spec.bindir = 'exe'
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -4,36 +4,63 @@ module Fritzbox
|
|
4
4
|
include ActiveModel::Model
|
5
5
|
|
6
6
|
attr_accessor \
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
:id,
|
8
|
+
:type,
|
9
|
+
:ain,
|
10
|
+
:present,
|
11
|
+
:name,
|
12
|
+
:manufacturer,
|
13
|
+
:group_members
|
14
|
+
|
15
|
+
ResourceNotFound = Class.new(RuntimeError)
|
14
16
|
|
15
17
|
class << self
|
16
18
|
def all(types: ['group', 'device'])
|
17
|
-
|
18
|
-
|
19
|
+
xml = parse(get(command: 'getdevicelistinfos'))
|
20
|
+
|
19
21
|
Array.wrap(types.map { |type| xml.dig('devicelist', type) }.flatten).compact.map do |data|
|
20
22
|
klass = Actor.descendants.find { |k| k.match?(data) } || Actor
|
21
23
|
self.in?([klass, Actor]) ? klass.new_from_api(data) : nil
|
22
24
|
end.compact
|
23
25
|
end
|
24
26
|
|
27
|
+
def find_by!(ain: nil)
|
28
|
+
data = parse(get(command: 'getdeviceinfos', ain: ain)).fetch('device')
|
29
|
+
klass = Actor.descendants.find { |k| k.match?(data) } || Actor
|
30
|
+
|
31
|
+
instance = klass.new(ain: ain)
|
32
|
+
instance.assign_from_api(data)
|
33
|
+
instance
|
34
|
+
rescue KeyError
|
35
|
+
raise ResourceNotFound, "Unable to find actor with ain='#{ain}'"
|
36
|
+
end
|
37
|
+
|
25
38
|
def new_from_api(data)
|
26
|
-
new
|
27
|
-
|
28
|
-
|
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
|
34
|
-
)
|
39
|
+
instance = new
|
40
|
+
instance.assign_from_api(data)
|
41
|
+
instance
|
35
42
|
end
|
36
43
|
end
|
44
|
+
|
45
|
+
def assign_from_api(data)
|
46
|
+
assign_attributes(
|
47
|
+
id: data.dig('@id').to_s,
|
48
|
+
type: data.dig('groupinfo').present? ? :group : :device,
|
49
|
+
ain: data.dig('@identifier').to_s,
|
50
|
+
present: data.dig('present') == '1',
|
51
|
+
name: (data.dig('name') || data.dig('@productname')).to_s,
|
52
|
+
manufacturer: (data.dig('manufacturer') || data.dig('@manufacturer')).to_s,
|
53
|
+
group_members: data.dig('groupinfo', 'members').to_s.split(',').presence
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def reload
|
58
|
+
xml = parse(get(command: 'getdeviceinfos', ain: ain))
|
59
|
+
assign_from_api(xml.fetch('device'))
|
60
|
+
self
|
61
|
+
rescue KeyError
|
62
|
+
raise ResourceNotFound, "Unable to reload actor with ain='#{ain}'"
|
63
|
+
end
|
37
64
|
end
|
38
65
|
end
|
39
66
|
end
|
@@ -14,19 +14,19 @@ module Fritzbox
|
|
14
14
|
def match?(data)
|
15
15
|
data.key?('hkr')
|
16
16
|
end
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
)
|
28
|
-
|
29
|
-
end
|
19
|
+
def assign_from_api(data)
|
20
|
+
super(data)
|
21
|
+
|
22
|
+
assign_attributes(
|
23
|
+
battery: data.dig('battery').to_i,
|
24
|
+
batterylow: data.dig('batterylow').to_i,
|
25
|
+
hkr_temp_is: data.dig('hkr', 'tist').to_i * 0.5,
|
26
|
+
hkr_temp_set: data.dig('hkr', 'tsoll').to_i * 0.5,
|
27
|
+
hkr_next_change_period: Time.at(data.dig('hkr', 'nextchange', 'endperiod').to_i),
|
28
|
+
hkr_next_change_temp: data.dig('hkr', 'nextchange', 'tchange').to_i * 0.5
|
29
|
+
)
|
30
30
|
end
|
31
31
|
|
32
32
|
def update_hkr_temp_set(value)
|
@@ -4,32 +4,12 @@ module Fritzbox
|
|
4
4
|
module Smarthome
|
5
5
|
class Lightbulb < Actor
|
6
6
|
|
7
|
-
|
8
|
-
:simpleonoff_state
|
7
|
+
include Properties::SimpleOnOff
|
9
8
|
|
10
9
|
class << self
|
11
10
|
def match?(data)
|
12
11
|
data.fetch('@productname', '') =~ /FRITZ!DECT 5\d{2}/i
|
13
12
|
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
13
|
end
|
34
14
|
end
|
35
15
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fritzbox
|
4
|
+
module Smarthome
|
5
|
+
module Properties
|
6
|
+
# Defines a common interface/behaviour for actors with the "simpleonoff" state.
|
7
|
+
# The including class is expected to have an `ain` attribute defined.
|
8
|
+
module SimpleOnOff
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
attr_accessor :simpleonoff_state
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def new_from_api(data)
|
17
|
+
instance = defined?(super) ? super : new
|
18
|
+
instance.simpleonoff_state = data.dig('simpleonoff', 'state').to_i
|
19
|
+
instance
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Boolean]
|
24
|
+
def active?
|
25
|
+
simpleonoff_state.to_s == "1"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Makes a request to the Fritzbox and set the current instance's active state.
|
29
|
+
#
|
30
|
+
# The instance state is kept in memory and not checked with the Fritzbox state. It is
|
31
|
+
# possible that the device is switched on/off through other means.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# lightbulb.active?
|
35
|
+
# # => true
|
36
|
+
# lightbulb.toggle!
|
37
|
+
# # => 0
|
38
|
+
# lightbulb.active?
|
39
|
+
# # => false
|
40
|
+
# @return [false, Integer] Returns the new on/off state or false when the request
|
41
|
+
# was unsuccessful
|
42
|
+
# @raise [ArgumentError] if the including class does not respond to `#ain`
|
43
|
+
def toggle!
|
44
|
+
raise ArgumentError, "Attribute `ain` is missing on #{inspect}" unless respond_to?(:ain)
|
45
|
+
value = active? ? 0 : 1
|
46
|
+
response =
|
47
|
+
Fritzbox::Smarthome::Resource.get(command: 'setsimpleonoff', ain: ain, onoff: value)
|
48
|
+
|
49
|
+
response.ok? && @simpleonoff_state = value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -17,6 +17,10 @@ module Fritzbox
|
|
17
17
|
HTTParty.get(url, **httparty_options)
|
18
18
|
end
|
19
19
|
|
20
|
+
def parse(response)
|
21
|
+
nori.parse(response.body)
|
22
|
+
end
|
23
|
+
|
20
24
|
private
|
21
25
|
|
22
26
|
delegate :config, to: Smarthome
|
@@ -52,6 +56,8 @@ module Fritzbox
|
|
52
56
|
@nori ||= Nori.new
|
53
57
|
end
|
54
58
|
end
|
59
|
+
|
60
|
+
delegate :get, :parse, to: :class
|
55
61
|
end
|
56
62
|
end
|
57
63
|
end
|
@@ -10,15 +10,15 @@ module Fritzbox
|
|
10
10
|
def match?(data)
|
11
11
|
data.key?('alert')
|
12
12
|
end
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
)
|
20
|
-
|
21
|
-
end
|
15
|
+
def assign_from_api(data)
|
16
|
+
super(data)
|
17
|
+
|
18
|
+
assign_attributes(
|
19
|
+
alert_state: data.dig('alert', 'state').to_i,
|
20
|
+
last_alert: Time.at(data.dig('alert', 'lastalertchgtimestamp').to_i)
|
21
|
+
)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -2,12 +2,13 @@ module Fritzbox
|
|
2
2
|
module Smarthome
|
3
3
|
class Switch < Actor
|
4
4
|
|
5
|
+
include Properties::SimpleOnOff
|
6
|
+
|
5
7
|
attr_accessor \
|
6
8
|
:switch_state,
|
7
9
|
:switch_mode,
|
8
10
|
:switch_lock,
|
9
11
|
:switch_devicelock,
|
10
|
-
:simpleonoff_state,
|
11
12
|
:powermeter_voltage,
|
12
13
|
:powermeter_power,
|
13
14
|
:powermeter_energy,
|
@@ -18,23 +19,22 @@ module Fritzbox
|
|
18
19
|
def match?(data)
|
19
20
|
data.key?('switch')
|
20
21
|
end
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
instance
|
37
|
-
end
|
24
|
+
def assign_from_api(data)
|
25
|
+
super(data)
|
26
|
+
|
27
|
+
assign_attributes(
|
28
|
+
switch_state: data.dig('switch', 'state').to_i,
|
29
|
+
switch_mode: data.dig('switch', 'mode').to_s,
|
30
|
+
switch_lock: data.dig('switch', 'lock').to_i,
|
31
|
+
switch_devicelock: data.dig('switch', 'devicelock').to_i,
|
32
|
+
powermeter_voltage: data.dig('powermeter', 'voltage').to_i,
|
33
|
+
powermeter_power: data.dig('powermeter', 'power').to_i,
|
34
|
+
powermeter_energy: data.dig('powermeter', 'energy').to_i,
|
35
|
+
temperature_celsius: data.dig('temperature', 'celsius').to_i,
|
36
|
+
temperature_offset: data.dig('temperature', 'offset').to_i
|
37
|
+
)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/lib/fritzbox/smarthome.rb
CHANGED
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.
|
4
|
+
version: 0.6.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: 2022-
|
11
|
+
date: 2022-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -173,6 +173,8 @@ files:
|
|
173
173
|
- lib/fritzbox/smarthome/heater.rb
|
174
174
|
- lib/fritzbox/smarthome/lightbulb.rb
|
175
175
|
- lib/fritzbox/smarthome/null_logger.rb
|
176
|
+
- lib/fritzbox/smarthome/properties.rb
|
177
|
+
- lib/fritzbox/smarthome/properties/simple_on_off.rb
|
176
178
|
- lib/fritzbox/smarthome/resource.rb
|
177
179
|
- lib/fritzbox/smarthome/smoke_detector.rb
|
178
180
|
- lib/fritzbox/smarthome/switch.rb
|