gpulido / homeassistant-airzone

Home Assistant Custom component to manage Airzone Climate installations
MIT License
26 stars 6 forks source link

Use with Airzone Localapi #11

Closed Mike-de-bike closed 3 years ago

Mike-de-bike commented 3 years ago

Hello,

I have got a AIRZONE AZX6WEBSCLOUDC (ethernet version) installed, airzone-Cloud working fine. On a server runs homeassistant (HA) inside docker container. Airzone Azx6... is reachable via tcp 3000, not via 5020. Question: Do I have to place a computer as a gateway with a usb to ethnernet cable for modbus connection in front of it, so that HA is able to connect to the airzone device? HA -> i.e. raspi -> airzone device.

Regards Stefan

gpulido commented 3 years ago

Hello Stefan, Currently this module works with the python-airzone library that uses the modbus connection through a serial->usb cable. You can use a raspi zero connected to the airzone device through modbus and use a "bridge" to expose to modbus-tcp using something like https://gist.github.com/gpulido/e3518ff90396ae6d4cd186fd41c9a2d1 However, if you have any integration document to use the tcp 3000 port I can take a look and try to adapt the module. Also at this moment the AZ6 version is not compatible with the python-airzone, it is a work in progress at this moment: https://github.com/gpulido/python-airzone/issues/2

Mike-de-bike commented 3 years ago

Hello Gabriel,

Please have a look at these documents.

MI_AZ6_WSCLAPI_A4_EN.pdf MI_AZ6_WSCLAPI_A4_ES.pdf

gpulido commented 3 years ago

Hello Mike, The good news are that with that integration, you don't need the modbus interface, the local api can be used to retrieve the information. The bad news are that modifications with the "python-airzone" library has to be done to be able to read from the api instead from modbus. It can be done, and it is not hard, but needs time.

Mike-de-bike commented 3 years ago

Gabriel, Thanks for reviewing it. I would appreciate it with open arms, if you can handle that integration as a feature request. 😀 👍 Regards Stefan

hopsor commented 3 years ago

Hi, I've been following this repo for some time. I wanted to add wifi control to my Daikin with Aidoo and manage it through homeassistant, however the modbus thingy was too much for me. Recently I discovered this twitter thread which basically confirms local API is available for Aidoo so I decided to get one. However, after successfully installing it I wasn't able to make any requests to the local API.

This morning I got a call from the airzone customer support and they confirmed me the Aidoo device doesn't have the local API feature, the tweet was wrong. However, they told me they are about to release an Aidoo Pro version which will definitely have it. I've been told I'll get a pro replacement as soon as they have them available.

Once I have it and I will be able to live test. So in case no one else has already done it I could contribute to the python-airzone library with the local api integration.

gpulido commented 3 years ago

Hello @hopsor, Any help is welcome!, at this moment I'm the only developer without a lot of free time (looking for a job at this moment :( ) but I'm a believer in Open Source, and if we can expand and improve the ha component and the python-airzone library to cover more kinds of integrations it would be awesome.

Just a comment regarding the aido and local API, I don't know how much does it cost to have it, but the modbus integration is really really cheap and easy to made: one raspberrypi Zero W (10€) one microsd (smallest posible) 5€, usb-rs485 (5€) and a mobile charger: Total 25€ tops. And the code that has to run on it is very easy: https://gist.github.com/gpulido/e3518ff90396ae6d4cd186fd41c9a2d1

If I had time I would create a sd image with it running using balenaos or something similar, but really it is just install a raspbian lite, and set a couple of files and thats it... I would try to create a manual.. BTW: I have been working with another Aidoo owner to make it work in its installation so it is become more stable... Let me know if you need more info.

hopsor commented 3 years ago

Hi @gpulido,

Thank you very much for offering your help with Aidoo modbus setup. The reason I was hesitating doing it this way was to keep it as simple as possible. Right now I have too many powered devices at home and I have 2 air conditioner machines. So following this approach will mean using 2x Aidoo + 2x RPi Zero W. With Aidoo + Local API it's just 2 devices connected to each x35a port of the HVAC without the need of connecting anything to a regular power socket.

In any case, I appreciate a lot your help and I will definitely consider it if in 2-3 months I'm not able to get my Aidoo Pro with the Local API. They told me they will send this replacement without incurring any costs so I'll keep my fingers crossed :-D

