Skip to content
This repository has been archived by the owner on Feb 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #167 from danielperna84/devel
Browse files Browse the repository at this point in the history
0.1.49
  • Loading branch information
danielperna84 authored Sep 16, 2018
2 parents 8d38005 + d0d29aa commit f1e005a
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 25 deletions.
4 changes: 4 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Version 0.1.49 (2018-09-16)
- Rework RSSI handling (Issue #164, Issue #121) @klada
- Prevent failure of everything when single host is down (Issue #162)

Version 0.1.48 (2018-09-13)
- Added Support for HmIP-SWO-PL and HmIP-SWO-B @dickesW
- Fix callbacks for channel 0 @klada
Expand Down
9 changes: 6 additions & 3 deletions pyhomematic/_hm.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ def __init__(self,
self.systemcallback = systemcallback
self.resolveparamsets = resolveparamsets
self.proxies = {}
self.failed_inits = []

# Create proxies to interact with CCU / Homegear
LOG.debug("__init__: Creating proxies")
Expand Down Expand Up @@ -551,12 +552,15 @@ def proxyInit(self):
except Exception as err:
LOG.debug("proxyInit: Exception: %s" % str(err))
LOG.warning("Failed to initialize proxy")
raise Exception
self.failed_inits.append(interface_id)

def stop(self):
"""To stop the server we de-init from the CCU / Homegear, then shut down our XML-RPC server."""
stopped = []
for _, proxy in self.proxies.items():
for interface_id, proxy in self.proxies.items():
if interface_id in self.failed_inits:
LOG.warning("ServerThread.stop: Not performing de-init for %s" % interface_id)
continue
if proxy._callbackip and proxy._callbackport:
callbackip = proxy._callbackip
callbackport = proxy._callbackport
Expand All @@ -573,7 +577,6 @@ def stop(self):
except Exception as err:
LOG.debug("proxyInit: Exception: %s" % str(err))
LOG.warning("Failed to de-initialize proxy")
raise Exception
self.proxies.clear()
LOG.info("Shutting down server")
self.server.shutdown()
Expand Down
12 changes: 6 additions & 6 deletions pyhomematic/devicetypes/actors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pyhomematic.devicetypes.misc import HMEvent
from pyhomematic.devicetypes.helper import (
HelperWorking, HelperActorState, HelperActorLevel, HelperActorBlindTilt, HelperActionOnTime,
HelperActionPress, HelperEventRemote, HelperWired)
HelperActionPress, HelperEventRemote, HelperWired, HelperRssiPeer, HelperRssiDevice)

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -34,7 +34,7 @@ def stop(self, channel=None):
self.actionNodeData("STOP", True, channel)


class Blind(GenericBlind, HelperWorking):
class Blind(GenericBlind, HelperWorking, HelperRssiPeer):
"""
Blind switch that raises and lowers roller shutters or window blinds.
"""
Expand Down Expand Up @@ -174,7 +174,7 @@ def ELEMENT(self):
return [2]


class Switch(GenericSwitch, HelperWorking):
class Switch(GenericSwitch, HelperWorking, HelperRssiPeer):
"""
Switch turning plugged in device on or off.
"""
Expand Down Expand Up @@ -268,7 +268,7 @@ def ELEMENT(self):
return self._doc


class RFSiren(GenericSwitch, HelperWorking):
class RFSiren(GenericSwitch, HelperWorking, HelperRssiPeer):
"""
HM-Sec-Sir-WM Siren
"""
Expand All @@ -286,7 +286,7 @@ def ELEMENT(self):
return [1, 2, 3]


class KeyMatic(HMActor, HelperActorState):
class KeyMatic(HMActor, HelperActorState, HelperRssiPeer):
"""
Lock, Unlock or Open KeyMatic.
"""
Expand Down Expand Up @@ -377,7 +377,7 @@ def ELEMENT(self):
return [1, 2]


class IPSwitchPowermeter(IPSwitch, HMSensor):
class IPSwitchPowermeter(IPSwitch, HMSensor, HelperRssiDevice):
"""
Switch turning plugged in device on or off and measuring energy consumption.
"""
Expand Down
10 changes: 8 additions & 2 deletions pyhomematic/devicetypes/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def __init__(self, device_description, proxy, resolveparamsets=False):
# - 0...n / getValue from channel (fix)
self._SENSORNODE = {}
self._BINARYNODE = {}
self._ATTRIBUTENODE = {"RSSI_PEER": [0]}
self._ATTRIBUTENODE = {}
self._WRITENODE = {}
self._EVENTNODE = {}
self._ACTIONNODE = {}
Expand Down Expand Up @@ -334,7 +334,13 @@ def _setNodeData(self, name, metadata, data, channel=None):
return False

def get_rssi(self, channel=0):
return self.getAttributeData("RSSI_PEER", channel)
"""
This is a stub method which is implemented by the helpers
HelperRssiPeer/HelperRssiDevice in order to provide a suitable
implementation for the device.
"""
#pylint: disable=unused-argument
return 0

@property
def ELEMENT(self):
Expand Down
24 changes: 22 additions & 2 deletions pyhomematic/devicetypes/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,28 @@ def __init__(self, device_description, proxy, resolveparamsets=False):
"PRESS_LONG_RELEASE": self.ELEMENT})

