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

Add Dyson Pure Cool Link support #7795

Merged
merged 7 commits into from
Jun 14, 2017
Merged

Conversation

CharlesBlonde
Copy link
Contributor

@CharlesBlonde CharlesBlonde commented May 27, 2017

Description:

This PR add Dyson purifier fans support.

This component is still in development and will be improve but I'm using it since months and I have been able to have successful feedback from other users: https://community.home-assistant.io/t/dyson-link-action-and-sensor/10145

So I think it is reliable enough to submit a first release. I have in mind other improvements (other sensors, heating and why not the vacuum 360 robot) so I decided to create a parent Dyson component with Dyson account information and fan/sensors child components.

One word on auto-discovery (mDNS): for an unknown reason, it's not very reliable (sometime it's work, sometime not). So in the documentation I'll add a word on how to setup the component using discovery and how to manually configure it if it's not working.

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#2721

Example entry for configuration.yaml (if applicable):

dyson:
  username: <dyson_account_user_email>
  password: <dyson_acount_password>
  language: <dyson_account_language>
  devices:
    - device_id: <device_id_1>
      device_ip: <device_ip_1>
    - device_id: <device_id_2>
      device_ip: <device_ip_2>
    ...

fan:
  - platform: dyson

sensor:
  - platform: dyson

Checklist:

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • Local tests with tox run successfully. Your PR cannot be merged unless tests pass (not tested with Python 3.6)
  • New dependencies have been added to the REQUIREMENTS variable (example).
  • New dependencies are only imported inside functions that use them (example).
  • New dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.

If the code does not interact with devices:

  • Local tests with tox run successfully. Your PR cannot be merged unless tests pass
  • Tests have been added to verify that the new code works.

@mention-bot
Copy link

@CharlesBlonde, thanks for your PR! By analyzing the history of the files in this pull request, we identified @fabaff, @balloob and @rmkraus to be potential reviewers.

@CoalaJoe
Copy link

Just thought about getting one. Is this cloud only? Or does it work in LAN?

@CharlesBlonde
Copy link
Contributor Author

In fact it's a mix between Cloud and LAN: all commands and all sensors values are from the LAN using MQTT. But the MQTT connection used authentication and the only way to get the encrypted credentials is to call Dyson web services (hosted on AWS). Technically, after initial connection, no more remote calls are done from this component.
But the device is reporting data to the web services too: I'm not 100% sure but while I was playing with the API, I get historical data (what? I don't know yet, maybe temperature, humidity or dust level). So if the web services is able to return values, I guess it means the device is sending data.
You can get more information here: https://github.com/CharlesBlonde/libpurecoollink even if I have to write a better documentation on how theses devices are working.

@CoalaJoe
Copy link

Thanks for the info. Great work you did there!

Copy link
Member

@pvizeli pvizeli left a comment

Choose a reason for hiding this comment

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

First round.

Please change your code to use the internal discovery for platforms. Look into andoird_ip_camera component to see how that should work.

timeout = config[DOMAIN].get(CONF_TIMEOUT)
retry = config[DOMAIN].get(CONF_RETRY)

if logged:
Copy link
Member

Choose a reason for hiding this comment

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

Hold the ident small as possible:

if not logged:
    _LOGGER...
    return False

CONF_LANGUAGE = "language"
CONF_TIMEOUT = "timeout"
CONF_RETRY = "retry"
CONF_DEVICES = "devices"
Copy link
Member

Choose a reason for hiding this comment

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

Use all exists CONF_* from const.py

@CharlesBlonde
Copy link
Contributor Author

Following your comments, I updated the components in order to dynamically create fan/sensor components instead of using components configured in configuration.yaml.

@CharlesBlonde
Copy link
Contributor Author

I updated the component to add auto/night mode as new features and not anymore like a speed.
It was a working hack but it prevents from using some setup (eg: defined speed and night mode).

For information:

  • auto mode: The purifier is in standby and activate only when the air quality decrease
  • night mode: lower the device brightness and if auto mode is set too, will limit the speed to 4 (speed is 1..10)

I updated the frontend component and submit another PR: home-assistant/frontend#300

I also renamed available speeds from string to integer when available (0002 became 2).

Copy link
Member

@pvizeli pvizeli left a comment

Choose a reason for hiding this comment

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

@turbokongen @balloob if the change on init of fan component legtitime or only a platform thing?

from homeassistant.components.dyson import DYSON_DEVICES

DEPENDENCIES = ['dyson']
REQUIREMENTS = ['libpurecoollink==0.1.5']
Copy link
Member

Choose a reason for hiding this comment

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

Remove this. That will be implicit with DEPENDENCIES

"""Called when new messages received from the fan."""
_LOGGER.debug("Message received for fan device %s : %s", self.name,
message)
if self.hass and self.entity_id:
Copy link
Member