Regarding helping with Local API integration in python-airzone, I'm looking forward to it. One of the reasons to get the Aidoo was to contribute with something to this community. From time to time (when I can find it) I like to do open source and this was a good opportunity to do so. Also if I can help with officially releasing this integration let me know. I'm totally new to HA development but I enjoy learning new things.

I'll keep you posted if I get any news of the Aidoo pro

Mike-de-bike commented 3 years ago

Screenshot_20210625-143243 Hello Gabriel, the API is working fine on version 3.3.4 of webserver. I will try to create an appropriate class for querying the local api. Do you have remarks and hints for me in implementing it in your python-airzone lib?

Regards Stefan

gpulido commented 3 years ago

That's great! Although I will need to make modifications to the Python airzone to be able to select between modbus and local API and use the same wrapper so it can be used directly on HA, the first step for you couk be just create a python module (file) that accepts the host configuration and retrieves the state as a python dictionary. Probably using the request library. With that part it would be very easy for me to adapt the python-airzone to use it. But that only solve the airzone-> ha. Then you can play yo be able to change things like the HVAC mode or the target tempertature using the local API. Again probably with a request and a post. You need to manage conversions and errors. What.do you think? If you can do it as a python module it would be amazing. Please open an issue in python-airzone "integrate local API" for tracking an make a fork so we can track the changes. This weekend I'm not going to be able to code. It on Monday I will help. Thank you!!!

Mike-de-bike commented 3 years ago

Hello Gabriel,

Good plan! Next days I will start working on it, when the time allows me to code. Python is my favorite programming language, so I am happy to be part of your amazing project. 👍 First of all I will start with the POST request like you have written. Greetings Stefan

jd1900 commented 3 years ago

Very interested in this, as I have the same version as @Mike-de-bike

gpulido commented 3 years ago

Now the python-airzone localapi implementation is done (version 0.8.0) the next step is to use it in this component.

gpulido commented 3 years ago

@Mike-de-bike A new localapi branch has been created. It is ready for being tested as component. Would you mind give it a try?

Mike-de-bike commented 3 years ago

@gpulido Hello Gabriel! I have installed python-airzone 0.8, here is my test result:

stefan@klapperkiste:~$ airzone_cli.py --help usage: airzone [-h] [-v] [--machine MACHINE] [--system {innobus,aido,localapi}] [--state {str,raw}] address port

positional arguments: address serial device or ip address for localapi port serial tcp port or http port for localapi

optional arguments: -h, --help show this help message and exit -v, --version show program's version number and exit --machine MACHINE Machine number where connect --system {innobus,aido,localapi} Type of Airzone System --state {str,raw} Get the formatted state, or the raw machine state stefan@klapperkiste:~$ airzone_cli.py -v airzone 0.8.0 stefan@klapperkiste:~$ airzone_cli.py --system localapi --machine 1 192.168.90.9 3000 Traceback (most recent call last): File "/usr/local/bin/airzone_cli.py", line 34, in args.func(args) File "/usr/local/bin/airzone_cli.py", line 16, in action m = airzone.airzone_factory(args.address, args.port, args.machine, args.system) File "/usr/local/lib/python3.7/dist-packages/airzone/init.py", line 8, in airzone_factory m = Machine(address, port, machineId) File "/usr/local/lib/python3.7/dist-packages/airzone/localapi.py", line 51, in init self._retrieve_system_data()
File "/usr/local/lib/python3.7/dist-packages/airzone/localapi.py", line 88, in _retrieve_system_data self.handle_response(response) AttributeError: 'Machine' object has no attribute 'handle_response'

Regards

Stefan

Mike-de-bike commented 3 years ago

@gpulido --EDITED-- Did a git clone --single-branch --branch localapi https://github.com/gpulido/homeassistant-airzone.git , that did the trick after ha restart. Config wizard shows up option localapi, but the Port Number is 7000. Here would be 3000 the correct value. Overwriting of the port value brings to a loop, form reset. Error message; Cannot connect with airzone TCP modbus

gpulido commented 3 years ago

Hello @Mike-de-bike Regarding the first issue using the python-airzone cli. Thanks for trying. I will review it and fix it. I hope it may not affect the ha.

To install the localapi branch. You should clone the repo and change to the localapi branch and copy the contents of the custom_components/airzone folder into your installation substituting the old folder and restart ha. The use the integrations and add the airzone one. It should allow you to pick localapi. If not something is wrong and I will review what is happening. The localapi branch can be identified easily as it has more files (innobus.py, aidoo.py, localapi.py)

