Skip to content

Commit

Permalink
Refactored sensor specialization.
Browse files Browse the repository at this point in the history
Instead of relying on a confusingly-named 'unknown' sentinel, moved these tags to the `Motion` type and gave that type a `.specialize` method to handle the state-sensitive specialization.

Now a truly "unknown" device will resolve to `Unknown` and will be filtered when loading devices.

Closes #28
  • Loading branch information
jaraco committed Jul 7, 2024
1 parent 17359ed commit d503298
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 34 deletions.
4 changes: 2 additions & 2 deletions jaraco/abode/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from . import config, settings
from .automation import Automation
from .devices import alarm as ALARM
from .devices.base import Device
from .devices.base import Device, Unknown
from .event_controller import EventController
from .exceptions import AuthenticationException
from .helpers import errors as ERROR
Expand Down Expand Up @@ -212,7 +212,7 @@ def _reuse_device(self, doc):
def _create_new_device(self, doc):
device = Device.new(doc, self)

if not device:
if isinstance(device, Unknown):
log.debug("Skipping unknown device: %s", doc)
return

Expand Down
42 changes: 11 additions & 31 deletions jaraco/abode/devices/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,23 +124,6 @@ def device_uuid(self):
)
return self.uuid

@staticmethod
def resolve_type_unknown(state):
if state['generic_type'] != 'unknown':
return

from .sensor import Sensor

if Sensor.is_sensor(state):
state['generic_type'] = 'sensor'
return

version = state.get('version', '')

state['generic_type'] = (
'occupancy' if version.startswith('MINIPIR') else 'motion'
)

@classmethod
def new(cls, state, client):
"""Create new device object for the given type."""
Expand All @@ -151,9 +134,9 @@ def new(cls, state, client):
raise jaraco.abode.Exception(ERROR.UNABLE_TO_MAP_DEVICE) from exc

state['generic_type'] = cls.get_generic_type(type_tag)
cls.resolve_type_unknown(state)
sensor = cls.by_type().get(state['generic_type'], lambda *args: None)
return sensor(state, client)
init_cls = cls.by_type().get(state['generic_type'], Unknown)
spec_cls = init_cls.specialize(state)
return spec_cls(state, client)

@classmethod
def by_type(cls):
Expand All @@ -166,15 +149,12 @@ def get_generic_type(cls, type_tag):
for sub_cls in iter_subclasses(cls)
for tag in sub_cls.tags
}
# These device types are all considered 'occupancy' but could apparently
# also be multi-sensors based on their state.
unknowns = (
'room_sensor',
'temperature_sensor',
# LM = LIGHT MOTION?
'lm',
'pir',
'povs',
)
lookup.update((f'device_type.{unknown}', 'unknown') for unknown in unknowns)
return lookup.get(type_tag.lower())

@classmethod
def specialize(cls, state):
return cls


class Unknown(Device):
pass
25 changes: 24 additions & 1 deletion jaraco/abode/devices/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,30 @@ class Connectivity(BinarySensor):


class Motion(BinarySensor):
pass
# These device types are all considered 'occupancy' but could apparently
# also be multi-sensors based on their state.
tags = (
'room_sensor',
'temperature_sensor',
# LM = LIGHT MOTION?
'lm',
'pir',
'povs',
)

@classmethod
def specialize(cls, state):
from . import sensor

new_type = (
sensor.Sensor
if sensor.Sensor.is_sensor(state)
else Occupancy
if state.get('version', '').startswith('MINIPIR')
else cls
)
state['generic_type'] = new_type.__name__.lower()
return new_type


class Occupancy(BinarySensor):
Expand Down
1 change: 1 addition & 0 deletions newsfragments/28.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactored sensor specialization.

0 comments on commit d503298

Please sign in to comment.