Skip to content

Commit

Permalink
Merge pull request #259 from coreGreenberet/group_switching_setXXLevel
Browse files Browse the repository at this point in the history
implemented ExtendedLinkedShutterGroup.set_slats_level
  • Loading branch information
coreGreenberet authored Dec 22, 2019
2 parents bea7850 + f9a3d56 commit e0ab086
Show file tree
Hide file tree
Showing 15 changed files with 273 additions and 41 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,4 @@ ENV/
/.pytest_cache
/apk
/TestResults
/venv38
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- API
- FunctionalChannels: DOOR_CHANNEL
- Python 3.8 support
- API
- ExtendedLinkedShutterGroup.set_slats_level
- added missing attributes
### Changed
- General
- removed homematicip-testing package. Pip will automatically install the latest tagged release. For a "nightly" build you just have to run it with the "--pre" argument.
Expand Down
11 changes: 10 additions & 1 deletion homematicip.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</InterpreterArguments>
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
<CommandLineArguments>--list-events</CommandLineArguments>
<InterpreterId>MSBuild|venv|$(MSBuildProjectFullPath)</InterpreterId>
<InterpreterId>MSBuild|venv38|$(MSBuildProjectFullPath)</InterpreterId>
<SuppressConfigureTestFrameworkPrompt>true</SuppressConfigureTestFrameworkPrompt>
<TestFramework>pytest</TestFramework>
<UnitTestPattern>test*.py</UnitTestPattern>
Expand Down Expand Up @@ -159,6 +159,15 @@
<Content Include="requirements_dev.txt" />
</ItemGroup>
<ItemGroup>
<Interpreter Include="venv38\">
<Id>venv38</Id>
<Version>3.8</Version>
<Description>venv38 (Python 3.8 (64-bit))</Description>
<InterpreterPath>Scripts\python.exe</InterpreterPath>
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
<Architecture>X64</Architecture>
</Interpreter>
<Interpreter Include="venv\">
<Id>venv</Id>
<Version>3.7</Version>
Expand Down
5 changes: 2 additions & 3 deletions homematicip/aio/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,9 @@ async def set_notification_sound_type(
*super().set_notification_sound_type(soundType, isHighToLow, channelIndex)
)


class AsyncGarageDoorModuleTormatic(GarageDoorModuleTormatic, AsyncDevice):
""" HMIP-MOD-TM (Garage Door Module Tormatic) """

async def send_door_command(self, doorCommand=DoorCommand.STOP):
return await self._connection.api_call(
*super().send_door_command(doorCommand)
)
return await self._connection.api_call(*super().send_door_command(doorCommand))
10 changes: 9 additions & 1 deletion homematicip/aio/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,12 @@ async def set_shutter_stop(self):
url, data = super().set_shutter_stop()
return await self._connection.api_call(url, data)

async def set_slats_level(self, slatsLevel, shutterlevel):
url, data = super().set_slats_level(slatsLevel, shutterlevel)
return await self._connection.api_call(url, data)


class AsyncLinkedSwitchingGroup(LinkedSwitchingGroup, AsyncSwitchingGroup):
class AsyncLinkedSwitchingGroup(LinkedSwitchingGroup, AsyncGroup):
async def set_light_group_switches(self, devices):
url, data = super().set_light_group_switches(devices)
return await self._connection.api_call(url, data)
Expand All @@ -92,6 +96,10 @@ async def set_shutter_stop(self):
url, data = super().set_shutter_stop()
return await self._connection.api_call(url, data)

async def set_slats_level(self, slatsLevel, shutterlevel):
url, data = super().set_slats_level(slatsLevel, shutterlevel)
return await self._connection.api_call(url, data)


class AsyncAlarmSwitchingGroup(AlarmSwitchingGroup, AsyncGroup):
async def set_on_time(self, onTimeSeconds):
Expand Down
15 changes: 15 additions & 0 deletions homematicip/base/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,3 +487,18 @@ class DoorCommand(AutoNameEnum):
STOP = auto()
CLOSE = auto()
PARTIAL_OPEN = auto()


