Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Daikin Climate - Better integration with Climate base component #16913

Merged
merged 9 commits into from
Oct 8, 2018
Merged

Conversation

MatteGary
Copy link
Contributor

@MatteGary MatteGary commented Sep 27, 2018

Description:

I made some modification do the Daikin Climate Component in order to better integrate the Daikin AC interface with the base Climate Component.
Improved functionality are:

  • Support for localization for Operation Mode

  • Support for Homekit Integration (if the AC is turned On, now the status is updated in Homekit)

Breaking Changes

In order to support localization for Operation Mode, now the available options for this field are changed according to:

old version / new version (english only)

  • Fan | Fan Only
  • Dry | Dry
  • Cool | Cool
  • Hot | Heat
  • Auto | Auto
  • Off | Off

For other languages, the new version is used according to the translated version.

Made some modification in order to better integrate the Daikin AC Component with the base Climate Component.
Benefits are:
Support localization for Operation Mode
Support for Homekit Integration (if the AC is turned On, now the status is updated in Homekit)
@homeassistant
Copy link
Contributor

Hi @MatteGary,

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@@ -262,4 +277,4 @@ def swing_list(self):
def update(self):
"""Retrieve latest state."""
self._api.update(no_throttle=self._force_refresh)
self._force_refresh = False
self._force_refresh = False

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no newline at end of file

if daikin_op_mode is not None:
value = DAIKIN_TO_HA_STATE.get(daikin_op_mode)
else:
value = tmp_value

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trailing whitespace

'[^a-z]',
'',
self._api.device.represent(daikin_attr)[1]
).title()
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank line contains whitespace

@mynameisdaniel32

This comment has been minimized.

@MatteGary

This comment has been minimized.

Fixed to .title() functionality in matching the Operation_Mode
@MatteGary

This comment has been minimized.

@mynameisdaniel32

This comment has been minimized.

@MatteGary

This comment has been minimized.

@mynameisdaniel32

This comment has been minimized.

@MatteGary

This comment has been minimized.

@MatteGary

This comment has been minimized.


