Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 79a121263f | |||
| 00ac6912e2 | |||
| 0f630e854e | |||
| 1ef5f7a64d | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -3,4 +3,4 @@ venv/ | |||||||
| __pycache__/ | __pycache__/ | ||||||
| dist/ | dist/ | ||||||
| **/*.egg-info/ | **/*.egg-info/ | ||||||
| test.py | test* | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								README.md
									
									
									
									
									
								
							| @ -1,13 +1,24 @@ | |||||||
| **This python package is unofficial and is not related in any way to Haier. It was developed by reversed engineered requests and can stop working at anytime!** | **This python package is unofficial and is not related in any way to Haier. It was developed by reversed engineered requests and can stop working at anytime!** | ||||||
|  |  | ||||||
| # pyhOn | # pyhOn | ||||||
|  | [](https://pypi.org/project/pyhOn) | ||||||
|  | [](https://pypi.org/project/pyhOn) | ||||||
|  | [](https://www.python.org/) | ||||||
|  | [](https://github.com/Andre0512/pyhOn/blob/main/LICENSE) | ||||||
|  | [](https://pypistats.org/packages/pyhon)   | ||||||
| Control your Haier appliances with python! | Control your Haier appliances with python! | ||||||
| The idea behind this library is, to make the use of all available commands as simple as possible. | The idea behind this library is, to make the use of all available commands as simple as possible. | ||||||
|  |  | ||||||
|  | ## Installation | ||||||
|  | ```bash | ||||||
|  | pip install pyhOn | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ### Quick overview | ### Quick overview | ||||||
| To get an idea of what is possible, use the commandline-tool `pyhOn`. This lists all available options of the appliances from your Haier Account. | To get an idea of what is possible, use the commandline-tool `pyhOn`. This command requests all available options of connected appliances from the hOn api of your Haier Account. | ||||||
| ```commandline | ```commandline | ||||||
| $ pyhOn --user example@mail.com --password pass123 | $ pyhOn --user example@mail.com --password pass123 | ||||||
| ========== Waschmaschine ========== | ========== WM - Waschmaschine ========== | ||||||
| commands: | commands: | ||||||
|   pauseProgram: pauseProgram command |   pauseProgram: pauseProgram command | ||||||
|   resumeProgram: resumeProgram command |   resumeProgram: resumeProgram command | ||||||
| @ -20,7 +31,6 @@ data: | |||||||
|   antiAllergyStatus: 0 |   antiAllergyStatus: 0 | ||||||
| ... | ... | ||||||
| ``` | ``` | ||||||
| The claim is, to see everything what you can see in your hOn app and to execute everything you can execute there. |  | ||||||
|  |  | ||||||
| ## Python-API | ## Python-API | ||||||
| ### List devices | ### List devices | ||||||
| @ -67,7 +77,11 @@ async with HonConnection(USER, PASSWORD) as hon: | |||||||
| ## Tested devices | ## Tested devices | ||||||
| - Haier Washing Machine HW90 | - Haier Washing Machine HW90 | ||||||
|  |  | ||||||
| _Unfortunately I don't have any more haier appliances_ | _Unfortunately I don't have any more Haier appliances..._ | ||||||
|  |  | ||||||
| ## Usage example | ## Usage example | ||||||
| This library is used for the custom [HomeAssistant Integration "Haier hOn"](https://github.com/Andre0512/hOn). | This library is used for the custom [HomeAssistant Integration "Haier hOn"](https://github.com/Andre0512/hOn). | ||||||
|  |  | ||||||
|  | ## Contribution | ||||||
|  | Any kind of contribution is welcome! | ||||||
|  |  | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ async def main(): | |||||||
|         password = getpass("Password for hOn account: ") |         password = getpass("Password for hOn account: ") | ||||||
|     async with HonConnection(user, password) as hon: |     async with HonConnection(user, password) as hon: | ||||||
|         for device in hon.devices: |         for device in hon.devices: | ||||||
|             print("=" * 10, device.nick_name, "=" * 10) |             print("=" * 10, device.appliance_type_name, "-", device.nick_name, "=" * 10) | ||||||
|             pretty_print({"commands": device.commands}) |             pretty_print({"commands": device.commands}) | ||||||
|             pretty_print({"data": device.data}) |             pretty_print({"data": device.data}) | ||||||
|  |  | ||||||
|  | |||||||
| @ -84,7 +84,7 @@ class HonConnection: | |||||||
|                 return {} |                 return {} | ||||||
|             return result |             return result | ||||||
|  |  | ||||||
|     async def load_attributes(self, device: HonDevice): |     async def load_attributes(self, device: HonDevice, loop=False): | ||||||
|         params = { |         params = { | ||||||
|             "macAddress": device.mac_address, |             "macAddress": device.mac_address, | ||||||
|             "applianceType": device.appliance_type_name, |             "applianceType": device.appliance_type_name, | ||||||
| @ -92,6 +92,10 @@ class HonConnection: | |||||||
|         } |         } | ||||||
|         url = f"{const.API_URL}/commands/v1/context" |         url = f"{const.API_URL}/commands/v1/context" | ||||||
|         async with self._session.get(url, params=params, headers=await self._headers) as response: |         async with self._session.get(url, params=params, headers=await self._headers) as response: | ||||||
|  |             if response.status_code >= 400 and not loop: | ||||||
|  |                 _LOGGER.error("%s - Error %s - %s", url, response.status_code, await response.text) | ||||||
|  |                 await self.setup() | ||||||
|  |                 return await self.load_attributes(device, loop=True) | ||||||
|             return (await response.json()).get("payload", {}) |             return (await response.json()).get("payload", {}) | ||||||
|  |  | ||||||
|     async def load_statistics(self, device: HonDevice): |     async def load_statistics(self, device: HonDevice): | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								pyhon/appliances/wm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								pyhon/appliances/wm.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | class Appliance: | ||||||
|  |     def __init__(self, data): | ||||||
|  |         self._data = data | ||||||
|  |  | ||||||
|  |     def get(self): | ||||||
|  |         if self._data["lastConnEvent.category"] == "DISCONNECTED": | ||||||
|  |             self._data["machMode"] = "0" | ||||||
|  |         return self._data | ||||||
| @ -1,9 +1,14 @@ | |||||||
|  | import importlib | ||||||
|  | from pprint import pprint | ||||||
|  |  | ||||||
| from pyhon.commands import HonCommand | from pyhon.commands import HonCommand | ||||||
|  |  | ||||||
|  |  | ||||||
| class HonDevice: | class HonDevice: | ||||||
|     def __init__(self, connector, appliance): |     def __init__(self, connector, appliance): | ||||||
|         self._appliance = appliance |         self._appliance = appliance | ||||||
|  |         for values in self._appliance.pop("attributes"): | ||||||
|  |             self._appliance[values["parName"]] = values["parValue"] | ||||||
|         self._connector = connector |         self._connector = connector | ||||||
|         self._appliance_model = {} |         self._appliance_model = {} | ||||||
|  |  | ||||||
| @ -123,6 +128,10 @@ class HonDevice: | |||||||
|     def statistics(self): |     def statistics(self): | ||||||
|         return self._statistics |         return self._statistics | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def appliance(self): | ||||||
|  |         return self._appliance | ||||||
|  |  | ||||||
|     async def load_commands(self): |     async def load_commands(self): | ||||||
|         raw = await self._connector.load_commands(self) |         raw = await self._connector.load_commands(self) | ||||||
|         self._appliance_model = raw.pop("applianceModel") |         self._appliance_model = raw.pop("applianceModel") | ||||||
| @ -160,6 +169,8 @@ class HonDevice: | |||||||
|         data = await self._connector.load_attributes(self) |         data = await self._connector.load_attributes(self) | ||||||
|         for name, values in data.get("shadow").get("parameters").items(): |         for name, values in data.get("shadow").get("parameters").items(): | ||||||
|             self._attributes[name] = values["parNewVal"] |             self._attributes[name] = values["parNewVal"] | ||||||
|  |         for name, value in data.get("lastConnEvent").items(): | ||||||
|  |             self._attributes[f"lastConnEvent.{name}"] = value | ||||||
|  |  | ||||||
|     async def load_statistics(self): |     async def load_statistics(self): | ||||||
|         self._statistics = await self._connector.load_statistics(self) |         self._statistics = await self._connector.load_statistics(self) | ||||||
| @ -169,4 +180,9 @@ class HonDevice: | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def data(self): |     def data(self): | ||||||
|         return self.attributes | self.parameters | self._appliance | self._statistics |         result = self.attributes | self.parameters | self.appliance | self._statistics | ||||||
|  |         try: | ||||||
|  |             extra = importlib.import_module(f'appliances.{self.appliance_type_name.lower()}') | ||||||
|  |             return result | extra.Appliance(result).get() | ||||||
|  |         except ModuleNotFoundError: | ||||||
|  |             return result | ||||||
|  | |||||||
| @ -76,7 +76,7 @@ class HonParameterRange(HonParameter): | |||||||
|     @value.setter |     @value.setter | ||||||
|     def value(self, value): |     def value(self, value): | ||||||
|         if self._min <= value <= self._max and not value % self._step: |         if self._min <= value <= self._max and not value % self._step: | ||||||
|             self._value = self._value |             self._value = value | ||||||
|         else: |         else: | ||||||
|             raise ValueError(f"Allowed: min {self._min} max {self._max} step {self._step}") |             raise ValueError(f"Allowed: min {self._min} max {self._max} step {self._step}") | ||||||
|  |  | ||||||
| @ -102,7 +102,7 @@ class HonParameterEnum(HonParameter): | |||||||
|     @value.setter |     @value.setter | ||||||
|     def value(self, value): |     def value(self, value): | ||||||
|         if value in self.values: |         if value in self.values: | ||||||
|             self._value = self._value |             self._value = value | ||||||
|         else: |         else: | ||||||
|             raise ValueError(f"Allowed values {self._value}") |             raise ValueError(f"Allowed values {self._value}") | ||||||
|  |  | ||||||
| @ -123,4 +123,4 @@ class HonParameterProgram(HonParameterEnum): | |||||||
|         if value in self.values: |         if value in self.values: | ||||||
|             self._command.set_program(value) |             self._command.set_program(value) | ||||||
|         else: |         else: | ||||||
|             raise ValueError(f"Allowed values {self._value}") |             raise ValueError(f"Allowed values {self._values}") | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								setup.py
									
									
									
									
									
								
							| @ -7,18 +7,31 @@ with open("README.md", "r") as f: | |||||||
|  |  | ||||||
| setup( | setup( | ||||||
|     name="pyhOn", |     name="pyhOn", | ||||||
|     version="0.2.1", |     version="0.2.5", | ||||||
|     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, | ||||||
|     long_description_content_type='text/markdown', |     long_description_content_type='text/markdown', | ||||||
|     url="https://github.com/Andre0512/pyh0n", |     project_urls={ | ||||||
|  |         "GitHub": "https://github.com/Andre0512/pyhOn", | ||||||
|  |         "PyPI": "https://pypi.org/project/pyhOn", | ||||||
|  |     }, | ||||||
|     license="MIT", |     license="MIT", | ||||||
|     platforms="any", |     platforms="any", | ||||||
|     packages=find_packages(), |     packages=find_packages(), | ||||||
|     include_package_data=True, |     include_package_data=True, | ||||||
|     python_requires=">=3.10", |     python_requires=">=3.10", | ||||||
|     install_requires=["aiohttp"], |     install_requires=["aiohttp"], | ||||||
|  |     classifiers=[ | ||||||
|  |         "Development Status :: 3 - Alpha", | ||||||
|  |         "Environment :: Console", | ||||||
|  |         "License :: OSI Approved :: MIT License", | ||||||
|  |         "Natural Language :: English", | ||||||
|  |         "Operating System :: OS Independent", | ||||||
|  |         "Programming Language :: Python :: 3.10", | ||||||
|  |         "Programming Language :: Python :: 3.11", | ||||||
|  |         "Topic :: Software Development :: Libraries :: Python Modules", | ||||||
|  |     ], | ||||||
|     entry_points={ |     entry_points={ | ||||||
|         'console_scripts': [ |         'console_scripts': [ | ||||||
|             'pyhOn = pyhon.__main__:start', |             'pyhOn = pyhon.__main__:start', | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	