Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-fritzconnection for
openSUSE:Factory checked in at 2025-07-14 10:52:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-fritzconnection (Old)
and /work/SRC/openSUSE:Factory/.python-fritzconnection.new.7373 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-fritzconnection"
Mon Jul 14 10:52:07 2025 rev:12 rq:1292503 version:1.15.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-fritzconnection/python-fritzconnection.changes
2025-06-17 18:23:43.978075940 +0200
+++
/work/SRC/openSUSE:Factory/.python-fritzconnection.new.7373/python-fritzconnection.changes
2025-07-14 10:57:53.512026949 +0200
@@ -1,0 +2,25 @@
+Sun Jul 13 13:09:15 UTC 2025 - Dirk Müller <[email protected]>
+
+- update to 1.15.0:
+ * support added for Python 3.14
+ * FritzConnection:
+ - additional argument `redact_debug_log` (default: False) for
+ optional redacting response in debug output. (#238) (#241)
+ - new method `get_cpu_temperatures()` providing a list of the
+ last recent cpu-temperatures.
+ FritzCall:
+ - new attribute `Path` for the class `Call` to access an
+ optional phone message. (#231)
+ FritzStatus:
+ - new method `get_avm_device_log()` to access system events.
+ Requires FritzOS 8. (#234)
+ - bugfix: in rare cases a session id of None has prevented a
+ successfull request of the http-interface.
+ -
`fritzconnection.lib.fritzhomeauto.FritzHomeAutomation.device_informations()`,
+ deprecated in 1.9.0
+ - `fritzconnection.lib.fritzstatus.FritzStatus.uptime()`,
+ deprecated in 1.9.0
+ - `fritzconnection.lib.fritzwlan.FritzWLAN.channel_infos()`,
+ deprecated in 1.9.0
+
+-------------------------------------------------------------------
Old:
----
fritzconnection-1.14.0.tar.gz
New:
----
fritzconnection-1.15.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-fritzconnection.spec ++++++
--- /var/tmp/diff_new_pack.0kQGSo/_old 2025-07-14 10:57:55.116093446 +0200
+++ /var/tmp/diff_new_pack.0kQGSo/_new 2025-07-14 10:57:55.132094109 +0200
@@ -18,7 +18,7 @@
%global pythons python3
Name: python-fritzconnection
-Version: 1.14.0
+Version: 1.15.0
Release: 0
Summary: A Python module to talk to a AVM fritzbox
License: MIT
++++++ fritzconnection-1.14.0.tar.gz -> fritzconnection-1.15.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/.gitignore
new/fritzconnection-1.15.0/.gitignore
--- old/fritzconnection-1.14.0/.gitignore 2024-08-12 17:58:36.000000000
+0200
+++ new/fritzconnection-1.15.0/.gitignore 2025-05-17 16:21:25.000000000
+0200
@@ -16,7 +16,8 @@
bin
build/*
dist/*
-docs/requirements.txt
+docs/requirements.out
+docs/requirements.local.txt
fritzconnection.egg-info/*
include
lib_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/.readthedocs.yml
new/fritzconnection-1.15.0/.readthedocs.yml
--- old/fritzconnection-1.14.0/.readthedocs.yml 2024-08-12 17:58:36.000000000
+0200
+++ new/fritzconnection-1.15.0/.readthedocs.yml 2025-05-17 16:21:25.000000000
+0200
@@ -3,11 +3,13 @@
build:
os: ubuntu-22.04
tools:
- python: "3.11"
+ python: "3.12"
python:
install:
- requirements: docs/requirements.txt
+ - method: pip
+ path: .
sphinx:
builder: html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/CONTRIBUTING.md
new/fritzconnection-1.15.0/CONTRIBUTING.md
--- old/fritzconnection-1.14.0/CONTRIBUTING.md 2024-08-12 17:58:36.000000000
+0200
+++ new/fritzconnection-1.15.0/CONTRIBUTING.md 2025-05-17 16:21:25.000000000
+0200
@@ -13,7 +13,9 @@
In general pull requests are welcome. Please create an issue first before
putting too much work into a pull request that may not get merged at the end,
for whatever reason. An issue can help to clarify points of view and motivation.
-For pull requests there is a golden rule: **keep them small**. Smaller pull
requests are easier to review and easier to merge – especially in cases when
not every part of a larger changeset should get merged and has to get
modifications.
+In case of providing a pull-request please do this for the
**development-branch** and not for the master-branch.
+
+For pull-requests there is a golden rule: **keep them small**. Smaller
pull-requests are easier to review and easier to merge – especially in cases
when not every part of a larger changeset should get merged and has to get
modifications.
Please avoid to just change the formatting. The result is most often nothing
else than git-diff pollution. This is especially true for `black` (or `blue` or
the corresponding modes in `ruff`) – this project startet before `black`. It is
ok to use these tools for modified code snippets, but not for a module.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/docs/conf.py
new/fritzconnection-1.15.0/docs/conf.py
--- old/fritzconnection-1.14.0/docs/conf.py 2024-08-12 17:58:36.000000000
+0200
+++ new/fritzconnection-1.15.0/docs/conf.py 2025-05-17 16:21:25.000000000
+0200
@@ -12,9 +12,9 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('..'))
+import os
+import sys
+sys.path.insert(0, os.path.abspath('..'))
# -- Project information -----------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/docs/requirements.in
new/fritzconnection-1.15.0/docs/requirements.in
--- old/fritzconnection-1.14.0/docs/requirements.in 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/docs/requirements.in 1970-01-01
01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
-Sphinx==5.1.1
-sphinx-rtd-theme==1.2.2
-fritzconnection
-furo==2023.3.27
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/docs/requirements.local.in
new/fritzconnection-1.15.0/docs/requirements.local.in
--- old/fritzconnection-1.14.0/docs/requirements.local.in 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/docs/requirements.local.in 1970-01-01
01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-Sphinx==5.1.1
-sphinx-rtd-theme==1.2.2
-furo==2023.3.27
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/docs/requirements.txt
new/fritzconnection-1.15.0/docs/requirements.txt
--- old/fritzconnection-1.14.0/docs/requirements.txt 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/docs/requirements.txt 2025-05-17
16:21:25.000000000 +0200
@@ -1,69 +1,3 @@
-#
-# This file is autogenerated by pip-compile with Python 3.12
-# by the following command:
-#
-# pip-compile --output-file=docs/requirements.txt --strip-extras
docs/requirements.local.in
-#
-alabaster==0.7.16
- # via sphinx
-babel==2.16.0
- # via sphinx
-beautifulsoup4==4.12.3
- # via furo
-certifi==2024.7.4
- # via requests
-charset-normalizer==3.3.2
- # via requests
-docutils==0.18.1
- # via
- # sphinx
- # sphinx-rtd-theme
-furo==2023.3.27
- # via -r docs/requirements.local.in
-idna==3.7
- # via requests
-imagesize==1.4.1
- # via sphinx
-jinja2==3.1.4
- # via sphinx
-markupsafe==2.1.5
- # via jinja2
-packaging==24.1
- # via sphinx
-pygments==2.18.0
- # via
- # furo
- # sphinx
-requests==2.32.3
- # via sphinx
-snowballstemmer==2.2.0
- # via sphinx
-soupsieve==2.5
- # via beautifulsoup4
-sphinx==5.1.1
- # via
- # -r docs/requirements.local.in
- # furo
- # sphinx-basic-ng
- # sphinx-rtd-theme
- # sphinxcontrib-jquery
-sphinx-basic-ng==1.0.0b2
- # via furo
-sphinx-rtd-theme==1.2.2
- # via -r docs/requirements.local.in
-sphinxcontrib-applehelp==2.0.0
- # via sphinx
-sphinxcontrib-devhelp==2.0.0
- # via sphinx
-sphinxcontrib-htmlhelp==2.1.0
- # via sphinx
-sphinxcontrib-jquery==4.1
- # via sphinx-rtd-theme
-sphinxcontrib-jsmath==1.0.1
- # via sphinx
-sphinxcontrib-qthelp==2.0.0
- # via sphinx
-sphinxcontrib-serializinghtml==2.0.0
- # via sphinx
-urllib3==2.2.2
- # via requests
+sphinx<7.4.0
+furo<2025.0.0
+#fritzconnection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/docs/sources/version_history.rst
new/fritzconnection-1.15.0/docs/sources/version_history.rst
--- old/fritzconnection-1.14.0/docs/sources/version_history.rst 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/docs/sources/version_history.rst 2025-05-17
16:21:25.000000000 +0200
@@ -4,6 +4,32 @@
===============
+1.15.0 - 2025-05-17
+-------------------
+
+- support added for Python 3.14
+- FritzConnection:
+
+ - additional argument `redact_debug_log` (default: False) for optional
redacting response in debug output. (#238) (#241)
+ - new method `get_cpu_temperatures()` providing a list of the last recent
cpu-temperatures. (Rewrite of #232).
+
+- FritzCall:
+
+ - new attribute `Path` for the class `Call` to access an optional phone
message. (#231)
+
+- FritzStatus:
+
+ - new method `get_avm_device_log()` to access system events. Requires
FritzOS 8. (#234)
+
+- bugfix: in rare cases a session id of None has prevented a successfull
request of the http-interface.
+
+- **removed**:
+
+ -
`fritzconnection.lib.fritzhomeauto.FritzHomeAutomation.device_informations()`,
deprecated in 1.9.0
+ - `fritzconnection.lib.fritzstatus.FritzStatus.uptime()`, deprecated in 1.9.0
+ - `fritzconnection.lib.fritzwlan.FritzWLAN.channel_infos()`, deprecated in
1.9.0
+
+
1.14.0 - 2024-08-12
-------------------
@@ -23,7 +49,7 @@
- bugfix: some devices may not return system-information the propper way,
causing errors on the cli output. In these cases the system-information will
get ignored. (#214)
- documentation: some typos corrected. (#202, #204)
- testing: `tox.ini` removed because of change to `nox`. Change from `pylint`
to `ruff` for linting.
-- deprecation: use of the `json` cache-format is discouraged. Use the default
pickle-format instead. The highly dynamic TR-064 parser may get an ouverhaul in
the future and to reduce the complexity of the parser the support of `json` for
caching will be removed.
+- **deprecation**: use of the `json` cache-format is discouraged. Use the
default pickle-format instead. The highly dynamic TR-064 parser may get an
ouverhaul in the future and to reduce the complexity of the parser the support
of `json` for caching will be removed.
1.13.2 - 2023-09-17
@@ -52,7 +78,7 @@
- command-line interface: the check for a given password has been removed and
substituted by a meaningfull error message in case of an authorization failure.
Not every service is password-protected and passwords can optional provided by
the environment. Therefore there is no need to require a password at cli level.
(Motivated by #192)
- bugfix: unneeded required password removed from the `fritzstatus`
command-line interface. (#192)
- bugfix: make `fritzwlan.get_beacon_security()` work with older router models
not supporting the `NewX_AVM-DE_PossibleBeaconTypes` argument. (#191)
-- deprecation: `fritzconnection.lib.fritzphonebook.list_phonebooks()`
+- **deprecation**: `fritzconnection.lib.fritzphonebook.list_phonebooks()`
1.12.2 - 2023-07-09
@@ -96,7 +122,7 @@
- bugfix: create new socket on lost connection. (#179)
-- Deprecations:
+- **Deprecations**:
-
`fritzconnection.lib.fritzhomeauto.FritzHomeAutomation.device_information()`
@@ -186,7 +212,8 @@
- New method `channel_info()` (#131)
- FritzHomeAutomation: New method `device_information()` (#131)
-- Deprecations:
+
+- **Deprecations**:
-
`fritzconnection.lib.fritzhomeauto.FritzHomeAutomation.device_informations()`
- `fritzconnection.lib.fritzstatus.FritzStatus.uptime()`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/fritzconnection/__init__.py
new/fritzconnection-1.15.0/fritzconnection/__init__.py
--- old/fritzconnection-1.14.0/fritzconnection/__init__.py 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/__init__.py 2025-05-17
16:21:25.000000000 +0200
@@ -13,7 +13,7 @@
# unused shortcut import are intended:
# ruff: noqa: F401
-__version__ = "1.14.0"
+__version__ = "1.15.0"
# import shortcuts
from .core.fritzconnection import FritzConnection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/core/fritzconnection.py
new/fritzconnection-1.15.0/fritzconnection/core/fritzconnection.py
--- old/fritzconnection-1.14.0/fritzconnection/core/fritzconnection.py
2024-08-12 17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/core/fritzconnection.py
2025-05-17 16:21:25.000000000 +0200
@@ -170,6 +170,12 @@
(json|pickle) and FRITZ_CACHEDIRECTORY (a path).
.. versionadded:: 1.10
+
+ `redact_debug_log` accepts a boolean for enabling redacting sensitiv
+ data (i.e. phone numbers) in debug outputs. Default is `False`.
+
+ .. versionadded:: 1.15
+
"""
def __init__(
@@ -186,6 +192,7 @@
cache_format: str | None = None,
pool_connections: int = DEFAULT_POOL_CONNECTIONS,
pool_maxsize: int = DEFAULT_POOL_MAXSIZE,
+ redact_debug_log: bool = False
):
"""
Initialisation of FritzConnection: reads all data from the box
@@ -237,6 +244,9 @@
`pool_connections` and `pool_maxsize` accept integers for
changing the default urllib3 settings in order to modify the
number of reusable connections.
+
+ `redact_debug_log` accepts a boolean for enabling redacting some
+ sensitiv data in debug outputs. Default is `False`.
"""
if address is None:
address = FRITZ_IP_ADDRESS
@@ -279,7 +289,7 @@
self.port = port
self.soaper = Soaper(
- address, port, user, password, timeout=timeout, session=session
+ address, port, user, password, timeout=timeout, session=session,
redact_debug_log=redact_debug_log
)
self.device_manager = DeviceManager(timeout=timeout, session=session)
self._load_router_api(
@@ -512,6 +522,18 @@
"""
self.call_action("DeviceConfig1", "Reboot")
+ def get_cpu_temperatures(self) -> list[int]:
+ """
+ Returns a list of the last measured cpu-temperatures.
+ The most recent entry is the first one in the list.
+ NOTE: this function call is experimental as it is based on a
+ non-public API.
+ """
+ url = f"{self.http_interface.router_url}/query.lua"
+ payload = {"CPUTEMP": "cpu:status/StatTemperature"}
+ response = self.http_interface.call_url(url, payload)
+ return list(map(int, response.json()["CPUTEMP"].split(",")))
+
# -------------------------------------------
# internal methods to load router-api:
# -------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/core/fritzhttp.py
new/fritzconnection-1.15.0/fritzconnection/core/fritzhttp.py
--- old/fritzconnection-1.14.0/fritzconnection/core/fritzhttp.py
2024-08-12 17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/core/fritzhttp.py
2025-05-17 16:21:25.000000000 +0200
@@ -54,14 +54,19 @@
return HTTP_PORT
@property
+ def router_url(self):
+ """Returns the combination of router address and port."""
+ return f"{self.fc.address}:{self.remote_port}"
+
+ @property
def login_url(self):
"""The login-url including protocol and configurable port."""
- return f"{self.fc.address}:{self.remote_port}{URL_LOGIN}"
+ return f"{self.router_url}{URL_LOGIN}"
@property
def homeauto_url(self):
"""The homeauto-url including protocol and configurable port."""
- return f"{self.fc.address}:{self.remote_port}{URL_HOMEAUTOSWITCH}"
+ return f"{self.router_url}{URL_HOMEAUTOSWITCH}"
def execute(self, command=None, identifier=None, **kwargs):
"""
@@ -78,13 +83,29 @@
"""
payload = {"switchcmd": command, "ain": identifier}
payload.update(kwargs)
+ response = self.call_url(self.homeauto_url, payload)
+ return response.headers.get('content-type'), response.text
+
+ def call_url(self, url, payload):
+ """
+ Makes a call to the router with the provided url. Returns the
+ request object in case of success. Otherwise a
+ FritzHttpInterfaceError will get raised.
+
+ Beside the public API documented by AVM this method allows calls
+ to undocumented APIs serving the router web-interface or
+ providing other data.
+
+ WARNING: For a reliable application it is highly discouraged to
+ use undocumented endpoints because they can change any time without
+ notice. So an application may not survive a router OS update.
+ """
for sid in self._get_sid():
payload['sid'] = sid
- with self.fc.session.get(
- self.homeauto_url, params=payload
- ) as response:
+ with self.fc.session.get(url, params=payload) as response:
if response.status_code == HTTPStatus.OK:
- return response.headers.get('content-type'), response.text
+ return response
+
msg = f"Request failed: http error code '{response.status_code}'"
if response.status_code == HTTPStatus.FORBIDDEN:
# can happen if FritzConnection was initialized
@@ -102,6 +123,9 @@
failed. This can happen on an invalide or expired sid. In this
case the sid gets regenerated for the second try.
"""
+ if self.sid is None:
+ # a session id of None can lead to irritation
+ self._set_sid_from_box()
yield self.sid
self._set_sid_from_box()
yield self.sid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/core/soaper.py
new/fritzconnection-1.15.0/fritzconnection/core/soaper.py
--- old/fritzconnection-1.14.0/fritzconnection/core/soaper.py 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/core/soaper.py 2025-05-17
16:21:25.000000000 +0200
@@ -8,6 +8,7 @@
import datetime
+from logging import DEBUG
import html
import re
@@ -190,6 +191,22 @@
exception = FRITZ_ERRORS.get(error_code, FritzConnectionException)
raise exception(message)
+def redact_response(redact: bool, input: str):
+ # avoid expansive regex matching, when not neccessary
+ if fritzlogger.level != DEBUG or not redact:
+ return input
+ # redact possible phone numbers
+ # numbers with len of 5 or more, sourounded by white spaces or bracket
+ redacted = re.sub(r"([\s\[\(])\d{5,}([\s\]\)])", r"\1******\2", input)
+
+ # redact external ip addresses
+ ext_ip_keys = 'New(ExternalIPAddress|ExternalIPv6Address)'
+ redacted = re.sub(r"(<{0}>)(.*)(</{0}>)".format(ext_ip_keys),
r"\1******\4", redacted)
+
+ # redact wifi passwords
+ wifi_pwd_keys = 'New(WEPKey\d+|PreSharedKey|KeyPassphrase)'
+ redacted = re.sub(r"(<{0}>)(.*)(</{0}>)".format(wifi_pwd_keys),
r"\1******\4", redacted)
+ return redacted
class Soaper:
"""
@@ -238,13 +255,14 @@
"ui4": int,
}
- def __init__(self, address, port, user, password, timeout=None,
session=None):
+ def __init__(self, address, port, user, password, timeout=None,
session=None, redact_debug_log=False):
self.address = address
self.port = port
self.user = user
self.password = password
self.timeout = timeout
self.session = session
+ self.redact_debug_log = redact_debug_log
def get_body(self, service, action_name, arguments):
"""Returns the body by template substitution."""
@@ -263,7 +281,7 @@
def handle_response(response):
fritzlogger.debug(f"response status: {response.status_code}")
- fritzlogger.debug(response.text)
+ fritzlogger.debug(redact_response(self.redact_debug_log,
response.text))
if response.status_code != 200:
raise_fritzconnection_error(response)
return self.parse_response(response, service, action_name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/lib/fritzcall.py
new/fritzconnection-1.15.0/fritzconnection/lib/fritzcall.py
--- old/fritzconnection-1.14.0/fritzconnection/lib/fritzcall.py 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/lib/fritzcall.py 2025-05-17
16:21:25.000000000 +0200
@@ -184,8 +184,9 @@
"""
Represents a call with the attributes provided by AVM. Instance
attributes are *Id*, *Type*, *Called*, *Caller*, *CallerNumber*,
- *CalledNumber*, *Name*, *Device*, *Port*, *Date*, *Duration* and
- *Count*. The spelling represents the original xml-node names.
+ *CalledNumber*, *Name*, *Device*, *Port*, *Date*, *Duration*,
+ *Count* and *Path* which can be set in case of an optional phone
+ message. The spelling represents the original xml-node names.
Additionally, the following attributes can be accessed by lowercase
names: *id* returning the Id as integer, *type* returning the Type
as integer, *date* returning the Date as datetime-instance,
@@ -209,6 +210,7 @@
self.Date = None
self.Duration = None
self.Count = None
+ self.Path = None
def __str__(self):
number = self.Called if self.type == 3 else self.Caller
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/lib/fritzhomeauto.py
new/fritzconnection-1.15.0/fritzconnection/lib/fritzhomeauto.py
--- old/fritzconnection-1.14.0/fritzconnection/lib/fritzhomeauto.py
2024-08-12 17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/lib/fritzhomeauto.py
2025-05-17 16:21:25.000000000 +0200
@@ -96,14 +96,6 @@
"""
return self._action('GetSpecificDeviceInfos', NewAIN=identifier)
- def device_informations(self) -> list[dict]:
- """
- .. deprecated:: 1.9.0
- Use :func:`get_device_information_list` instead.
- """
- warn('This method is deprecated. Use "get_device_information_list"
instead.', DeprecationWarning)
- return self.get_device_information_list()
-
def device_information(self) -> list[dict]:
"""
.. deprecated:: 1.12.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/lib/fritzstatus.py
new/fritzconnection-1.15.0/fritzconnection/lib/fritzstatus.py
--- old/fritzconnection-1.14.0/fritzconnection/lib/fritzstatus.py
2024-08-12 17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/lib/fritzstatus.py
2025-05-17 16:21:25.000000000 +0200
@@ -2,11 +2,18 @@
Module to read status-information from an AVM FritzBox.
"""
-
from __future__ import annotations
+import datetime
from collections import namedtuple
-from warnings import warn
+
+from fritzconnection.core.processor import (
+ Storage,
+ InstanceAttributeFactory,
+ processor,
+ process_node,
+)
+from fritzconnection.core.utils import get_xml_root
from .fritzbase import AbstractLibraryBase
from .fritztools import (
@@ -17,10 +24,10 @@
)
DefaultConnectionService = namedtuple(
- "DefaultConnectionService",
- "prefix connection_service postfix"
+ "DefaultConnectionService", "prefix connection_service postfix"
)
+
def _integer_or_original(value):
"""
Tries to convert value to an integer. Returns this integer on
@@ -32,6 +39,44 @@
return value
+@processor
+class Event:
+ """
+ Represents an AVM DeviceLog entry with the subnodes given as
+ class-attributes. The default types are strings as extracted from
+ the xml-source.
+ """
+
+ id = None
+ group = None
+ date = None
+ time = None
+ msg = None
+
+ @property
+ def datetime(self):
+ return datetime.datetime.strptime(f"{self.date}{self.time}",
"%d.%m.%y%H:%M:%S")
+
+
+class DeviceLog(Storage):
+ """
+ The AVM DeviceLog is a list of Event-nodes stored in the `events`
+ instance attribute. But instances of DeviceLog are also iterables
+ for the events.
+ """
+
+ Event = InstanceAttributeFactory(Event)
+
+ def __init__(self, root):
+ self.events = list()
+ super().__init__(self.events)
+ process_node(self, root)
+
+ def __iter__(self):
+ for event in self.events:
+ yield event
+
+
class FritzStatus(AbstractLibraryBase):
"""
Class for requesting status-information: up, down, ip, activity
@@ -107,15 +152,6 @@
return status["NewUptime"]
@property
- def uptime(self) -> int:
- """
- .. deprecated:: 1.9.0
- Use :func:`connection_uptime` instead.
- """
- warn('This method is deprecated. Use "connection_uptime" instead.',
DeprecationWarning)
- return self.connection_uptime
-
- @property
def device_uptime(self) -> int:
"""Device uptime in seconds."""
status = self.fc.call_action("DeviceInfo1", "GetInfo")
@@ -124,7 +160,7 @@
@property
def str_uptime(self) -> str:
"""Connection uptime in human-readable format."""
- mins, secs = divmod(self.uptime, 60)
+ mins, secs = divmod(self.connection_uptime, 60)
hours, mins = divmod(mins, 60)
return "%02d:%02d:%02d" % (hours, mins, secs)
@@ -139,9 +175,7 @@
value = status["NewX_AVM_DE_TotalBytesSent64"]
except KeyError:
# fallback for older FritzOS Versions not providing a 64 bit value:
- status = self.fc.call_action(
- "WANCommonIFC1", "GetTotalBytesSent"
- )
+ status = self.fc.call_action("WANCommonIFC1", "GetTotalBytesSent")
value = status["NewTotalBytesSent"]
return _integer_or_original(value)
@@ -156,9 +190,7 @@
value = status["NewX_AVM_DE_TotalBytesReceived64"]
except KeyError:
# fallback for older FritzOS Versions not providing a 64 bit value:
- status = self.fc.call_action(
- "WANCommonIFC1", "GetTotalBytesReceived"
- )
+ status = self.fc.call_action("WANCommonIFC1",
"GetTotalBytesReceived")
value = status["NewTotalBytesReceived"]
return _integer_or_original(value)
@@ -324,10 +356,7 @@
# check for the corresponding action
# whether mesh is supported
try:
- return (
- "X_AVM-DE_GetMeshListPath"
- in self.fc.services["Hosts1"].actions
- )
+ return "X_AVM-DE_GetMeshListPath" in
self.fc.services["Hosts1"].actions
except KeyError:
# can happen if "Hosts1" is not known
return False
@@ -345,6 +374,43 @@
"""
return ArgumentNamespace(self.fc.call_action("DeviceInfo1", "GetInfo"))
+ def get_avm_device_log(self, filter: str | None = None) -> DeviceLog:
+ """
+ The avm device log is a list of events with the attributes `id`,
+ `group`, `date`, `time` and `msg` holding information like "DSL
+ synchronization starting (training)" and other system messages.
+ The Method returns a DeviceLog instance holding a list of Event
+ instances. The DeviceLog instance is an iterable and can be
+ used on a FritzStatus instance like:
+
+ >>> device_log = fritzstatus.get_avm_device_log()
+ >>> for event in device_log:
+ >>> print(event.datetime, event.msg)
+
+ The returned events can be filtered by groups like 'sys', 'net',
+ 'fon', 'wlan' or 'usb'. To filter by a group provide the
+ group-name as filter-argument.
+ """
+ result = self.fc.call_action("DeviceInfo1",
"X_AVM-DE_GetDeviceLogPath")
+ path = result["NewDeviceLogPath"]
+ if filter:
+ path = f"{path}&filter={filter}"
+ url = f"{self.fc.address}:{self.fc.port}{path}"
+ root_node = get_xml_root(url, session=self.fc.session)
+ return DeviceLog(root_node)
+
+ def get_cpu_temperatures(self) -> list[int]:
+ """
+ Returns a list of the last measured cpu-temperatures (Celsius).
+ The most recent entry is the first one in the list.
+ NOTE: this function call is experimental as it is based on a
+ non-public API.
+ """
+ url = f"{self.fc.http_interface.router_url}/query.lua"
+ payload = {"CPUTEMP": "cpu:status/StatTemperature"}
+ response = self.fc.http_interface.call_url(url, payload)
+ return list(map(int, response.json()["CPUTEMP"].split(",")))
+
def get_default_connection_service(self) -> DefaultConnectionService:
"""
Returns a namedtuple of type DefaultConnectionService:
@@ -352,14 +418,11 @@
`device_connection` -> str (like "WANPPPConnection")
`postfix` -> str
"""
- result = self.fc.call_action(
- "Layer3Forwarding1", "GetDefaultConnectionService"
- )
- prefix, connection_service, postfix = \
- result["NewDefaultConnectionService"].split('.', 2)
- return DefaultConnectionService(
- prefix, connection_service, postfix
- )
+ result = self.fc.call_action("Layer3Forwarding1",
"GetDefaultConnectionService")
+ prefix, connection_service, postfix = result[
+ "NewDefaultConnectionService"
+ ].split(".", 2)
+ return DefaultConnectionService(prefix, connection_service, postfix)
@property
def connection_service(self) -> str:
@@ -388,7 +451,8 @@
@property
def has_wan_support(self) -> bool:
"""
- True is the device supports a WAN interface.
+ True if the device supports a WAN interface.
False otherwise.
"""
return "Layer3Forwarding1" in self.fc.services
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/lib/fritzwlan.py
new/fritzconnection-1.15.0/fritzconnection/lib/fritzwlan.py
--- old/fritzconnection-1.14.0/fritzconnection/lib/fritzwlan.py 2024-08-12
17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/lib/fritzwlan.py 2025-05-17
16:21:25.000000000 +0200
@@ -13,7 +13,6 @@
import itertools
import random
import string
-from warnings import warn
from ..core.exceptions import FritzServiceError
from .fritzbase import AbstractLibraryBase
@@ -208,14 +207,6 @@
"""Alternative channels (as string)"""
return self.channel_info()['NewPossibleChannels']
- def channel_infos(self) -> dict:
- """
- .. deprecated:: 1.9.0
- Use :func:`channel_info` instead.
- """
- warn('This method is deprecated. Use "channel_info" instead.',
DeprecationWarning)
- return self.channel_info()
-
def channel_info(self) -> dict:
"""
Return a dictionary with the keys *NewChannel* and
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/fritzconnection-1.14.0/fritzconnection/tests/test_soaper.py
new/fritzconnection-1.15.0/fritzconnection/tests/test_soaper.py
--- old/fritzconnection-1.14.0/fritzconnection/tests/test_soaper.py
2024-08-12 17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/fritzconnection/tests/test_soaper.py
2025-05-17 16:21:25.000000000 +0200
@@ -30,6 +30,7 @@
get_html_safe_value,
is_html_response,
raise_fritzconnection_error,
+ redact_response,
remove_html_tags,
)
@@ -286,3 +287,146 @@
def test_get_converted_value_fails(data_type, value):
with pytest.raises(ValueError):
get_converted_value(data_type, value)
+
+def test_redact_debug_log_phone_numbers():
+ response = """
+ <?xml version="1.0"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:GetInfoResponse xmlns:u="urn:dslforum-org:service:DeviceInfo:1">
+ <NewManufacturerName>AVM</NewManufacturerName>
+ <NewManufacturerOUI>00040E</NewManufacturerOUI>
+ <NewModelName>FRITZ!Box 7530 AX</NewModelName>
+ <NewDescription>FRITZ!Box 7530 AX Release 256.08.00</NewDescription>
+ <NewProductClass>FRITZ!Box</NewProductClass>
+ <NewSerialNumber>aabbccddeeff</NewSerialNumber>
+ <NewSoftwareVersion>256.08.00</NewSoftwareVersion>
+ <NewHardwareVersion>FRITZ!Box 7530 AX</NewHardwareVersion>
+ <NewSpecVersion>1.0</NewSpecVersion>
+ <NewProvisioningCode></NewProvisioningCode>
+ <NewUpTime>86446</NewUpTime>
+ <NewDeviceLog>
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer 491234567890 war nicht
erfolgreich. Ursache: DNS-Fehler
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer 491234567891 war nicht
erfolgreich. Ursache: DNS-Fehler
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer 491234567892 war nicht
erfolgreich. Ursache: DNS-Fehler
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer 491234567893 war nicht
erfolgreich. Ursache: DNS-Fehler
+ </u:GetInfoResponse>
+ </s:Body>
+ </s:Envelope>
+ """
+
+ result = redact_response(False, response)
+ assert result == response
+
+ result = redact_response(True, response)
+ assert result == """
+ <?xml version="1.0"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:GetInfoResponse xmlns:u="urn:dslforum-org:service:DeviceInfo:1">
+ <NewManufacturerName>AVM</NewManufacturerName>
+ <NewManufacturerOUI>00040E</NewManufacturerOUI>
+ <NewModelName>FRITZ!Box 7530 AX</NewModelName>
+ <NewDescription>FRITZ!Box 7530 AX Release 256.08.00</NewDescription>
+ <NewProductClass>FRITZ!Box</NewProductClass>
+ <NewSerialNumber>aabbccddeeff</NewSerialNumber>
+ <NewSoftwareVersion>256.08.00</NewSoftwareVersion>
+ <NewHardwareVersion>FRITZ!Box 7530 AX</NewHardwareVersion>
+ <NewSpecVersion>1.0</NewSpecVersion>
+ <NewProvisioningCode></NewProvisioningCode>
+ <NewUpTime>86446</NewUpTime>
+ <NewDeviceLog>
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer ****** war nicht
erfolgreich. Ursache: DNS-Fehler
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer ****** war nicht
erfolgreich. Ursache: DNS-Fehler
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer ****** war nicht
erfolgreich. Ursache: DNS-Fehler
+ 23.11.24 12:28:10 Anmeldung der Internetrufnummer ****** war nicht
erfolgreich. Ursache: DNS-Fehler
+ </u:GetInfoResponse>
+ </s:Body>
+ </s:Envelope>
+ """
+
+def test_redact_debug_log_external_ip_addresses():
+ response = """
+ <?xml version="1.0" encoding="utf-8"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:GetExternalIPAddressResponse
xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
+ <NewExternalIPAddress>12.34.56.78</NewExternalIPAddress>
+ </u:GetExternalIPAddressResponse>
+ </s:Body>
+ </s:Envelope>
+ <?xml version="1.0" encoding="utf-8"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:X_AVM_DE_GetExternalIPv6AddressResponse
xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
+ <NewExternalIPv6Address>0011:2233:4455:6677::0abcd</NewExternalIPv6Address>
+ <NewPrefixLength>64</NewPrefixLength>
+ <NewValidLifetime>0</NewValidLifetime>
+ <NewPreferedLifetime>0</NewPreferedLifetime>
+ </u:X_AVM_DE_GetExternalIPv6AddressResponse>
+ </s:Body>
+ </s:Envelope>
+ """
+
+ result = redact_response(False, response)
+ assert result == response
+
+ result = redact_response(True, response)
+ assert result == """
+ <?xml version="1.0" encoding="utf-8"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:GetExternalIPAddressResponse
xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
+ <NewExternalIPAddress>******</NewExternalIPAddress>
+ </u:GetExternalIPAddressResponse>
+ </s:Body>
+ </s:Envelope>
+ <?xml version="1.0" encoding="utf-8"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:X_AVM_DE_GetExternalIPv6AddressResponse
xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
+ <NewExternalIPv6Address>******</NewExternalIPv6Address>
+ <NewPrefixLength>64</NewPrefixLength>
+ <NewValidLifetime>0</NewValidLifetime>
+ <NewPreferedLifetime>0</NewPreferedLifetime>
+ </u:X_AVM_DE_GetExternalIPv6AddressResponse>
+ </s:Body>
+ </s:Envelope>
+ """
+
+def test_redact_debug_log_wifi_passwords():
+ response = """
+ <?xml version="1.0"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:GetSecurityKeysResponse
xmlns:u="urn:dslforum-org:service:WLANConfiguration:3">
+ <NewWEPKey0>0123456789</NewWEPKey0>
+ <NewWEPKey1></NewWEPKey1>
+ <NewWEPKey2>01234 6789</NewWEPKey2>
+ <NewWEPKey3></NewWEPKey3>
+
<NewPreSharedKey>0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF</NewPreSharedKey>
+ <NewKeyPassphrase>MY_GREAT_WIFI_PSK</NewKeyPassphrase>
+ </u:GetSecurityKeysResponse>
+ </s:Body>
+ </s:Envelope>
+ """
+
+ result = redact_response(False, response)
+ assert result == response
+
+ result = redact_response(True, response)
+ assert result == """
+ <?xml version="1.0"?>
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
+ <s:Body>
+ <u:GetSecurityKeysResponse
xmlns:u="urn:dslforum-org:service:WLANConfiguration:3">
+ <NewWEPKey0>******</NewWEPKey0>
+ <NewWEPKey1>******</NewWEPKey1>
+ <NewWEPKey2>******</NewWEPKey2>
+ <NewWEPKey3>******</NewWEPKey3>
+ <NewPreSharedKey>******</NewPreSharedKey>
+ <NewKeyPassphrase>******</NewKeyPassphrase>
+ </u:GetSecurityKeysResponse>
+ </s:Body>
+ </s:Envelope>
+ """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/noxfile.py
new/fritzconnection-1.15.0/noxfile.py
--- old/fritzconnection-1.14.0/noxfile.py 2024-08-12 17:58:36.000000000
+0200
+++ new/fritzconnection-1.15.0/noxfile.py 2025-05-17 16:21:25.000000000
+0200
@@ -1,7 +1,7 @@
import nox
-PYTHON_TEST_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13")
+PYTHON_TEST_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13",
"3.14")
PYTHON_DEVELOPMENT_VERSION = "3.11"
@@ -48,10 +48,11 @@
"pip-compile",
"--strip-extras",
"-q",
- "--output-file=docs/requirements.txt",
- "docs/requirements.local.in"
+ "--output-file=docs/requirements.out",
+ "docs/requirements.txt"
+ #"docs/requirements.local.in"
)
- session.install("-r", "docs/requirements.txt")
+ session.install("-r", "docs/requirements.out")
session.run("sphinx-build", "docs", "docs_out")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/fritzconnection-1.14.0/setup.py
new/fritzconnection-1.15.0/setup.py
--- old/fritzconnection-1.14.0/setup.py 2024-08-12 17:58:36.000000000 +0200
+++ new/fritzconnection-1.15.0/setup.py 2025-05-17 16:21:25.000000000 +0200
@@ -44,6 +44,7 @@
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Topic :: Software Development :: Libraries :: Python Modules",
],
keywords="AVM FRITZ!Box fritzbox fritz TR-064 AHA-HTTP homeautomation",