From 0d993ccbcba88f8d29c08dc985975ba4a1e57ad5 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 4 Oct 2020 17:15:18 +0000 Subject: [PATCH 01/29] add syno system data and actions --- synology_dsm/api/core/system.py | 118 ++++++++++++++++++++++++++++++++ synology_dsm/synology_dsm.py | 18 +++++ 2 files changed, 136 insertions(+) create mode 100644 synology_dsm/api/core/system.py diff --git a/synology_dsm/api/core/system.py b/synology_dsm/api/core/system.py new file mode 100644 index 00000000..c9f1a2fb --- /dev/null +++ b/synology_dsm/api/core/system.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +"""DSM System data and actions.""" + + +class SynoCoreSystem(object): + """Class containing System data and actions.""" + + API_KEY = "SYNO.Core.System" + + def __init__(self, dsm): + self._dsm = dsm + self._data = {} + + def update(self): + """Updates System data.""" + raw_data = self._dsm.get(self.API_KEY, "info") + if raw_data: + self._data = raw_data["data"] + + ### get information + @property + def cpu_clock_speed(self): + """Gets System CPU clock speed.""" + return self._data.get('cpu_clock_speed', {}) + + @property + def cpu_cores(self): + """Gets System CPU cores.""" + return self._data.get('cpu_cores', {}) + + @property + def cpu_family(self): + """Gets System CPU family.""" + return self._data.get('cpu_family', {}) + + @property + def cpu_series(self): + """Gets System CPU series.""" + return self._data.get('cpu_series', {}) + + @property + def enabled_ntp(self): + """Gets System NTP state.""" + return self._data.get('enabled_ntp', {}) + + @property + def ntp_server(self): + """Gets System NTP server.""" + return self._data.get('ntp_server', {}) + + @property + def firmware_ver(self): + """Gets System firmware version.""" + return self._data.get('firmware_ver', {}) + + @property + def model(self): + """Gets System model.""" + return self._data.get('model', {}) + + @property + def ram_size(self): + """Gets System ram size.""" + return self._data.get('ram_size', {}) + + @property + def serial(self): + """Gets System serial number.""" + return self._data.get('serial', {}) + + @property + def sys_temp(self): + """Gets System temperature.""" + return self._data.get('sys_temp', {}) + + @property + def time(self): + """Gets System time.""" + return self._data.get('time', {}) + + @property + def time_zone(self): + """Gets System time zone.""" + return self._data.get('time_zone', {}) + + @property + def time_zone_desc(self): + """Gets System time zone description.""" + return self._data.get('time_zone_desc', {}) + + @property + def up_time(self): + """Gets System uptime.""" + return self._data.get('up_time', {}) + + @property + def usb_dev(self): + """Gets System connected usb devices.""" + return self._data.get('usb_dev', []) + + ### do system actions + def shutdown(self): + """Shutdown NAS.""" + res = self._dsm.get( + self.API_KEY, + "shutdown", + max_version=1, # shutdown method is only available on api version 1 + ) + return res + + def reboot(self): + """Reboot NAS.""" + res = self._dsm.get( + self.API_KEY, + "reboot", + max_version=1, # reboot method is only available on api version 1 + ) + return res diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 71cc4b44..af88eabd 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -22,6 +22,7 @@ from .api.core.security import SynoCoreSecurity from .api.core.utilization import SynoCoreUtilization from .api.core.share import SynoCoreShare +from .api.core.system import SynoCoreSystem from .api.download_station import SynoDownloadStation from .api.dsm.information import SynoDSMInformation from .api.dsm.network import SynoDSMNetwork @@ -79,6 +80,7 @@ def __init__( self._storage = None self._share = None self._surveillance = None + self._system = None # Build variables if use_https: @@ -325,6 +327,9 @@ def update(self, with_information=False, with_network=False): if self._surveillance: self._surveillance.update() + if self._system: + self._system.update() + def reset(self, api): """Reset an API to avoid fetching in on update.""" if isinstance(api, str): @@ -351,6 +356,9 @@ def reset(self, api): if api == SynoSurveillanceStation.API_KEY: self._surveillance = None return True + if api == SynoCoreSystem.API_KEY: + self._system = None + return True if isinstance(api, SynoDownloadStation): self._download = None return True @@ -366,6 +374,9 @@ def reset(self, api): if isinstance(api, SynoStorage): self._storage = None return True + if isinstance(api, SynoCoreSystem): + self._system = None + return True if isinstance(api, SynoSurveillanceStation): self._surveillance = None @@ -421,6 +432,13 @@ def share(self): self._share = SynoCoreShare(self) return self._share + @property + def system(self): + """Gets NAS system information.""" + if not self._system: + self._system = SynoCoreSystem(self) + return self._system + @property def surveillance_station(self): """Gets NAS SurveillanceStation.""" From 1041b769b4bb10843d7c4510bc3f882ad9a91c24 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 4 Oct 2020 17:20:17 +0000 Subject: [PATCH 02/29] add system usage examples --- README.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.rst b/README.rst index 9c3fc46c..92eb787f 100644 --- a/README.rst +++ b/README.rst @@ -190,6 +190,22 @@ Surveillance Station usage surveillance.set_home_mode(True) +System usage +-------------------------- + +.. code-block:: python + + from synology_dsm import SynologyDSM + + api = SynologyDSM("", "", "", "") + system = api.system + + # Reboot NAS + system.reboot() + + # Shutdown NAS + system.shutdown() + Credits / Special Thanks ======================== From 9e91ec029cbcab5aec24bc5272cfbaa75a6ce4c4 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 4 Oct 2020 20:28:15 +0000 Subject: [PATCH 03/29] add upgrade information --- README.rst | 14 ++++++++++++++ synology_dsm/api/core/upgrade.py | 26 ++++++++++++++++++++++++++ synology_dsm/synology_dsm.py | 15 +++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 synology_dsm/api/core/upgrade.py diff --git a/README.rst b/README.rst index 92eb787f..9bbe276a 100644 --- a/README.rst +++ b/README.rst @@ -207,6 +207,20 @@ System usage system.shutdown() +Upgrade usage +-------------------------- + +.. code-block:: python + + from synology_dsm import SynologyDSM + + api = SynologyDSM("", "", "", "") + upgrade = api.upgrade + + # check if DSM update is available + if upgrade.update_available: + do something ... + Credits / Special Thanks ======================== - https://github.com/florianeinfalt diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py new file mode 100644 index 00000000..0f8542ae --- /dev/null +++ b/synology_dsm/api/core/upgrade.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +"""DSM Upgrade data and actions.""" + + +class SynoCoreUpgrade(object): + """Class containing upgrade data and actions.""" + + API_BASE_KEY = "SYNO.Core.Upgrade" + API_SERVER_KEY = API_BASE_KEY + ".Server" + + def __init__(self, dsm): + self._dsm = dsm + self._data = {} + + def update(self): + """Updates Upgrade data.""" + raw_data = self._dsm.get(self.API_SERVER_KEY, "check") + if raw_data: + self._data.update(raw_data["data"]) + + @property + def update_available(self): + """Gets all Upgrade info.""" + if self._data.get("update", None): + return bool(self._data["update"]["available"]) + return None diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index af88eabd..39c8b607 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -21,6 +21,7 @@ from .api.core.security import SynoCoreSecurity from .api.core.utilization import SynoCoreUtilization +from .api.core.upgrade import SynoCoreUpgrade from .api.core.share import SynoCoreShare from .api.core.system import SynoCoreSystem from .api.download_station import SynoDownloadStation @@ -81,6 +82,7 @@ def __init__( self._share = None self._surveillance = None self._system = None + self._upgrade = None # Build variables if use_https: @@ -330,6 +332,9 @@ def update(self, with_information=False, with_network=False): if self._system: self._system.update() + if self._upgrade: + self._upgrade.update() + def reset(self, api): """Reset an API to avoid fetching in on update.""" if isinstance(api, str): @@ -359,6 +364,9 @@ def reset(self, api): if api == SynoCoreSystem.API_KEY: self._system = None return True + if api == SynoCoreUpgrade.API_BASE_KEY: + self._upgrade = None + return True if isinstance(api, SynoDownloadStation): self._download = None return True @@ -418,6 +426,13 @@ def utilisation(self): self._utilisation = SynoCoreUtilization(self) return self._utilisation + @property + def upgrade(self): + """Gets NAS upgrade informations.""" + if not self._upgrade: + self._upgrade = SynoCoreUpgrade(self) + return self._upgrade + @property def storage(self): """Gets NAS storage informations.""" From ce8c2c4e64dc1bb01c2a8dd07cb41b6d1f152922 Mon Sep 17 00:00:00 2001 From: Quentame Date: Wed, 14 Oct 2020 23:58:38 +0200 Subject: [PATCH 04/29] Fix default login Exception (#73) --- synology_dsm/exceptions.py | 13 +++++++------ synology_dsm/synology_dsm.py | 7 +++++-- tests/__init__.py | 6 ++++++ tests/test_synology_dsm.py | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/synology_dsm/exceptions.py b/synology_dsm/exceptions.py index 377d40f7..2a0c4b45 100644 --- a/synology_dsm/exceptions.py +++ b/synology_dsm/exceptions.py @@ -51,39 +51,40 @@ def __init__(self, api, code, details): # Login class SynologyDSMLoginFailedException(SynologyDSMException): """Failed to login exception.""" - pass + def __init__(self, code, details=None): + super(SynologyDSMLoginFailedException, self).__init__(API_AUTH, code, details) class SynologyDSMLoginInvalidException(SynologyDSMLoginFailedException): """Invalid password & not admin account exception.""" def __init__(self, username): message = "Invalid password or not admin account: %s" % username - super(SynologyDSMLoginInvalidException, self).__init__(API_AUTH, 400, message) + super(SynologyDSMLoginInvalidException, self).__init__(400, message) class SynologyDSMLoginDisabledAccountException(SynologyDSMLoginFailedException): """Guest & disabled account exception.""" def __init__(self, username): message = "Guest or disabled account: %s" % username - super(SynologyDSMLoginDisabledAccountException, self).__init__(API_AUTH, 401, message) + super(SynologyDSMLoginDisabledAccountException, self).__init__(401, message) class SynologyDSMLoginPermissionDeniedException(SynologyDSMLoginFailedException): """No access to login exception.""" def __init__(self, username): message = "Permission denied for account: %s" % username - super(SynologyDSMLoginPermissionDeniedException, self).__init__(API_AUTH, 402, message) + super(SynologyDSMLoginPermissionDeniedException, self).__init__(402, message) class SynologyDSMLogin2SARequiredException(SynologyDSMLoginFailedException): """2SA required to login exception.""" def __init__(self, username): message = "Two-step authentication required for account: %s" % username - super(SynologyDSMLogin2SARequiredException, self).__init__(API_AUTH, 403, message) + super(SynologyDSMLogin2SARequiredException, self).__init__(403, message) class SynologyDSMLogin2SAFailedException(SynologyDSMLoginFailedException): """2SA code failed exception.""" def __init__(self): message = "Two-step authentication failed, retry with a new pass code" - super(SynologyDSMLogin2SAFailedException, self).__init__(API_AUTH, 404, message) + super(SynologyDSMLogin2SAFailedException, self).__init__(404, message) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 71cc4b44..0e12b3e7 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -156,9 +156,12 @@ def login(self, otp_code=None): 401: SynologyDSMLoginDisabledAccountException(self.username), 402: SynologyDSMLoginPermissionDeniedException(self.username), 403: SynologyDSMLogin2SARequiredException(self.username), - 404: SynologyDSMLogin2SAFailedException, + 404: SynologyDSMLogin2SAFailedException(), } - raise switcher.get(result["error"]["code"], SynologyDSMLoginFailedException) + raise switcher.get( + result["error"]["code"], + SynologyDSMLoginFailedException(result["error"]["code"], self.username), + ) # Parse result if valid self._session_id = result["data"]["sid"] diff --git a/tests/__init__.py b/tests/__init__.py index be29abf3..4c3cd9a8 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -19,6 +19,7 @@ from .const import ( ERROR_INSUFFICIENT_USER_PRIVILEGE, ERROR_AUTH_INVALID_CREDENTIALS, + ERROR_AUTH_MAX_TRIES, ERROR_AUTH_OTP_AUTHENTICATE_FAILED, DEVICE_TOKEN, ) @@ -105,6 +106,8 @@ VALID_PASSWORD = "valid_password" VALID_OTP = "123456" +USER_MAX_TRY = "user_max" + class SynologyDSMMock(SynologyDSM): """Mocked SynologyDSM.""" @@ -192,6 +195,9 @@ def _execute_request(self, method, url, params, **kwargs): if VALID_USER in url and VALID_PASSWORD in url: return API_SWITCHER[self.dsm_version]["AUTH_LOGIN"] + if USER_MAX_TRY in url: + return ERROR_AUTH_MAX_TRIES + return ERROR_AUTH_INVALID_CREDENTIALS if self.API_URI in url: diff --git a/tests/test_synology_dsm.py b/tests/test_synology_dsm.py index 1461e49b..03bebbd6 100644 --- a/tests/test_synology_dsm.py +++ b/tests/test_synology_dsm.py @@ -12,6 +12,7 @@ SynologyDSMLoginInvalidException, SynologyDSMLogin2SARequiredException, SynologyDSMLogin2SAFailedException, + SynologyDSMLoginFailedException, ) from synology_dsm.const import API_AUTH, API_INFO @@ -24,6 +25,7 @@ VALID_PASSWORD, VALID_USER, VALID_USER_2SA, + USER_MAX_TRY, ) from .const import SESSION_ID, DEVICE_TOKEN, SYNO_TOKEN @@ -222,6 +224,20 @@ def test_login_2sa_failed(self): assert api._syno_token is None assert api._device_token is None + def test_login_basic_failed(self): + """Test basic failed login.""" + api = SynologyDSMMock( + VALID_HOST, VALID_PORT, USER_MAX_TRY, VALID_PASSWORD, VALID_SSL + ) + + with pytest.raises(SynologyDSMLoginFailedException) as error: + api.login() + error_value = error.value.args[0] + assert error_value["api"] == "SYNO.API.Auth" + assert error_value["code"] == 407 + assert error_value["reason"] == "Max Tries (if auto blocking is set to true)" + assert error_value["details"] == USER_MAX_TRY + def test_request_timeout(self): """Test request timeout.""" api = SynologyDSMMock( From 212f029478e55500f43ba42196cecc82bdc97d10 Mon Sep 17 00:00:00 2001 From: Quentame Date: Thu, 15 Oct 2020 00:48:35 +0200 Subject: [PATCH 05/29] Migrate to Python 3.6+ (#70) * Migrate to Python 3.6+ Drop support of Python < 3.6 - remove six + future deps + usage - update deps - remove encoding - remove (object) * Fix pylint - pip3 super() style - remove simplejson dep + usage * Black format * lint setup * Travix CI py version * Use f string * Basic Typing * Revert setup version bump --- .travis.yml | 6 +- requirements.txt | 8 +- requirements_test.txt | 3 +- scripts/check_format.sh | 16 ---- setup.py | 14 +-- synology_dsm/api/core/security.py | 3 +- synology_dsm/api/core/share.py | 3 +- synology_dsm/api/core/utilization.py | 3 +- synology_dsm/api/download_station/__init__.py | 2 +- synology_dsm/api/download_station/task.py | 2 +- synology_dsm/api/dsm/information.py | 3 +- synology_dsm/api/dsm/network.py | 3 +- synology_dsm/api/storage/storage.py | 4 +- .../api/surveillance_station/__init__.py | 6 +- .../api/surveillance_station/camera.py | 4 +- synology_dsm/const.py | 1 - synology_dsm/exceptions.py | 30 +++--- synology_dsm/helpers.py | 3 +- synology_dsm/synology_dsm.py | 92 +++++++++---------- tests/__init__.py | 17 ++-- .../dsm_5/core/const_5_core_utilization.py | 1 - tests/api_data/dsm_5/dsm/const_5_dsm_info.py | 1 - .../api_data/dsm_5/dsm/const_5_dsm_network.py | 1 - .../dsm_5/storage/const_5_storage_storage.py | 13 ++- .../dsm_6/core/const_6_core_security.py | 1 - .../api_data/dsm_6/core/const_6_core_share.py | 1 - .../dsm_6/core/const_6_core_utilization.py | 1 - .../const_6_download_station_info.py | 1 - .../const_6_download_station_stat.py | 1 - .../const_6_download_station_task.py | 1 - tests/api_data/dsm_6/dsm/const_6_dsm_info.py | 1 - .../api_data/dsm_6/dsm/const_6_dsm_network.py | 1 - .../dsm_6/storage/const_6_storage_storage.py | 76 ++++++++++++--- .../const_6_surveillance_station_camera.py | 1 - .../const_6_surveillance_station_home_mode.py | 1 - tests/const.py | 1 - tests/test_synology_dsm.py | 1 - tests/test_synology_dsm_5.py | 1 - 38 files changed, 165 insertions(+), 163 deletions(-) delete mode 100755 scripts/check_format.sh diff --git a/.travis.yml b/.travis.yml index be5944a2..c1a73ea7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,8 @@ dist: xenial language: python python: - - 2.7 - - 3.4 + - 3.6 + - 3.7 - 3.8 cache: pip: true @@ -17,7 +17,7 @@ install: - python setup.py sdist before_script: - pylint synology_dsm tests - - ./scripts/check_format.sh + - black --check --fast . script: - py.test diff --git a/requirements.txt b/requirements.txt index 6ff91026..ca3f09a8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,3 @@ -requests>=2.20.0 -urllib3>=1.24.3,<1.25 -six>=1.14.0 -future>=0.18.2 -simplejson>=3.16.0 +requests>=2.24.0 +# Constrain urllib3 to ensure we deal with CVE-2019-11236 & CVE-2019-11324 +urllib3>=1.24.3 diff --git a/requirements_test.txt b/requirements_test.txt index f15a8e3d..d69693d8 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,3 +1,4 @@ pytest -pylint>=1.9.5,<=2.4.4 +pylint>=2.6.0 pylint-strict-informational==0.1 +black==20.8b1 diff --git a/scripts/check_format.sh b/scripts/check_format.sh deleted file mode 100755 index 32522cf2..00000000 --- a/scripts/check_format.sh +++ /dev/null @@ -1,16 +0,0 @@ -./scripts/common.sh - -if ! hash python3; then - echo "python3 is not installed" - exit 0 -fi - -ver=$(python3 -V 2>&1 | sed 's/.* \([0-9]\).\([0-9]\).*/\1\2/') -if [ "$ver" -lt "36" ]; then - echo "This script requires python 3.6 or greater" - exit 0 -fi - -pip install black==19.10b0 - -black --check --fast . diff --git a/setup.py b/setup.py index 058c8ccd..5f5a3411 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- +"""Synology DSM setup.""" # NOTE(ProtoThis) Guidelines for Major.Minor.Micro # - Major means an API contract change @@ -7,7 +7,6 @@ # - Micro means change of any kind (unless significant enough for a minor/major). from setuptools import setup, find_packages -from codecs import open REPO_URL = "https://github.com/ProtoThis/python-synology" VERSION = "0.9.0" @@ -25,23 +24,24 @@ download_url=REPO_URL + "/tarball/" + VERSION, description="Python API for communication with Synology DSM", long_description=long_description, - author="FG van Zeelst (ProtoThis)", + author="Quentin POLLET (Quentame) & FG van Zeelst (ProtoThis)", packages=find_packages(include=["synology_dsm*"]), install_requires=required, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", + python_requires=">=3.6", license="MIT", classifiers=[ + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Software Development :: Libraries", ], keywords=["synology-dsm", "synology"], ) diff --git a/synology_dsm/api/core/security.py b/synology_dsm/api/core/security.py index 12ece8f0..fcc074c1 100644 --- a/synology_dsm/api/core/security.py +++ b/synology_dsm/api/core/security.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM Security data.""" -class SynoCoreSecurity(object): +class SynoCoreSecurity: """Class containing Security data.""" API_KEY = "SYNO.Core.SecurityScan.Status" diff --git a/synology_dsm/api/core/share.py b/synology_dsm/api/core/share.py index 6e38f40c..bcc5ad56 100644 --- a/synology_dsm/api/core/share.py +++ b/synology_dsm/api/core/share.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- """Shared Folders data.""" from synology_dsm.helpers import SynoFormatHelper -class SynoCoreShare(object): +class SynoCoreShare: """Class containing Share data.""" API_KEY = "SYNO.Core.Share" diff --git a/synology_dsm/api/core/utilization.py b/synology_dsm/api/core/utilization.py index d42ff874..e768c51e 100644 --- a/synology_dsm/api/core/utilization.py +++ b/synology_dsm/api/core/utilization.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- """DSM Utilization data.""" from synology_dsm.helpers import SynoFormatHelper -class SynoCoreUtilization(object): +class SynoCoreUtilization: """Class containing Utilization data.""" API_KEY = "SYNO.Core.System.Utilization" diff --git a/synology_dsm/api/download_station/__init__.py b/synology_dsm/api/download_station/__init__.py index 13d7dce1..94866dd5 100644 --- a/synology_dsm/api/download_station/__init__.py +++ b/synology_dsm/api/download_station/__init__.py @@ -2,7 +2,7 @@ from .task import SynoDownloadTask -class SynoDownloadStation(object): +class SynoDownloadStation: """An implementation of a Synology DownloadStation.""" API_KEY = "SYNO.DownloadStation.*" diff --git a/synology_dsm/api/download_station/task.py b/synology_dsm/api/download_station/task.py index 7a07561b..b4b6a6cb 100644 --- a/synology_dsm/api/download_station/task.py +++ b/synology_dsm/api/download_station/task.py @@ -1,7 +1,7 @@ """DownloadStation task.""" -class SynoDownloadTask(object): +class SynoDownloadTask: """An representation of a Synology DownloadStation task.""" def __init__(self, data): diff --git a/synology_dsm/api/dsm/information.py b/synology_dsm/api/dsm/information.py index 0c3a6b24..7c73cc9e 100644 --- a/synology_dsm/api/dsm/information.py +++ b/synology_dsm/api/dsm/information.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM Information data.""" -class SynoDSMInformation(object): +class SynoDSMInformation: """Class containing Information data.""" API_KEY = "SYNO.DSM.Info" diff --git a/synology_dsm/api/dsm/network.py b/synology_dsm/api/dsm/network.py index 7a214025..451d111c 100644 --- a/synology_dsm/api/dsm/network.py +++ b/synology_dsm/api/dsm/network.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM Network data.""" -class SynoDSMNetwork(object): +class SynoDSMNetwork: """Class containing Network data.""" API_KEY = "SYNO.DSM.Network" diff --git a/synology_dsm/api/storage/storage.py b/synology_dsm/api/storage/storage.py index 0eb9d3b2..ed2ce661 100644 --- a/synology_dsm/api/storage/storage.py +++ b/synology_dsm/api/storage/storage.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- """DSM Storage data.""" -from __future__ import division from synology_dsm.helpers import SynoFormatHelper -class SynoStorage(object): +class SynoStorage: """Class containing Storage data.""" API_KEY = "SYNO.Storage.CGI.Storage" diff --git a/synology_dsm/api/surveillance_station/__init__.py b/synology_dsm/api/surveillance_station/__init__.py index 112d3797..047284de 100644 --- a/synology_dsm/api/surveillance_station/__init__.py +++ b/synology_dsm/api/surveillance_station/__init__.py @@ -5,7 +5,7 @@ from .const import MOTION_DETECTION_BY_SURVEILLANCE, MOTION_DETECTION_DISABLED -class SynoSurveillanceStation(object): +class SynoSurveillanceStation: """An implementation of a Synology SurveillanceStation.""" API_KEY = "SYNO.SurveillanceStation.*" @@ -37,12 +37,12 @@ def update(self): )["data"] ) - live_view_data = self._dsm.get( + live_view_datas = self._dsm.get( self.CAMERA_API_KEY, "GetLiveViewPath", {"idList": ",".join(str(k) for k in self._cameras_by_id)}, )["data"] - for live_view_data in live_view_data: + for live_view_data in live_view_datas: self._cameras_by_id[live_view_data["id"]].live_view.update(live_view_data) # Global diff --git a/synology_dsm/api/surveillance_station/camera.py b/synology_dsm/api/surveillance_station/camera.py index 5096a03f..0c32812e 100644 --- a/synology_dsm/api/surveillance_station/camera.py +++ b/synology_dsm/api/surveillance_station/camera.py @@ -2,7 +2,7 @@ from .const import RECORDING_STATUS, MOTION_DETECTION_DISABLED -class SynoCamera(object): +class SynoCamera: """An representation of a Synology SurveillanceStation camera.""" def __init__(self, data, live_view_data=None): @@ -62,7 +62,7 @@ def is_recording(self): return self._data["recStatus"] in RECORDING_STATUS -class SynoCameraLiveView(object): +class SynoCameraLiveView: """An representation of a Synology SurveillanceStation camera live view.""" def __init__(self, data): diff --git a/synology_dsm/const.py b/synology_dsm/const.py index a471e452..9d4609b9 100644 --- a/synology_dsm/const.py +++ b/synology_dsm/const.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Library constants.""" # APIs diff --git a/synology_dsm/exceptions.py b/synology_dsm/exceptions.py index 2a0c4b45..799fdc99 100644 --- a/synology_dsm/exceptions.py +++ b/synology_dsm/exceptions.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Library exceptions.""" from .const import API_AUTH, ERROR_AUTH, ERROR_COMMON, ERROR_DOWNLOAD_SEARCH, ERROR_DOWNLOAD_TASK, ERROR_FILE, ERROR_SURVEILLANCE, ERROR_VIRTUALIZATION @@ -24,7 +23,7 @@ def __init__(self, api, code, details=None): reason = "Unknown" error_message={"api": api, "code": code, "reason": reason, "details": details} - super(SynologyDSMException, self).__init__(error_message) + super().__init__(error_message) # Request class SynologyDSMRequestException(SynologyDSMException): @@ -34,57 +33,56 @@ def __init__(self, exception): ex_reason = exception.args[0] if hasattr(exception.args[0], "reason"): ex_reason = exception.args[0].reason - message = "%s = %s" % (ex_class, ex_reason) - super(SynologyDSMRequestException, self).__init__(None, -1, message) + super().__init__(None, -1, f"{ex_class} = {ex_reason}") # API class SynologyDSMAPINotExistsException(SynologyDSMException): """API not exists exception.""" def __init__(self, api): - super(SynologyDSMAPINotExistsException, self).__init__(api, -2, "API %s does not exists" % api) + super().__init__(api, -2, f"API {api} does not exists") class SynologyDSMAPIErrorException(SynologyDSMException): """API returns an error exception.""" def __init__(self, api, code, details): - super(SynologyDSMAPIErrorException, self).__init__(api, code, details) + super().__init__(api, code, details) # Login class SynologyDSMLoginFailedException(SynologyDSMException): """Failed to login exception.""" def __init__(self, code, details=None): - super(SynologyDSMLoginFailedException, self).__init__(API_AUTH, code, details) + super().__init__(API_AUTH, code, details) class SynologyDSMLoginInvalidException(SynologyDSMLoginFailedException): """Invalid password & not admin account exception.""" def __init__(self, username): - message = "Invalid password or not admin account: %s" % username - super(SynologyDSMLoginInvalidException, self).__init__(400, message) + message = f"Invalid password or not admin account: {username}" + super().__init__(400, message) class SynologyDSMLoginDisabledAccountException(SynologyDSMLoginFailedException): """Guest & disabled account exception.""" def __init__(self, username): - message = "Guest or disabled account: %s" % username - super(SynologyDSMLoginDisabledAccountException, self).__init__(401, message) + message = f"Guest or disabled account: {username}" + super().__init__(401, message) class SynologyDSMLoginPermissionDeniedException(SynologyDSMLoginFailedException): """No access to login exception.""" def __init__(self, username): - message = "Permission denied for account: %s" % username - super(SynologyDSMLoginPermissionDeniedException, self).__init__(402, message) + message = f"Permission denied for account: {username}" + super().__init__(402, message) class SynologyDSMLogin2SARequiredException(SynologyDSMLoginFailedException): """2SA required to login exception.""" def __init__(self, username): - message = "Two-step authentication required for account: %s" % username - super(SynologyDSMLogin2SARequiredException, self).__init__(403, message) + message = f"Two-step authentication required for account: {username}" + super().__init__(403, message) class SynologyDSMLogin2SAFailedException(SynologyDSMLoginFailedException): """2SA code failed exception.""" def __init__(self): message = "Two-step authentication failed, retry with a new pass code" - super(SynologyDSMLogin2SAFailedException, self).__init__(404, message) + super().__init__(404, message) diff --git a/synology_dsm/helpers.py b/synology_dsm/helpers.py index e7647f45..8098771e 100644 --- a/synology_dsm/helpers.py +++ b/synology_dsm/helpers.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """Helpers.""" -class SynoFormatHelper(object): +class SynoFormatHelper: """Class containing various formatting functions.""" @staticmethod diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 0e12b3e7..8ac0506a 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -1,11 +1,11 @@ -# -*- coding: utf-8 -*- """Class to interact with Synology DSM.""" +from json import JSONDecodeError +from urllib.parse import quote import socket + import urllib3 -import six from requests import Session from requests.exceptions import RequestException -from simplejson.errors import JSONDecodeError from .exceptions import ( SynologyDSMAPIErrorException, @@ -29,13 +29,8 @@ from .api.surveillance_station import SynoSurveillanceStation from .const import API_AUTH, API_INFO -if six.PY2: - from future.moves.urllib.parse import quote -else: - from urllib.parse import quote # pylint: disable=import-error,no-name-in-module - -class SynologyDSM(object): +class SynologyDSM: """Class containing the main Synology DSM functions.""" DSM_5_WEIRD_URL_API = [ @@ -44,14 +39,14 @@ class SynologyDSM(object): def __init__( self, - dsm_ip, - dsm_port, - username, - password, - use_https=False, - timeout=None, - device_token=None, - debugmode=False, + dsm_ip: str, + dsm_port: int, + username: str, + password: str, + use_https: bool = False, + timeout: int = None, + device_token: str = None, + debugmode: bool = False, ): self.username = username self._password = password @@ -86,16 +81,16 @@ def __init__( # disable SSL warnings due to the auto-genenerated cert urllib3.disable_warnings() - self._base_url = "https://%s:%s" % (dsm_ip, dsm_port) + self._base_url = f"https://{dsm_ip}:{dsm_port}" else: - self._base_url = "http://%s:%s" % (dsm_ip, dsm_port) + self._base_url = f"http://{dsm_ip}:{dsm_port}" - def _debuglog(self, message): + def _debuglog(self, message: str): """Outputs message if debug mode is enabled.""" if self._debugmode: print("DEBUG: " + message) - def _is_weird_api_url(self, api): + def _is_weird_api_url(self, api: str) -> bool: """Returns True if the API URL is not common (nas_base_url/webapi/path?params) [Only handles DSM 5 for now].""" return ( api in self.DSM_5_WEIRD_URL_API @@ -104,15 +99,12 @@ def _is_weird_api_url(self, api): and int(self._information.version) < 7321 # < DSM 6 ) - def _build_url(self, api): + def _build_url(self, api: str) -> str: if self._is_weird_api_url(api): if api == SynoStorage.API_KEY: - return ( - "%s/webman/modules/StorageManager/storagehandler.cgi?" - % self._base_url - ) + return f"{self._base_url}/webman/modules/StorageManager/storagehandler.cgi?" - return "%s/webapi/%s?" % (self._base_url, self.apis[api]["path"]) + return f"{self._base_url}/webapi/{self.apis[api]['path']}?" def discover_apis(self): """Retreives available API infos from the NAS.""" @@ -125,7 +117,7 @@ def apis(self): """Gets available API infos from the NAS.""" return self._apis - def login(self, otp_code=None): + def login(self, otp_code: str = None): """Create a logged session.""" # First reset the session self._debuglog("Creating new session") @@ -180,20 +172,26 @@ def login(self, otp_code=None): return True @property - def device_token(self): + def device_token(self) -> str: """Gets the device token to remember the 2SA access was granted on this device.""" return self._device_token - def get(self, api, method, params=None, **kwargs): + def get(self, api: str, method: str, params: dict = None, **kwargs): """Handles API GET request.""" return self._request("GET", api, method, params, **kwargs) - def post(self, api, method, params=None, **kwargs): + def post(self, api: str, method: str, params: dict = None, **kwargs): """Handles API POST request.""" return self._request("POST", api, method, params, **kwargs) def _request( - self, request_method, api, method, params=None, retry_once=True, **kwargs + self, + request_method: str, + api: str, + method: str, + params: dict = None, + retry_once: bool = True, + **kwargs ): """Handles API request.""" # Discover existing APIs @@ -252,17 +250,13 @@ def _request( return response - def _execute_request(self, method, url, params, **kwargs): + def _execute_request(self, method: str, url: str, params: dict, **kwargs): """Function to execute and handle a request.""" # Execute Request try: if method == "GET": - if six.PY2: - items = params.iteritems() - else: - items = params.items() encoded_params = "&".join( - "%s=%s" % (key, quote(str(value))) for key, value in items + f"{key}={quote(str(value))}" for key, value in params.items() ) response = self._session.get( url, params=encoded_params, timeout=self._timeout, **kwargs @@ -300,9 +294,9 @@ def _execute_request(self, method, url, params, **kwargs): raise RequestException(response) except (RequestException, JSONDecodeError) as exp: - raise SynologyDSMRequestException(exp) + raise SynologyDSMRequestException(exp) from exp - def update(self, with_information=False, with_network=False): + def update(self, with_information: bool = False, with_network: bool = False): """Updates the various instanced modules.""" if self._download: self._download.update() @@ -328,7 +322,7 @@ def update(self, with_information=False, with_network=False): if self._surveillance: self._surveillance.update() - def reset(self, api): + def reset(self, api: any) -> bool: """Reset an API to avoid fetching in on update.""" if isinstance(api, str): if api in ("information", SynoDSMInformation.API_KEY): @@ -376,56 +370,56 @@ def reset(self, api): return False @property - def download_station(self): + def download_station(self) -> SynoDownloadStation: """Gets NAS DownloadStation.""" if not self._download: self._download = SynoDownloadStation(self) return self._download @property - def information(self): + def information(self) -> SynoDSMInformation: """Gets NAS informations.""" if not self._information: self._information = SynoDSMInformation(self) return self._information @property - def network(self): + def network(self) -> SynoDSMNetwork: """Gets NAS network informations.""" if not self._network: self._network = SynoDSMNetwork(self) return self._network @property - def security(self): + def security(self) -> SynoCoreSecurity: """Gets NAS security informations.""" if not self._security: self._security = SynoCoreSecurity(self) return self._security @property - def utilisation(self): + def utilisation(self) -> SynoCoreUtilization: """Gets NAS utilisation informations.""" if not self._utilisation: self._utilisation = SynoCoreUtilization(self) return self._utilisation @property - def storage(self): + def storage(self) -> SynoStorage: """Gets NAS storage informations.""" if not self._storage: self._storage = SynoStorage(self) return self._storage @property - def share(self): + def share(self) -> SynoCoreShare: """Gets NAS shares information.""" if not self._share: self._share = SynoCoreShare(self) return self._share @property - def surveillance_station(self): + def surveillance_station(self) -> SynoSurveillanceStation: """Gets NAS SurveillanceStation.""" if not self._surveillance: self._surveillance = SynoSurveillanceStation(self) diff --git a/tests/__init__.py b/tests/__init__.py index 4c3cd9a8..a7356fbe 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- """Library tests.""" -import six +from json import JSONDecodeError +from urllib.parse import urlencode + from requests.exceptions import ConnectionError as ConnError, RequestException, SSLError -from simplejson.errors import JSONDecodeError from synology_dsm import SynologyDSM from synology_dsm.exceptions import SynologyDSMRequestException @@ -71,7 +71,9 @@ "DSM_INFORMATION": DSM_5_DSM_INFORMATION, "DSM_NETWORK": DSM_5_DSM_NETWORK, "CORE_UTILIZATION": DSM_5_CORE_UTILIZATION, - "STORAGE_STORAGE": {"RAID": DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL,}, + "STORAGE_STORAGE": { + "RAID": DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL, + }, }, 6: { "API_INFO": DSM_6_API_INFO, @@ -93,11 +95,6 @@ } -if six.PY2: - from future.moves.urllib.parse import urlencode -else: - from urllib.parse import urlencode # pylint: disable=import-error,no-name-in-module - VALID_HOST = "nas.mywebsite.me" VALID_PORT = "443" VALID_SSL = True @@ -161,7 +158,7 @@ def _execute_request(self, method, url, params, **kwargs): if VALID_PORT not in url and "https" not in url: raise SynologyDSMRequestException( - JSONDecodeError("Expecting value", "document", 0, None) + JSONDecodeError("Expecting value", "document", 0) ) if VALID_PORT not in url: diff --git a/tests/api_data/dsm_5/core/const_5_core_utilization.py b/tests/api_data/dsm_5/core/const_5_core_utilization.py index 94b201e0..9abce7da 100644 --- a/tests/api_data/dsm_5/core/const_5_core_utilization.py +++ b/tests/api_data/dsm_5/core/const_5_core_utilization.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 5 SYNO.Core.System.Utilization data.""" DSM_5_CORE_UTILIZATION = { diff --git a/tests/api_data/dsm_5/dsm/const_5_dsm_info.py b/tests/api_data/dsm_5/dsm/const_5_dsm_info.py index 453bc8cb..6fd6d059 100644 --- a/tests/api_data/dsm_5/dsm/const_5_dsm_info.py +++ b/tests/api_data/dsm_5/dsm/const_5_dsm_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 5 SYNO.DSM.Info data.""" DSM_5_DSM_INFORMATION_DS410J = { diff --git a/tests/api_data/dsm_5/dsm/const_5_dsm_network.py b/tests/api_data/dsm_5/dsm/const_5_dsm_network.py index 98e272bc..2ab5f3cb 100644 --- a/tests/api_data/dsm_5/dsm/const_5_dsm_network.py +++ b/tests/api_data/dsm_5/dsm/const_5_dsm_network.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 5 SYNO.DSM.Network data.""" DSM_5_DSM_NETWORK = { diff --git a/tests/api_data/dsm_5/storage/const_5_storage_storage.py b/tests/api_data/dsm_5/storage/const_5_storage_storage.py index 674fed66..9af04897 100644 --- a/tests/api_data/dsm_5/storage/const_5_storage_storage.py +++ b/tests/api_data/dsm_5/storage/const_5_storage_storage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 5 SYNO.Storage.CGI.Storage data.""" from tests.const import UNIQUE_KEY @@ -253,10 +252,18 @@ "vol_path": "/volume1", "vspace_can_do": { "drbd": { - "resize": {"can_do": False, "errCode": 53504, "stopService": False,} + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } }, "flashcache": { - "apply": {"can_do": False, "errCode": 53504, "stopService": False,}, + "apply": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, "remove": { "can_do": False, "errCode": 53504, diff --git a/tests/api_data/dsm_6/core/const_6_core_security.py b/tests/api_data/dsm_6/core/const_6_core_security.py index 10339865..e695887d 100644 --- a/tests/api_data/dsm_6/core/const_6_core_security.py +++ b/tests/api_data/dsm_6/core/const_6_core_security.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.SecurityScan.Status data.""" DSM_6_CORE_SECURITY = { diff --git a/tests/api_data/dsm_6/core/const_6_core_share.py b/tests/api_data/dsm_6/core/const_6_core_share.py index 08f37662..fe663582 100644 --- a/tests/api_data/dsm_6/core/const_6_core_share.py +++ b/tests/api_data/dsm_6/core/const_6_core_share.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.Share data.""" DSM_6_CORE_SHARE = { diff --git a/tests/api_data/dsm_6/core/const_6_core_utilization.py b/tests/api_data/dsm_6/core/const_6_core_utilization.py index 490aacfa..dac2678c 100644 --- a/tests/api_data/dsm_6/core/const_6_core_utilization.py +++ b/tests/api_data/dsm_6/core/const_6_core_utilization.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.System.Utilization data.""" DSM_6_CORE_UTILIZATION_ERROR_1055 = { diff --git a/tests/api_data/dsm_6/download_station/const_6_download_station_info.py b/tests/api_data/dsm_6/download_station/const_6_download_station_info.py index 9ef80a7e..5f8fadb5 100644 --- a/tests/api_data/dsm_6/download_station/const_6_download_station_info.py +++ b/tests/api_data/dsm_6/download_station/const_6_download_station_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.DownloadStation.Info data.""" DSM_6_DOWNLOAD_STATION_INFO_INFO = { diff --git a/tests/api_data/dsm_6/download_station/const_6_download_station_stat.py b/tests/api_data/dsm_6/download_station/const_6_download_station_stat.py index b5f8c004..34a6ef61 100644 --- a/tests/api_data/dsm_6/download_station/const_6_download_station_stat.py +++ b/tests/api_data/dsm_6/download_station/const_6_download_station_stat.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.DownloadStation.Statistic data.""" DSM_6_DOWNLOAD_STATION_STAT_INFO = { diff --git a/tests/api_data/dsm_6/download_station/const_6_download_station_task.py b/tests/api_data/dsm_6/download_station/const_6_download_station_task.py index 1c7b7179..180c87c8 100644 --- a/tests/api_data/dsm_6/download_station/const_6_download_station_task.py +++ b/tests/api_data/dsm_6/download_station/const_6_download_station_task.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.DownloadStation.Task data.""" DSM_6_DOWNLOAD_STATION_TASK_LIST = { diff --git a/tests/api_data/dsm_6/dsm/const_6_dsm_info.py b/tests/api_data/dsm_6/dsm/const_6_dsm_info.py index c20191a0..f43f9a62 100644 --- a/tests/api_data/dsm_6/dsm/const_6_dsm_info.py +++ b/tests/api_data/dsm_6/dsm/const_6_dsm_info.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.DSM.Info data.""" DSM_6_DSM_INFORMATION_DS213_PLUS = { diff --git a/tests/api_data/dsm_6/dsm/const_6_dsm_network.py b/tests/api_data/dsm_6/dsm/const_6_dsm_network.py index 48304626..38a6d05f 100644 --- a/tests/api_data/dsm_6/dsm/const_6_dsm_network.py +++ b/tests/api_data/dsm_6/dsm/const_6_dsm_network.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.DSM.Network data.""" DSM_6_DSM_NETWORK = { diff --git a/tests/api_data/dsm_6/storage/const_6_storage_storage.py b/tests/api_data/dsm_6/storage/const_6_storage_storage.py index 6535b9a8..a86913e1 100644 --- a/tests/api_data/dsm_6/storage/const_6_storage_storage.py +++ b/tests/api_data/dsm_6/storage/const_6_storage_storage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Storage.CGI.Storage data.""" from tests.const import UNIQUE_KEY @@ -1979,7 +1978,10 @@ "env": { "batchtask": {"max_task": 64, "remain_task": 64}, "bay_number": "4", - "data_scrubbing": {"sche_enabled": "0", "sche_status": "disabled",}, + "data_scrubbing": { + "sche_enabled": "0", + "sche_status": "disabled", + }, "ebox": [], "fs_acting": False, "isSyncSysPartition": False, @@ -1993,8 +1995,15 @@ "ram_size": 4, "ram_size_required": 32, "showpooltab": False, - "status": {"system_crashed": False, "system_need_repair": False,}, - "support": {"ebox": True, "raid_cross": True, "sysdef": True,}, + "status": { + "system_crashed": False, + "system_need_repair": False, + }, + "support": { + "ebox": True, + "raid_cross": True, + "sysdef": True, + }, "support_fit_fs_limit": True, "unique_key": UNIQUE_KEY, "volume_full_critical": 0.1, @@ -2040,9 +2049,21 @@ { "designedDiskCount": 3, "devices": [ - {"id": "sdc", "slot": 2, "status": "normal",}, - {"id": "sdb", "slot": 1, "status": "normal",}, - {"id": "sda", "slot": 0, "status": "normal",}, + { + "id": "sdc", + "slot": 2, + "status": "normal", + }, + { + "id": "sdb", + "slot": 1, + "status": "normal", + }, + { + "id": "sda", + "slot": 0, + "status": "normal", + }, ], "hasParity": True, "minDevSize": "4000681164800", @@ -2053,7 +2074,10 @@ } ], "scrubbingStatus": "no_action", - "size": {"total": "7991698522112", "used": "7991698522112",}, + "size": { + "total": "7991698522112", + "used": "7991698522112", + }, "space_path": "/dev/md2", "ssd_trim": {"support": "not support"}, "status": "normal", @@ -2068,9 +2092,21 @@ } }, "flashcache": { - "apply": {"can_do": True, "errCode": 0, "stopService": True,}, - "remove": {"can_do": True, "errCode": 0, "stopService": False,}, - "resize": {"can_do": True, "errCode": 0, "stopService": False,}, + "apply": { + "can_do": True, + "errCode": 0, + "stopService": True, + }, + "remove": { + "can_do": True, + "errCode": 0, + "stopService": False, + }, + "resize": { + "can_do": True, + "errCode": 0, + "stopService": False, + }, }, "snapshot": { "resize": { @@ -2142,9 +2178,21 @@ } }, "flashcache": { - "apply": {"can_do": True, "errCode": 0, "stopService": True,}, - "remove": {"can_do": True, "errCode": 0, "stopService": False,}, - "resize": {"can_do": True, "errCode": 0, "stopService": False,}, + "apply": { + "can_do": True, + "errCode": 0, + "stopService": True, + }, + "remove": { + "can_do": True, + "errCode": 0, + "stopService": False, + }, + "resize": { + "can_do": True, + "errCode": 0, + "stopService": False, + }, }, "snapshot": { "resize": { diff --git a/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_camera.py b/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_camera.py index e2187bd1..d39848b8 100644 --- a/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_camera.py +++ b/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_camera.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.SurveillanceStation.Camera data.""" DSM_6_SURVEILLANCE_STATION_CAMERA_LIST = { diff --git a/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_home_mode.py b/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_home_mode.py index 1b7afde5..b58735bc 100644 --- a/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_home_mode.py +++ b/tests/api_data/dsm_6/surveillance_station/const_6_surveillance_station_home_mode.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.API.SurveillanceStation.HomeMode data.""" DSM_6_SURVEILLANCE_STATION_HOME_MODE_GET_INFO = { diff --git a/tests/const.py b/tests/const.py index c5466528..6e938f53 100644 --- a/tests/const.py +++ b/tests/const.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Test constants.""" # API test data are localized in diff --git a/tests/test_synology_dsm.py b/tests/test_synology_dsm.py index 03bebbd6..87071b24 100644 --- a/tests/test_synology_dsm.py +++ b/tests/test_synology_dsm.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Synology DSM tests.""" from unittest import TestCase import pytest diff --git a/tests/test_synology_dsm_5.py b/tests/test_synology_dsm_5.py index c1141357..ee0577c7 100644 --- a/tests/test_synology_dsm_5.py +++ b/tests/test_synology_dsm_5.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Synology DSM tests.""" from unittest import TestCase From 5244a49c43626eeca8fb78198e0cdb41fe2432f3 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:43:21 +0000 Subject: [PATCH 06/29] correct alphabetically order --- synology_dsm/synology_dsm.py | 83 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 39c8b607..d7d25f9b 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -20,10 +20,10 @@ ) from .api.core.security import SynoCoreSecurity -from .api.core.utilization import SynoCoreUtilization -from .api.core.upgrade import SynoCoreUpgrade from .api.core.share import SynoCoreShare from .api.core.system import SynoCoreSystem +from .api.core.upgrade import SynoCoreUpgrade +from .api.core.utilization import SynoCoreUtilization from .api.download_station import SynoDownloadStation from .api.dsm.information import SynoDSMInformation from .api.dsm.network import SynoDSMNetwork @@ -77,11 +77,11 @@ def __init__( self._information = None self._network = None self._security = None - self._utilisation = None - self._storage = None self._share = None + self._storage = None self._surveillance = None self._system = None + self._utilisation = None self._upgrade = None # Build variables @@ -343,49 +343,48 @@ def reset(self, api): if hasattr(self, "_" + api): setattr(self, "_" + api, None) return True - if api == SynoDownloadStation.API_KEY: - self._download = None - return True if api == SynoCoreSecurity.API_KEY: self._security = None return True if api == SynoCoreShare.API_KEY: self._share = None return True + if api == SynoCoreSystem.API_KEY: + self._system = None + return True + if api == SynoCoreUpgrade.API_BASE_KEY: + self._upgrade = None + return True if api == SynoCoreUtilization.API_KEY: self._utilisation = None return True + if api == SynoDownloadStation.API_KEY: + self._download = None + return True if api == SynoStorage.API_KEY: self._storage = None return True if api == SynoSurveillanceStation.API_KEY: self._surveillance = None return True - if api == SynoCoreSystem.API_KEY: - self._system = None - return True - if api == SynoCoreUpgrade.API_BASE_KEY: - self._upgrade = None - return True - if isinstance(api, SynoDownloadStation): - self._download = None - return True if isinstance(api, SynoCoreSecurity): self._security = None return True if isinstance(api, SynoCoreShare): self._share = None return True + if isinstance(api, SynoCoreSystem): + self._system = None + return True if isinstance(api, SynoCoreUtilization): self._utilisation = None return True + if isinstance(api, SynoDownloadStation): + self._download = None + return True if isinstance(api, SynoStorage): self._storage = None return True - if isinstance(api, SynoCoreSystem): - self._system = None - return True - if isinstance(api, SynoSurveillanceStation): self._surveillance = None return True @@ -420,18 +419,11 @@ def security(self): return self._security @property - def utilisation(self): - """Gets NAS utilisation informations.""" - if not self._utilisation: - self._utilisation = SynoCoreUtilization(self) - return self._utilisation - - @property - def upgrade(self): - """Gets NAS upgrade informations.""" - if not self._upgrade: - self._upgrade = SynoCoreUpgrade(self) - return self._upgrade + def share(self): + """Gets NAS shares information.""" + if not self._share: + self._share = SynoCoreShare(self) + return self._share @property def storage(self): @@ -441,11 +433,11 @@ def storage(self): return self._storage @property - def share(self): - """Gets NAS shares information.""" - if not self._share: - self._share = SynoCoreShare(self) - return self._share + def surveillance_station(self): + """Gets NAS SurveillanceStation.""" + if not self._surveillance: + self._surveillance = SynoSurveillanceStation(self) + return self._surveillance @property def system(self): @@ -455,8 +447,15 @@ def system(self): return self._system @property - def surveillance_station(self): - """Gets NAS SurveillanceStation.""" - if not self._surveillance: - self._surveillance = SynoSurveillanceStation(self) - return self._surveillance + def upgrade(self): + """Gets NAS upgrade informations.""" + if not self._upgrade: + self._upgrade = SynoCoreUpgrade(self) + return self._upgrade + + @property + def utilisation(self): + """Gets NAS utilisation informations.""" + if not self._utilisation: + self._utilisation = SynoCoreUtilization(self) + return self._utilisation From 18927703ec0c83dcc41dc0705f86fdb26251f51c Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:44:37 +0000 Subject: [PATCH 07/29] add SynoCoreUpgrade instance --- synology_dsm/synology_dsm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index d7d25f9b..06610f11 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -376,6 +376,9 @@ def reset(self, api): if isinstance(api, SynoCoreSystem): self._system = None return True + if isinstance(api, SynoCoreUpgrade): + self._utilisation = None + return True if isinstance(api, SynoCoreUtilization): self._utilisation = None return True From 97bc9319a02cdf785aa5f13667e95e1f9bda6f5b Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:50:51 +0000 Subject: [PATCH 08/29] simplify update_available() --- synology_dsm/api/core/upgrade.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index 0f8542ae..49a62574 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -21,6 +21,4 @@ def update(self): @property def update_available(self): """Gets all Upgrade info.""" - if self._data.get("update", None): - return bool(self._data["update"]["available"]) - return None + return self._data["update"].get("available") From 5b63dfdebfb22840b3d5283805cf1e8a3dea844b Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:53:17 +0000 Subject: [PATCH 09/29] correct defaults of .get() --- synology_dsm/api/core/system.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/synology_dsm/api/core/system.py b/synology_dsm/api/core/system.py index c9f1a2fb..f3e04e7d 100644 --- a/synology_dsm/api/core/system.py +++ b/synology_dsm/api/core/system.py @@ -21,77 +21,77 @@ def update(self): @property def cpu_clock_speed(self): """Gets System CPU clock speed.""" - return self._data.get('cpu_clock_speed', {}) + return self._data.get('cpu_clock_speed') @property def cpu_cores(self): """Gets System CPU cores.""" - return self._data.get('cpu_cores', {}) + return self._data.get('cpu_cores') @property def cpu_family(self): """Gets System CPU family.""" - return self._data.get('cpu_family', {}) + return self._data.get('cpu_family') @property def cpu_series(self): """Gets System CPU series.""" - return self._data.get('cpu_series', {}) + return self._data.get('cpu_series') @property def enabled_ntp(self): """Gets System NTP state.""" - return self._data.get('enabled_ntp', {}) + return self._data.get('enabled_ntp') @property def ntp_server(self): """Gets System NTP server.""" - return self._data.get('ntp_server', {}) + return self._data.get('ntp_server') @property def firmware_ver(self): """Gets System firmware version.""" - return self._data.get('firmware_ver', {}) + return self._data.get('firmware_ver') @property def model(self): """Gets System model.""" - return self._data.get('model', {}) + return self._data.get('model') @property def ram_size(self): """Gets System ram size.""" - return self._data.get('ram_size', {}) + return self._data.get('ram_size') @property def serial(self): """Gets System serial number.""" - return self._data.get('serial', {}) + return self._data.get('serial') @property def sys_temp(self): """Gets System temperature.""" - return self._data.get('sys_temp', {}) + return self._data.get('sys_temp') @property def time(self): """Gets System time.""" - return self._data.get('time', {}) + return self._data.get('time') @property def time_zone(self): """Gets System time zone.""" - return self._data.get('time_zone', {}) + return self._data.get('time_zone') @property def time_zone_desc(self): """Gets System time zone description.""" - return self._data.get('time_zone_desc', {}) + return self._data.get('time_zone_desc') @property def up_time(self): """Gets System uptime.""" - return self._data.get('up_time', {}) + return self._data.get('up_time') @property def usb_dev(self): From abcb8f1a31a8c7ee8750982d26028b815b4cfa6d Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:55:33 +0000 Subject: [PATCH 10/29] harmonize use of API_KEY --- synology_dsm/api/core/upgrade.py | 4 ++-- synology_dsm/synology_dsm.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index 49a62574..6cfdb627 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -5,8 +5,8 @@ class SynoCoreUpgrade(object): """Class containing upgrade data and actions.""" - API_BASE_KEY = "SYNO.Core.Upgrade" - API_SERVER_KEY = API_BASE_KEY + ".Server" + API_KEY = "SYNO.Core.Upgrade" + API_SERVER_KEY = API_KEY + ".Server" def __init__(self, dsm): self._dsm = dsm diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 06610f11..1d4292fc 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -352,7 +352,7 @@ def reset(self, api): if api == SynoCoreSystem.API_KEY: self._system = None return True - if api == SynoCoreUpgrade.API_BASE_KEY: + if api == SynoCoreUpgrade.API_KEY: self._upgrade = None return True if api == SynoCoreUtilization.API_KEY: From bdfd8c804a67587925ce1f4e3c378808c9f1d2b8 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:08:12 +0000 Subject: [PATCH 11/29] update docs --- README.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.rst b/README.rst index 9bbe276a..0876cd60 100644 --- a/README.rst +++ b/README.rst @@ -206,6 +206,33 @@ System usage # Shutdown NAS system.shutdown() + # Manual update system information + system.update() + + # Get CPU information + system.cpu_clock_speed() + system.cpu_cores() + system.cpu_family() + system.cpu_series() + + # Get NTP settings + system.enabled_ntp() + system.ntp_server() + + # Get system information + system.firmware_ver() + system.model() + system.ram_size() + system.serial() + system.sys_temp() + system.time() + system.time_zone() + system.time_zone_desc() + system.up_time() + + # Get list of all connected USB devices + system.usb_dev() + Upgrade usage -------------------------- @@ -217,6 +244,9 @@ Upgrade usage api = SynologyDSM("", "", "", "") upgrade = api.upgrade + # Manual update upgrade information + upgrade.update() + # check if DSM update is available if upgrade.update_available: do something ... From 3c94ef3fce6a14a01c34b28a4c5a0978ce6e8ebc Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:32:01 +0000 Subject: [PATCH 12/29] add test data --- .../dsm_6/core/const_6_core_system.py | 39 +++++++++++++++++++ .../dsm_6/core/const_6_core_upgrade.py | 11 ++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/api_data/dsm_6/core/const_6_core_system.py create mode 100644 tests/api_data/dsm_6/core/const_6_core_upgrade.py diff --git a/tests/api_data/dsm_6/core/const_6_core_system.py b/tests/api_data/dsm_6/core/const_6_core_system.py new file mode 100644 index 00000000..5abb9396 --- /dev/null +++ b/tests/api_data/dsm_6/core/const_6_core_system.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +"""DSM 6 SYNO.Core.System data.""" + +DSM_6_CORE_SYSTEM = { + "data":{ + "cpu_clock_speed":1400, + "cpu_cores":"4", + "cpu_family":"RTD1296", + "cpu_series":"SoC", + "cpu_vendor":"Realtek", + "enabled_ntp":True, + "firmware_date":"2020/07/14", + "firmware_ver":"DSM 6.2.3-25426 Update 2", + "model":"DS218play", + "ntp_server":"pool.ntp.org", + "ram_size":1024, + "serial":"123456abcdefg", + "support_esata":"no", + "sys_temp":40, + "sys_tempwarn":False, + "systempwarn":False, + "temperature_warning":False, + "time":"2020-10-16 20:26:58", + "time_zone":"Amsterdam", + "time_zone_desc":"(GMT+01:00) Amsterdam, Berlin, Rome, Stockholm, Vienna", + "up_time":"289:31:54", + "usb_dev":[ + { + "cls":"disk", + "pid":"2621", + "producer":"Western Digital Technologies, Inc.", + "product":"Elements 2621", + "rev":"10.26", + "vid":"1058" + } + ] + }, + "success":True +} diff --git a/tests/api_data/dsm_6/core/const_6_core_upgrade.py b/tests/api_data/dsm_6/core/const_6_core_upgrade.py new file mode 100644 index 00000000..0e003c1a --- /dev/null +++ b/tests/api_data/dsm_6/core/const_6_core_upgrade.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +"""DSM 6 SYNO.Core.Upgrade data.""" + +DSM_6_CORE_SYSTEM = { + "data":{ + "update":{ + "available":False + } + }, + "success":True +} From fbc28100627584bd5eaddf1c195eef591142c390 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:41:41 +0000 Subject: [PATCH 13/29] due to #70 --- synology_dsm/api/core/system.py | 3 +-- synology_dsm/api/core/upgrade.py | 3 +-- tests/api_data/dsm_6/core/const_6_core_system.py | 1 - tests/api_data/dsm_6/core/const_6_core_upgrade.py | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/synology_dsm/api/core/system.py b/synology_dsm/api/core/system.py index f3e04e7d..af9faa51 100644 --- a/synology_dsm/api/core/system.py +++ b/synology_dsm/api/core/system.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM System data and actions.""" -class SynoCoreSystem(object): +class SynoCoreSystem: """Class containing System data and actions.""" API_KEY = "SYNO.Core.System" diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index 6cfdb627..debaa84c 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM Upgrade data and actions.""" -class SynoCoreUpgrade(object): +class SynoCoreUpgrade: """Class containing upgrade data and actions.""" API_KEY = "SYNO.Core.Upgrade" diff --git a/tests/api_data/dsm_6/core/const_6_core_system.py b/tests/api_data/dsm_6/core/const_6_core_system.py index 5abb9396..2073e436 100644 --- a/tests/api_data/dsm_6/core/const_6_core_system.py +++ b/tests/api_data/dsm_6/core/const_6_core_system.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.System data.""" DSM_6_CORE_SYSTEM = { diff --git a/tests/api_data/dsm_6/core/const_6_core_upgrade.py b/tests/api_data/dsm_6/core/const_6_core_upgrade.py index 0e003c1a..8b393ed0 100644 --- a/tests/api_data/dsm_6/core/const_6_core_upgrade.py +++ b/tests/api_data/dsm_6/core/const_6_core_upgrade.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.Upgrade data.""" DSM_6_CORE_SYSTEM = { From 4e190d4ce819838f387cd8c584064db7cc952807 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:45:07 +0000 Subject: [PATCH 14/29] update docs --- README.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 0876cd60..ddba2dc3 100644 --- a/README.rst +++ b/README.rst @@ -210,28 +210,28 @@ System usage system.update() # Get CPU information - system.cpu_clock_speed() - system.cpu_cores() - system.cpu_family() - system.cpu_series() + system.cpu_clock_speed + system.cpu_cores + system.cpu_family + system.cpu_series # Get NTP settings - system.enabled_ntp() - system.ntp_server() + system.enabled_ntp + system.ntp_server # Get system information - system.firmware_ver() - system.model() - system.ram_size() - system.serial() - system.sys_temp() - system.time() - system.time_zone() - system.time_zone_desc() - system.up_time() + system.firmware_ver + system.model + system.ram_size + system.serial + system.sys_temp + system.time + system.time_zone + system.time_zone_desc + system.up_time # Get list of all connected USB devices - system.usb_dev() + system.usb_dev Upgrade usage From 34bf335491c21fddca1dcef274c1733c6dd5a02c Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 19:01:57 +0000 Subject: [PATCH 15/29] solve conflict --- synology_dsm/synology_dsm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 1d4292fc..64618290 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -335,7 +335,7 @@ def update(self, with_information=False, with_network=False): if self._upgrade: self._upgrade.update() - def reset(self, api): + def reset(self, api: any) -> bool: """Reset an API to avoid fetching in on update.""" if isinstance(api, str): if api in ("information", SynoDSMInformation.API_KEY): @@ -436,7 +436,7 @@ def storage(self): return self._storage @property - def surveillance_station(self): + def surveillance_station(self) -> SynoSurveillanceStation: """Gets NAS SurveillanceStation.""" if not self._surveillance: self._surveillance = SynoSurveillanceStation(self) @@ -457,7 +457,7 @@ def upgrade(self): return self._upgrade @property - def utilisation(self): + def utilisation(self) -> SynoCoreUtilization: """Gets NAS utilisation informations.""" if not self._utilisation: self._utilisation = SynoCoreUtilization(self) From d4c006c32fed75ef4c329b09ee0aa2ecfebaf5ca Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 4 Oct 2020 17:15:18 +0000 Subject: [PATCH 16/29] add syno system data and actions --- synology_dsm/api/core/system.py | 118 ++++++++++++++++++++++++++++++++ synology_dsm/synology_dsm.py | 18 +++++ 2 files changed, 136 insertions(+) create mode 100644 synology_dsm/api/core/system.py diff --git a/synology_dsm/api/core/system.py b/synology_dsm/api/core/system.py new file mode 100644 index 00000000..c9f1a2fb --- /dev/null +++ b/synology_dsm/api/core/system.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +"""DSM System data and actions.""" + + +class SynoCoreSystem(object): + """Class containing System data and actions.""" + + API_KEY = "SYNO.Core.System" + + def __init__(self, dsm): + self._dsm = dsm + self._data = {} + + def update(self): + """Updates System data.""" + raw_data = self._dsm.get(self.API_KEY, "info") + if raw_data: + self._data = raw_data["data"] + + ### get information + @property + def cpu_clock_speed(self): + """Gets System CPU clock speed.""" + return self._data.get('cpu_clock_speed', {}) + + @property + def cpu_cores(self): + """Gets System CPU cores.""" + return self._data.get('cpu_cores', {}) + + @property + def cpu_family(self): + """Gets System CPU family.""" + return self._data.get('cpu_family', {}) + + @property + def cpu_series(self): + """Gets System CPU series.""" + return self._data.get('cpu_series', {}) + + @property + def enabled_ntp(self): + """Gets System NTP state.""" + return self._data.get('enabled_ntp', {}) + + @property + def ntp_server(self): + """Gets System NTP server.""" + return self._data.get('ntp_server', {}) + + @property + def firmware_ver(self): + """Gets System firmware version.""" + return self._data.get('firmware_ver', {}) + + @property + def model(self): + """Gets System model.""" + return self._data.get('model', {}) + + @property + def ram_size(self): + """Gets System ram size.""" + return self._data.get('ram_size', {}) + + @property + def serial(self): + """Gets System serial number.""" + return self._data.get('serial', {}) + + @property + def sys_temp(self): + """Gets System temperature.""" + return self._data.get('sys_temp', {}) + + @property + def time(self): + """Gets System time.""" + return self._data.get('time', {}) + + @property + def time_zone(self): + """Gets System time zone.""" + return self._data.get('time_zone', {}) + + @property + def time_zone_desc(self): + """Gets System time zone description.""" + return self._data.get('time_zone_desc', {}) + + @property + def up_time(self): + """Gets System uptime.""" + return self._data.get('up_time', {}) + + @property + def usb_dev(self): + """Gets System connected usb devices.""" + return self._data.get('usb_dev', []) + + ### do system actions + def shutdown(self): + """Shutdown NAS.""" + res = self._dsm.get( + self.API_KEY, + "shutdown", + max_version=1, # shutdown method is only available on api version 1 + ) + return res + + def reboot(self): + """Reboot NAS.""" + res = self._dsm.get( + self.API_KEY, + "reboot", + max_version=1, # reboot method is only available on api version 1 + ) + return res diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 8ac0506a..b92b7d72 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -22,6 +22,7 @@ from .api.core.security import SynoCoreSecurity from .api.core.utilization import SynoCoreUtilization from .api.core.share import SynoCoreShare +from .api.core.system import SynoCoreSystem from .api.download_station import SynoDownloadStation from .api.dsm.information import SynoDSMInformation from .api.dsm.network import SynoDSMNetwork @@ -74,6 +75,7 @@ def __init__( self._storage = None self._share = None self._surveillance = None + self._system = None # Build variables if use_https: @@ -322,6 +324,9 @@ def update(self, with_information: bool = False, with_network: bool = False): if self._surveillance: self._surveillance.update() + if self._system: + self._system.update() + def reset(self, api: any) -> bool: """Reset an API to avoid fetching in on update.""" if isinstance(api, str): @@ -348,6 +353,9 @@ def reset(self, api: any) -> bool: if api == SynoSurveillanceStation.API_KEY: self._surveillance = None return True + if api == SynoCoreSystem.API_KEY: + self._system = None + return True if isinstance(api, SynoDownloadStation): self._download = None return True @@ -363,6 +371,9 @@ def reset(self, api: any) -> bool: if isinstance(api, SynoStorage): self._storage = None return True + if isinstance(api, SynoCoreSystem): + self._system = None + return True if isinstance(api, SynoSurveillanceStation): self._surveillance = None @@ -418,6 +429,13 @@ def share(self) -> SynoCoreShare: self._share = SynoCoreShare(self) return self._share + @property + def system(self): + """Gets NAS system information.""" + if not self._system: + self._system = SynoCoreSystem(self) + return self._system + @property def surveillance_station(self) -> SynoSurveillanceStation: """Gets NAS SurveillanceStation.""" From b61e90d23968ef80b4695bca17360bd726dab44e Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 4 Oct 2020 17:20:17 +0000 Subject: [PATCH 17/29] add system usage examples --- README.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.rst b/README.rst index 9c3fc46c..92eb787f 100644 --- a/README.rst +++ b/README.rst @@ -190,6 +190,22 @@ Surveillance Station usage surveillance.set_home_mode(True) +System usage +-------------------------- + +.. code-block:: python + + from synology_dsm import SynologyDSM + + api = SynologyDSM("", "", "", "") + system = api.system + + # Reboot NAS + system.reboot() + + # Shutdown NAS + system.shutdown() + Credits / Special Thanks ======================== From 8d6bef6e2165c62a9b69d2a4b56e5c5e15e0943c Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 4 Oct 2020 20:28:15 +0000 Subject: [PATCH 18/29] add upgrade information --- README.rst | 14 ++++++++++++++ synology_dsm/api/core/upgrade.py | 26 ++++++++++++++++++++++++++ synology_dsm/synology_dsm.py | 15 +++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 synology_dsm/api/core/upgrade.py diff --git a/README.rst b/README.rst index 92eb787f..9bbe276a 100644 --- a/README.rst +++ b/README.rst @@ -207,6 +207,20 @@ System usage system.shutdown() +Upgrade usage +-------------------------- + +.. code-block:: python + + from synology_dsm import SynologyDSM + + api = SynologyDSM("", "", "", "") + upgrade = api.upgrade + + # check if DSM update is available + if upgrade.update_available: + do something ... + Credits / Special Thanks ======================== - https://github.com/florianeinfalt diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py new file mode 100644 index 00000000..0f8542ae --- /dev/null +++ b/synology_dsm/api/core/upgrade.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +"""DSM Upgrade data and actions.""" + + +class SynoCoreUpgrade(object): + """Class containing upgrade data and actions.""" + + API_BASE_KEY = "SYNO.Core.Upgrade" + API_SERVER_KEY = API_BASE_KEY + ".Server" + + def __init__(self, dsm): + self._dsm = dsm + self._data = {} + + def update(self): + """Updates Upgrade data.""" + raw_data = self._dsm.get(self.API_SERVER_KEY, "check") + if raw_data: + self._data.update(raw_data["data"]) + + @property + def update_available(self): + """Gets all Upgrade info.""" + if self._data.get("update", None): + return bool(self._data["update"]["available"]) + return None diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index b92b7d72..524fd931 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -21,6 +21,7 @@ from .api.core.security import SynoCoreSecurity from .api.core.utilization import SynoCoreUtilization +from .api.core.upgrade import SynoCoreUpgrade from .api.core.share import SynoCoreShare from .api.core.system import SynoCoreSystem from .api.download_station import SynoDownloadStation @@ -76,6 +77,7 @@ def __init__( self._share = None self._surveillance = None self._system = None + self._upgrade = None # Build variables if use_https: @@ -327,6 +329,9 @@ def update(self, with_information: bool = False, with_network: bool = False): if self._system: self._system.update() + if self._upgrade: + self._upgrade.update() + def reset(self, api: any) -> bool: """Reset an API to avoid fetching in on update.""" if isinstance(api, str): @@ -356,6 +361,9 @@ def reset(self, api: any) -> bool: if api == SynoCoreSystem.API_KEY: self._system = None return True + if api == SynoCoreUpgrade.API_BASE_KEY: + self._upgrade = None + return True if isinstance(api, SynoDownloadStation): self._download = None return True @@ -415,6 +423,13 @@ def utilisation(self) -> SynoCoreUtilization: self._utilisation = SynoCoreUtilization(self) return self._utilisation + @property + def upgrade(self): + """Gets NAS upgrade informations.""" + if not self._upgrade: + self._upgrade = SynoCoreUpgrade(self) + return self._upgrade + @property def storage(self) -> SynoStorage: """Gets NAS storage informations.""" From 609bc320224f7c2b8452263d21dd23c0d4c2c7fe Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:43:21 +0000 Subject: [PATCH 19/29] correct alphabetically order --- synology_dsm/synology_dsm.py | 83 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 524fd931..bf9aa14f 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -20,10 +20,10 @@ ) from .api.core.security import SynoCoreSecurity -from .api.core.utilization import SynoCoreUtilization -from .api.core.upgrade import SynoCoreUpgrade from .api.core.share import SynoCoreShare from .api.core.system import SynoCoreSystem +from .api.core.upgrade import SynoCoreUpgrade +from .api.core.utilization import SynoCoreUtilization from .api.download_station import SynoDownloadStation from .api.dsm.information import SynoDSMInformation from .api.dsm.network import SynoDSMNetwork @@ -72,11 +72,11 @@ def __init__( self._information = None self._network = None self._security = None - self._utilisation = None - self._storage = None self._share = None + self._storage = None self._surveillance = None self._system = None + self._utilisation = None self._upgrade = None # Build variables @@ -340,49 +340,48 @@ def reset(self, api: any) -> bool: if hasattr(self, "_" + api): setattr(self, "_" + api, None) return True - if api == SynoDownloadStation.API_KEY: - self._download = None - return True if api == SynoCoreSecurity.API_KEY: self._security = None return True if api == SynoCoreShare.API_KEY: self._share = None return True + if api == SynoCoreSystem.API_KEY: + self._system = None + return True + if api == SynoCoreUpgrade.API_BASE_KEY: + self._upgrade = None + return True if api == SynoCoreUtilization.API_KEY: self._utilisation = None return True + if api == SynoDownloadStation.API_KEY: + self._download = None + return True if api == SynoStorage.API_KEY: self._storage = None return True if api == SynoSurveillanceStation.API_KEY: self._surveillance = None return True - if api == SynoCoreSystem.API_KEY: - self._system = None - return True - if api == SynoCoreUpgrade.API_BASE_KEY: - self._upgrade = None - return True - if isinstance(api, SynoDownloadStation): - self._download = None - return True if isinstance(api, SynoCoreSecurity): self._security = None return True if isinstance(api, SynoCoreShare): self._share = None return True + if isinstance(api, SynoCoreSystem): + self._system = None + return True if isinstance(api, SynoCoreUtilization): self._utilisation = None return True + if isinstance(api, SynoDownloadStation): + self._download = None + return True if isinstance(api, SynoStorage): self._storage = None return True - if isinstance(api, SynoCoreSystem): - self._system = None - return True - if isinstance(api, SynoSurveillanceStation): self._surveillance = None return True @@ -417,18 +416,11 @@ def security(self) -> SynoCoreSecurity: return self._security @property - def utilisation(self) -> SynoCoreUtilization: - """Gets NAS utilisation informations.""" - if not self._utilisation: - self._utilisation = SynoCoreUtilization(self) - return self._utilisation - - @property - def upgrade(self): - """Gets NAS upgrade informations.""" - if not self._upgrade: - self._upgrade = SynoCoreUpgrade(self) - return self._upgrade + def share(self): + """Gets NAS shares information.""" + if not self._share: + self._share = SynoCoreShare(self) + return self._share @property def storage(self) -> SynoStorage: @@ -438,11 +430,11 @@ def storage(self) -> SynoStorage: return self._storage @property - def share(self) -> SynoCoreShare: - """Gets NAS shares information.""" - if not self._share: - self._share = SynoCoreShare(self) - return self._share + def surveillance_station(self) -> SynoSurveillanceStation: + """Gets NAS SurveillanceStation.""" + if not self._surveillance: + self._surveillance = SynoSurveillanceStation(self) + return self._surveillance @property def system(self): @@ -452,8 +444,15 @@ def system(self): return self._system @property - def surveillance_station(self) -> SynoSurveillanceStation: - """Gets NAS SurveillanceStation.""" - if not self._surveillance: - self._surveillance = SynoSurveillanceStation(self) - return self._surveillance + def upgrade(self): + """Gets NAS upgrade informations.""" + if not self._upgrade: + self._upgrade = SynoCoreUpgrade(self) + return self._upgrade + + @property + def utilisation(self) -> SynoCoreUtilization: + """Gets NAS utilisation informations.""" + if not self._utilisation: + self._utilisation = SynoCoreUtilization(self) + return self._utilisation From 2a3e60933b2f6dff2245498d67da2006c4a04b65 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:44:37 +0000 Subject: [PATCH 20/29] add SynoCoreUpgrade instance --- synology_dsm/synology_dsm.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index bf9aa14f..b9e041a8 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -373,6 +373,9 @@ def reset(self, api: any) -> bool: if isinstance(api, SynoCoreSystem): self._system = None return True + if isinstance(api, SynoCoreUpgrade): + self._utilisation = None + return True if isinstance(api, SynoCoreUtilization): self._utilisation = None return True From 13a63fac696caf7667d3257fdcee90869301aa16 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:50:51 +0000 Subject: [PATCH 21/29] simplify update_available() --- synology_dsm/api/core/upgrade.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index 0f8542ae..49a62574 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -21,6 +21,4 @@ def update(self): @property def update_available(self): """Gets all Upgrade info.""" - if self._data.get("update", None): - return bool(self._data["update"]["available"]) - return None + return self._data["update"].get("available") From b8780503e08b3242f0f9fe0223b47ad833f7a8d7 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:53:17 +0000 Subject: [PATCH 22/29] correct defaults of .get() --- synology_dsm/api/core/system.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/synology_dsm/api/core/system.py b/synology_dsm/api/core/system.py index c9f1a2fb..f3e04e7d 100644 --- a/synology_dsm/api/core/system.py +++ b/synology_dsm/api/core/system.py @@ -21,77 +21,77 @@ def update(self): @property def cpu_clock_speed(self): """Gets System CPU clock speed.""" - return self._data.get('cpu_clock_speed', {}) + return self._data.get('cpu_clock_speed') @property def cpu_cores(self): """Gets System CPU cores.""" - return self._data.get('cpu_cores', {}) + return self._data.get('cpu_cores') @property def cpu_family(self): """Gets System CPU family.""" - return self._data.get('cpu_family', {}) + return self._data.get('cpu_family') @property def cpu_series(self): """Gets System CPU series.""" - return self._data.get('cpu_series', {}) + return self._data.get('cpu_series') @property def enabled_ntp(self): """Gets System NTP state.""" - return self._data.get('enabled_ntp', {}) + return self._data.get('enabled_ntp') @property def ntp_server(self): """Gets System NTP server.""" - return self._data.get('ntp_server', {}) + return self._data.get('ntp_server') @property def firmware_ver(self): """Gets System firmware version.""" - return self._data.get('firmware_ver', {}) + return self._data.get('firmware_ver') @property def model(self): """Gets System model.""" - return self._data.get('model', {}) + return self._data.get('model') @property def ram_size(self): """Gets System ram size.""" - return self._data.get('ram_size', {}) + return self._data.get('ram_size') @property def serial(self): """Gets System serial number.""" - return self._data.get('serial', {}) + return self._data.get('serial') @property def sys_temp(self): """Gets System temperature.""" - return self._data.get('sys_temp', {}) + return self._data.get('sys_temp') @property def time(self): """Gets System time.""" - return self._data.get('time', {}) + return self._data.get('time') @property def time_zone(self): """Gets System time zone.""" - return self._data.get('time_zone', {}) + return self._data.get('time_zone') @property def time_zone_desc(self): """Gets System time zone description.""" - return self._data.get('time_zone_desc', {}) + return self._data.get('time_zone_desc') @property def up_time(self): """Gets System uptime.""" - return self._data.get('up_time', {}) + return self._data.get('up_time') @property def usb_dev(self): From aa217cf5ace98c4cb23c254ea657ec64e7e61b35 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 17:55:33 +0000 Subject: [PATCH 23/29] harmonize use of API_KEY --- synology_dsm/api/core/upgrade.py | 4 ++-- synology_dsm/synology_dsm.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index 49a62574..6cfdb627 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -5,8 +5,8 @@ class SynoCoreUpgrade(object): """Class containing upgrade data and actions.""" - API_BASE_KEY = "SYNO.Core.Upgrade" - API_SERVER_KEY = API_BASE_KEY + ".Server" + API_KEY = "SYNO.Core.Upgrade" + API_SERVER_KEY = API_KEY + ".Server" def __init__(self, dsm): self._dsm = dsm diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index b9e041a8..5d09fbd2 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -349,7 +349,7 @@ def reset(self, api: any) -> bool: if api == SynoCoreSystem.API_KEY: self._system = None return True - if api == SynoCoreUpgrade.API_BASE_KEY: + if api == SynoCoreUpgrade.API_KEY: self._upgrade = None return True if api == SynoCoreUtilization.API_KEY: From 907e74ca1a1f0a58ebf8645278ea2948bb7d7917 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:08:12 +0000 Subject: [PATCH 24/29] update docs --- README.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.rst b/README.rst index 9bbe276a..0876cd60 100644 --- a/README.rst +++ b/README.rst @@ -206,6 +206,33 @@ System usage # Shutdown NAS system.shutdown() + # Manual update system information + system.update() + + # Get CPU information + system.cpu_clock_speed() + system.cpu_cores() + system.cpu_family() + system.cpu_series() + + # Get NTP settings + system.enabled_ntp() + system.ntp_server() + + # Get system information + system.firmware_ver() + system.model() + system.ram_size() + system.serial() + system.sys_temp() + system.time() + system.time_zone() + system.time_zone_desc() + system.up_time() + + # Get list of all connected USB devices + system.usb_dev() + Upgrade usage -------------------------- @@ -217,6 +244,9 @@ Upgrade usage api = SynologyDSM("", "", "", "") upgrade = api.upgrade + # Manual update upgrade information + upgrade.update() + # check if DSM update is available if upgrade.update_available: do something ... From 17016a9eb724008e2d57d010dd6b90a2305c45bb Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:32:01 +0000 Subject: [PATCH 25/29] add test data --- .../dsm_6/core/const_6_core_system.py | 39 +++++++++++++++++++ .../dsm_6/core/const_6_core_upgrade.py | 11 ++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/api_data/dsm_6/core/const_6_core_system.py create mode 100644 tests/api_data/dsm_6/core/const_6_core_upgrade.py diff --git a/tests/api_data/dsm_6/core/const_6_core_system.py b/tests/api_data/dsm_6/core/const_6_core_system.py new file mode 100644 index 00000000..5abb9396 --- /dev/null +++ b/tests/api_data/dsm_6/core/const_6_core_system.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +"""DSM 6 SYNO.Core.System data.""" + +DSM_6_CORE_SYSTEM = { + "data":{ + "cpu_clock_speed":1400, + "cpu_cores":"4", + "cpu_family":"RTD1296", + "cpu_series":"SoC", + "cpu_vendor":"Realtek", + "enabled_ntp":True, + "firmware_date":"2020/07/14", + "firmware_ver":"DSM 6.2.3-25426 Update 2", + "model":"DS218play", + "ntp_server":"pool.ntp.org", + "ram_size":1024, + "serial":"123456abcdefg", + "support_esata":"no", + "sys_temp":40, + "sys_tempwarn":False, + "systempwarn":False, + "temperature_warning":False, + "time":"2020-10-16 20:26:58", + "time_zone":"Amsterdam", + "time_zone_desc":"(GMT+01:00) Amsterdam, Berlin, Rome, Stockholm, Vienna", + "up_time":"289:31:54", + "usb_dev":[ + { + "cls":"disk", + "pid":"2621", + "producer":"Western Digital Technologies, Inc.", + "product":"Elements 2621", + "rev":"10.26", + "vid":"1058" + } + ] + }, + "success":True +} diff --git a/tests/api_data/dsm_6/core/const_6_core_upgrade.py b/tests/api_data/dsm_6/core/const_6_core_upgrade.py new file mode 100644 index 00000000..0e003c1a --- /dev/null +++ b/tests/api_data/dsm_6/core/const_6_core_upgrade.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +"""DSM 6 SYNO.Core.Upgrade data.""" + +DSM_6_CORE_SYSTEM = { + "data":{ + "update":{ + "available":False + } + }, + "success":True +} From f9c8819384f18f0ba18b11b1289370465e15f017 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:41:41 +0000 Subject: [PATCH 26/29] due to #70 --- synology_dsm/api/core/system.py | 3 +-- synology_dsm/api/core/upgrade.py | 3 +-- tests/api_data/dsm_6/core/const_6_core_system.py | 1 - tests/api_data/dsm_6/core/const_6_core_upgrade.py | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/synology_dsm/api/core/system.py b/synology_dsm/api/core/system.py index f3e04e7d..af9faa51 100644 --- a/synology_dsm/api/core/system.py +++ b/synology_dsm/api/core/system.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM System data and actions.""" -class SynoCoreSystem(object): +class SynoCoreSystem: """Class containing System data and actions.""" API_KEY = "SYNO.Core.System" diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index 6cfdb627..debaa84c 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- """DSM Upgrade data and actions.""" -class SynoCoreUpgrade(object): +class SynoCoreUpgrade: """Class containing upgrade data and actions.""" API_KEY = "SYNO.Core.Upgrade" diff --git a/tests/api_data/dsm_6/core/const_6_core_system.py b/tests/api_data/dsm_6/core/const_6_core_system.py index 5abb9396..2073e436 100644 --- a/tests/api_data/dsm_6/core/const_6_core_system.py +++ b/tests/api_data/dsm_6/core/const_6_core_system.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.System data.""" DSM_6_CORE_SYSTEM = { diff --git a/tests/api_data/dsm_6/core/const_6_core_upgrade.py b/tests/api_data/dsm_6/core/const_6_core_upgrade.py index 0e003c1a..8b393ed0 100644 --- a/tests/api_data/dsm_6/core/const_6_core_upgrade.py +++ b/tests/api_data/dsm_6/core/const_6_core_upgrade.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """DSM 6 SYNO.Core.Upgrade data.""" DSM_6_CORE_SYSTEM = { From 5d58f17f1ec43b6e798fe0839ba9873fcc6b10c4 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Fri, 16 Oct 2020 18:45:07 +0000 Subject: [PATCH 27/29] update docs --- README.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 0876cd60..ddba2dc3 100644 --- a/README.rst +++ b/README.rst @@ -210,28 +210,28 @@ System usage system.update() # Get CPU information - system.cpu_clock_speed() - system.cpu_cores() - system.cpu_family() - system.cpu_series() + system.cpu_clock_speed + system.cpu_cores + system.cpu_family + system.cpu_series # Get NTP settings - system.enabled_ntp() - system.ntp_server() + system.enabled_ntp + system.ntp_server # Get system information - system.firmware_ver() - system.model() - system.ram_size() - system.serial() - system.sys_temp() - system.time() - system.time_zone() - system.time_zone_desc() - system.up_time() + system.firmware_ver + system.model + system.ram_size + system.serial + system.sys_temp + system.time + system.time_zone + system.time_zone_desc + system.up_time # Get list of all connected USB devices - system.usb_dev() + system.usb_dev Upgrade usage From c6b337c496e3a7af1a36f85322175ea1a4302b0d Mon Sep 17 00:00:00 2001 From: Quentame Date: Sun, 18 Oct 2020 19:37:40 +0200 Subject: [PATCH 28/29] Apply suggestions from code review: function return type --- synology_dsm/synology_dsm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 5d09fbd2..87f09d54 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -419,7 +419,7 @@ def security(self) -> SynoCoreSecurity: return self._security @property - def share(self): + def share(self) -> SynoCoreShare: """Gets NAS shares information.""" if not self._share: self._share = SynoCoreShare(self) @@ -440,14 +440,14 @@ def surveillance_station(self) -> SynoSurveillanceStation: return self._surveillance @property - def system(self): + def system(self) -> SynoCoreSystem: """Gets NAS system information.""" if not self._system: self._system = SynoCoreSystem(self) return self._system @property - def upgrade(self): + def upgrade(self) -> SynoCoreUpgrade: """Gets NAS upgrade informations.""" if not self._upgrade: self._upgrade = SynoCoreUpgrade(self) From 81bafb11cfd5954db06d8309dc515b001fd0457b Mon Sep 17 00:00:00 2001 From: Quentame Date: Sun, 18 Oct 2020 19:46:01 +0200 Subject: [PATCH 29/29] Don't save previous update data --- synology_dsm/api/core/upgrade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synology_dsm/api/core/upgrade.py b/synology_dsm/api/core/upgrade.py index debaa84c..838444ee 100644 --- a/synology_dsm/api/core/upgrade.py +++ b/synology_dsm/api/core/upgrade.py @@ -15,7 +15,7 @@ def update(self): """Updates Upgrade data.""" raw_data = self._dsm.get(self.API_SERVER_KEY, "check") if raw_data: - self._data.update(raw_data["data"]) + self._data = raw_data["data"] @property def update_available(self):