Choose a reason for hiding this comment

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

if self.hass should not needed or you have done a desine misstake. Make sure that your device is receive callback after HOMEASSISTANT_START or register your device callback inside async_added_to_hass.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. I guess I add this test before refactoring the constructor.

_LOGGER.info("Creating device %s", device.name)
self.hass = hass
self._device = device
self._device.add_message_listener(self.on_message)
Copy link
Member

Choose a reason for hiding this comment

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

See commend above. Please move the init as first function inside your object.

@CharlesBlonde
Copy link
Contributor Author

I choose to add the new services (set auto/night mode) in the fan parent component in order to have them all in the same place but if you prefer I can move them in the Dyson component. I don't know if other fan devices from other manufacturer support this features.
I you prefer to have them in the Dyson platform, should I prefix them with dyson_ (eg: dyson_set_auto_mode, dyson_set_night_mode) ?
And I'll fix the other remarks as soon as possible.

@pvizeli
Copy link
Member

pvizeli commented Jun 8, 2017

You component/platform looks good. It should be ready to merge after your address our comments.

If you want this service, you need move it into your platform with namesufix. But I think you need not this service and can use set_level and add auto, night to speed list...

@CharlesBlonde
Copy link
Contributor Author

Adding auto/night to speed list was what I did before my last commit. But, at least for the night mode, it has to be used in addition to speed level:

  • If speed in 0..10, setting night mode will lower the device brightness
  • If speed == AUTO, setting night mode will lower the brightness and limit the speed to 4 (instead of 10 if auto mode is set without night mode)

But I can remove auto mode and add it to the speed list (it is already in the list in fact). I follow the mobile app who is using AUTO mode like an external option but in fact, it is considered internally like a speed.

So, what I have to do (tell me if I'm wrong):

  • Remove set_auto_mode service, remove the option from the frontend and remove SUPPORT_AUTO_MODE from parent component.
  • Rename set_night_mode to dyson_set_night_mode and add this service to the Dyson platform.
  • Fix previous comments

Just one question about the constant SUPPORT_NIGHT_MODE: Should it be in the init.py file or in the fan/dyson.py file ?

@pvizeli
Copy link
Member

pvizeli commented Jun 8, 2017

Yes.

You can not make custom UI change for platform inside fan card. In this case you need not have a SUPPORT_NIGHT_MODE. You can only call the service.

@CharlesBlonde
Copy link
Contributor Author

I move the NIGHT_MODE to the dyson fan component and rollback any changes to fan/__init__.py file.

I'll do other improvement in the future in other(s) PR.

But is there a reason I can not use supported_feature like for media_player for example ?
What I wanted to do is adding supported features in the parent fan component (like night mode but I'm planing to add other features) and use this variable in the more-info_fan.html. Like SUPPORT_VOLUME_SET for media_player component (display volume slider only if setting volume is supported).

I agree to add a

@property
def support_mode(self):
  return []

To the fan parent component but I don't understand the difference between this and the supported_feature who is already existing. I should be missing something :)

And s***, I broke the Travis build with Python 3.6 ... :'(

Copy link
Member

@pvizeli pvizeli left a comment

Choose a reason for hiding this comment

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

So we go into finishing 👍

_LOGGER.info("Creating device %s", device.name)
self.hass = hass
self._device = device
self._device.add_message_listener(self.on_message)
Copy link
Member

@pvizeli pvizeli Jun 13, 2017

Choose a reason for hiding this comment

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

Move that into async_added_to_hass

"""Called when new messages received from the fan."""
_LOGGER.debug("Message received for fan device %s : %s", self.name,
message)
if self.entity_id:
Copy link
Member

Choose a reason for hiding this comment

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

If you do it right, you need this check not

self.hass = hass
self._device = device
self._name = "{} filter life".format(self._device.name)
self._device.add_message_listener(self.on_message)
Copy link
Member

Choose a reason for hiding this comment

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

Move that into async_added_to_hass

if self._device.state:
return self._device.state.filter_life
else:
return None
Copy link
Member

Choose a reason for hiding this comment

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

return STATE_UNKNOWN from const.

@pvizeli
Copy link
Member

pvizeli commented Jun 13, 2017

supported_feature is only for core thins. In your example you add SUPPORT_MODE to this and on UI we can print the list of mode that are supported on it.

@CharlesBlonde
Copy link
Contributor Author

Ok, it make sense, thanks for the quick answer!
And I hope the last commit will be the right one :)

Copy link
Member

@pvizeli pvizeli left a comment

Choose a reason for hiding this comment

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

Merge after test are pass

@pvizeli pvizeli merged commit 8c0967a into home-assistant:dev Jun 14, 2017
@balloob balloob mentioned this pull request Jun 16, 2017
@home-assistant home-assistant locked and limited conversation to collaborators Oct 20, 2017
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.

None yet

6 participants