Let.me know

Mike-de-bike commented 3 years ago

@gpulido Yes, I edited my post above, not smart. please read it again.

gpulido commented 3 years ago

Sorry for that. The mail didn't send me the updated post :( Ok I will look into it asap. Would you mind take a look to the logs?

Mike-de-bike commented 3 years ago

`2021-07-14 16:02:45 WARNING (SyncWorker_0) [homeassistant.loader] We found a custom integration hacs which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant 2021-07-14 16:02:45 WARNING (SyncWorker1) [homeassistant.loader] We found a custom integration airzone which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant 2021-07-14 16:04:06 WARNING (MainThread) [homeassistant.util.async] Detected I/O inside the event loop. This is causing stability issues. Please report issue to the custom component author for airzone doing I/O at custom_components/airzone/config_flow.py, line 48: airzone_factory(host, port, machine_id, system_class, **aidoo_args)

`

Mike-de-bike commented 3 years ago

Sorry for that. The mail didn't send me the updated post :(

In the past I did reply by my mail client, but that replies did not reach you... so I am writing on the github webpage.

gpulido commented 3 years ago

Hello @Mike-de-bike I have just released a 0.8.1 version for the python-airzone that solves the cli bug. Please take a look. Also I have updated the ha component (localapi branch) to use the new version. Please give it a try.

Regarding the log from HA, the problem is the use of the sync request library instead of an async one.

I've just created an async branch on python-airzone: async_requests where I have changed the requests library with aiohttp. Give it a try also and if it works I will merge and make the 0.8.2 version with async requests and update the ha component to use it properly.

Mike-de-bike commented 3 years ago

Hello @gpulido Your are on a good way! :-) I have tested the 0.8.1 of python-airzone, there is an issue yet, which I have opened on that rep. Here, the ha integration of localapi is unsuccessfull, because of 0.8.1. In the configuration wizard of the ha cc airzone, it is not easy to change the port number to 3000. Maybe prepolulate it, when switching to localapi. Regards Stefan

gpulido commented 3 years ago

Hello @Mike-de-bike I have commented on the python-airzone issue. Regarding the configuration wizard I know that is a PITA, but it is the default behaviour for the "port" parameters on the config flow for HA. To change it more easily, try to select the entire number (the 7000) and then write down the 3000.

I will try to take a look to the configuration options to check if it can be "defaulted" Thanks for the idea.

Let me know if once you have it properly configured it at least can retreive the machine and zones

gpulido commented 3 years ago

From https://github.com/gpulido/python-airzone/issues/15

Hello @gpulido I have updated the homeassistant-airzone code, restarted HA -> integration is added successfully, no devices / entities are displayed. Good work so far! :-) HA-custom_integration-airzone-wizard-success HA-custom_integration_airzone

@gpulido Output of: stefan@pizzabox:/usr/local/lib/python3.7/dist-packages/airzone$ sudo python3 __init__.py Printing Post JSON data [{'systemID': 1, 'zoneID': 1, 'name': 'Titus-1', 'on': 0, 'maxTemp': 30, 'minTemp': 18, 'setpoint': 23, 'roomTemp': 24.200001, 'mode': 2, 'coldStages': 1, 'coldStage': 1, 'heatStages': 1, 'heatStage': 1, 'humidity': 68, 'units': 0, 'errors': [], 'air_demand': 0, 'floor_demand': 0}, {'systemID': 1, 'zoneID': 2, 'name': 'Eltern-2', 'on': 0, 'maxTemp': 30, 'minTemp': 18, 'setpoint': 23, 'roomTemp': 24.200001, 'modes': [1, 4, 2, 3, 5], 'mode': 2, 'coldStages': 1, 'coldStage': 1, 'heatStages': 1, 'heatStage': 1, 'humidity': 67, 'units': 0, 'errors': [], 'air_demand': 0, 'floor_demand': 0}, {'systemID': 1, 'zoneID': 3, 'name': 'Thea-3', 'on': 0, 'maxTemp': 30, 'minTemp': 18, 'setpoint': 23, 'roomTemp': 25, 'mode': 2, 'coldStages': 1, 'coldStage': 1, 'heatStages': 1, 'heatStage': 1, 'humidity': 63, 'units': 0, 'errors': [], 'air_demand': 0, 'floor_demand': 0}, {'systemID': 1, 'zoneID': 4, 'name': 'Ella-4', 'on': 0, 'maxTemp': 30, 'minTemp': 18, 'setpoint': 23, 'roomTemp': 24.700001, 'mode': 2, 'coldStages': 1, 'coldStage': 1, 'heatStages': 1, 'heatStage': 1, 'humidity': 70, 'units': 0, 'errors': [], 'air_demand': 0, 'floor_demand': 0}, {'systemID': 1, 'zoneID': 5, 'name': 'Buero-5', 'on': 0, 'maxTemp': 30, 'minTemp': 18, 'setpoint': 23, 'roomTemp': 25.200001, 'mode': 2, 'coldStages': 1, 'coldStage': 1, 'heatStages': 1, 'heatStage': 1, 'humidity': 63, 'units': 0, 'errors': [], 'air_demand': 0, 'floor_demand': 0}] Number of zones: 5 Machine with id: 1Mode: OperationMode.COOLING Zones 1 2 3 4 5