class ShadingStateType(AutoNameEnum):
NOT_POSSIBLE = auto()
NOT_EXISTENT = auto()
POSITION_USED = auto()
TILT_USED = auto()
NOT_USED = auto()
MIXED = auto()


class GroupVisibility(AutoNameEnum):
INVISIBLE_GROUP_AND_CONTROL = auto()
INVISIBLE_CONTROL = auto()
VISIBLE = auto()
1 change: 0 additions & 1 deletion homematicip/base/functionalChannels.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,6 @@ def __init__(self):
self.processing = False
self.ventilationPositionSupported = True


def from_json(self, js, groups: Iterable[Group]):
super().from_json(js, groups)
self.doorState = js["doorState"]
Expand Down
2 changes: 1 addition & 1 deletion homematicip/base/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def handle_config(json_state: str, anonymize: bool) -> str:
"00000000-0000-0000-0000-{0:0>12}",
)
# generate dummy SGTIN
c = anonymizeConfig(c, "\"[A-Z0-9]{24}\"", "\"3014F711{0:0>16}\"")
c = anonymizeConfig(c, '"[A-Z0-9]{24}"', '"3014F711{0:0>16}"')
# remove refresh Token
c = anonymizeConfig(c, '"refreshToken": ?"[^"]+"', '"refreshToken": null')
# location
Expand Down
8 changes: 3 additions & 5 deletions homematicip/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def __init__(self, connection):
self.updateState = DeviceUpdateState.UP_TO_DATE
self.firmwareVersion = None
self.firmwareVersionInteger = (
0
) # firmwareVersion = A.B.C -> firmwareVersionInteger ((A<<16)|(B<<8)|C)
0 # firmwareVersion = A.B.C -> firmwareVersionInteger ((A<<16)|(B<<8)|C)
)
self.availableFirmwareVersion = None
self.unreach = None
self.lowBat = None
Expand Down Expand Up @@ -1651,6 +1651,7 @@ def __str__(self):
self.notificationSoundTypeLowToHigh,
)


class GarageDoorModuleTormatic(Device):
""" HMIP-MOD-TM (Garage Door Module Tormatic) """

Expand All @@ -1661,7 +1662,6 @@ def __init__(self, connection):
self.processing = False
self.ventilationPositionSupported = False


def from_json(self, js):
super().from_json(js)
c = get_functional_channel("DOOR_CHANNEL", js)
Expand All @@ -1671,7 +1671,6 @@ def from_json(self, js):
self.processing = c["processing"]
self.ventilationPositionSupported = c["ventilationPositionSupported"]


def __str__(self):
return "{} doorState({}) on({}) processing({}) ventilationPositionSupported({})".format(
super().__str__(),
Expand All @@ -1684,4 +1683,3 @@ def __str__(self):
def send_door_command(self, doorCommand=DoorCommand.STOP):
data = {"channelIndex": 1, "deviceId": self.id, "doorCommand": doorCommand}
return self._restCall("device/control/sendDoorCommand", json.dumps(data))

89 changes: 69 additions & 20 deletions homematicip/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,20 +140,25 @@ def __init__(self, connection):
self.slatsLevel = None
self.dutyCycle = None
self.lowBat = None
self.primaryShadingLevel = 0.0
self.primaryShadingStateType = ShadingStateType.NOT_EXISTENT
self.processing = None
self.secondaryShadingLevel = 0.0
self.secondaryShadingStateType = ShadingStateType.NOT_EXISTENT

def from_json(self, js, devices):
super().from_json(js, devices)
self.on = js["on"]
self.dimLevel = js["dimLevel"]
self.dutyCycle = js["dutyCycle"]
self.lowBat = js["lowBat"]
try: # TODO: FIX that ugly hack -> maybe linked_switching shouldn't inherit
# anymore from switchingGroup
self.processing = js["processing"]
self.shutterLevel = js["shutterLevel"]
self.slatsLevel = js["slatsLevel"]
except:
pass
self.set_attr_from_dict("on", js)
self.set_attr_from_dict("dimLevel", js)
self.set_attr_from_dict("dutyCycle", js)
self.set_attr_from_dict("lowBat", js)
self.set_attr_from_dict("processing", js)
self.set_attr_from_dict("shutterLevel", js)
self.set_attr_from_dict("slatsLevel", js)
self.set_attr_from_dict("primaryShadingLevel", js)
self.set_attr_from_dict("primaryShadingStateType", js, ShadingStateType)
self.set_attr_from_dict("secondaryShadingLevel", js)
self.set_attr_from_dict("secondaryShadingStateType", js, ShadingStateType)

def set_switch_state(self, on=True):
data = {"groupId": self.id, "on": on}
Expand All @@ -169,6 +174,14 @@ def set_shutter_level(self, level):
data = {"groupId": self.id, "shutterLevel": level}
return self._restCall("group/switching/setShutterLevel", body=json.dumps(data))

def set_slats_level(self, slatsLevel, shutterlevel):
data = {
"groupId": self.id,
"shutterLevel": shutterlevel,
"slatsLevel": slatsLevel,
}
return self._restCall("group/switching/setSlatsLevel", body=json.dumps(data))

def set_shutter_stop(self):
data = {"groupId": self.id}
return self._restCall("group/switching/stop", body=json.dumps(data))
Expand All @@ -186,7 +199,7 @@ def __str__(self):
)


