Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ jobs:
name: mypy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Install dependencies
Expand Down
11 changes: 7 additions & 4 deletions pyfritzhome/devicetypes/fritzhomedeviceswitch.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""The switch device class."""

# -*- coding: utf-8 -*-

import logging
from typing import Optional

from .fritzhomedevicebase import FritzhomeDeviceBase
from .fritzhomedevicefeatures import FritzhomeDeviceFeatures
Expand All @@ -14,9 +16,10 @@ class FritzhomeDeviceSwitch(FritzhomeDeviceBase):

switch_state = None
switch_mode = None
lock = None
lock: Optional[bool] = None
device_lock: Optional[bool] = None

def _update_from_node(self, node):
def _update_from_node(self, node) -> None:
super()._update_from_node(node)
if self.present is False:
return
Expand All @@ -26,7 +29,7 @@ def _update_from_node(self, node):

# Switch
@property
def has_switch(self):
def has_switch(self) -> bool:
"""Check if the device has switch function."""
if self._has_feature(FritzhomeDeviceFeatures.SWITCH):
# for AVM plugs like FRITZ!DECT 200 and FRITZ!DECT 210
Expand All @@ -38,7 +41,7 @@ def has_switch(self):
return True
return False

def _update_switch_from_node(self, node):
def _update_switch_from_node(self, node) -> None:
_LOGGER.debug("update switch device")
if self._has_feature(FritzhomeDeviceFeatures.SWITCH):
val = node.find("switch")
Expand Down
6 changes: 4 additions & 2 deletions pyfritzhome/devicetypes/fritzhomedevicethermostat.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""The thermostat device class."""

# -*- coding: utf-8 -*-

import logging
import time
from typing import Optional

from .fritzhomedevicebase import FritzhomeDeviceBase
from .fritzhomedevicefeatures import FritzhomeDeviceFeatures
Expand All @@ -17,8 +19,8 @@ class FritzhomeDeviceThermostat(FritzhomeDeviceBase):
target_temperature = None
eco_temperature = None
comfort_temperature = None
device_lock = None
lock = None
device_lock: Optional[bool] = None
lock: Optional[bool] = None
error_code = None
window_open = None
window_open_endtime = None
Expand Down
29 changes: 16 additions & 13 deletions pyfritzhome/devicetypes/fritzhomeentitybase.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

# -*- coding: utf-8 -*-

from __future__ import print_function
from __future__ import annotations

import logging
from abc import ABC
from typing import TYPE_CHECKING

# Avoid circular import
if TYPE_CHECKING:
from pyfritzhome.fritzhome import Fritzhome

import logging
from xml.etree import ElementTree

from .fritzhomedevicefeatures import FritzhomeDeviceFeatures

_LOGGER = logging.getLogger(__name__)
Expand All @@ -16,29 +22,26 @@
class FritzhomeEntityBase(ABC):
"""The Fritzhome Entity class."""

_fritz = None
_fritz: Fritzhome
ain: str
_functionsbitmask: int = 0
supported_features = None
supported_features: list = []

def __init__(self, fritz=None, node=None):
def __init__(self, fritz=None, node=None) -> None:
"""Create an entity base object."""
if fritz is not None:
self._fritz = fritz
if node is not None:
self._update_from_node(node)

def __repr__(self):
def __repr__(self) -> str:
"""Return a string."""
return "{ain} {name}".format(
ain=self.ain,
name=self.name,
)
return f"{self.ain} {self.name}"

def _has_feature(self, feature: FritzhomeDeviceFeatures) -> bool:
return feature in FritzhomeDeviceFeatures(self._functionsbitmask)

def _update_from_node(self, node):
def _update_from_node(self, node) -> None:
_LOGGER.debug(ElementTree.tostring(node))
self.ain = node.attrib["identifier"]
self._functionsbitmask = int(node.attrib["functionbitmask"])
Expand All @@ -51,7 +54,7 @@ def _update_from_node(self, node):
self.supported_features.append(feature)

@property
def device_and_unit_id(self):
def device_and_unit_id(self) -> tuple:
"""Get the device and possible unit id."""
if self.ain.startswith("tmp") or self.ain.startswith("grp"):
return (self.ain, None)
Expand All @@ -75,6 +78,6 @@ def get_node_value_as_int_as_bool(self, elem, node) -> bool:
"""Get the node value as boolean."""
return bool(self.get_node_value_as_int(elem, node))

def get_temp_from_node(self, elem, node):
def get_temp_from_node(self, elem, node) -> float:
"""Get the node temp value as float."""
return float(self.get_node_value(elem, node)) / 2
7 changes: 4 additions & 3 deletions pyfritzhome/devicetypes/fritzhometemplate.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
"""The template class."""

# -*- coding: utf-8 -*-

import logging

from .fritzhomeentitybase import FritzhomeEntityBase
from .fritzhomedevicefeatures import FritzhomeDeviceFeatures
from .fritzhomeentitybase import FritzhomeEntityBase

_LOGGER = logging.getLogger(__name__)


class FritzhomeTemplate(FritzhomeEntityBase):
"""The Fritzhome Template class."""

devices = None
devices: list = []
features = None
apply_hkr_summer = None
apply_hkr_temperature = None
Expand All @@ -24,7 +25,7 @@ class FritzhomeTemplate(FritzhomeEntityBase):
apply_color = None
apply_dialhelper = None

def _update_from_node(self, node):
def _update_from_node(self, node) -> None:
_LOGGER.debug("update template")
super()._update_from_node(node)

Expand Down
21 changes: 9 additions & 12 deletions pyfritzhome/fritzhome.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
"""The main fritzhome handling class."""
# -*- coding: utf-8 -*-

from __future__ import print_function
# -*- coding: utf-8 -*-

import hashlib
import logging
import time
from typing import Optional
from xml.etree import ElementTree

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

from requests import exceptions, Session
from requests import Session, exceptions

from .errors import InvalidError, LoginError, NotLoggedInError
from .fritzhomedevice import FritzhomeDevice
from .fritzhomedevice import FritzhomeTemplate
from typing import Dict, Optional
from .fritzhomedevice import FritzhomeDevice, FritzhomeTemplate

_LOGGER = logging.getLogger(__name__)


class Fritzhome(object):
class Fritzhome:
"""Fritzhome object to communicate with the device."""

_sid = None
_session = None
_devices: Optional[Dict[str, FritzhomeDevice]] = None
_templates: Optional[Dict[str, FritzhomeTemplate]] = None
_session: Session
_devices: Optional[dict[str, FritzhomeDevice]] = None
_templates: Optional[dict[str, FritzhomeTemplate]] = None

def __init__(self, host, user, password, ssl_verify=True):
"""Create a fritzhome object."""
Expand Down Expand Up @@ -59,7 +56,7 @@ def _login_request(self, username=None, secret=None):
plain = self._request(url, params)
dom = ElementTree.fromstring(plain)
sid = dom.findtext("SID")
blocktime = int(dom.findtext("BlockTime"))
blocktime = int(dom.findtext("BlockTime") or "0")
challenge = dom.findtext("Challenge")

return (sid, challenge, blocktime)
Expand Down
7 changes: 7 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,10 @@ match-dir = pyfritzhome/*
[pydocstyle]
ignore = D203,D213
match-dir = pyfritzhome/*

[mypy]
warn_unused_configs = True
warn_redundant_casts = True
warn_unused_ignores = True
strict_equality = True
check_untyped_defs = True