Skip to content

Commit

Permalink
feat: add PyViCareGateway class (#334)
Browse files Browse the repository at this point in the history
  • Loading branch information
CFenner authored Dec 27, 2023
1 parent 16eb10d commit f69604d
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 9 deletions.
7 changes: 6 additions & 1 deletion PyViCare/PyViCareDeviceConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from PyViCare.PyViCareRadiatorActuator import RadiatorActuator
from PyViCare.PyViCareRoomSensor import RoomSensor
from PyViCare.PyViCareElectricalEnergySystem import ElectricalEnergySystem
from PyViCare.PyViCareGateway import Gateway
from PyViCare.PyViCareVentilationDevice import VentilationDevice

logger = logging.getLogger('ViCare')
Expand Down Expand Up @@ -54,6 +55,9 @@ def asRoomSensor(self):

def asElectricalEnergySystem(self):
return ElectricalEnergySystem(self.service)

Check warning on line 58 in PyViCare/PyViCareDeviceConfig.py

View workflow job for this annotation

GitHub Actions / build (3.6)

W293 blank line contains whitespace

Check warning on line 58 in PyViCare/PyViCareDeviceConfig.py

View workflow job for this annotation

GitHub Actions / build (3.8)

W293 blank line contains whitespace

Check warning on line 58 in PyViCare/PyViCareDeviceConfig.py

View workflow job for this annotation

GitHub Actions / build (3.9)

W293 blank line contains whitespace
def asGateway(self):
return Gateway(self.service)

def asVentilation(self):
return VentilationDevice(self.service)
Expand Down Expand Up @@ -84,7 +88,8 @@ def asAutoDetectDevice(self):
(self.asElectricalEnergySystem, r"E3_TCU10_x07", ["type:tcu"]),
(self.asElectricalEnergySystem, r"E3_EEBus", ["type:eebus"]),
(self.asElectricalEnergySystem, r"E3_VitoCharge_03", ["type:energy_storage"]),
(self.asVentilation, r"E3_ViAir", ["type:ventilation"])
(self.asVentilation, r"E3_ViAir", ["type:ventilation"]),
(self.asGateway, r"Heatbox1", ["type:gateway;VitoconnectOpto1"])
]

for (creator_method, type_name, roles) in device_types:
Expand Down
9 changes: 9 additions & 0 deletions PyViCare/PyViCareGateway.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from PyViCare.PyViCareDevice import Device
from PyViCare.PyViCareUtils import handleNotSupported


class Gateway(Device):

@handleNotSupported
def getWifiSignalStrength(self):
return self.service.getProperty("gateway.wifi")["properties"]["strength"]["value"]
18 changes: 12 additions & 6 deletions PyViCare/PyViCareService.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ def buildSetPropertyUrl(accessor, property_name, action):
return f'/features/installations/{accessor.id}/gateways/{accessor.serial}/devices/{accessor.device_id}/features/{property_name}/commands/{action}'


def buildGetPropertyUrl(accessor, property_name):
return f'/features/installations/{accessor.id}/gateways/{accessor.serial}/devices/{accessor.device_id}/features/{property_name}'