class LinkedSwitchingGroup(SwitchingGroup):
class LinkedSwitchingGroup(Group):
def set_light_group_switches(self, devices):
switchChannels = []
for d in devices:
Expand Down Expand Up @@ -224,19 +237,55 @@ def set_on_time(self, onTimeSeconds):
class ExtendedLinkedShutterGroup(Group):
def __init__(self, connection):
super().__init__(connection)
self.dutyCycle = None
self.lowBat = None
self.shutterLevel = None
self.slatsLevel = None
self.topSlatsLevel = None
self.bottomSlatsLevel = None
self.topShutterLevel = None
self.bottomShutterLevel = None
self.processing = None
self.primaryShadingLevel = 0.0
self.primaryShadingStateType = ShadingStateType.NOT_EXISTENT
self.secondaryShadingLevel = 0.0
self.secondaryShadingStateType = ShadingStateType.NOT_EXISTENT
self.groupVisibility = GroupVisibility.INVISIBLE_GROUP_AND_CONTROL

def from_json(self, js, devices):
super().from_json(js, devices)
self.shutterLevel = js["shutterLevel"]
self.set_attr_from_dict("dutyCycle", js)
self.set_attr_from_dict("lowBat", js)
self.set_attr_from_dict("groupVisibility", js, GroupVisibility)
self.set_attr_from_dict("topSlatsLevel", js)
self.set_attr_from_dict("bottomSlatsLevel", js)
self.set_attr_from_dict("topShutterLevel", js)
self.set_attr_from_dict("bottomShutterLevel", js)
self.set_attr_from_dict("processing", js)
self.set_attr_from_dict("shutterLevel", js)
self.set_attr_from_dict("slatsLevel", js)
self.set_attr_from_dict("primaryShadingLevel", js)
self.set_attr_from_dict("primaryShadingStateType", js, ShadingStateType)
self.set_attr_from_dict("secondaryShadingLevel", js)
self.set_attr_from_dict("secondaryShadingStateType", js, ShadingStateType)

def __str__(self):
return "{} shutterLevel({})".format(super().__str__(), self.shutterLevel)
return "{} shutterLevel({}) slatsLevel({})".format(
super().__str__(), self.shutterLevel, self.slatsLevel
)

def set_shutter_level(self, level):
data = {"groupId": self.id, "shutterLevel": level}
return self._restCall("group/switching/setShutterLevel", body=json.dumps(data))

def set_slats_level(self, slatsLevel, shutterlevel):
data = {
"groupId": self.id,
"shutterLevel": shutterlevel,
"slatsLevel": slatsLevel,
}
return self._restCall("group/switching/setSlatsLevel", body=json.dumps(data))

