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 new component: BMW connected drive #12277

Merged
merged 15 commits into from
Feb 20, 2018

Conversation

ChristianKuehnel
Copy link
Contributor

@ChristianKuehnel ChristianKuehnel commented Feb 10, 2018

Description:

This is a basic implementation of a sensor for BMW Connected Drive vehicles. In the current version your're getting:

  • device tracker for your vehicle
  • current mileage, fuel and remaining range

I could only test this with one BMW model. So there might be changes necessary to make it work with other models...

Related issue (if applicable): N/A

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

Example entry for configuration.yaml (if applicable):

bmw_connected_drive:
  mycar:
    username: your_name
    password: your_password
    country: country_of_your_connected_drive_account

Checklist:

  • The code change is tested and works locally.

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
  • 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.

from bimmer_connected import BimmerConnected
self.bimmer = BimmerConnected(vin, username, password, cache=True)
self.name = name

Choose a reason for hiding this comment

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

blank line at end of file

@ChristianKuehnel ChristianKuehnel changed the title new component: BMW connected drive [WIP] new component: BMW connected drive Feb 11, 2018
@gerard33
Copy link
Contributor

gerard33 commented Feb 11, 2018

@ChristianKuehnel, let's get in touch to see how we can join forces.
I was already working on a BMW ConnectedDrive component as well, https://community.home-assistant.io/t/wip-bmw-connected-drive-custom-component/39569/65.

I my version the VIN isn't needed and I have some extra sensors and also switches in use.
I also have some API output for an electric (i3) and hybrid car. So we can use that to support those cars as well. And my X1 has head_unit: EntryEvo, so that's something that can be supported as well in your bimmer module on PyPi.

I was facing an issue however with warnings that updating the sensors took longer than the scheduled update interval of 0:00:30. @danielperna84 was just now helping me to find the cause of that issue.
So I suggest to expand your version with the useful parts of my code as mentioned above.

@danielperna84
Copy link
Contributor

What I noticed while looking at bimmer-connected: it uses the german API endpoint. Having followed the thread @gerard33 has mentioned it is actually required to be able to use different URLs so people from other countries can use this as well.

@gerard33
Copy link
Contributor

gerard33 commented Feb 11, 2018

I tried to use the German url and that actually worked, but then I got errors using the BMW CD app, so using the local url is indeed the best solution.
These are all mentioned on www.bmw-connecteddrive.com.

@ChristianKuehnel
Copy link
Contributor Author

@gerard33 just commented on the community page, lets discuss there how to proceed.
https://community.home-assistant.io/t/wip-bmw-connected-drive-custom-component/39569/65.

@ChristianKuehnel ChristianKuehnel changed the title new component: BMW connected drive new component: BMW connected drive [WIP] Feb 11, 2018
* Update are now triggered from BMWConnectedDriveVehicle.
* removed polling from sensor and device_tracker
* backend URL is not detected automatically based on current country
* vehicles are discovered automatically
* updates are async now

resolves:
* bimmerconnected/bimmer_connected#3
* bimmerconnected/bimmer_connected#5
"""
import logging

from homeassistant.components.bmw_connected_drive \

Choose a reason for hiding this comment

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

'homeassistant.components.bmw_connected_drive.BMWConnectedDriveEntity' imported but unused

password = account_config[CONF_PASSWORD]
country = account_config[CONF_COUNTRY]
_LOGGER.debug('Adding new account %s', name)
bimmer = BMWConnectedDriveEntity(hass, username, password, country, name)

Choose a reason for hiding this comment

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

line too long (81 > 79 characters)

@ChristianKuehnel
Copy link
Contributor Author

@danielperna84 the portal is now selected based on the country you define as config parameter.

@gerard33 I'm done with my major refactoring of the setup and update process. Now the update is triggered by a timer in the components/bmw_connected_drive.py and that then triggers the different sensors.

@ChristianKuehnel ChristianKuehnel changed the title new component: BMW connected drive [WIP] new component: BMW connected drive Feb 15, 2018
@ChristianKuehnel
Copy link
Contributor Author

I ran the current implementation over the last 24 hours in my test setup and it worked fine. It does not yet contain all the values you could get from your BMW but I think we could start rolling it out and get some feedback from the users. I suspect there might be some issues with different BMW models and different countries.

There is a ton of more features available from the BMW portal, but we can add these later on.

@ChristianKuehnel
Copy link
Contributor Author

@MartinHjelmare thx for the extensive code review! I just uploaded the changes.

To be honest, I did not really understand how async works in Home Assistant. Is there a good documentation available?

@MartinHjelmare
Copy link
Member

'mileage',
]

VAILD_ATTRIBUTES = LENGTH_ATTRIBUTES + [
Copy link
Member

Choose a reason for hiding this comment

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

Typo, same as before.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, yes was a copy an past error. I removed the duplicated code.

def add_update_listener(self, listener):
"""Add a listener for update notifications."""
self._update_listeners.append(listener)
listener()
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you should call the callback from this method. It's better to separate responsibilities, and let the caller call the callback explicitly if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

)

@asyncio.coroutine
def async_added_to_hass(self):
Copy link
Member

Choose a reason for hiding this comment

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

You can't use this method here, since this is not an entity. The device tracker component is special like that. It creates its own entities and you can only create a device class that reports to the entity via the see method.

I don't think there will be a race for the device tracker if you register and call the callback during setup_scanner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

Show latest data after startup.
"""
self._account.add_update_listener(self.update)
self.update()
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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What should I remove?