class HelperWired(HMDevice):
"""Remove the RSSI_PEER attribute"""
"""Remove the RSSI-related attributes"""
def __init__(self, device_description, proxy, resolveparamsets=False):
super().__init__(device_description, proxy, resolveparamsets)

self.ATTRIBUTENODE.pop("RSSI_PEER", None)
self.ATTRIBUTENODE.pop("RSSI_DEVICE", None)


class HelperRssiDevice(HMDevice):
"""Used for devices which report their RSSI value through RSSI_DEVICE"""
def __init__(self, device_description, proxy, resolveparamsets=False):
super().__init__(device_description, proxy, resolveparamsets)
self.ATTRIBUTENODE["RSSI_DEVICE"] = [0]

def get_rssi(self, channel=0):
return self.getAttributeData("RSSI_DEVICE", channel)


class HelperRssiPeer(HMDevice):
"""Used for devices which report their RSSI value through RSSI_PEER"""
def __init__(self, device_description, proxy, resolveparamsets=False):
super().__init__(device_description, proxy, resolveparamsets)
self.ATTRIBUTENODE["RSSI_PEER"] = [0]

def get_rssi(self, channel=0):
return self.getAttributeData("RSSI_PEER", channel)
4 changes: 2 additions & 2 deletions pyhomematic/devicetypes/misc.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from pyhomematic.devicetypes.generic import HMDevice
from pyhomematic.devicetypes.helper import HelperActionPress, HelperEventRemote, HelperEventPress
from pyhomematic.devicetypes.helper import HelperActionPress, HelperEventRemote, HelperEventPress, HelperRssiPeer

LOG = logging.getLogger(__name__)

Expand All @@ -21,7 +21,7 @@ def ELEMENT(self):
return [c for c in range(1, 51)]


class Remote(HMEvent, HelperEventRemote, HelperActionPress):
class Remote(HMEvent, HelperEventRemote, HelperActionPress, HelperRssiPeer):
"""Remote handle buttons."""

@property
Expand Down
12 changes: 6 additions & 6 deletions pyhomematic/devicetypes/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
HelperLowBatIP, HelperSabotageIP,
HelperBinaryState,
HelperSensorState,
HelperWired, HelperEventRemote)
HelperWired, HelperEventRemote, HelperRssiPeer, HelperRssiDevice)

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -35,7 +35,7 @@ def ELEMENT(self):
return [1]


class ShutterContact(IPShutterContact, HelperSabotage):
class ShutterContact(IPShutterContact, HelperSabotage, HelperRssiPeer):
"""Door / Window contact that emits its open/closed state."""
pass

Expand All @@ -60,7 +60,7 @@ def is_not_tilted(self, channel=None):
return not self.get_state(channel)


class RotaryHandleSensor(HMSensor, HelperSensorState, HelperLowBat, HelperSabotage):
class RotaryHandleSensor(HMSensor, HelperSensorState, HelperLowBat, HelperSabotage, HelperRssiPeer):
"""Window handle contact."""
def is_open(self, channel=None):
""" Returns True if the handle is set to open. """
Expand Down Expand Up @@ -105,7 +105,7 @@ def is_added_strong(self, channel=None):
return self.get_state(channel) == 2


