Skip to content

Basic MQTT vacuum support#9386

Merged
pvizeli merged 15 commits into
home-assistant:devfrom
johnboiles:mqtt-vacuum
Sep 15, 2017
Merged

Basic MQTT vacuum support#9386
pvizeli merged 15 commits into
home-assistant:devfrom
johnboiles:mqtt-vacuum

Conversation

@johnboiles
Copy link
Copy Markdown
Contributor

@johnboiles johnboiles commented Sep 11, 2017

Basic MQTT vacuum support

Useful for retrofitting older Roombas and other non-wifi vacuums to be controlled via Home Assistant.

See also my WIP ESP8266 firmware that works with this branch (README.md coming soon on that repo).

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

Basic example entry for configuration.yaml:

vacuum:
  - platform: mqtt

More advanced example entry for configuration.yaml:

vacuum:
  - platform: mqtt
    name: "Roomba 650 #2"
    command_topic: vacuum2/command
    state_topic: vacuum2/state
    supported_features:
      - turn_on
      - turn_off
      - return_to_base
      - status

Forum Discussion(s):

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
  • (N/A) New dependencies have been added to the REQUIREMENTS variable (example).
  • (N/A) New dependencies are only imported inside functions that use them (example).
  • (N/A) 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.

@homeassistant
Copy link
Copy Markdown
Contributor