daikin_op_mode = DAIKIN_TO_HA_STATE[tmp_value]
if daikin_op_mode is not None:
value = DAIKIN_TO_HA_STATE.get(daikin_op_mode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can this work? We already have the value from the dict in daikin_op_mode. We shouldn't need to get it again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that I can make this part a little bit better, as soon as I can I will do that. The if statement is definetly too much. But the dictionary DAIKIN_TO_HA_STATE is necessary to map the operation_mode from the AC into the accepted one in HA climate component (there are some mismatch, like ‘heat’ vs ‘hot’). That’s way in the previous version the localization wasn’t working.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but you're using the same dictionary twice. That looks like a bug. We should only need to do one lookup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not an expert in Python (I work more with .NET tools), how can I use a key-value dictionary in “both direction”? (I mean, one time I’m using the key to get the value, and the next time I should use the value to get the key)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dictionaries in Python are "one way" only. Keys are unique, but values don't have to be unique. It's possible to iterate over a dictionary, check for a value and then save the key(s) that match the value. What is the goal with this part of the code? If you explain that we can try to figure out the best way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll try to explain: in the original component’s code, there was no mapping between the operation mode formthe daikin AC unit and the one for the base HA climate component. The list of available operation mode and the actual operation mode was just the ones available for the Daikin AC with a starting Uppercase. This was ok for most of the functionality, but what wasn’t working was:

  • Localization: the operation mode was indeed something like ‘Off’, ‘Hot’, ‘Auto’, but it was just hardcoded from the component. It was ok for english user, but that didn’t match the lsbel in the climate translation file, which are ‘off’, ‘heat’, ‘auto’ (as you can see there is also a mismatch between Hot and Heat).
  • Homekit integration (and possibly other platform): this part wasn’t working at all. Since Homekit interact with the base HA climate component, and due to the mismatch I describe before, I wasn't able to use Homekit to get or set the status of the AC.

I managed to make it eork using a dictionary to translate Daikin Operation Mode to HA Operation Mode (DAIKIN_TO_HA_STATE) and the other way around (HA_STATE_TO_DAIKIN).

Since, as you point it out, the mapping is the same in the two direction, I can change the behavior removing the dictionary and using something like a Tuple (or at least that is what I would use in C#). Do you have any suggestion? Otherwhise tomorrow I’ll try to find sometime to fix this.
Tks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dictionary is what we always use for translating modes between home assistant and device. You still didn't explain what you want to do with this part of the code. Do we want to end up with Daikin mode or home assistant mode, after the translation?

If it's home assistant mode, we should only use DAIKIN_TO_HA_STATE dictionary one time, not twice in a row.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how I would expect us to do it:

daikin_mode = re.sub(
    '[^a-z]', '', self._api.device.represent(daikin_attr)[1])

ha_mode = DAIKIN_TO_HA_STATE.get(daikin_mode)
value = ha_mode

@@ -76,7 +85,7 @@ def __init__(self, api):
self._force_refresh = False
self._list = {
ATTR_OPERATION_MODE: list(
map(str.title, set(HA_STATE_TO_DAIKIN.values()))
map(str, set(DAIKIN_TO_HA_STATE.values()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need the str copy?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making it a set doesn't seem necessary either. We know what the values are and they are unique. The dictionary is a constant so it won't change unless we change it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this part I made just little modification to make it work properly, but the logics is the one from the original commit for the daikin component.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're here, please clean it up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to:

self._list = {
    ATTR_OPERATION_MODE: list(HA_STATE_TO_DAIKIN),
    ...
}

@mynameisdaniel32

This comment has been minimized.

@mynameisdaniel32

This comment has been minimized.

@MatteGary

This comment has been minimized.

if value.title() in self._list[attr]:
values[daikin_attr] = value.lower()
if value in self._list[attr]:
values[daikin_attr] = HA_STATE_TO_DAIKIN[value];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

statement ends with a semicolon

self._api.device.represent(daikin_attr)[1]
).title()
daikin_mode = re.sub(
'[^a-z]','',self._api.device.represent(daikin_attr)[1])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace after ','

ATTR_OPERATION_MODE: list(
map(str.title, set(HA_STATE_TO_DAIKIN.values()))
),
ATTR_OPERATION_MODE: list(DAIKIN_TO_HA_STATE),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be:

ATTR_OPERATION_MODE: list(HA_STATE_TO_DAIKIN),

We want to use the ha states so we use the keys of the HA_STATE_TO_DAIKIN dictionary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check my lasts commit? I’m quite sure that I should use the other dictionary in that point. Today I’m not able to test since I’m travelling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the modification you suggested, but I'm not able to test it right now. I'm hoping that @mynameisdaniel32 can test it sooner than I can 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I managed to run a quick test, and it seems to work good. As soon as I can I will run some further tests.

@mynameisdaniel32
Copy link
Contributor

mynameisdaniel32 commented Oct 2, 2018

Just did another test of this (latest version), most modes work fine, but I'm seeing problems with some.

When selecting 'hot' or 'fan' from the HA UI I get the task exceptions errors below (and nothing happens on the AC). When selecting 'heat' from HomeKit, the bottom (invalid value) error shows. All other operation modes seem to work fine.

2018-10-02 12:59:09 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
    result = coro.throw(exc)
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/service.py", line 224, in _handle_service_platform_call
    await getattr(entity, func)(**data)
  File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/climate/daikin.py", line 239, in set_operation_mode
    self.set({ATTR_OPERATION_MODE: operation_mode})
  File "/home/homeassistant/.homeassistant/custom_components/climate/daikin.py", line 178, in set
    values[daikin_attr] = HA_STATE_TO_DAIKIN[value]
KeyError: 'hot'
2018-10-02 12:59:20 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
    result = coro.throw(exc)
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/service.py", line 224, in _handle_service_platform_call
    await getattr(entity, func)(**data)
  File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/climate/daikin.py", line 239, in set_operation_mode
    self.set({ATTR_OPERATION_MODE: operation_mode})
  File "/home/homeassistant/.homeassistant/custom_components/climate/daikin.py", line 178, in set
    values[daikin_attr] = HA_STATE_TO_DAIKIN[value]
KeyError: 'fan'
2018-10-02 13:00:12 ERROR (Thread-2) [custom_components.climate.daikin] Invalid value operation_mode for heat

@MatteGary
Copy link
Contributor Author

Just did another test of this (latest version), most modes work fine, but I'm seeing problems with some. ...

@mynameisdaniel32 thanks for your precise testing. This week I don’t have much time to do testing, but I will try to find some. Thanks a lot.

Change in list of Operation Mode
'',
self._api.device.represent(daikin_attr)[1]
).title()
daikin_mode = re.sub('[^a-z]', '', self._api.device.represent(daikin_attr)[1])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (90 > 79 characters)

self._api.device.represent(daikin_attr)[1]
).title()
daikin_mode = re.sub('[^a-z]', '',
self._api.device.represent(daikin_attr)[1])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuation line under-indented for visual indent

Copy link
Member

@MartinHjelmare MartinHjelmare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Let me know when you're happy with testing and we can merge.

@MartinHjelmare
Copy link
Member

MartinHjelmare commented Oct 2, 2018

Please update the PR description with a paragraph about the breaking change for the release notes. This is a breaking change since we change the names of the available operating modes of this platform.

@MatteGary
Copy link
Contributor Author

@MartinHjelmare I'm OK with testing, I think we can merge this PR so that everyone else can play with it.

@MartinHjelmare
Copy link
Member

Great!

@MartinHjelmare MartinHjelmare merged commit ee5e1fa into home-assistant:dev Oct 8, 2018
@ghost ghost removed the in progress label Oct 8, 2018
@charlietomo
Copy link

This looks like a good fix. How can I test it or when might I expect it in the main release, so my Hass.io would get updated? I am running the latest (0.80) but still see "hot" so don't think this has made it yet?

@MatteGary
Copy link
Contributor Author

@charlietomo If you want to test it now you can copy the PR code into a custom component. Regarding the merge in the main release, it's all up to the usual process of PR of getting into stable release, I don't know how long will it take to see this PR in the main release.

@charlietomo
Copy link

Thanks. I downloaded the raw file as daikin.py and moved it into /config/custom_components/climate/daikin.py. I'm using Hass.io and this worked; things now say Heat.
More importantly for me, the Home app on iOS now functions much better. I can set the different modes :-)
I don't know what the "normal process" is, hence the question. But I'm happy with my working solution now so thanks again.

@balloob balloob mentioned this pull request Oct 26, 2018
@charlietomo
Copy link

Just an update and thankyou message. I see that in 0.81 which I just upgraded to on Hass.io this has made it into the main release. I removed my /config/custom_components/climate/daikin.py file and everything is still working well. Thanks again for this.

@MatteGary
Copy link
Contributor Author

@charlietomo you're welcome! As soon as I have time I'll have a look at the 22°C issue.

@charlietomo
Copy link

@MatteGary there has been some work (solved?) done on the 22°C issue over here. I haven't got it to work yet but I think that is "user error" trying to merge these new changes with other code changes to handle the 22°C issue. Ideally both changes could be merged and end up in the main release!

@fredrike fredrike mentioned this pull request Nov 14, 2018
4 tasks
@home-assistant home-assistant locked and limited conversation to collaborators Feb 5, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants