Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
7dcb34559b | |||
5db13a90e7 | |||
9ee5dbc956 | |||
d4c6ccdce3 | |||
9594b9ebd8 | |||
b011d98e07 | |||
ad864286fc | |||
13cff8caa0 | |||
5fc6245806 | |||
1dad0e14b8 | |||
b04c601ad6 | |||
3ec0f5a006 | |||
78bc85132f | |||
191928287f | |||
c0aab8b99d | |||
b37715d0ca | |||
411effd814 | |||
a68dcac379 | |||
40cc0013a5 | |||
f2aa3dc8fd | |||
e887371bec | |||
18b0ecdd68 |
@ -1,16 +1,21 @@
|
|||||||
import importlib
|
import importlib
|
||||||
|
import logging
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from pyhon import helper
|
from pyhon import helper
|
||||||
from pyhon.commands import HonCommand
|
from pyhon.commands import HonCommand
|
||||||
|
from pyhon.parameter.base import HonParameter
|
||||||
from pyhon.parameter.fixed import HonParameterFixed
|
from pyhon.parameter.fixed import HonParameterFixed
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from pyhon import HonAPI
|
from pyhon import HonAPI
|
||||||
|
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class HonAppliance:
|
class HonAppliance:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, api: Optional["HonAPI"], info: Dict[str, Any], zone: int = 0
|
self, api: Optional["HonAPI"], info: Dict[str, Any], zone: int = 0
|
||||||
@ -29,7 +34,7 @@ class HonAppliance:
|
|||||||
try:
|
try:
|
||||||
self._extra = importlib.import_module(
|
self._extra = importlib.import_module(
|
||||||
f"pyhon.appliances.{self.appliance_type.lower()}"
|
f"pyhon.appliances.{self.appliance_type.lower()}"
|
||||||
).Appliance()
|
).Appliance(self)
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
self._extra = None
|
self._extra = None
|
||||||
|
|
||||||
@ -165,7 +170,8 @@ class HonAppliance:
|
|||||||
def settings(self):
|
def settings(self):
|
||||||
result = {}
|
result = {}
|
||||||
for name, command in self._commands.items():
|
for name, command in self._commands.items():
|
||||||
for key, setting in command.settings.items():
|
for key in command.setting_keys:
|
||||||
|
setting = command.settings.get(key, HonParameter(key, {}))
|
||||||
result[f"{name}.{key}"] = setting
|
result[f"{name}.{key}"] = setting
|
||||||
if self._extra:
|
if self._extra:
|
||||||
return self._extra.settings(result)
|
return self._extra.settings(result)
|
||||||
@ -214,4 +220,4 @@ class HonAppliance:
|
|||||||
{"commands": helper.create_command(self.commands)},
|
{"commands": helper.create_command(self.commands)},
|
||||||
whitespace="\u200B \u200B ",
|
whitespace="\u200B \u200B ",
|
||||||
)
|
)
|
||||||
return result.replace(self.mac_address, "12-34-56-78-90-ab")
|
return result.replace(self.mac_address, "xx-xx-xx-xx-xx-xx")
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
class Appliance:
|
class Appliance:
|
||||||
|
def __init__(self, appliance):
|
||||||
|
self.parent = appliance
|
||||||
|
|
||||||
def data(self, data):
|
def data(self, data):
|
||||||
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
||||||
data["attributes"]["parameters"]["machMode"] = "0"
|
data["attributes"]["parameters"]["machMode"] = "0"
|
||||||
|
17
pyhon/appliances/ov.py
Normal file
17
pyhon/appliances/ov.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
class Appliance:
|
||||||
|
def __init__(self, appliance):
|
||||||
|
self.parent = appliance
|
||||||
|
|
||||||
|
def data(self, data):
|
||||||
|
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
||||||
|
data["attributes"]["parameters"]["temp"] = "0"
|
||||||
|
data["attributes"]["parameters"]["onOffStatus"] = "0"
|
||||||
|
data["attributes"]["parameters"]["remoteCtrValid"] = "0"
|
||||||
|
data["attributes"]["parameters"]["remainingTimeMM"] = "0"
|
||||||
|
|
||||||
|
data["active"] = data["attributes"]["parameters"]["onOffStatus"] == "1"
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def settings(self, settings):
|
||||||
|
return settings
|
@ -1,10 +1,22 @@
|
|||||||
|
from pyhon.parameter.fixed import HonParameterFixed
|
||||||
|
|
||||||
|
|
||||||
class Appliance:
|
class Appliance:
|
||||||
|
def __init__(self, appliance):
|
||||||
|
self.parent = appliance
|
||||||
|
|
||||||
def data(self, data):
|
def data(self, data):
|
||||||
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
||||||
data["attributes"]["parameters"]["machMode"] = "0"
|
data["attributes"]["parameters"]["machMode"] = "0"
|
||||||
data["active"] = bool(data.get("attributes", {}).get("activity"))
|
data["active"] = bool(data.get("attributes", {}).get("activity"))
|
||||||
data["pause"] = data["attributes"]["parameters"]["machMode"] == "3"
|
data["pause"] = data["attributes"]["parameters"]["machMode"] == "3"
|
||||||
|
if program := int(data["attributes"]["parameters"]["prCode"]):
|
||||||
|
ids = self.parent.settings["startProgram.program"].ids
|
||||||
|
data["programName"] = ids.get(program, "")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def settings(self, settings):
|
def settings(self, settings):
|
||||||
|
dry_level = settings.get("startProgram.dryLevel")
|
||||||
|
if isinstance(dry_level, HonParameterFixed) and dry_level.value == "11":
|
||||||
|
settings.pop("startProgram.dryLevel", None)
|
||||||
return settings
|
return settings
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
class Appliance:
|
class Appliance:
|
||||||
|
def __init__(self, appliance):
|
||||||
|
self.parent = appliance
|
||||||
|
|
||||||
def data(self, data):
|
def data(self, data):
|
||||||
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
||||||
data["attributes"]["parameters"]["machMode"] = "0"
|
data["attributes"]["parameters"]["machMode"] = "0"
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
class Appliance:
|
class Appliance:
|
||||||
|
def __init__(self, appliance):
|
||||||
|
self.parent = appliance
|
||||||
|
|
||||||
def data(self, data):
|
def data(self, data):
|
||||||
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
|
||||||
data["attributes"]["parameters"]["machMode"] = "0"
|
data["attributes"]["parameters"]["machMode"] = "0"
|
||||||
|
@ -24,7 +24,7 @@ class HonCommand:
|
|||||||
self._api: HonAPI = api
|
self._api: HonAPI = api
|
||||||
self._appliance: "HonAppliance" = appliance
|
self._appliance: "HonAppliance" = appliance
|
||||||
self._name: str = name
|
self._name: str = name
|
||||||
self._programs: Optional[Dict[str, "HonCommand"]] = programs or {}
|
self._programs: Optional[Dict[str, "HonCommand"]] = programs
|
||||||
self._program_name: str = program_name
|
self._program_name: str = program_name
|
||||||
self._description: str = attributes.get("description", "")
|
self._description: str = attributes.get("description", "")
|
||||||
self._parameters: Dict[str, HonParameter] = self._create_parameters(
|
self._parameters: Dict[str, HonParameter] = self._create_parameters(
|
||||||
@ -89,8 +89,6 @@ class HonCommand:
|
|||||||
for key, parameter in (
|
for key, parameter in (
|
||||||
command._parameters | command._ancillary_parameters
|
command._parameters | command._ancillary_parameters
|
||||||
).items():
|
).items():
|
||||||
if isinstance(parameter, HonParameterFixed):
|
|
||||||
continue
|
|
||||||
if key not in keys:
|
if key not in keys:
|
||||||
keys.append(key)
|
keys.append(key)
|
||||||
return keys
|
return keys
|
||||||
@ -108,7 +106,6 @@ class HonCommand:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def settings(self) -> Dict[str, HonParameter]:
|
def settings(self) -> Dict[str, HonParameter]:
|
||||||
"""Parameters with typology enum and range"""
|
|
||||||
return {
|
return {
|
||||||
s: param
|
s: param
|
||||||
for s in self.setting_keys
|
for s in self.setting_keys
|
||||||
|
@ -12,7 +12,7 @@ from pyhon.connection.auth import HonAuth
|
|||||||
from pyhon.connection.handler.anonym import HonAnonymousConnectionHandler
|
from pyhon.connection.handler.anonym import HonAnonymousConnectionHandler
|
||||||
from pyhon.connection.handler.hon import HonConnectionHandler
|
from pyhon.connection.handler.hon import HonConnectionHandler
|
||||||
|
|
||||||
_LOGGER = logging.getLogger()
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class HonAPI:
|
class HonAPI:
|
||||||
@ -74,13 +74,15 @@ class HonAPI:
|
|||||||
"applianceType": appliance.appliance_type,
|
"applianceType": appliance.appliance_type,
|
||||||
"code": appliance.info["code"],
|
"code": appliance.info["code"],
|
||||||
"applianceModelId": appliance.appliance_model_id,
|
"applianceModelId": appliance.appliance_model_id,
|
||||||
"firmwareId": appliance.info["eepromId"],
|
|
||||||
"macAddress": appliance.mac_address,
|
"macAddress": appliance.mac_address,
|
||||||
"fwVersion": appliance.info["fwVersion"],
|
|
||||||
"os": const.OS,
|
"os": const.OS,
|
||||||
"appVersion": const.APP_VERSION,
|
"appVersion": const.APP_VERSION,
|
||||||
"series": appliance.info["series"],
|
"series": appliance.info["series"],
|
||||||
}
|
}
|
||||||
|
if firmware_id := appliance.info.get("eepromId"):
|
||||||
|
params["firmwareId"] = firmware_id
|
||||||
|
if firmware_version := appliance.info.get("fwVersion"):
|
||||||
|
params["fwVersion"] = firmware_version
|
||||||
url: str = f"{const.API_URL}/commands/v1/retrieve"
|
url: str = f"{const.API_URL}/commands/v1/retrieve"
|
||||||
async with self._hon.get(url, params=params) as response:
|
async with self._hon.get(url, params=params) as response:
|
||||||
result: Dict = (await response.json()).get("payload", {})
|
result: Dict = (await response.json()).get("payload", {})
|
||||||
|
@ -182,13 +182,14 @@ class HonAuth:
|
|||||||
await self._error_logger(response)
|
await self._error_logger(response)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def _parse_token_data(self, text: str) -> None:
|
def _parse_token_data(self, text: str) -> bool:
|
||||||
if access_token := re.findall("access_token=(.*?)&", text):
|
if access_token := re.findall("access_token=(.*?)&", text):
|
||||||
self._access_token = access_token[0]
|
self._access_token = access_token[0]
|
||||||
if refresh_token := re.findall("refresh_token=(.*?)&", text):
|
if refresh_token := re.findall("refresh_token=(.*?)&", text):
|
||||||
self._refresh_token = refresh_token[0]
|
self._refresh_token = refresh_token[0]
|
||||||
if id_token := re.findall("id_token=(.*?)&", text):
|
if id_token := re.findall("id_token=(.*?)&", text):
|
||||||
self._id_token = id_token[0]
|
self._id_token = id_token[0]
|
||||||
|
return True if access_token and refresh_token and id_token else False
|
||||||
|
|
||||||
async def _get_token(self, url: str) -> bool:
|
async def _get_token(self, url: str) -> bool:
|
||||||
async with self._request.get(url) as response:
|
async with self._request.get(url) as response:
|
||||||
@ -214,7 +215,9 @@ class HonAuth:
|
|||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
await self._error_logger(response)
|
await self._error_logger(response)
|
||||||
return False
|
return False
|
||||||
self._parse_token_data(await response.text())
|
if not self._parse_token_data(await response.text()):
|
||||||
|
await self._error_logger(response)
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def _api_auth(self) -> bool:
|
async def _api_auth(self) -> bool:
|
||||||
@ -228,7 +231,10 @@ class HonAuth:
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
await self._error_logger(response)
|
await self._error_logger(response)
|
||||||
return False
|
return False
|
||||||
self._cognito_token = json_data["cognitoUser"]["Token"]
|
self._cognito_token = json_data.get("cognitoUser", {}).get("Token", "")
|
||||||
|
if not self._cognito_token:
|
||||||
|
_LOGGER.error(json_data)
|
||||||
|
raise exceptions.HonAuthenticationError()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def authenticate(self) -> None:
|
async def authenticate(self) -> None:
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
from pyhon.parameter.base import HonParameter
|
||||||
|
|
||||||
|
|
||||||
def key_print(data, key="", start=True):
|
def key_print(data, key="", start=True):
|
||||||
result = ""
|
result = ""
|
||||||
if isinstance(data, list):
|
if isinstance(data, list):
|
||||||
@ -44,12 +47,21 @@ def pretty_print(data, key="", intend=0, is_list=False, whitespace=" "):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_parameter(command, parameter):
|
||||||
|
if programs := command.programs:
|
||||||
|
for program in programs.values():
|
||||||
|
if data := program.settings.get(parameter):
|
||||||
|
return data
|
||||||
|
return command.settings.get(parameter)
|
||||||
|
|
||||||
|
|
||||||
def create_command(commands, concat=False):
|
def create_command(commands, concat=False):
|
||||||
result = {}
|
result = {}
|
||||||
for name, command in commands.items():
|
for name, command in commands.items():
|
||||||
if not concat:
|
if not concat:
|
||||||
result[name] = {}
|
result[name] = {}
|
||||||
for parameter, data in command.settings.items():
|
for parameter in command.setting_keys:
|
||||||
|
data = get_parameter(command, parameter)
|
||||||
if data.typology == "enum":
|
if data.typology == "enum":
|
||||||
value = data.values
|
value = data.values
|
||||||
elif data.typology == "range":
|
elif data.typology == "range":
|
||||||
|
@ -47,7 +47,7 @@ class Hon:
|
|||||||
|
|
||||||
async def _create_appliance(self, appliance_data: Dict[str, Any], zone=0) -> None:
|
async def _create_appliance(self, appliance_data: Dict[str, Any], zone=0) -> None:
|
||||||
appliance = HonAppliance(self._api, appliance_data, zone=zone)
|
appliance = HonAppliance(self._api, appliance_data, zone=zone)
|
||||||
if appliance.mac_address is None:
|
if appliance.mac_address == "":
|
||||||
return
|
return
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
*[
|
*[
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Dict, Any
|
from typing import Dict, Any, List
|
||||||
|
|
||||||
|
|
||||||
class HonParameter:
|
class HonParameter:
|
||||||
@ -17,6 +17,10 @@ class HonParameter:
|
|||||||
def value(self) -> str | float:
|
def value(self) -> str | float:
|
||||||
return self._value if self._value is not None else "0"
|
return self._value if self._value is not None else "0"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def values(self) -> List[str]:
|
||||||
|
return list(str(self.value))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def category(self) -> str:
|
def category(self) -> str:
|
||||||
return self._category
|
return self._category
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List, TYPE_CHECKING
|
from typing import List, TYPE_CHECKING, Dict
|
||||||
|
|
||||||
from pyhon.parameter.enum import HonParameterEnum
|
from pyhon.parameter.enum import HonParameterEnum
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ class HonParameterProgram(HonParameterEnum):
|
|||||||
super().__init__(key, {})
|
super().__init__(key, {})
|
||||||
self._command = command
|
self._command = command
|
||||||
self._value: str = command.program
|
self._value: str = command.program
|
||||||
self._values: List[str] = list(command.programs)
|
self._programs: Dict[str, "HonCommand"] = command.programs
|
||||||
self._typology: str = "enum"
|
self._typology: str = "enum"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -25,9 +25,18 @@ class HonParameterProgram(HonParameterEnum):
|
|||||||
if value in self.values:
|
if value in self.values:
|
||||||
self._command.program = value
|
self._command.program = value
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Allowed values {self._values}")
|
raise ValueError(f"Allowed values {self.values}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def values(self) -> List[str]:
|
def values(self) -> List[str]:
|
||||||
values = [v for v in self._values if all(f not in v for f in self._FILTER)]
|
values = [v for v in self._programs if all(f not in v for f in self._FILTER)]
|
||||||
return sorted(values)
|
return sorted(values)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ids(self):
|
||||||
|
values = {
|
||||||
|
int(p.parameters["prCode"].value): n
|
||||||
|
for i, (n, p) in enumerate(self._programs.items())
|
||||||
|
if "iot_" not in n and p.parameters.get("prCode")
|
||||||
|
}
|
||||||
|
return dict(sorted(values.items()))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Dict, Any
|
from typing import Dict, Any, List
|
||||||
|
|
||||||
from pyhon.parameter.base import HonParameter
|
from pyhon.parameter.base import HonParameter
|
||||||
|
|
||||||
@ -47,3 +47,7 @@ class HonParameterRange(HonParameter):
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Allowed: min {self._min} max {self._max} step {self._step}"
|
f"Allowed: min {self._min} max {self._max} step {self._step}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def values(self) -> List[str]:
|
||||||
|
return [str(i) for i in range(int(self.min), int(self.max) + 1, int(self.step))]
|
||||||
|
2
setup.py
2
setup.py
@ -7,7 +7,7 @@ with open("README.md", "r") as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="pyhOn",
|
name="pyhOn",
|
||||||
version="0.8.0b6",
|
version="0.9.1",
|
||||||
author="Andre Basche",
|
author="Andre Basche",
|
||||||
description="Control hOn devices with python",
|
description="Control hOn devices with python",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
|
Reference in New Issue
Block a user