Skip to content

Add sensors for BMW electric cars#14293

Merged
MartinHjelmare merged 4 commits intohome-assistant:devfrom
gerard33:bmw-electric
May 8, 2018
Merged

Add sensors for BMW electric cars#14293
MartinHjelmare merged 4 commits intohome-assistant:devfrom
gerard33:bmw-electric

Conversation

@gerard33
Copy link
Copy Markdown
Contributor

@gerard33 gerard33 commented May 4, 2018

Description:

Add new sensors for BMW vehicles.
CC @ChristianKuehnel @m1n3rva

General:

  • Binary sensor for parking_lights
  • Binary sensor for condition_based_services
  • Binary sensor for check_control_messages

For electric and hybrid cars:

  • Binary sensor for charging_status
  • Binary sensor for connection_status
  • Sensor for charging_time_remaining
  • Sensor for charging_status
  • Sensor for max_range_electric
  • Sensor for charging_level_hv
  • Sensor for remaining_range_electric

Breaking change
The current sensor remaining_range_fuel is replaced by remaining_range_total for cars with a combustion engine.

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass

@rafale77
Copy link
Copy Markdown
Contributor

rafale77 commented May 5, 2018

Just tested this and it is not recognizing my car as electrical (it is an i3)

@gerard33
Copy link
Copy Markdown
Contributor Author

gerard33 commented May 5, 2018

@rafale77 can you share a screenshot with all the cars entities from the States page?

@rafale77
Copy link
Copy Markdown
Contributor

rafale77 commented May 5, 2018

I was looking for it and actually there is none of the additional sensors. Not sure if I pulled this wrong. I am in US. Not sure if the server has an impact.

@gerard33
Copy link
Copy Markdown
Contributor Author

gerard33 commented May 5, 2018

Server should not have impact, so probably something with the pull.
You can try the custom component which is available here https://github.com/gerard33/home-assistant/tree/bmw-dev/bmw_connecteddrive.
That is tested with an i3 in US, see this post https://community.home-assistant.io/t/bmw-connecteddrive-component/39569/249?u=gerard33.

@rafale77
Copy link
Copy Markdown
Contributor

rafale77 commented May 5, 2018

Sorry for the wrong message, I oddly had two version of Hass installed and updating no longer updates my virtual env one which is strange. It is all working.

# device class plug: On means device is plugged in,
# Off means device is unplugged
if self._attribute == 'connection_status':
self._state = bool(vehicle_state._attributes['connectionStatus'] ==
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.

You don't need to use bool here.

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.

Removed bool

elif self._attribute == 'charging_level_hv':
return '%'
else:
self._unit_of_measurement = None
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.

Return None.

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.

Changed it to return None

@@ -53,8 +45,6 @@ def __init__(self, account, vehicle, attribute: str, sensor_name, icon):
self._unit_of_measurement = None
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.

This isn't used anymore.

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.

Removed the line

Copy link
Copy Markdown

@m1n3rva m1n3rva left a comment

Choose a reason for hiding this comment

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

Hey @gerard33,

great job integrating all of the different vehicle types into the sensor!

I added some comments on the design of the sensor and the readability of the code. Nothing major, rather some hints to improve it.

result[window.name] = window.state.value
elif self._attribute == 'door_lock_state':
result['door_lock_state'] = vehicle_state.door_lock_state.value
result['last_update_reason'] = vehicle_state.last_update_reason
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This function is not getting a huge if/elseif statement. This makes it a bit hard to read and maintain. Should we split up this monster class into one class per sensor type and use inheritance?

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 sounds like a plan. I would suggest to discuss this seperately, so we can first get this PR finished. Then we can implement the other parts on our list, such as sending the position, the imperial vs metric units, the lscType and the stuff you mentioned here regarding the design and readability of the code.

device = BMWConnectedDriveSensor(account, vehicle, key,
value[0], value[1])
devices.append(device)
if vehicle.has_hv_battery:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You could also use vehicle.drive_train_attributes here. This will already give you a list of available attributes. This way you're flexible if we add more attributes to bimmer_connected.

Then you would not need SENSOR_TYPES_ELEC and SENSOR_TYPES

Copy link
Copy Markdown
Contributor Author

@gerard33 gerard33 May 6, 2018

Choose a reason for hiding this comment

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

The vehicle.drive_train_attributes is being used in the sensor code.
It contains a lot of attributes, but not the ones which are used for the binary_sensors (only charging_status is used in both).
Maybe it's a good idea to add this to bimmer_connected for the binary sensors as well in a next release.

elif self._attribute == 'lights_parking':
result['lights_parking'] = vehicle_state.parking_lights.value
elif self._attribute == 'condition_based_services':
for report in vehicle_state.condition_based_services:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You could extract the formatting of the CBS data into a separate function:

@staticmethod
def _format_cbs_report(report):
   result = dict()
   service_type = report.service_type.lower().replace('_', ' ')
   ...
  return result

This would make the function more readable.

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.

Or maybe also something that can be done in bimmer_connected?
Otherwise I can indeed make a separate function for this in a next version.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@gerard33
I just had a look at the code and this is quite specific for the HA use case, where you need a dictionary as result. I would rather not implement this in bimmer connected.

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.

@m1n3rva the function is implemented in the component in #14424.

# Possible values: LOCKED, SECURED, SELECTIVE_LOCKED, UNLOCKED
self._state = vehicle_state.door_lock_state not in \
[LockState.LOCKED, LockState.SECURED]
# device class light: On means light detected, Off means no light
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Similar: huge if statement for the different types of sensors.

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.

See my first comment.

elif self._attribute == 'charging_status':
result['charging_status'] = vehicle_state.charging_status.value
result['last_charging_end_result'] = \
vehicle_state._attributes['lastChargingEndResult']
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.

Travis is failing on three of these accesses to private attributes. You can disable that check above those lines. But you should probably change this in the library so that we don't have to access private attributes.

Copy link
Copy Markdown
Contributor Author

@gerard33 gerard33 May 7, 2018

Choose a reason for hiding this comment

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

Thanks! Have disabled those checks for now. It's on the issue list to add these to the library
bimmerconnected/bimmer_connected#73.

charging_state = vehicle_state.charging_status in \
[ChargingState.CHARGING]

if self._attribute == 'mileage':
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.

You could make a constant dict that maps the attributes to the icon and lookup that here, if attribute is not charging_level_hv.

def unit_of_measurement(self) -> str:
"""Get the unit of measurement."""
return self._unit_of_measurement
if self._attribute in (
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.

You could use a dict here too.

@MartinHjelmare
Copy link
Copy Markdown
Member

I'm going to merge this now. A new PR that cleans up some of the if...elif trails would be great.

@MartinHjelmare MartinHjelmare merged commit ba7333e into home-assistant:dev May 8, 2018
@gerard33 gerard33 deleted the bmw-electric branch May 8, 2018 20:04
@gerard33 gerard33 mentioned this pull request May 12, 2018
2 tasks
@balloob balloob mentioned this pull request May 28, 2018
@home-assistant home-assistant locked and limited conversation to collaborators Sep 5, 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