Compare commits

...

3 Commits

Author SHA1 Message Date
3c7ad3f395 Fix changed hOn login 2023-06-07 02:27:02 +02:00
31c03faca8 Get program name 2023-05-29 19:05:37 +02:00
a081ef1f97 Add favourites to progams hon#47 2023-05-28 19:24:02 +02:00
12 changed files with 73 additions and 44 deletions

View File

@ -2,6 +2,7 @@ import importlib
import json import json
import logging import logging
from contextlib import suppress from contextlib import suppress
from copy import copy
from datetime import datetime, timedelta from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
@ -214,8 +215,29 @@ class HonAppliance:
self._appliance_model = raw.pop("applianceModel") self._appliance_model = raw.pop("applianceModel")
raw.pop("dictionaryId", None) raw.pop("dictionaryId", None)
self._commands = self._get_commands(raw) self._commands = self._get_commands(raw)
await self._add_favourites()
await self._recover_last_command_states() await self._recover_last_command_states()
async def _add_favourites(self):
favourites = await self._api.command_favourites(self)
for favourite in favourites:
name = favourite.get("favouriteName")
command = favourite.get("command")
command_name = command.get("commandName")
program_name = command.get("programName", "").split(".")[-1].lower()
base = copy(self._commands[command_name].categories[program_name])
for data in command.values():
if isinstance(data, str):
continue
for key, value in data.items():
if parameter := base.parameters.get(key):
with suppress(ValueError):
parameter.value = value
extra_param = HonParameterFixed("favourite", {"fixedValue": "1"}, "custom")
base.parameters.update(favourite=extra_param)
base.parameters["program"].set_value(name)
self._commands[command_name].categories[name] = base
async def load_attributes(self): async def load_attributes(self):
self._attributes = await self.api.load_attributes(self) self._attributes = await self.api.load_attributes(self)
for name, values in self._attributes.pop("shadow").get("parameters").items(): for name, values in self._attributes.pop("shadow").get("parameters").items():
@ -276,6 +298,8 @@ class HonAppliance:
"statistics": self.statistics, "statistics": self.statistics,
"additional_data": self._additional_data, "additional_data": self._additional_data,
} }
if self._extra and data.get("attributes"):
data = self._extra.data(data)
if command_only: if command_only:
data.pop("attributes") data.pop("attributes")
data.pop("appliance") data.pop("appliance")

13
pyhon/appliances/base.py Normal file
View File

@ -0,0 +1,13 @@
class ApplianceBase:
def __init__(self, appliance):
self.parent = appliance
def data(self, data):
program_name = "No Program"
if program := int(data["attributes"]["parameters"].get("prCode", "0")):
if ids := self.parent.settings["startProgram.program"].ids:
program_name = ids.get(program, program_name)
data["programName"] = program_name
def settings(self, settings):
return settings

View File