def set_shutter_stop(self):
data = {"groupId": self.id}
return self._restCall("group/switching/stop", body=json.dumps(data))
Expand Down Expand Up @@ -820,11 +869,11 @@ def __init__(self, connection):
self.minute = 0
self.astroOffset = 0
self.astroLimitationType = (
"NO_LIMITATION"
) # NOT_EARLIER_THAN_TIME, NOT_LATER_THAN_TIME
"NO_LIMITATION" # NOT_EARLIER_THAN_TIME, NOT_LATER_THAN_TIME
)
self.switchTimeMode = (
"REGULAR_SWITCH_TIME"
) # ASTRO_SUNRISE_SWITCH_TIME, ASTRO_SUNSET_SWITCH_TIME
"REGULAR_SWITCH_TIME" # ASTRO_SUNRISE_SWITCH_TIME, ASTRO_SUNSET_SWITCH_TIME
)
self.dimLevel = 1.0
self.rampTime = 0

Expand Down Expand Up @@ -868,8 +917,8 @@ def __init__(self, connection):
self.on = None
self.dimLevel = None
self.profileId = (
None
) # Not sure why it is there. You can't use it to query something.
None # Not sure why it is there. You can't use it to query something.
)
self.profileMode = None

def from_json(self, js, devices):
Expand Down
27 changes: 26 additions & 1 deletion homematicip_demo/fake_cloud_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,9 @@ async def post_hmip_device_control_sendDoorCommand(
"PARTIAL_OPEN": "VENTILATION_POSITION",
"STOP": "POSITION_UNKNOWN",
}
d["functionalChannels"][channelIndex]["doorState"] = switcher.get(js["doorCommand"], "POSITION_UNKNOWN")
d["functionalChannels"][channelIndex]["doorState"] = switcher.get(
js["doorCommand"], "POSITION_UNKNOWN"
)

return web.json_response(None)

Expand Down Expand Up @@ -838,6 +840,29 @@ async def post_hmip_group_switching_setShutterLevel(
response = self.errorCode("INVALID_GROUP", 404)
return response

@validate_authorization
async def post_hmip_group_switching_setSlatsLevel(
self, request: web.Request
) -> web.Response:
response = web.json_response(None)

js = json.loads(request.data)
if js["groupId"] in self.data["groups"]:
g = self.data["groups"][js["groupId"]]
g["shutterLevel"] = js["shutterLevel"]
g["slatsLevel"] = js["slatsLevel"]

else:
response = self.errorCode("INVALID_GROUP", 404)
return response

@validate_authorization
async def post_hmip_group_switching_stop(
self, request: web.Request
) -> web.Response:
response = web.json_response(None)
return response

@validate_authorization
async def post_hmip_group_heating_setSetPointTemperature(
self, request: web.Request
Expand Down
31 changes: 30 additions & 1 deletion homematicip_demo/json_data/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -4474,7 +4474,11 @@
"lowBat": null,
"metaGroupId": "00000000-0000-0000-0000-000000000017",
"on": true,
"processing": null,
"primaryShadingLevel": 1.0,
"primaryShadingStateType": "POSITION_USED",
"processing": false,
"secondaryShadingLevel": null,
"secondaryShadingStateType": "NOT_EXISTENT",
"shutterLevel": null,
"slatsLevel": null,
"type": "SWITCHING",
Expand Down Expand Up @@ -5462,6 +5466,31 @@
"type": "HUMIDITY_WARNING_RULE_GROUP",
"unreach": false,
"ventilationRecommended": false
},
"00000000-0000-0000-0000-000000000050": {
"bottomShutterLevel": 1.0,
"bottomSlatsLevel": 1.0,
"channels": [],
"dutyCycle": false,
"groupVisibility": "VISIBLE",
"homeId": "00000000-0000-0000-0000-000000000001",
"id": "00000000-0000-0000-0000-000000000050",
"label": "Rollos",
"lastStatusUpdate": 1573078054795,
"lowBat": null,
"metaGroupId": null,
"primaryShadingLevel": 1.0,
"primaryShadingStateType": "POSITION_USED",
"processing": false,
"secondaryShadingLevel": null,
"secondaryShadingStateType": "NOT_EXISTENT",
"sensorSpecificParameters": {},
"shutterLevel": 1.0,
"slatsLevel": null,
"topShutterLevel": 0.0,
"topSlatsLevel": 0.0,
"type": "EXTENDED_LINKED_SHUTTER",
"unreach": false
}
},
"home": {
Expand Down
Loading

0 comments on commit e0ab086

Please sign in to comment.