Skip to content

allow wildcards in subscription#12247

Merged
balloob merged 8 commits intohome-assistant:devfrom
escoand:mqtt-allow-wildcards
Feb 9, 2018
Merged

allow wildcards in subscription#12247
balloob merged 8 commits intohome-assistant:devfrom
escoand:mqtt-allow-wildcards

Conversation

@escoand
Copy link
Copy Markdown
Contributor

@escoand escoand commented Feb 8, 2018

Description:

Currently it's possible to use a subscription topic with wildcards but an error is thrown when received because it's not equals the received topic. This PR adds the missing match to the subscription topic.

Example entry for configuration.yaml (if applicable):

device_tracker:
  - platform: mqtt
    devices:
      device1: 'home/+/BLE_11:22:33:44:55:66'
      device2: 'home/+/BLE_22:33:44:55:66:77'

Checklist:

  • The code change is tested and works locally.

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

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.

if mqtt._match_topic(subscription, topic):
hass.async_add_job(async_see(
dev_id=dev_id_lookup[subscription],
location_name=payload))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

trailing whitespace

async_see(dev_id=dev_id_lookup[topic], location_name=payload))
for subscription in dev_id_lookup:
if mqtt._match_topic(subscription, topic):
hass.async_add_job(async_see(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

trailing whitespace

hass.async_add_job(
async_see(dev_id=dev_id_lookup[topic], location_name=payload))
for subscription in dev_id_lookup:
if mqtt._match_topic(subscription, topic):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

trailing whitespace

@escoand escoand requested a review from a team as a code owner February 8, 2018 19:16
hass.async_add_job(
async_see(dev_id=dev_id_lookup[topic], location_name=payload))
for subscription in dev_id_lookup:
if mqtt.match_topic(subscription, topic):
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.

Why not just create a separate callback for each subscription?

Copy link
Copy Markdown
Member

@OttoWinter OttoWinter Feb 8, 2018

Choose a reason for hiding this comment

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

Like this:

for dev_id, topic in devices.items():
    @callback
    def async_tracker_message_received(topic, payload, qos):
        """Handle received MQTT message."""
        hass.async_add_job(
            async_see(dev_id=dev_id, location_name=payload))

    yield from mqtt.async_subscribe(
        hass, topic, async_tracker_message_received, qos)

Copy link
Copy Markdown
Contributor Author

@escoand escoand Feb 8, 2018

Choose a reason for hiding this comment

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

Is it good style to pass the loop-local dev_id variable into a callback?
What value has the callback internal dev_id?
The one from the loop or something unpredictable?

Copy link
Copy Markdown
Member

@OttoWinter OttoWinter Feb 8, 2018

Choose a reason for hiding this comment

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

That is indeed true, this wouldn't work
image

But using a callback creator should work:

def make_callback(dev_id):
    @callback
    def async_tracker_message_received(...):
        # [...]
    return async_tracker_message_received

for dev_id, topic in devices.items():
    yield from mqtt.async_subscribe(hass, topic, make_callback(dev_id), qos)

I believe this would still be better than handling the topic matching yourself, since mqtt already handles matching and knows best how to do that.

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.

According to https://stackoverflow.com/a/3431699/3775041 this should also work:

    for dev_id, topic in devices.items():
        @callback
        def async_tracker_message_received(topic, payload, qos, dev_id=dev_id):
            """Handle received MQTT message."""
            hass.async_add_job(
                async_see(dev_id=dev_id, location_name=payload))

        yield from mqtt.async_subscribe(
            hass, topic, async_tracker_message_received, qos)

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.

But you are right, the mqtt-outside handling of topics is not the best idea.

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.

BTW the old code also uses this strange callback-outside variable style with the dev_id_lookup dictionary.

@balloob
Copy link
Copy Markdown
Member

balloob commented Feb 9, 2018

Can you add a test to make sure that it works.

@escoand
Copy link
Copy Markdown
Contributor Author

escoand commented Feb 9, 2018

I don't have experiences with test creation. Who can support me?

@todschmidt
Copy link
Copy Markdown
Contributor

@escoand Just take a look at test/components/device_tracker/test_mqtt.py. The last test should be easy enough to duplicate and add some tests will publishing to several topics and making sure they all get processed. Test both '+' and '#'

@escoand escoand closed this Feb 9, 2018
@escoand escoand reopened this Feb 9, 2018
@todschmidt
Copy link
Copy Markdown
Contributor

What you have is fine since the initial state will != what you are testing. The test look to be failing though. You can run the test locally using tox. Make sure your updates are in whatever ha is being loaded (ie use a virtual env and you can do pip -e homeassistant to point to your dev copy), an running this will run the test on the one file onlytox test/components/device_tracker/test_mqtt.yp

@escoand
Copy link
Copy Markdown
Contributor Author

escoand commented Feb 9, 2018

Ok, but now I've fixed my build errors.

@balloob balloob added this to the 0.63 milestone Feb 9, 2018
@balloob balloob merged commit cad9e9a into home-assistant:dev Feb 9, 2018
@escoand escoand deleted the mqtt-allow-wildcards branch February 10, 2018 08:59
balloob pushed a commit that referenced this pull request Feb 10, 2018
* allow wildcards in subscription

* remove whitespaces

* make function public

* also implement for mqtt_json

* avoid mqtt-outside topic matching

* add wildcard tests

* add not matching wildcard tests

* fix not-matching tests
@balloob balloob mentioned this pull request Feb 10, 2018
@home-assistant home-assistant locked and limited conversation to collaborators May 29, 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.

7 participants