class ViCareDeviceAccessor:
def __init__(self, id: int, serial: str, device_id: str) -> None:
self.id = id
Expand All @@ -45,13 +41,21 @@ def __init__(self, oauth_manager: AbstractViCareOAuthManager, accessor: ViCareDe
self.roles = roles

def getProperty(self, property_name: str) -> Any:
url = buildGetPropertyUrl(
self.accessor, property_name)
url = self.buildGetPropertyUrl(property_name)
return self.oauth_manager.get(url)

Check warning on line 46 in PyViCare/PyViCareService.py

View workflow job for this annotation

GitHub Actions / build (3.8)

W293 blank line contains whitespace

Check warning on line 46 in PyViCare/PyViCareService.py

View workflow job for this annotation

GitHub Actions / build (3.9)

W293 blank line contains whitespace
def buildGetPropertyUrl(self, property_name):
if self._isGateway():
return f'/features/installations/{self.accessor.id}/gateways/{self.accessor.serial}/features/{property_name}'
return f'/features/installations/{self.accessor.id}/gateways/{self.accessor.serial}/devices/{self.accessor.device_id}/features/{property_name}'


def hasRoles(self, requested_roles) -> bool:

Check failure on line 53 in PyViCare/PyViCareService.py

View workflow job for this annotation

GitHub Actions / build (3.8)

E303 too many blank lines (2)

Check failure on line 53 in PyViCare/PyViCareService.py

View workflow job for this annotation

GitHub Actions / build (3.9)

E303 too many blank lines (2)
return hasRoles(requested_roles, self.roles)

def _isGateway(self) -> bool:
return self.hasRoles(["type:gateway;VitoconnectOpto1"])

def setProperty(self, property_name: str, action: str, data: Any) -> Any:
url = buildSetPropertyUrl(
self.accessor, property_name, action)
Expand All @@ -61,4 +65,6 @@ def setProperty(self, property_name: str, action: str, data: Any) -> Any:

def fetch_all_features(self) -> Any:
url = f'/features/installations/{self.accessor.id}/gateways/{self.accessor.serial}/devices/{self.accessor.device_id}/features/'
if self._isGateway():
url = f'/features/installations/{self.accessor.id}/gateways/{self.accessor.serial}/features/'
return self.oauth_manager.get(url)
65 changes: 65 additions & 0 deletions tests/response/VitoconnectOpto1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"data": [
{
"apiVersion": 1,
"commands": {},
"feature": "gateway.devices",
"gatewayId": "################",
"isEnabled": true,
"isReady": true,
"properties": {
"devices": {
"type": "DeviceList",
"value": [
{
"fingerprint": "xxx",
"id": "gateway",
"modelId": "Heatbox1",
"modelVersion": "xxx",
"name": "Heatbox 1, Vitoconnect",
"roles": [
"type:gateway;VitoconnectOpto1",
"type:legacy"
],
"status": "online",
"type": "vitoconnect"
},
{
"fingerprint": "xxx",
"id": "0",
"modelId": "VScotHO1_40",
"modelVersion": "xxx",
"name": "VT 200 (HO1A / HO1B)",
"roles": [
"type:boiler",
"type:legacy",
"type:product;VScotHO1"
],
"status": "online",
"type": "heating"
}
]
}
},
"timestamp": "2023-12-25T04:01:00.448Z",
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/features/gateway.devices"
},
{
"apiVersion": 1,
"commands": {},
"feature": "gateway.wifi",
"gatewayId": "################",
"isEnabled": true,
"isReady": true,
"properties": {
"strength": {
"type": "number",
"unit": "",
"value": -69
}
},
"timestamp": "2023-12-26T20:44:41.417Z",
"uri": "https://api.viessmann.com/iot/v1/features/installations/#######/gateways/################/features/gateway.wifi"
}
]
}
11 changes: 11 additions & 0 deletions tests/test_PyViCareDeviceConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,14 @@ def test_autoDetect_Vitoair_FS_300E_asVentilation(self):
c = PyViCareDeviceConfig(self.service, "0", "E3_ViAir_300F", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("VentilationDevice", type(device_type).__name__)

def test_autoDetect_VitoconnectOpto1_asGateway(self):
c = PyViCareDeviceConfig(self.service, "0", "Heatbox1", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("Gateway", type(device_type).__name__)

def test_autoDetect_RoleGateway_asGateway(self):
self.service.hasRoles = has_roles(["type:gateway;VitoconnectOpto1"])
c = PyViCareDeviceConfig(self.service, "0", "Unknown", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("Gateway", type(device_type).__name__)
16 changes: 14 additions & 2 deletions tests/test_PyViCareService.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class PyViCareServiceTest(unittest.TestCase):

def setUp(self):
self.oauth_mock = Mock()
accessor = ViCareDeviceAccessor("[id]", "[serial]", "[device]")
self.service = ViCareService(self.oauth_mock, accessor, [])
self.accessor = ViCareDeviceAccessor("[id]", "[serial]", "[device]")
self.service = ViCareService(self.oauth_mock, self.accessor, [])

def test_getProperty(self):
self.service.getProperty("someprop")
Expand All @@ -25,3 +25,15 @@ def test_setProperty_string(self):
self.service.setProperty("someprop", "doaction", '{}')
self.oauth_mock.post.assert_called_once_with(
'/features/installations/[id]/gateways/[serial]/devices/[device]/features/someprop/commands/doaction', '{}')

def test_getProperty_gateway(self):
self.service = ViCareService(self.oauth_mock, self.accessor, ["type:gateway;VitoconnectOpto1"])
self.service.getProperty("someprop")
self.oauth_mock.get.assert_called_once_with(
'/features/installations/[id]/gateways/[serial]/features/someprop')

def test_fetch_all_features_gateway(self):
self.service = ViCareService(self.oauth_mock, self.accessor, ["type:gateway;VitoconnectOpto1"])
self.service.fetch_all_features()
self.oauth_mock.get.assert_called_once_with(
'/features/installations/[id]/gateways/[serial]/features/')
3 changes: 3 additions & 0 deletions tests/test_TestForMissingProperties.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ def test_missingProperties(self):
# Ignored for now as both are not documented in https://documentation.viessmann.com/static/iot/data-points
'device.messages.errors.raw',
'device.productIdentification',

# gateway
'gateway.devices', # not used

Check failure on line 66 in tests/test_TestForMissingProperties.py

View workflow job for this annotation

GitHub Actions / build (3.8)

E261 at least two spaces before inline comment

Check failure on line 66 in tests/test_TestForMissingProperties.py

View workflow job for this annotation

GitHub Actions / build (3.9)

E261 at least two spaces before inline comment
]

all_features = self.read_all_features()
Expand Down
14 changes: 14 additions & 0 deletions tests/test_VitoconnectOpto1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import unittest

from PyViCare.PyViCareGateway import Gateway
from tests.ViCareServiceMock import ViCareServiceMock


class VitoconnectOpto1(unittest.TestCase):
def setUp(self):
self.service = ViCareServiceMock('response/VitoconnectOpto1.json')
self.device = Gateway(self.service)

def test_getWifiSignalStrength(self):
self.assertEqual(
self.device.getWifiSignalStrength(), -69)

0 comments on commit f69604d

Please sign in to comment.