core/homeassistant/components/nissan_leaf/sensor.py

114 lines
3.3 KiB
Python
Raw Normal View History

Nissan Leaf Integration (Carwings / NissanConnect EV) (#19786) * Added work so far. * Change interval so nobody drains their battery when I put this online * Added the warning notice. * Async setup * Still broken, but we're getting there. * Back to synchronous, moved refresh stuff into DataStore * Functional sensors! * Added working switches, tweaked intervals a bit * Fixed turn off result * Moved plug status to binary_sensor, added smart intervals * Documentation and car nickname stuff * Syntax fixes and coveragerc additions * Style fixes * Fixing the final line length * Fixed an issue with newer models and bad climate data * Forgot to check my line endings. * New icons for most of the components * Hotfix for handling Nissan's awful servers * Merge in fixes made by Phil Cole Remove invalid FIXMEs and update TODOs Fixes for pylint and test for CarwingsError exception rather than Exception Flake8 fixes Add pycarwings2 to requirements_all.txt Add extra configuration documentation. Use pycarwings2 from pip. Check server dates between requests. Add sensor device class for battery. Async conversion fixes flake8 fixes and docstrings Non-async charging is OK Handle multiple cars in the configuration Convert to async. Better imports for platforms Fix scanning interval & prevent extra refreshes. async switchover Check discovery_info to prevent load of platforms Ensure update frequency is always above a minimum interval (1 min). Platforms don't have return values Use values() instead of items() when not using key Use snake_case (LeafCore becomes leaf_core) commit 418b6bbcc49cf2909aac85869440435410abf3fd * Add pycarwings2 to requirements_all.txt * Make stopping charge error an 'info'. Remove TODO. * Request update from car after sending start charging command. * Delay initial (slow) update for 15 seconds and make async * Flake8 line length fixes * Try to fix D401 'imperative mood' git diff tox errors * Try to fix more D401 'imperative mood' tox errors * Default interval of an hour in code, to match comments. * Update to pycarwings2 2.3 * Update to pycarwings2 2.3 in requirements_all.txt * Remove documentation, instead refering to home-assistant.io * Remove unneeded dispatcher_send() * Remove unneeded requirements comments * Combine excess debugging. * Remove single line method signal_components() * Bump to version 2.4 of pycarwings2 * Remove unused dispatcher_send * Simplify logging of LeafEntity registration * Update requirements_all.txt * Multiple changes Increase timeout to 30 seconds Only consider battery_status Fix plugged in status Better attempts at try/exception handling * Fix line length * Use pycarwings 2.5 * Remove pointless 'is True' * Remove unnecessary 'is True/False' * Remove unnecessary 'is True/False' * Use LENGTH_MILES and LENGTH_KILOMETERS * Remove excess logging in setup_platform() * Remove unnecessary 'is True' * Use pycarwings2 version 2.6 * Require pycarwings2 version 2.7. * Increase sleep delay for climate and location reponses. * Remove unnecessary 'is True' * Increase frequent polling warning to _LOGGER.warning() * Use DEVICE_CLASS_BATTERY * Remove extraneous 'is True'. * Move icon strings to constants. * Remove unneeded key. * LeafRangeSensor ac_on property is internal. * Flake8 missing line * Remove homebridge attributes. * Remove round battery % and range to whole numbers * Use pycarwings2 2.8 * Move to embedded component model * Reduce maximum attempts to 10 (5 mins) * Include attempt count in 'waiting' log message * Use await instead of yield. Remove @asyncio.coroutine decorators. * Add @filcole as nissan_leaf codeowner * Fix checking for if not data returned from vehicle. Don't double send signal on location update. * Exposed updated_on, update_in_progress and next_update attributes. * Add nissan_leaf.update service that triggers an update. * Flake8 line fixes * Remove excess and double logging. * Add updated_on attribute for device tracker. * Fix crash if pycarwings2 doesn't provide cruising ranges. * Minor changes * Minor changes * Minor changes * Minor changes * Minor changes
2019-02-15 13:35:26 +00:00
"""Battery Charge and Range Support for the Nissan Leaf."""
import logging
from homeassistant.components.nissan_leaf import (
DATA_BATTERY, DATA_CHARGING, DATA_LEAF, DATA_RANGE_AC, DATA_RANGE_AC_OFF,
LeafEntity)
from homeassistant.const import DEVICE_CLASS_BATTERY
from homeassistant.helpers.icon import icon_for_battery_level
from homeassistant.util.distance import LENGTH_KILOMETERS, LENGTH_MILES
from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['nissan_leaf']
ICON_RANGE = 'mdi:speedometer'
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Sensors setup."""
_LOGGER.debug("setup_platform nissan_leaf sensors, discovery_info=%s",
discovery_info)
devices = []
for key, value in hass.data[DATA_LEAF].items():
_LOGGER.debug("adding sensor for item key=%s, value=%s", key, value)
devices.append(LeafBatterySensor(value))
devices.append(LeafRangeSensor(value, True))
devices.append(LeafRangeSensor(value, False))
add_devices(devices, True)
class LeafBatterySensor(LeafEntity):
"""Nissan Leaf Battery Sensor."""
@property
def name(self):
"""Sensor Name."""
return self.car.leaf.nickname + " Charge"
@property
def device_class(self):
"""Return the device class of the sensor."""
return DEVICE_CLASS_BATTERY
@property
def state(self):
"""Battery state percentage."""
return round(self.car.data[DATA_BATTERY])
@property
def unit_of_measurement(self):
"""Battery state measured in percentage."""
return '%'
@property
def icon(self):
"""Battery state icon handling."""
chargestate = self.car.data[DATA_CHARGING]
return icon_for_battery_level(
battery_level=self.state,
charging=chargestate
)
class LeafRangeSensor(LeafEntity):
"""Nissan Leaf Range Sensor."""
def __init__(self, car, ac_on):
"""Set-up range sensor. Store if AC on."""
self._ac_on = ac_on
super().__init__(car)
@property
def name(self):
"""Update sensor name depending on AC."""
if self._ac_on is True:
return self.car.leaf.nickname + " Range (AC)"
return self.car.leaf.nickname + " Range"
def log_registration(self):
"""Log registration."""
_LOGGER.debug(
"Registered LeafRangeSensor component with HASS for VIN %s",
self.car.leaf.vin)
@property
def state(self):
"""Battery range in miles or kms."""
if self._ac_on:
ret = self.car.data[DATA_RANGE_AC]
else:
ret = self.car.data[DATA_RANGE_AC_OFF]
if (not self.car.hass.config.units.is_metric or
self.car.force_miles):
ret = IMPERIAL_SYSTEM.length(ret, METRIC_SYSTEM.length_unit)
return round(ret)
@property
def unit_of_measurement(self):
"""Battery range unit."""
if (not self.car.hass.config.units.is_metric or
self.car.force_miles):
return LENGTH_MILES
return LENGTH_KILOMETERS
@property
def icon(self):
"""Nice icon for range."""
return ICON_RANGE