gpulido commented 3 years ago

After some changes:

@gpulido Here is the log of homeassistant for the wizard action: 2021-07-16 08:23:07 WARNING (SyncWorker1) [homeassistant.loader] We found a custom integration airzone which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant 2021-07-16 08:32:51 WARNING (MainThread) [homeassistant.util.async] Detected I/O inside the event loop. This is causing stability issues. Please report issue to the custom component author for airzone doing I/O at custom_components/airzone/climate.py, line 49: machine = airzone_factory(host, port, machine_id, system_class, aidoo_args) 2021-07-16 08:32:51 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform await asyncio.shield(task) File "/config/custom_components/airzone/climate.py", line 73, in async_setup_entry devices = await hass.async_add_executor_job(get_devices(config)) File "/config/custom_components/airzone/climate.py", line 49, in get_devices machine = airzone_factory(host, port, machine_id, system_class, aidoo_args) File "/usr/local/lib/python3.8/site-packages/airzone/init.py", line 8, in airzone_factory m = Machine(address, port, machineId) File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 51, in init self.retrieve_system_data() File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 86, in retrieve_system_data response = requests.post(url=self._API_ENDPOINT, File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 119, in post return request('post', url, data=data, json=json, kwargs) File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 61, in request return session.request(method=method, url=url, kwargs) File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 542, in request resp = self.send(prep, send_kwargs) File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 655, in send r = adapter.send(request, kwargs) File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 439, in send resp = conn.urlopen( File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 699, in urlopen httplib_response = self._make_request( File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 394, in _make_request conn.request(method, url, httplib_request_kw) File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 234, in request super(HTTPConnection, self).request(method, url, body=body, headers=headers) File "/usr/local/lib/python3.8/http/client.py", line 1252, in request self._send_request(method, url, body, headers, encode_chunked) File "/usr/local/lib/python3.8/http/client.py", line 1263, in _send_request self.putrequest(method, url, skips) File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 214, in putrequest return HTTPConnection.putrequest(self, method, url, *args, **kwargs) File "/usr/src/homeassistant/homeassistant/util/async.py", line 151, in protected_loop_func checkloop() File "/usr/src/homeassistant/homeassistant/util/async.py", line 140, in check_loop raise RuntimeError( RuntimeError: I/O must be done in the executor; Use await hass.async_add_executor_job() at custom_components/airzone/climate.py, line 49: machine = airzone_factory(host, port, machine_id, system_class, **aidoo_args)

gpulido commented 3 years ago

Hello @Mike-de-bike I've made a new push with some changes to try to avoid the I/O problem. Please let me know if worked.

Mike-de-bike commented 3 years ago

hello @gpulido I did clone the latest version, pumping it in HA, restarted it, but no luck, same errors after new integration attempt:

2021-07-16 18:29:15 WARNING (MainThread) [homeassistant.util.async_] Detected I/O inside the event loop. This is causing stability issues. Please report issue to the custom component author for airzone doing I/O at custom_components/airzone/climate.py, line 45: machine = await hass.async_add_executor_job(airzone_factory(host, port, machine_id, system_class, **aidoo_args))                                                                                                                                  
2021-07-16 18:29:15 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):                                                                                                                                      
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform                                                            
    await asyncio.shield(task)                                                                                                                                          
  File "/config/custom_components/airzone/climate.py", line 69, in async_setup_entry                                                                                    
    devices = await async_get_devices(config, hass)                                                                                                                     
  File "/config/custom_components/airzone/climate.py", line 45, in async_get_devices                                                                                    
    machine = await hass.async_add_executor_job(airzone_factory(host, port, machine_id, system_class, **aidoo_args))                                                    
  File "/usr/local/lib/python3.8/site-packages/airzone/__init__.py", line 8, in airzone_factory                                                                         
    m = Machine(address, port, machineId)                                                                                                                               
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 51, in __init__                                                                               
    self.retrieve_system_data()                                                                                                                                         
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 86, in retrieve_system_data                                                                   
    response = requests.post(url=self._API_ENDPOINT,                                                                                                                    
  File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 119, in post                                                                                      
    return request('post', url, data=data, json=json, **kwargs)                                                                                                         
  File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 61, in request                                                                                    
    return session.request(method=method, url=url, **kwargs)                                                                                                            
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 542, in request                                                                              
    resp = self.send(prep, **send_kwargs)                                                                                                                               
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 655, in send                                                                                 
    r = adapter.send(request, **kwargs)                                                                                                                                 
  File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 439, in send                                                                                 
    resp = conn.urlopen(                                                                                                                                                
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 699, in urlopen                                                                         
    httplib_response = self._make_request(                                                                                                                              
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 394, in _make_request                                                                   
    conn.request(method, url, **httplib_request_kw)                                                                                                                     
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 234, in request                                                                             
    super(HTTPConnection, self).request(method, url, body=body, headers=headers)
  File "/usr/local/lib/python3.8/http/client.py", line 1252, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/lib/python3.8/http/client.py", line 1263, in _send_request
    self.putrequest(method, url, **skips)
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 214, in putrequest
    return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 151, in protected_loop_func
    check_loop()
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 140, in check_loop
    raise RuntimeError(
RuntimeError: I/O must be done in the executor; Use `await hass.async_add_executor_job()` at custom_components/airzone/climate.py, line 45: machine = await hass.async_add_executor_job(airzone_factory(host, port, machine_id, system_class, **aidoo_args))
gpulido commented 3 years ago

Hello @Mike-de-bike My fault I forgot to add the lambda to the async wrapper. Please test again with my last commit.

Mike-de-bike commented 3 years ago

hello @gpulido hope your are healthy again. pulled your fixed code: here is the result of reintegrating it:

2021-07-17 10:15:07 WARNING (SyncWorker_1) [homeassistant.loader] We found a custom integration airzone which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2021-07-17 10:15:07 WARNING (SyncWorker_0) [homeassistant.loader] We found a custom integration hacs which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2021-07-17 10:15:42 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform
    await asyncio.shield(task)
  File "/config/custom_components/airzone/climate.py", line 69, in async_setup_entry
    devices = await async_get_devices(config, hass)
  File "/config/custom_components/airzone/climate.py", line 52, in async_get_devices
    from localapi import LocalAPIMachine as Machine
ModuleNotFoundError: No module named 'localapi'
Mike-de-bike commented 3 years ago

@gpulido Do you have interest in doing an remote session with me on my system, i.e. with zoom or something else? You could try to fix the problem at the heart....

gpulido commented 3 years ago

@Mike-de-bike I'm embarrassed. That was a very silly mistake importing the local modules. I think I've solved it. I'm at this moment out for the weekend and editing with my phone. Sorry for the inconvenience. Please try again :)

Mike-de-bike commented 3 years ago

hello @gpulido :-) python editing by phone, fine thing! Next try results in:

2021-07-17 11:59:21 WARNING (SyncWorker_1) [homeassistant.loader] We found a custom integration hacs which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2021-07-17 11:59:21 WARNING (SyncWorker_0) [homeassistant.loader] We found a custom integration airzone which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2021-07-17 11:59:28 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform
    await asyncio.shield(task)
  File "/config/custom_components/airzone/climate.py", line 69, in async_setup_entry
    devices = await async_get_devices(config, hass)
  File "/config/custom_components/airzone/climate.py", line 52, in async_get_devices
    from .localapi import LocalAPIMachine as Machine
  File "/config/custom_components/airzone/localapi.py", line 18, in <module>
    class LocalAPIZone(ClimateEntity):
  File "/config/custom_components/airzone/localapi.py", line 32, in LocalAPIZone
    def airzone_zone(self, value):
TypeError: descriptor 'setter' for 'property' objects doesn't apply to a 'function' object
gpulido commented 3 years ago

@Mike-de-bike Another silly mistake. Fixed. Try again :) One comment: when you post code into markdown (like this) you need to use three backticks after and before the code to be properly formatted instead of just one.

Mike-de-bike commented 3 years ago

@gpulido Here we go again, step by step. :-)


Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform
    await asyncio.shield(task)
  File "/config/custom_components/airzone/climate.py", line 69, in async_setup_entry
    devices = await async_get_devices(config, hass)
  File "/config/custom_components/airzone/climate.py", line 57, in async_get_devices
    devices = [Machine(machine)] + [Zone(z) for z in machine.get_zones()]
  File "/config/custom_components/airzone/localapi.py", line 147, in __init__
    self._name = "Airzone Machine "  + str(airzone_machine._machineId)
AttributeError: 'Machine' object has no attribute '_machineId```
gpulido commented 3 years ago

@Mike-de-bike Fixed. I'm sorry in a normal situation I would just run all the code against a a fake server and check all by myself.

Mike-de-bike commented 3 years ago

@gpulido iteration is going on :-)

2021-07-18 09:19:19 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform
    await asyncio.shield(task)
  File "/config/custom_components/airzone/climate.py", line 69, in async_setup_entry
    devices = await async_get_devices(config, hass)
  File "/config/custom_components/airzone/climate.py", line 57, in async_get_devices
    devices = [Machine(machine)] + [Zone(z) for z in machine.get_zones()]
AttributeError: 'Machine' object has no attribute 'get_zones'
gpulido commented 3 years ago

@Mike-de-bike Fixed.

Mike-de-bike commented 3 years ago

@gpulido next:

2021-07-18 12:55:24 ERROR (MainThread) [homeassistant.components.climate] airzone: Error on device update!
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 432, in _async_add_entity
    await entity.async_device_update(warning=False)
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 550, in async_device_update
    await task
  File "/config/custom_components/airzone/localapi.py", line 199, in async_update
    self.airzone_machine.retrieve_system_data()
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 86, in retrieve_system_data
    response = requests.post(url=self._API_ENDPOINT,
  File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 119, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 699, in urlopen
    httplib_response = self._make_request(
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 394, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 234, in request
    super(HTTPConnection, self).request(method, url, body=body, headers=headers)
  File "/usr/local/lib/python3.8/http/client.py", line 1252, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/lib/python3.8/http/client.py", line 1263, in _send_request
    self.putrequest(method, url, **skips)
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 214, in putrequest
    return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 151, in protected_loop_func
    check_loop()
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 140, in check_loop
    raise RuntimeError(
RuntimeError: I/O must be done in the executor; Use `await hass.async_add_executor_job()` at custom_components/airzone/localapi.py, line 199: self.airzone_machine.retrieve_system_data()
2021-07-18 12:55:24 ERROR (MainThread) [homeassistant.components.climate] Error adding entities for domain climate with platform airzone
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 383, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 443, in _async_add_entity
    if entity.unique_id is not None:
  File "/config/custom_components/airzone/localapi.py", line 134, in unique_id
    return self._airzone_zone.unique_id
AttributeError: 'Zone' object has no attribute 'unique_id'
2021-07-18 12:55:24 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 258, in _async_setup_platform
    await asyncio.gather(*pending)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 383, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 443, in _async_add_entity
    if entity.unique_id is not None:
  File "/config/custom_components/airzone/localapi.py", line 134, in unique_id
    return self._airzone_zone.unique_id
AttributeError: 'Zone' object has no attribute 'unique_id'
gpulido commented 3 years ago

@Mike-de-bike Made a quick fix until python-airzone provides proper unique_id

Mike-de-bike commented 3 years ago

@gpulido please give me another fix! :-)

2021-07-18 14:46:02 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 250, in _async_setup_platform
    await asyncio.shield(task)
  File "/config/custom_components/airzone/climate.py", line 69, in async_setup_entry
    devices = await async_get_devices(config, hass)
  File "/config/custom_components/airzone/climate.py", line 52, in async_get_devices
    from .localapi import LocalAPIMachine as Machine
  File "/config/custom_components/airzone/localapi.py", line 135
    return f'{self.airzone_zone.name}_Z{str(self.airzone_zone._zone_id)}
                                                                       ^
SyntaxError: EOL while scanning string literal
Mike-de-bike commented 3 years ago

@gpulido forget the last, missing high comma this is the next:


2021-07-18 14:55:48 ERROR (MainThread) [homeassistant.components.climate] airzone: Error on device update!
Traceback (most recent call last):                                                                                                                                      
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 432, in _async_add_entity                                                                
    await entity.async_device_update(warning=False)                                                                                                                     
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 550, in async_device_update
    await task
  File "/config/custom_components/airzone/localapi.py", line 200, in async_update
    self.airzone_machine.retrieve_system_data()
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 86, in retrieve_system_data
    response = requests.post(url=self._API_ENDPOINT,
  File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 119, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/requests/adapters.py", line 439, in send
    resp = conn.urlopen(
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 699, in urlopen
    httplib_response = self._make_request(
  File "/usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py", line 394, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 234, in request
    super(HTTPConnection, self).request(method, url, body=body, headers=headers)
  File "/usr/local/lib/python3.8/http/client.py", line 1252, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/lib/python3.8/http/client.py", line 1263, in _send_request
    self.putrequest(method, url, **skips)
  File "/usr/local/lib/python3.8/site-packages/urllib3/connection.py", line 214, in putrequest
    return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 151, in protected_loop_func
    check_loop()
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 140, in check_loop
    raise RuntimeError(
RuntimeError: I/O must be done in the executor; Use `await hass.async_add_executor_job()` at custom_components/airzone/localapi.py, line 200: self.airzone_machine.retrieve_system_data()
2021-07-18 14:55:48 ERROR (MainThread) [homeassistant.components.climate] Error adding entities for domain climate with platform airzone
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 383, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 499, in _async_add_entity
    capabilities=entity.capability_attributes,
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 207, in capability_attributes
    data[ATTR_FAN_MODES] = self.fan_modes
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 384, in fan_modes
    raise NotImplementedError
NotImplementedError
2021-07-18 14:55:48 ERROR (MainThread) [homeassistant.components.climate] Error while setting up airzone platform for climate
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 258, in _async_setup_platform
    await asyncio.gather(*pending)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 383, in async_add_entities
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 499, in _async_add_entity
    capabilities=entity.capability_attributes,
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 207, in capability_attributes
    data[ATTR_FAN_MODES] = self.fan_modes
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 384, in fan_modes
    raise NotImplementedError
NotImplementedError```
gpulido commented 3 years ago

Hello @Mike-de-bike Sorry for the delay. As I was back to a PC I just created a fake server to properly test the component and solve several issues in batch. I have just committed a new fix. At least it should allow you to create the entities (one machine and one for each zone). Let me know if it worked now. Again sorry for all the patches it was a very quick implementation with a lots of bugs.

Mike-de-bike commented 3 years ago

@gpulido Nice Work! One error in the log:

2021-07-20 08:36:52 ERROR (MainThread) [homeassistant.helpers.entity] Update for climate.titus_1 fails
Traceback (most recent call last):                                                                                                                                      
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 350, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 558, in async_device_update
    raise exc
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/airzone/localapi.py", line 140, in update
    _LOGGER.debug(str(self._airzone_zone))
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 224, in __str__
    " Name: " + str(self.name) + \
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 182, in name
    return self.zone_state['name']
KeyError: 'name'

HA-CI-integration-airzone HA-CI-integration-airzone-entities HA-CI-airzone-card HA-CI-airzone-zone-history

gpulido commented 3 years ago

@Mike-de-bike Nice! Some questions:

1 - I noticed from your screenshoots that you are not using the "climate card" (the one with the wheel). Can you confirm that change of machine state works, and the on /off of zones works and the change temperature?

2 - I didn't add the fan / speed selection because I'm not sure if it is a property that is different for each zone or global to all zones connected to the machine.

3 - If you wish you can translate the messages to dutch (it is the right word?). Take a look to the translations.en and create a copy with the translations.nl

4 - Regarding the error, does it keep working after the error of it just crash the entire component?. It is an strange error as the name is a property that we know is on the zone.

Mike-de-bike commented 3 years ago

@gpulido

  1. Using the climate card. HA-CI-airzone-climate-card Change of set temperature is working, but the following error occurs in the ha log:
2021-07-20 15:20:52 ERROR (MainThread) [homeassistant.helpers.entity] Update for climate.eltern_2 fails
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 350, in async_update_ha_state
    await self.async_device_update()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 558, in async_device_update
    raise exc
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/airzone/localapi.py", line 140, in update
    _LOGGER.debug(str(self._airzone_zone))
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 224, in __str__
    " Name: " + str(self.name) + \
  File "/usr/local/lib/python3.8/site-packages/airzone/localapi.py", line 182, in name
    return self.zone_state['name']
KeyError: 'name'

Enable / disable of the zone fails, same error as before.

  1. Via API there is no option to set the fan speed.
  2. My language is german - there is a working translation.
  3. The component is valid after the error.
  4. The climate card for the machine. HA-custom_integration_airzone_machine Correct parameter display.

Using the temperature setter:

2021-07-20 15:37:52 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140461838569968] 
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 185, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1491, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1526, in _execute_service
    await handler.job.target(service_call)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 213, in handle_service
    await self.hass.helpers.service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 658, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 760, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 695, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 548, in async_service_temperature_set
    await entity.async_set_temperature(**kwargs)
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 408, in async_set_temperature
    await self.hass.async_add_executor_job(
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 404, in set_temperature
    raise NotImplementedError()
NotImplementedError

Operation mode error:

2021-07-20 15:38:57 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection] [140461838569968] 'Machine' object has no attribute 'set_operation_mode'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/websocket_api/commands.py", line 185, in handle_call_service
    await hass.services.async_call(
  File "/usr/src/homeassistant/homeassistant/core.py", line 1491, in async_call
    task.result()
  File "/usr/src/homeassistant/homeassistant/core.py", line 1526, in _execute_service
    await handler.job.target(service_call)
  File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 213, in handle_service
    await self.hass.helpers.service.entity_service_call(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 658, in entity_service_call
    future.result()  # pop exception if have
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 760, in async_request_call
    await coro
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 695, in _handle_entity_call
    await result
  File "/usr/src/homeassistant/homeassistant/components/climate/__init__.py", line 434, in async_set_hvac_mode
    await self.hass.async_add_executor_job(self.set_hvac_mode, hvac_mode)
  File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/airzone/localapi.py", line 199, in set_hvac_mode
    self._airzone_machine.set_operation_mode(new_op)
AttributeError: 'Machine' object has no attribute 'set_operation_mode'

and the rest, too.

Mike-de-bike commented 3 years ago

@gpulido HA-custom_integration_airzone_machine

gpulido commented 3 years ago

@Mike-de-bike Some questions: 1 / 4 - I don't understand the problem with the name, the only explanation that I have is that when you change any parameters with the 'put', the response is not the the same as if we do a post to retrieve the status. Can you confirm that any time you made a put to change anything the answer contains ALL system and zones data?. One solution could just change the python-airzone to change the parameters with the put, but not using the response to update the state just wait for the next cycle of updating.

2 - The fan speed is on the document, maybe your system doesn't have it, but it is documented here: https://github.com/gpulido/homeassistant-airzone/files/6701070/MI_AZ6_WSCLAPI_A4_EN.pdf it is something that your system doesnt' have?

3 - Sorry about the language. I don't know why I thought you were from the Netherlands

Regarding the error changing the machine state, I've fixed it.

gpulido commented 3 years ago

Last commit I added the fan control to the machine.

Mike-de-bike commented 3 years ago

don't understand the problem with the name, the only explanation that I have is that when you change any parameters with the 'put', the response is not the the same as if we do a post to retrieve the status. Can you confirm that any time you made a put to change anything the answer contains ALL system and zones data?.

@gpulido The localapi in python airzone was operating correctly at last before your refactoring witch decorators by setting and getting. Maybe need to test it again.

gpulido commented 3 years ago

@Mike-de-bike I think I found the problem. Reviewing all conversations I found this: https://github.com/gpulido/python-airzone/issues/6#issuecomment-873572387 If you check the code it was a print of the state_machine, and if you review it doesn't have all the properties, just some of them, for example the zone "name" is missing.

The only explanation is that when a put is made to the localapi to change any value the answer doesn't contains ALL the data, just some of them. As we were using that answer as the "new state dictionary", some of the properties are lost temporally.

When the automatic update kicks and calls the retrieve_machine it does a full post request that would fill all the properties, however if anyone try to reach any of the properties between the put and the post they would be missing.

You can confirm this just doing a put using a rest api (as you already have done) updating any zone property and printing the json that is returned by the system.

I'm going to change the python-airzone to not use the put answer for updating the whole system.