@ -1,12 +1,10 @@
class Appliance: from pyhon.appliances.base import ApplianceBase
def __init__(self, appliance):
self.parent = appliance
class Appliance(ApplianceBase):
def data(self, data): def data(self, data):
super().data(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"))
return data return data
def settings(self, settings):
return settings

View File

@ -1,8 +1,9 @@
class Appliance: from pyhon.appliances.base import ApplianceBase
def __init__(self, appliance):
self.parent = appliance
class Appliance(ApplianceBase):
def data(self, data): def data(self, data):
super().data(data)
if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED": if data["attributes"]["lastConnEvent"]["category"] == "DISCONNECTED":
data["attributes"]["parameters"]["temp"] = "0" data["attributes"]["parameters"]["temp"] = "0"
data["attributes"]["parameters"]["onOffStatus"] = "0" data["attributes"]["parameters"]["onOffStatus"] = "0"
@ -16,6 +17,3 @@ class Appliance:
data["programName"] = ids.get(program, "") data["programName"] = ids.get(program, "")
return data return data
def settings(self, settings):
return settings

View File

@ -1,11 +1,9 @@
from pyhon.parameter.fixed import HonParameterFixed from pyhon.appliances.base import ApplianceBase
class Appliance: class Appliance(ApplianceBase):
def __init__(self, appliance):
self.parent = appliance
def data(self, data): def data(self, data):
super().data(data)
if data["attributes"]["parameters"]["holidayMode"] == "1": if data["attributes"]["parameters"]["holidayMode"] == "1":
data["modeZ1"] = "holiday" data["modeZ1"] = "holiday"
elif data["attributes"]["parameters"]["intelligenceMode"] == "1": elif data["attributes"]["parameters"]["intelligenceMode"] == "1":
@ -23,6 +21,3 @@ class Appliance:
data["modeZ2"] = "no_mode" data["modeZ2"] = "no_mode"
return data return data
def settings(self, settings):
return settings

View File

@ -1,18 +1,14 @@
from pyhon.appliances.base import ApplianceBase
from pyhon.parameter.fixed import HonParameterFixed from pyhon.parameter.fixed import HonParameterFixed
class Appliance: class Appliance(ApplianceBase):
def __init__(self, appliance):
self.parent = appliance
def data(self, data): def data(self, data):
super().data(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):

View File

@ -1,8 +1,9 @@
class Appliance: from pyhon.appliances.base import ApplianceBase
def __init__(self, appliance):
self.parent = appliance
class Appliance(ApplianceBase):
def data(self, data): def data(self, data):
super().data(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"))

View File

@ -1,8 +1,9 @@
class Appliance: from pyhon.appliances.base import ApplianceBase
def __init__(self, appliance):
self.parent = appliance
class Appliance(ApplianceBase):
def data(self, data): def data(self, data):
super().data(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"))

View File

@ -134,9 +134,7 @@ class HonAuth:
fw_uid, loaded_str = context[0] fw_uid, loaded_str = context[0]
self._login_data.fw_uid = fw_uid self._login_data.fw_uid = fw_uid
self._login_data.loaded = json.loads(loaded_str) self._login_data.loaded = json.loads(loaded_str)
self._login_data.url = login_url.replace( self._login_data.url = login_url.replace(const.AUTH_API, "")
"/".join(const.AUTH_API.split("/")[:-1]), ""
)
return True return True
await self._error_logger(response) await self._error_logger(response)
return False return False
@ -149,8 +147,8 @@ class HonAuth:
"descriptor": "apex://LightningLoginCustomController/ACTION$login", "descriptor": "apex://LightningLoginCustomController/ACTION$login",
"callingDescriptor": "markup://c:loginForm", "callingDescriptor": "markup://c:loginForm",
"params": { "params": {
"username": quote(self._login_data.email), "username": self._login_data.email,
"password": quote(self._login_data.password), "password": self._login_data.password,
"startUrl": start_url, "startUrl": start_url,
}, },
} }
@ -172,7 +170,7 @@ class HonAuth:
async with self._request.post( async with self._request.post(
const.AUTH_API + "/s/sfsites/aura", const.AUTH_API + "/s/sfsites/aura",
headers={"Content-Type": "application/x-www-form-urlencoded"}, headers={"Content-Type": "application/x-www-form-urlencoded"},
data="&".join(f"{k}={json.dumps(v)}" for k, v in data.items()), data="&".join(f"{k}={quote(json.dumps(v))}" for k, v in data.items()),
params=params, params=params,
) as response: ) as response:
if response.status == 200: if response.status == 200:
@ -210,7 +208,7 @@ class HonAuth:
url_search = re.findall( url_search = re.findall(
"href\\s*=\\s*[\"'](.*?)[\"']", await response.text() "href\\s*=\\s*[\"'](.*?)[\"']", await response.text()
) )
url = "/".join(const.AUTH_API.split("/")[:-1]) + url_search[0] url = const.AUTH_API + url_search[0]
async with self._request.get(url) as response: async with self._request.get(url) as response:
if response.status != 200: if response.status != 200:
await self._error_logger(response) await self._error_logger(response)

View File

@ -1,10 +1,10 @@
AUTH_API = "https://he-accounts.force.com/SmartHome" AUTH_API = "https://account2.hon-smarthome.com"
API_URL = "https://api-iot.he.services" API_URL = "https://api-iot.he.services"
API_KEY = "GRCqFhC6Gk@ikWXm1RmnSmX1cm,MxY-configuration" API_KEY = "GRCqFhC6Gk@ikWXm1RmnSmX1cm,MxY-configuration"
APP = "hon" APP = "hon"
# All seen id's (different accounts, different devices) are the same, so I guess this hash is static # All seen id's (different accounts, different devices) are the same, so I guess this hash is static
CLIENT_ID = "3MVG9QDx8IX8nP5T2Ha8ofvlmjLZl5L_gvfbT9.HJvpHGKoAS_dcMN8LYpTSYeVFCraUnV.2Ag1Ki7m4znVO6" CLIENT_ID = "3MVG9QDx8IX8nP5T2Ha8ofvlmjLZl5L_gvfbT9.HJvpHGKoAS_dcMN8LYpTSYeVFCraUnV.2Ag1Ki7m4znVO6"
APP_VERSION = "2.0.9" APP_VERSION = "2.0.10"
OS_VERSION = 31 OS_VERSION = 31
OS = "android" OS = "android"
DEVICE_MODEL = "exynos9820" DEVICE_MODEL = "exynos9820"

View File

@ -44,6 +44,11 @@ class HonParameterProgram(HonParameterEnum):
values = { values = {
int(p.parameters["prCode"].value): n int(p.parameters["prCode"].value): n
for i, (n, p) in enumerate(self._programs.items()) for i, (n, p) in enumerate(self._programs.items())
if "iot_" not in n and p.parameters.get("prCode") if "iot_" not in n
and p.parameters.get("prCode")
and not ((fav := p.parameters.get("favourite")) and fav.value == "1")
} }
return dict(sorted(values.items())) return dict(sorted(values.items()))
def set_value(self, value: str):
self._value = value

View File

@ -7,7 +7,7 @@ with open("README.md", "r") as f:
setup( setup(
name="pyhOn", name="pyhOn",
version="0.11.3", version="0.12.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,