Hi @johnboiles,

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!

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (83 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (92 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (114 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (83 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (117 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (103 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (102 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (83 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (111 > 79 characters)

Comment thread tests/components/vacuum/test_mqtt.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

line too long (83 > 79 characters)

@pvizeli
Copy link
Copy Markdown
Member

pvizeli commented Sep 11, 2017

That is cool 👍 link your firmware to documentation

@johnboiles
Copy link
Copy Markdown
Contributor Author

Thanks @pvizeli. Planning to write some docs on that tonight. Starting with docs here to get the home assistant process rolling

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please use the new style self.hass.components.mqtt.async_....

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

will do!

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please use last change: self.async_schedule_...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will do!

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think that need to be more generic like other mqtt component. Maybe wuth templates (that support also json) and variable topics for that points. In yiur case you can set all the sane topic and use the tempkate to parse the correct value on it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok sure, will do

Copy link
Copy Markdown
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.

Cool!

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Only allow the methods in SERVICE_TO_STRING:

vol.All(cv.ensure_list, vol.In(SERVICE_TO_STRING.keys())),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please sort the imported names alphabetically 🔡 and break the line with parenthesis.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is there a doc somewhere about code-style things that aren't otherwise enforced by flake8/pylint/pydocstyle?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here are our recommendations: https://home-assistant.io/developers/development_guidelines/. Neither of my comments here are mentioned there though.

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will do. Thanks for the link!

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Stale docstring.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

https://home-assistant.io/components/vacuum.mqtt/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👍 good catch

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need to overwrite this property if you don't return a dict with contents.

Copy link
Copy Markdown
Contributor Author

@johnboiles johnboiles Sep 13, 2017

Choose a reason for hiding this comment

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

Ah cool. I'll have to do more reading about what sort of things typically go in device_state_attributes to see if there's anything meaningful I could be returning.

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will do, thanks for the links!

Copy link
Copy Markdown
Contributor Author

@johnboiles johnboiles Sep 13, 2017

Choose a reason for hiding this comment

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

I noticed the superclass VacuumDevice, has code like this

    def stop(self, **kwargs):
        """Stop the vacuum cleaner."""
        raise NotImplementedError()

    def async_stop(self, **kwargs):
        """Stop the vacuum cleaner.

        This method must be run in the event loop and returns a coroutine.
        """
        return self.hass.async_add_job(partial(self.stop, **kwargs))

Does it make sense to update the superclass code to remove the non-async version?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No, each platform will decide to use either the sync or the async version of the method, so one of them will be overwritten. The service handler in the base component will always use the async version.

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use the new async version that @pvizeli mentioned: self.async_schedule_update_ha_state()

This applies to all methods below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👍

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
Copy link
Copy Markdown
Member

@MartinHjelmare MartinHjelmare Sep 12, 2017

Choose a reason for hiding this comment

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

Other mqtt platforms have configurable payloads. Maybe we want that here too, continuing @pvizeli's suggestion on generalization.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Totally open to that. It will add a ton of configuration options which might look intimidating to newer users. But I think that's probably an ok tradeoff

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
payload,
error_value=None)
if state:
if state == 'cleaning':
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm open to ideas on how to handle the state enum in a generic way as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I wonder if it'd be better to just handle state as a set of bools potentially with their own topics/templates, then determine a state on the home assistant side.

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
if state:
if state == 'cleaning':
self._is_cleaning = True
self._status = "Cleaning"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is there already a strategy for localization that's used in Home Assistant?

Copy link
Copy Markdown
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.

Looks good. Some small things:

  • Please revert change on demo. We run that thread for a better coverage of sync function
  • Don't add a lot of defaults to the schema. Look to light/mqtt.py - It should work in same way
  • Move the change from vacuum/init into your platform if you realy need this

Address this 3 Points and we are fine to merge it 👍 good work

@johnboiles
Copy link
Copy Markdown
Contributor Author

Please revert change on demo. We run that thread for a better coverage of sync function

Done. I don't feel strongly but I think it'd be nice if the demo.py implementation used the async_* service methods if that's the best practice (mentioned in this comment). I just copied and pasted demo.py to make my implementation and I bet that's a pretty common workflow. What do you think?

Move the change from vacuum/init into your platform if you realy need this

Done; moved into vacuum/mqtt.py. I need a way to map the bitmask to strings so that I can parse the config, so I definitely need SERVICE_TO_STRING and STRING_TO_SERVICE.

Don't add a lot of defaults to the schema. Look to light/mqtt.py - It should work in same way

For this component, I think opinionated defaults make sense for a two reasons:

  1. Opinionated defaults here serve to nudge MQTT client vacuum developers towards a shared MQTT vacuum protocol. There aren't many MQTT client vacuum implementations in the wild, so likely people writing new ones will have Home Assistant in mind. If all the MQTT client vacuum implementations congeal around the same protocol, then there's minimal configuration complexity for Home Assistant users.
  2. The normal case is to only have one vacuum (as opposed to lights, where it'd be normal to have multiple). That means setting default topics (e.g. vacuum/command) makes reasonable sense. The only reason you'd need to change the topic name is if you had multiple vacuums.

Copy link
Copy Markdown
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.

Noting possible improvements (for the future).

payload,
error_value=None)
if battery_level is not None:
self._battery_level = int(battery_level)
Copy link
Copy Markdown
Member

@MartinHjelmare MartinHjelmare Sep 14, 2017

Choose a reason for hiding this comment

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

A possible improvement (for the future) would be to use a nested dict to lookup the template, function for modifying the value, and value attribute name, from the topic. Then all the topic checks could be replaced with one code block.

Also I think you could just have the whole config as an instance attribute and use the string constants to lookup what you need in the config.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's a good idea

mqtt.async_publish(self.hass, self._command_topic,
self._payload_turn_on, self._qos, self._retain)
self._status = 'Cleaning'
self.async_schedule_update_ha_state()
Copy link
Copy Markdown
Member

@MartinHjelmare MartinHjelmare Sep 14, 2017

Choose a reason for hiding this comment

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

Since all of the methods have a very similar structure, an improvement (for the future) would be to add a helper method, that takes the support, payload and status as arguments. Then use the helper method in all these methods.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea

@pvizeli pvizeli dismissed MartinHjelmare’s stale review September 15, 2017 09:56

Would be addressed

@pvizeli
Copy link
Copy Markdown
Member

pvizeli commented Sep 15, 2017

We can allow to discovery this platform. So you can make a new platform for your firmware that discovery the mqtt platform with correct settings... Like a lot camera platform does with mjepeg platform. Or we provide a ready to use copy past config inside documentation for your firmware 👍

@home-assistant home-assistant deleted a comment from houndci-bot Sep 15, 2017
@pvizeli pvizeli merged commit 175b4ae into home-assistant:dev Sep 15, 2017
@pvizeli
Copy link
Copy Markdown
Member

pvizeli commented Sep 15, 2017

Good work 👍 I will try out with my roomba

Comment thread homeassistant/components/vacuum/mqtt.py Outdated
DEFAULT_PAYLOAD_CLEAN_SPOT = 'clean_spot'
DEFAULT_PAYLOAD_LOCATE = 'locate'
DEFAULT_PAYLOAD_START_PAUSE = 'start_pause'
DEFAULT_BATTERY_LEVEL_TOPIC = 'vacuum/state'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removing sane defaults is a bummer to me. Every home assistant user that wants to use this component will now need to add an at least ~10 line config block to configuration.yaml. I bet this configuration will be exactly the same (copied and pasted from the github.io docs example) for 80% of people.

Copy link
Copy Markdown
Contributor Author

@johnboiles johnboiles Sep 15, 2017

Choose a reason for hiding this comment

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

@MartinHjelmare what do you think? If you both agree then I'll drop the issue.

Seems to me that managing configuration.yaml config is already really hard for Home Assistant users. I'm in favor of whatever makes it easier/simpler.

Comment thread tests/components/vacuum/test_mqtt.py Outdated
CONF_NAME: 'mqtttest',
ATTR_SUPPORTED_FEATURES: services_to_strings(ALL_SERVICES),
}
vacuum.DOMAIN: self.default_config.update({
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Neat, great to have these shared defaults from self.default_config. Thanks for the cleanup

@johnboiles
Copy link
Copy Markdown
Contributor Author

@pvizeli @MartinHjelmare see my comment on https://github.com/home-assistant/home-assistant/pull/9386/files/fb24fdf19af0b49328e8daa656a63f3fcd398cda..60d9f71386aa597e4ed39b5a86022f7e66c6d412#r139182488 and here about removing the defaults. It's a bummer to me that users will now need a 10+ line config block in configuration.yaml for settings that will probably be exactly the same for most users (likely copied and pasted from the example in the home assistant docs). Removing defaults from the code makes it harder for users to get started with this platform, and potentially increases the likelihood of causing breaking changes for users (e.g. if we need to change the config schema for some reason and users have the default config copied and pasted into their configuration.yaml).

That's the only thing I disagree with from @pvizeli's changes. Otherwise thanks for the cleanup @pvizeli! I'm excited to get this out there. I'll update the docs PR tonight

@MartinHjelmare
Copy link
Copy Markdown
Member

Less defaults is in line with the other mqtt platforms. Hopefully it's just a one time setup of that part of the config, so I think it's OK.

@johnboiles
Copy link
Copy Markdown
Contributor Author

Ok cool thanks for chiming in @MartinHjelmare!

I'll update the docs PR to reflect @pvizeli's changes tonight!

@johnboiles johnboiles deleted the mqtt-vacuum branch September 16, 2017 05:02
@balloob balloob mentioned this pull request Sep 22, 2017
@home-assistant home-assistant locked and limited conversation to collaborators Mar 3, 2018
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