The self.update()? I need this so the state of the sensor is available right after the start of hass. If I want to trigger this from the central component, I would have to find out when all of the setup operations were completed.

Copy link
Member

Choose a reason for hiding this comment

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

Yes remove this line here. See my comment above about how to add devices so that update will be called when they are added.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, so an alternative if you really want to keep the logging with entity_id in update is to schedule a call to update here. In that case, use yield from self.hass.async_add_job(self.update).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I call add_devices(devices, True) from setup_platform even without me logging the entity_id, I get this error:

2018-02-19 16:55:32 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 239, in _step
    result = coro.send(None)
  File "/home/kuehnelc/git/home-assistant/homeassistant/helpers/entity.py", line 196, in async_update_ha_state
    "No entity id specified for entity {}".format(self.name))
homeassistant.exceptions.NoEntitySpecifiedError: No entity id specified for entity 530i xDrive remaining_range_fuel

I'm not sure why that is.

Your version with yield from self.hass.async_add_job(self.update) works just as fine as self.update(). So I'll take your version. Not sure why you want update do be called via async_add_job, it's only doing a bit of string processing. There is no IO in the update function. But as it works, I'm fine with that 😄 ...

Copy link
Member

Choose a reason for hiding this comment

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

The update method calls schedule_update_ha_state which needs to be done from a sync context.

Copy link
Member

Choose a reason for hiding this comment

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

Regarding error, yeah sorry, the entity_id is also required when scheduling a state update, ie in schedule_update_ha_state, so the my suggestion to call add_devices like that was totally wrong. The logic about this changed recently and I hadn't really understood all the consequences until now.

for sensor in VALID_ATTRIBUTES:
device = BMWConnectedDriveSensor(account, vehicle, sensor)
devices.append(device)
return add_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.

Remove the return. Just call add_devices(devices, True) to have the update method be called during entity addition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

add_devices(devices, True) resulted in some weird "no entity_id set" errors.
But `add_devices(devices)' (without true) works just fine.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, the entity_id will not be set during the update before add operation. All other attributes will be available though. Either remove the logging about entity_id in update, or do the schedule the update from async_added_to_hass.

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.

This looks good! Fix the final comment and we can merge.

"""Initialize the Tracker."""
self._see = see
self.vehicle = vehicle
self._account = account
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem to be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, you have a good eye for these things...

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.

Great!

@MartinHjelmare MartinHjelmare changed the title new component: BMW connected drive Add new component: BMW connected drive Feb 20, 2018
@MartinHjelmare MartinHjelmare merged commit 316eb59 into home-assistant:dev Feb 20, 2018
@ChristianKuehnel
Copy link
Contributor Author

@MartinHjelmare thx for your help! 👍 😄

@gerard33 good news, it's merged 🥂 So you can now add your additional sensors on top of the dev branch.

@balloob balloob mentioned this pull request Feb 22, 2018
@robbz23
Copy link

robbz23 commented Mar 6, 2018

@ChristianKuehnel @gerard33 I have a i3 and I am interested in helping although I don't have too much experience in Python, I am pretty good at other languages. How can I help make this better?

@ChristianKuehnel
Copy link
Contributor Author

@robbz23
Do you happen to live in the US or Canada? Because there we're trying to figure out how to make it work there...

@robbz23
Copy link

robbz23 commented Mar 10, 2018

Sorry I'm an American living in Sweden. Both the component and extra work.

1 similar comment
@robbz23
Copy link

robbz23 commented Mar 10, 2018

Sorry I'm an American living in Sweden. Both the component and extra work.

@home-assistant home-assistant locked and limited conversation to collaborators Jul 26, 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.

None yet

7 participants