Skip to content

Commit

Permalink
Define properties via ActiveModel::Attributes (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
klausmeyer authored Jul 5, 2024
1 parent a0c1383 commit c64a573
Show file tree
Hide file tree
Showing 18 changed files with 238 additions and 211 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## v0.8.0

* Use `ActiveModel::Attributes`
* Allow usage in Rails `7.1` and `7.2`
* Drop usage in Rails `< 7.0`

## v0.7.0

* Measure HTTP request duration
Expand Down
4 changes: 2 additions & 2 deletions fritzbox-smarthome.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

spec.add_dependency 'activesupport', '>= 5.1', '<= 7.1'
spec.add_dependency 'activemodel', '>= 5.1', '<= 7.1.3.2'
spec.add_dependency 'activesupport', '>= 7.0', '<= 8'
spec.add_dependency 'activemodel', '>= 7.0', '<= 8'
spec.add_dependency 'csv', '~> 3.2' # For httparty to silence deprecation warning in ruby >= 3.3.0
spec.add_dependency 'httparty', '~> 0.20'
spec.add_dependency 'nori', '~> 2.6'
Expand Down
12 changes: 6 additions & 6 deletions lib/fritzbox/smarthome.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ module Fritzbox
module Smarthome
class Configuration
include ActiveModel::Model
include ActiveModel::Attributes

attr_accessor \
:endpoint, \
:username, \
:password,
:verify_ssl,
:logger
attribute :endpoint, :string
attribute :username, :string
attribute :password, :string
attribute :verify_ssl, :boolean
attribute :logger
end

@config = Configuration.new.tap do |defaults|
Expand Down
16 changes: 8 additions & 8 deletions lib/fritzbox/smarthome/actor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ module Fritzbox
module Smarthome
class Actor < Resource
include ActiveModel::Model
include ActiveModel::Attributes

attr_accessor \
:id,
:type,
:ain,
:present,
:name,
:manufacturer,
:group_members
attribute :id, :string
attribute :type #, :symbol
attribute :ain, :string
attribute :present, :string
attribute :name, :string
attribute :manufacturer, :string
attribute :group_members #, :string, array: true

ResourceNotFound = Class.new(RuntimeError)

Expand Down
14 changes: 6 additions & 8 deletions lib/fritzbox/smarthome/heater.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
module Fritzbox
module Smarthome
class Heater < Actor

attr_accessor \
:battery,
:batterylow,
:hkr_temp_is,
:hkr_temp_set,
:hkr_next_change_period,
:hkr_next_change_temp
attribute :battery, :integer
attribute :batterylow, :integer
attribute :hkr_temp_is, :float
attribute :hkr_temp_set, :float
attribute :hkr_next_change_period, :time
attribute :hkr_next_change_temp, :float

class << self
def match?(data)
Expand Down
3 changes: 0 additions & 3 deletions lib/fritzbox/smarthome/lightbulb.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# frozen_string_literal: true

module Fritzbox
module Smarthome
class Lightbulb < Actor

include Properties::SimpleOnOff

class << self
Expand Down
2 changes: 0 additions & 2 deletions lib/fritzbox/smarthome/null_logger.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# frozen_string_literal: true

module Fritzbox
module Smarthome
class NullLogger < Logger
Expand Down
5 changes: 1 addition & 4 deletions lib/fritzbox/smarthome/properties.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
# frozen_string_literal: true

require 'fritzbox/smarthome/properties/simple_on_off'

module Fritzbox
module Smarthome
module Properties
end
module Properties; end
end
end
11 changes: 5 additions & 6 deletions lib/fritzbox/smarthome/properties/simple_on_off.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ module SimpleOnOff
extend ActiveSupport::Concern

included do
attr_accessor :simpleonoff_state
attribute :simpleonoff_state, :integer
end

module ClassMethods
def new_from_api(data)
instance = defined?(super) ? super : new
instance.simpleonoff_state = data.dig('simpleonoff', 'state').to_i
instance.simpleonoff_state = data.dig('simpleonoff', 'state')
instance
end
end

# @return [Boolean]
def active?
simpleonoff_state.to_s == "1"
simpleonoff_state == 1
end

# Makes a request to the Fritzbox and set the current instance's active state.
Expand All @@ -43,10 +43,9 @@ def active?
def toggle!
raise ArgumentError, "Attribute `ain` is missing on #{inspect}" unless respond_to?(:ain)
value = active? ? 0 : 1
response =
Fritzbox::Smarthome::Resource.get(command: 'setsimpleonoff', ain: ain, onoff: value)
response = Fritzbox::Smarthome::Resource.get(command: 'setsimpleonoff', ain: ain, onoff: value)

response.ok? && @simpleonoff_state = value
response.ok? && self.simpleonoff_state = value
end
end
end
Expand Down
6 changes: 2 additions & 4 deletions lib/fritzbox/smarthome/smoke_detector.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
module Fritzbox
module Smarthome
class SmokeDetector < Actor

attr_accessor \
:alert_state,
:last_alert
attribute :alert_state, :integer
attribute :last_alert, :time

class << self
def match?(data)
Expand Down
38 changes: 18 additions & 20 deletions lib/fritzbox/smarthome/switch.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
module Fritzbox
module Smarthome
class Switch < Actor

include Properties::SimpleOnOff

attr_accessor \
:switch_state,
:switch_mode,
:switch_lock,
:switch_devicelock,
:powermeter_voltage,
:powermeter_power,
:powermeter_energy,
:temperature_celsius,
:temperature_offset
attribute :switch_state, :integer
attribute :switch_mode, :string
attribute :switch_lock, :integer
attribute :switch_devicelock, :integer
attribute :powermeter_voltage, :integer
attribute :powermeter_power, :integer
attribute :powermeter_energy, :integer
attribute :temperature_celsius, :integer
attribute :temperature_offset, :integer

class << self
def match?(data)
Expand All @@ -25,15 +23,15 @@ def assign_from_api(data)
super(data)

assign_attributes(
switch_state: data.dig('switch', 'state').to_i,
switch_mode: data.dig('switch', 'mode').to_s,
switch_lock: data.dig('switch', 'lock').to_i,
switch_devicelock: data.dig('switch', 'devicelock').to_i,
powermeter_voltage: data.dig('powermeter', 'voltage').to_i,
powermeter_power: data.dig('powermeter', 'power').to_i,
powermeter_energy: data.dig('powermeter', 'energy').to_i,
temperature_celsius: data.dig('temperature', 'celsius').to_i,
temperature_offset: data.dig('temperature', 'offset').to_i
switch_state: data.dig('switch', 'state'),
switch_mode: data.dig('switch', 'mode'),
switch_lock: data.dig('switch', 'lock'),
switch_devicelock: data.dig('switch', 'devicelock'),
powermeter_voltage: data.dig('powermeter', 'voltage'),
powermeter_power: data.dig('powermeter', 'power'),
powermeter_energy: data.dig('powermeter', 'energy'),
temperature_celsius: data.dig('temperature', 'celsius'),
temperature_offset: data.dig('temperature', 'offset')
)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/fritzbox/smarthome/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Fritzbox
module Smarthome
VERSION = '0.7.0'.freeze
VERSION = '0.8.0'.freeze
end
end
112 changes: 63 additions & 49 deletions spec/fritzbox/smarthome/actor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,68 +40,82 @@
expect(actors.size).to eq 7

actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::Heater
expect(actor.type).to eq :device
expect(actor.id).to eq '18'
expect(actor.ain).to eq '12345 678901'
expect(actor.name).to eq 'Heizung Wohnzimmer'
expect(actor.manufacturer).to eq 'AVM'
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::Heater
expect(actor.attributes).to include(
'type' => :device,
'id' => '18',
'ain' => '12345 678901',
'name' => 'Heizung Wohnzimmer',
'manufacturer' => 'AVM',
'group_members' => nil,
)

actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::Heater
expect(actor.type).to eq :device
expect(actor.id).to eq '16'
expect(actor.ain).to eq '12345 678902'
expect(actor.name).to eq 'Heizung Küche'
expect(actor.manufacturer).to eq 'AVM'
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::Heater
expect(actor.attributes).to include(
'type' => :device,
'id' => '16',
'ain' => '12345 678902',
'name' => 'Heizung Küche',
'manufacturer' => 'AVM',
'group_members' => nil,
)

actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::SmokeDetector
expect(actor.type).to eq :device
expect(actor.id).to eq '15'
expect(actor.ain).to eq '12345 678903'
expect(actor.name).to eq 'Rauchmelder Wohnzimmer'
expect(actor.manufacturer).to eq '0x2c3c'
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::SmokeDetector
expect(actor.attributes).to include(
'type' => :device,
'id' => '15',
'ain' => '12345 678903',
'name' => 'Rauchmelder Wohnzimmer',
'manufacturer' => '0x2c3c',
'group_members' => nil,
)

actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::SmokeDetector
expect(actor.type).to eq :device
expect(actor.id).to eq '14'
expect(actor.ain).to eq '12345 678904'
expect(actor.name).to eq 'Rauchmelder Küche'
expect(actor.manufacturer).to eq '0x2c3c'
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::SmokeDetector
expect(actor.attributes).to include(
'type' => :device,
'id' => '14',
'ain' => '12345 678904',
'name' => 'Rauchmelder Küche',
'manufacturer' => '0x2c3c',
'group_members' => nil,
)

actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::Switch
expect(actor.type).to eq :device
expect(actor.id).to eq '13'
expect(actor.ain).to eq '12345 678905'
expect(actor.name).to eq 'FRITZ!DECT 200 Steckdose'
expect(actor.manufacturer).to eq 'AVM'
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::Switch
expect(actor.attributes).to include(
'type' => :device,
'id' => '13',
'ain' => '12345 678905',
'name' => 'FRITZ!DECT 200 Steckdose',
'manufacturer' => 'AVM',
'group_members' => nil,
)

# An unrecognised device that couldn't be linked to a specific Actor subclass:
actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::Actor
expect(actor.type).to eq :device
expect(actor.id).to eq "4711"
expect(actor.ain).to eq "12345 54321"
expect(actor.name).to eq "Sub-Etha Radio Transmitter"
expect(actor.manufacturer).to eq ""
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::Actor
expect(actor.attributes).to include(
'type' => :device,
'id' => '4711',
'ain' => '12345 54321',
'name' => 'Sub-Etha Radio Transmitter',
'manufacturer' => '',
'group_members' => nil,
)

actor = actors.shift
expect(actor.class).to eq Fritzbox::Smarthome::Lightbulb
expect(actor.type).to eq :device
expect(actor.id).to eq "406"
expect(actor.ain).to eq "11111 2233445"
expect(actor.name).to eq "Flurlampe"
expect(actor.manufacturer).to eq "AVM"
expect(actor.group_members).to be nil
expect(actor.class).to eq Fritzbox::Smarthome::Lightbulb
expect(actor.attributes).to include(
'type' => :device,
'id' => '406',
'ain' => '11111 2233445',
'name' => 'Flurlampe',
'manufacturer' => 'AVM',
'group_members' => nil,
)
end
end

Expand Down
Loading

0 comments on commit c64a573

Please sign in to comment.