From 1d4ff2200aab284b5ee5656fb8792bbc10a25f6d Mon Sep 17 00:00:00 2001 From: Christoph Massmann Date: Thu, 14 Dec 2023 10:38:24 +0100 Subject: [PATCH] used new FritzHomeAutomation object Signed-off-by: Christoph Massmann --- requirements.txt | 2 +- src/conftest.py | 6 ++-- src/fritzbox_smart_home.py | 59 ++++++++++++++------------------ src/test_fritzbox_smart_home.py | 25 ++++++++++---- src/test_fritzconnection_mock.py | 10 +++--- 5 files changed, 54 insertions(+), 48 deletions(-) diff --git a/requirements.txt b/requirements.txt index e0fe74a..e9de2dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -fritzconnection>=1.3.0 +fritzconnection>=1.12.0 requests lxml \ No newline at end of file diff --git a/src/conftest.py b/src/conftest.py index 2568926..fa23e24 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -1,4 +1,4 @@ -from unittest.mock import patch,MagicMock +from unittest.mock import patch import pytest from test_response_mock import ResponseMock from test_fritzconnection_mock import FritzConnectionMock @@ -7,7 +7,7 @@ @pytest.fixture(autouse=True) -def fixture_version(request): # request param is fixture +def fixture_version(request): # request param is fixture with patch('requests.request', side_effect=ResponseMock) as mock_requests: mock_requests.side_effect.version = request.param if hasattr(request, "param") else None yield @@ -15,4 +15,4 @@ def fixture_version(request): # request param is fixture @pytest.fixture(autouse=True) def connection(request): - return FritzConnectionMock(version = request.param if hasattr(request, "param") else None) + return FritzConnectionMock(version=request.param if hasattr(request, "param") else None) diff --git a/src/fritzbox_smart_home.py b/src/fritzbox_smart_home.py index 397896e..41a0193 100755 --- a/src/fritzbox_smart_home.py +++ b/src/fritzbox_smart_home.py @@ -5,7 +5,7 @@ @see https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_homeauto.pdf """ -from fritzconnection import FritzConnection +from fritzconnection.lib.fritzhomeauto import FritzHomeAutomation from fritzbox_config import FritzboxConfig from fritzbox_munin_plugin_interface import MuninPluginInterface,main_handler @@ -13,43 +13,34 @@ class FritzboxSmartHome(MuninPluginInterface): __connection = None - def __init__(self, fritzbox_connection: FritzConnection): + def __init__(self, fritzbox_connection: FritzHomeAutomation): self.__connection = fritzbox_connection - def __retrieve_smart_home(self) -> []: - smart_home_data = [] - - for i in range(0, 20): - data = self.__connection.call_action('X_AVM-DE_Homeauto1', 'GetGenericDeviceInfos', arguments={'NewIndex': i}) - smart_home_data.append(data) - - return smart_home_data - def print_stats(self): - smart_home_data = self.__retrieve_smart_home() + smart_home_data = self.__connection.get_device_information_list() print("multigraph temperatures") for data in smart_home_data: if 'NewTemperatureIsValid' in data and data['NewTemperatureIsValid'] == 'VALID': - print (f"t{data['NewDeviceId']}.value {float(data['NewTemperatureCelsius']) / 10}") + print(f"t{data['NewDeviceId']}.value {float(data['NewTemperatureCelsius']) / 10}") print("multigraph energy") for data in smart_home_data: if 'NewMultimeterIsValid' in data and data['NewMultimeterIsValid'] == 'VALID': - print (f"e{data['NewDeviceId']}.value {data['NewMultimeterEnergy']}") + print(f"e{data['NewDeviceId']}.value {data['NewMultimeterEnergy']}") print("multigraph powers") for data in smart_home_data: if 'NewMultimeterIsValid' in data and data['NewMultimeterIsValid'] == 'VALID': - print (f"p{data['NewDeviceId']}.value {float(data['NewMultimeterPower']) / 100}") + print(f"p{data['NewDeviceId']}.value {float(data['NewMultimeterPower']) / 100}") print("multigraph states") for data in smart_home_data: if 'NewSwitchIsValid' in data and data['NewSwitchIsValid'] == 'VALID': state = 1 if 'NewSwitchState' in data and data['NewSwitchState'] == 'OFF': state = 0 - print (f"s{data['NewDeviceId']}.value {state}") + print(f"s{data['NewDeviceId']}.value {state}") def print_config(self): - smart_home_data = self.__retrieve_smart_home() + smart_home_data = self.__connection.get_device_information_list() print("multigraph temperatures") print("graph_title Smart Home temperature") print("graph_vlabel degrees Celsius") @@ -58,10 +49,10 @@ def print_config(self): for data in smart_home_data: if 'NewTemperatureIsValid' in data and data['NewTemperatureIsValid'] == 'VALID': - print (f"t{data['NewDeviceId']}.label {data['NewDeviceName']}") - print (f"t{data['NewDeviceId']}.type GAUGE") - print (f"t{data['NewDeviceId']}.graph LINE") - print (f"t{data['NewDeviceId']}.info Temperature [{data['NewProductName']}], Offset: {float(data['NewTemperatureOffset']) / 10}°C") + print(f"t{data['NewDeviceId']}.label {data['NewDeviceName']}") + print(f"t{data['NewDeviceId']}.type GAUGE") + print(f"t{data['NewDeviceId']}.graph LINE") + print(f"t{data['NewDeviceId']}.info Temperature [{data['NewProductName']}], Offset: {float(data['NewTemperatureOffset']) / 10}°C") print("multigraph energy") print("graph_title Smart Home energy consumption") @@ -71,10 +62,10 @@ def print_config(self): print("graph_period hour") for data in smart_home_data: if 'NewMultimeterIsValid' in data and data['NewMultimeterIsValid'] == 'VALID': - print (f"e{data['NewDeviceId']}.label {data['NewDeviceName']}") - print (f"e{data['NewDeviceId']}.type DERIVE") - print (f"e{data['NewDeviceId']}.graph LINE") - print (f"e{data['NewDeviceId']}.info Energy consumption (Wh) [{data['NewProductName']}]") + print(f"e{data['NewDeviceId']}.label {data['NewDeviceName']}") + print(f"e{data['NewDeviceId']}.type DERIVE") + print(f"e{data['NewDeviceId']}.graph LINE") + print(f"e{data['NewDeviceId']}.info Energy consumption (Wh) [{data['NewProductName']}]") print("multigraph powers") print("graph_title Smart Home powers") @@ -83,10 +74,10 @@ def print_config(self): print("graph_scale no") for data in smart_home_data: if 'NewMultimeterIsValid' in data and data['NewMultimeterIsValid'] == 'VALID': - print (f"p{data['NewDeviceId']}.label {data['NewDeviceName']}") - print (f"p{data['NewDeviceId']}.type GAUGE") - print (f"p{data['NewDeviceId']}.graph LINE") - print (f"p{data['NewDeviceId']}.info Power (W) [{data['NewProductName']}]") + print(f"p{data['NewDeviceId']}.label {data['NewDeviceName']}") + print(f"p{data['NewDeviceId']}.type GAUGE") + print(f"p{data['NewDeviceId']}.graph LINE") + print(f"p{data['NewDeviceId']}.info Power (W) [{data['NewProductName']}]") print("multigraph states") print("graph_title Smart Home switch states") @@ -95,12 +86,12 @@ def print_config(self): print("graph_scale no") for data in smart_home_data: if 'NewSwitchIsValid' in data and data['NewSwitchIsValid'] == 'VALID': - print (f"s{data['NewDeviceId']}.label {data['NewDeviceName']}") - print (f"s{data['NewDeviceId']}.type GAUGE") - print (f"s{data['NewDeviceId']}.graph LINE") - print (f"s{data['NewDeviceId']}.info Switch state [{data['NewProductName']}]") + print(f"s{data['NewDeviceId']}.label {data['NewDeviceName']}") + print(f"s{data['NewDeviceId']}.type GAUGE") + print(f"s{data['NewDeviceId']}.graph LINE") + print(f"s{data['NewDeviceId']}.info Switch state [{data['NewProductName']}]") if __name__ == '__main__': config = FritzboxConfig() - main_handler(FritzboxSmartHome(FritzConnection(address=config.server, user=config.user, password=config.password, use_tls=config.use_tls))) + main_handler(FritzboxSmartHome(FritzHomeAutomation(address=config.server, user=config.user, password=config.password, use_tls=config.use_tls))) diff --git a/src/test_fritzbox_smart_home.py b/src/test_fritzbox_smart_home.py index 29165db..809ac80 100644 --- a/src/test_fritzbox_smart_home.py +++ b/src/test_fritzbox_smart_home.py @@ -10,9 +10,9 @@ @pytest.mark.parametrize("connection", ["7590-7.57"], indirect=True) class TestFritzboxSmartHome: - def test_config(self, connection: MagicMock, capsys): # pylint: disable=unused-argument - smart_home = FritzboxSmartHome(connection) - smart_home.print_config() + def test_config(self, connection: MagicMock, capsys): # pylint: disable=unused-argument + sut = FritzboxSmartHome(connection) + sut.print_config() assert capsys.readouterr().out == """multigraph temperatures graph_title Smart Home temperature @@ -53,9 +53,9 @@ def test_config(self, connection: MagicMock, capsys): # pylint: disable=unused-a s16.info Switch state [FRITZ!DECT 210] """ - def test_smart_home(self, connection: MagicMock, capsys): # pylint: disable=unused-argument - uptime = FritzboxSmartHome(connection) - uptime.print_stats() + def test_smart_home(self, connection: MagicMock, capsys): # pylint: disable=unused-argument + sut = FritzboxSmartHome(connection) + sut.print_stats() assert capsys.readouterr().out == """multigraph temperatures t16.value 7.0 @@ -65,4 +65,17 @@ def test_smart_home(self, connection: MagicMock, capsys): # pylint: disable=unus p16.value 0.0 multigraph states s16.value 0 +""" + + def test_smart_home_empty_devices(self, capsys): # pylint: disable=unused-argument + connection = MagicMock() + connection.get_device_information_list.return_value = {} + + sut = FritzboxSmartHome(connection) + sut.print_stats() + + assert capsys.readouterr().out == """multigraph temperatures +multigraph energy +multigraph powers +multigraph states """ \ No newline at end of file diff --git a/src/test_fritzconnection_mock.py b/src/test_fritzconnection_mock.py index 05d4566..51b7c8e 100644 --- a/src/test_fritzconnection_mock.py +++ b/src/test_fritzconnection_mock.py @@ -8,15 +8,17 @@ class FritzConnectionMock: # pylint: disable=too-few-public-methods def __init__(self, version): self.version = version - def call_action(self, *args, **kwargs) -> {}: index = 0 if 'arguments' in kwargs and 'NewIndex' in kwargs['arguments']: index = kwargs['arguments']['NewIndex'] + json_object = self.get_device_information_list() + + return json_object[index] if len(json_object) > index else {} + + def get_device_information_list(self, *args, **kwargs) -> {}: file_name = 'smart_home_devices.json' file_dir = f"{os.path.dirname(__file__)}/fixtures/fritzbox{self.version}" with open(file_dir + "/" + file_name, "r", encoding="utf-8") as file: - json_object = json.load(file) - - return json_object[index] if len(json_object) > index else {} + return json.load(file)