class WaterSensor(HMSensor, HelperSensorState, HelperLowBat):
class WaterSensor(HMSensor, HelperSensorState, HelperLowBat, HelperRssiPeer):
"""Watter detect sensor."""

def is_dry(self, channel=None):
Expand All @@ -121,7 +121,7 @@ def is_water(self, channel=None):
return self.get_state(channel) == 2


class PowermeterGas(HMSensor):
class PowermeterGas(HMSensor, HelperRssiPeer):
"""Powermeter for Gas and energy."""

def __init__(self, device_description, proxy, resolveparamsets=False):
Expand Down Expand Up @@ -167,7 +167,7 @@ def __init__(self, device_description, proxy, resolveparamsets=False):
"ERROR_SMOKE_CHAMBER": self.ELEMENT})


class IPSmoke(HMSensor):
class IPSmoke(HMSensor, HelperRssiDevice):
"""HomeMatic IP Smoke sensor"""

def __init__(self, device_description, proxy, resolveparamsets=False):
Expand Down
6 changes: 3 additions & 3 deletions pyhomematic/devicetypes/thermostats.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from pyhomematic.devicetypes.generic import HMDevice
from pyhomematic.devicetypes.sensors import AreaThermostat
from pyhomematic.devicetypes.helper import HelperValveState, HelperBatteryState, HelperLowBat, HelperLowBatIP
from pyhomematic.devicetypes.helper import HelperValveState, HelperBatteryState, HelperLowBat, HelperLowBatIP, HelperRssiPeer

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -123,7 +123,7 @@ def __init__(self, device_description, proxy, resolveparamsets=False):
"CONTROL_MODE": [1]})


class Thermostat(HMThermostat, HelperBatteryState, HelperValveState):
class Thermostat(HMThermostat, HelperBatteryState, HelperValveState, HelperRssiPeer):
"""
HM-CC-RT-DN, HM-CC-RT-DN-BoM
ClimateControl-Radiator Thermostat that measures temperature and allows to set a target temperature or use some automatic mode.
Expand All @@ -144,7 +144,7 @@ def __init__(self, device_description, proxy, resolveparamsets=False):
"CONTROL_MODE": [4]})


class ThermostatWall(HMThermostat, AreaThermostat, HelperBatteryState):
class ThermostatWall(HMThermostat, AreaThermostat, HelperBatteryState, HelperRssiPeer):
"""
HM-TC-IT-WM-W-EU
ClimateControl-Wall Thermostat that measures temperature and allows to set a target temperature or use some automatic mode.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def readme():

PACKAGE_NAME = 'pyhomematic'
HERE = os.path.abspath(os.path.dirname(__file__))
VERSION = '0.1.48'
VERSION = '0.1.49'

PACKAGES = find_packages(exclude=['tests', 'tests.*', 'dist', 'build'])

Expand Down
23 changes: 23 additions & 0 deletions tests/test_pyhomematic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pyhomematic import vccu
from pyhomematic import HMConnection
from pyhomematic import devicetypes
from pyhomematic.devicetypes.helper import HelperRssiDevice, HelperRssiPeer

logging.basicConfig(level=logging.INFO)
LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -145,5 +146,27 @@ def test_0_pyhomematic_classes(self):
else:
LOG.warning("Device class missing for: %s" % deviceobject.TYPE)


class Test_3_HelperClassHierarchy(unittest.TestCase):
"""
Some helper classes are mutally exclusive (such as HelperRssiPeer/HelperRssiDevice).
Since many device implementations inherit from other implementation classes we need
to be extra careful when plugging in such mutally excluse helpers somewhere in the
class hierarchy. This test case may be used for checking the currently available device
classes for such situations.
"""
def setUp(self):
self.device_classes = set(devicetypes.SUPPORTED.values())

def test_rssi_helper(self):
for klass in self.device_classes:
both_rssi_helpers_used = issubclass(HelperRssiDevice, klass) and issubclass(HelperRssiPeer, klass)
self.assertFalse(
both_rssi_helpers_used,
"The class %s inherits from both HelperRssiDevice and HelperRssiPeer, which is not supported." % klass
)


if __name__ == '__main__':
unittest.main()

0 comments on commit f1e005a

Please sign in to comment.