mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Remove mychevy component (#59629)
This commit is contained in:
parent
f596cb19fd
commit
da8bfed793
@ -668,7 +668,6 @@ omit =
|
|||||||
homeassistant/components/mutesync/binary_sensor.py
|
homeassistant/components/mutesync/binary_sensor.py
|
||||||
homeassistant/components/nest/const.py
|
homeassistant/components/nest/const.py
|
||||||
homeassistant/components/mvglive/sensor.py
|
homeassistant/components/mvglive/sensor.py
|
||||||
homeassistant/components/mychevy/*
|
|
||||||
homeassistant/components/mycroft/*
|
homeassistant/components/mycroft/*
|
||||||
homeassistant/components/mysensors/__init__.py
|
homeassistant/components/mysensors/__init__.py
|
||||||
homeassistant/components/mysensors/binary_sensor.py
|
homeassistant/components/mysensors/binary_sensor.py
|
||||||
|
@ -1,155 +0,0 @@
|
|||||||
"""Support for MyChevy."""
|
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
import mychevy.mychevy as mc
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
|
||||||
from homeassistant.helpers import config_validation as cv, discovery
|
|
||||||
from homeassistant.util import Throttle
|
|
||||||
|
|
||||||
DOMAIN = "mychevy"
|
|
||||||
UPDATE_TOPIC = DOMAIN
|
|
||||||
ERROR_TOPIC = f"{DOMAIN}_error"
|
|
||||||
|
|
||||||
MYCHEVY_SUCCESS = "success"
|
|
||||||
MYCHEVY_ERROR = "error"
|
|
||||||
|
|
||||||
NOTIFICATION_ID = "mychevy_website_notification"
|
|
||||||
NOTIFICATION_TITLE = "MyChevy website status"
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30)
|
|
||||||
ERROR_SLEEP_TIME = timedelta(minutes=30)
|
|
||||||
|
|
||||||
CONF_COUNTRY = "country"
|
|
||||||
DEFAULT_COUNTRY = "us"
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
|
||||||
{
|
|
||||||
DOMAIN: vol.Schema(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
|
||||||
vol.Required(CONF_PASSWORD): cv.string,
|
|
||||||
vol.Optional(CONF_COUNTRY, default=DEFAULT_COUNTRY): vol.All(
|
|
||||||
cv.string, vol.In(["us", "ca"])
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
extra=vol.ALLOW_EXTRA,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class EVSensorConfig:
|
|
||||||
"""The EV sensor configuration."""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self, name, attr, unit_of_measurement=None, icon=None, extra_attrs=None
|
|
||||||
):
|
|
||||||
"""Create new sensor configuration."""
|
|
||||||
self.name = name
|
|
||||||
self.attr = attr
|
|
||||||
self.extra_attrs = extra_attrs or []
|
|
||||||
self.unit_of_measurement = unit_of_measurement
|
|
||||||
self.icon = icon
|
|
||||||
|
|
||||||
|
|
||||||
class EVBinarySensorConfig:
|
|
||||||
"""The EV binary sensor configuration."""
|
|
||||||
|
|
||||||
def __init__(self, name, attr, device_class=None):
|
|
||||||
"""Create new binary sensor configuration."""
|
|
||||||
self.name = name
|
|
||||||
self.attr = attr
|
|
||||||
self.device_class = device_class
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, base_config):
|
|
||||||
"""Set up the mychevy component."""
|
|
||||||
config = base_config.get(DOMAIN)
|
|
||||||
|
|
||||||
email = config.get(CONF_USERNAME)
|
|
||||||
password = config.get(CONF_PASSWORD)
|
|
||||||
country = config.get(CONF_COUNTRY)
|
|
||||||
hass.data[DOMAIN] = MyChevyHub(
|
|
||||||
mc.MyChevy(email, password, country), hass, base_config
|
|
||||||
)
|
|
||||||
hass.data[DOMAIN].start()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class MyChevyHub(threading.Thread):
|
|
||||||
"""MyChevy Hub.
|
|
||||||
|
|
||||||
Connecting to the mychevy website is done through a selenium
|
|
||||||
webscraping process. That can only run synchronously. In order to
|
|
||||||
prevent blocking of other parts of Home Assistant the architecture
|
|
||||||
launches a polling loop in a thread.
|
|
||||||
|
|
||||||
When new data is received, sensors are updated, and hass is
|
|
||||||
signaled that there are updates. Sensors are not created until the
|
|
||||||
first update, which will be 60 - 120 seconds after the platform
|
|
||||||
starts.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, client, hass, hass_config):
|
|
||||||
"""Initialize MyChevy Hub."""
|
|
||||||
super().__init__()
|
|
||||||
self._client = client
|
|
||||||
self.hass = hass
|
|
||||||
self.hass_config = hass_config
|
|
||||||
self.cars = []
|
|
||||||
self.status = None
|
|
||||||
self.ready = False
|
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
|
||||||
def update(self):
|
|
||||||
"""Update sensors from mychevy website.
|
|
||||||
|
|
||||||
This is a synchronous polling call that takes a very long time
|
|
||||||
(like 2 to 3 minutes long time)
|
|
||||||
|
|
||||||
"""
|
|
||||||
self._client.login()
|
|
||||||
self._client.get_cars()
|
|
||||||
self.cars = self._client.cars
|
|
||||||
if self.ready is not True:
|
|
||||||
discovery.load_platform(self.hass, "sensor", DOMAIN, {}, self.hass_config)
|
|
||||||
discovery.load_platform(
|
|
||||||
self.hass, "binary_sensor", DOMAIN, {}, self.hass_config
|
|
||||||
)
|
|
||||||
self.ready = True
|
|
||||||
self.cars = self._client.update_cars()
|
|
||||||
|
|
||||||
def get_car(self, vid):
|
|
||||||
"""Compatibility to work with one car."""
|
|
||||||
if self.cars:
|
|
||||||
for car in self.cars:
|
|
||||||
if car.vid == vid:
|
|
||||||
return car
|
|
||||||
return None
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
"""Thread run loop."""
|
|
||||||
# We add the status device first outside of the loop
|
|
||||||
|
|
||||||
# And then busy wait on threads
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
_LOGGER.info("Starting mychevy loop")
|
|
||||||
self.update()
|
|
||||||
self.hass.helpers.dispatcher.dispatcher_send(UPDATE_TOPIC)
|
|
||||||
time.sleep(MIN_TIME_BETWEEN_UPDATES.total_seconds())
|
|
||||||
except Exception: # pylint: disable=broad-except
|
|
||||||
_LOGGER.exception(
|
|
||||||
"Error updating mychevy data. "
|
|
||||||
"This probably means the OnStar link is down again"
|
|
||||||
)
|
|
||||||
self.hass.helpers.dispatcher.dispatcher_send(ERROR_TOPIC)
|
|
||||||
time.sleep(ERROR_SLEEP_TIME.total_seconds())
|
|
@ -1,79 +0,0 @@
|
|||||||
"""Support for MyChevy binary sensors."""
|
|
||||||
from homeassistant.components.binary_sensor import (
|
|
||||||
DOMAIN as BINARY_SENSOR_DOMAIN,
|
|
||||||
BinarySensorEntity,
|
|
||||||
)
|
|
||||||
from homeassistant.core import callback
|
|
||||||
from homeassistant.util import slugify
|
|
||||||
|
|
||||||
from . import DOMAIN as MYCHEVY_DOMAIN, UPDATE_TOPIC, EVBinarySensorConfig
|
|
||||||
|
|
||||||
SENSORS = [EVBinarySensorConfig("Plugged In", "plugged_in", "plug")]
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
|
||||||
"""Set up the MyChevy sensors."""
|
|
||||||
if discovery_info is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
sensors = []
|
|
||||||
hub = hass.data[MYCHEVY_DOMAIN]
|
|
||||||
for sconfig in SENSORS:
|
|
||||||
for car in hub.cars:
|
|
||||||
sensors.append(EVBinarySensor(hub, sconfig, car.vid))
|
|
||||||
|
|
||||||
async_add_entities(sensors)
|
|
||||||
|
|
||||||
|
|
||||||
class EVBinarySensor(BinarySensorEntity):
|
|
||||||
"""Base EVSensor class.
|
|
||||||
|
|
||||||
The only real difference between sensors is which units and what
|
|
||||||
attribute from the car object they are returning. All logic can be
|
|
||||||
built with just setting subclass attributes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, connection, config, car_vid):
|
|
||||||
"""Initialize sensor with car connection."""
|
|
||||||
self._conn = connection
|
|
||||||
self._name = config.name
|
|
||||||
self._attr = config.attr
|
|
||||||
self._type = config.device_class
|
|
||||||
self._is_on = None
|
|
||||||
self._car_vid = car_vid
|
|
||||||
self.entity_id = f"{BINARY_SENSOR_DOMAIN}.{MYCHEVY_DOMAIN}_{slugify(self._car.name)}_{slugify(self._name)}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self):
|
|
||||||
"""Return if on."""
|
|
||||||
return self._is_on
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _car(self):
|
|
||||||
"""Return the car."""
|
|
||||||
return self._conn.get_car(self._car_vid)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Register callbacks."""
|
|
||||||
self.async_on_remove(
|
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
||||||
UPDATE_TOPIC, self.async_update_callback
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_update_callback(self):
|
|
||||||
"""Update state."""
|
|
||||||
if self._car is not None:
|
|
||||||
self._is_on = getattr(self._car, self._attr, None)
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""Return the polling state."""
|
|
||||||
return False
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "mychevy",
|
|
||||||
"name": "myChevrolet",
|
|
||||||
"documentation": "https://www.home-assistant.io/integrations/mychevy",
|
|
||||||
"requirements": ["mychevy==2.1.1"],
|
|
||||||
"codeowners": [],
|
|
||||||
"iot_class": "cloud_polling"
|
|
||||||
}
|
|
@ -1,186 +0,0 @@
|
|||||||
"""Support for MyChevy sensors."""
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN, SensorEntity
|
|
||||||
from homeassistant.const import PERCENTAGE
|
|
||||||
from homeassistant.core import callback
|
|
||||||
from homeassistant.helpers.icon import icon_for_battery_level
|
|
||||||
from homeassistant.util import slugify
|
|
||||||
|
|
||||||
from . import (
|
|
||||||
DOMAIN as MYCHEVY_DOMAIN,
|
|
||||||
ERROR_TOPIC,
|
|
||||||
MYCHEVY_ERROR,
|
|
||||||
MYCHEVY_SUCCESS,
|
|
||||||
UPDATE_TOPIC,
|
|
||||||
EVSensorConfig,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
BATTERY_SENSOR = "batteryLevel"
|
|
||||||
|
|
||||||
SENSORS = [
|
|
||||||
EVSensorConfig("Mileage", "totalMiles", "miles", "mdi:speedometer"),
|
|
||||||
EVSensorConfig("Electric Range", "electricRange", "miles", "mdi:speedometer"),
|
|
||||||
EVSensorConfig("Charged By", "estimatedFullChargeBy"),
|
|
||||||
EVSensorConfig("Charge Mode", "chargeMode"),
|
|
||||||
EVSensorConfig(
|
|
||||||
"Battery Level", BATTERY_SENSOR, PERCENTAGE, "mdi:battery", ["charging"]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
|
||||||
"""Set up the MyChevy sensors."""
|
|
||||||
if discovery_info is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
hub = hass.data[MYCHEVY_DOMAIN]
|
|
||||||
sensors = [MyChevyStatus()]
|
|
||||||
for sconfig in SENSORS:
|
|
||||||
for car in hub.cars:
|
|
||||||
sensors.append(EVSensor(hub, sconfig, car.vid))
|
|
||||||
|
|
||||||
add_entities(sensors)
|
|
||||||
|
|
||||||
|
|
||||||
class MyChevyStatus(SensorEntity):
|
|
||||||
"""A string representing the charge mode."""
|
|
||||||
|
|
||||||
_name = "MyChevy Status"
|
|
||||||
_icon = "mdi:car-connected"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""Initialize sensor with car connection."""
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Register callbacks."""
|
|
||||||
self.async_on_remove(
|
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
||||||
UPDATE_TOPIC, self.success
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.async_on_remove(
|
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
||||||
ERROR_TOPIC, self.error
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def success(self):
|
|
||||||
"""Update state, trigger updates."""
|
|
||||||
if self._state != MYCHEVY_SUCCESS:
|
|
||||||
_LOGGER.debug("Successfully connected to mychevy website")
|
|
||||||
self._state = MYCHEVY_SUCCESS
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def error(self):
|
|
||||||
"""Update state, trigger updates."""
|
|
||||||
_LOGGER.error(
|
|
||||||
"Connection to mychevy website failed. "
|
|
||||||
"This probably means the mychevy to OnStar link is down"
|
|
||||||
)
|
|
||||||
self._state = MYCHEVY_ERROR
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self):
|
|
||||||
"""Return the icon."""
|
|
||||||
return self._icon
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self):
|
|
||||||
"""Return the state."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""Return the polling state."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class EVSensor(SensorEntity):
|
|
||||||
"""Base EVSensor class.
|
|
||||||
|
|
||||||
The only real difference between sensors is which units and what
|
|
||||||
attribute from the car object they are returning. All logic can be
|
|
||||||
built with just setting subclass attributes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, connection, config, car_vid):
|
|
||||||
"""Initialize sensor with car connection."""
|
|
||||||
self._conn = connection
|
|
||||||
self._name = config.name
|
|
||||||
self._attr = config.attr
|
|
||||||
self._extra_attrs = config.extra_attrs
|
|
||||||
self._unit_of_measurement = config.unit_of_measurement
|
|
||||||
self._icon = config.icon
|
|
||||||
self._state = None
|
|
||||||
self._state_attributes = {}
|
|
||||||
self._car_vid = car_vid
|
|
||||||
|
|
||||||
self.entity_id = f"{SENSOR_DOMAIN}.{MYCHEVY_DOMAIN}_{slugify(self._car.name)}_{slugify(self._name)}"
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Register callbacks."""
|
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
|
||||||
UPDATE_TOPIC, self.async_update_callback
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _car(self):
|
|
||||||
"""Return the car."""
|
|
||||||
return self._conn.get_car(self._car_vid)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self):
|
|
||||||
"""Return the icon."""
|
|
||||||
if self._attr == BATTERY_SENSOR:
|
|
||||||
charging = self._state_attributes.get("charging", False)
|
|
||||||
return icon_for_battery_level(self.state, charging)
|
|
||||||
return self._icon
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_update_callback(self):
|
|
||||||
"""Update state."""
|
|
||||||
if self._car is not None:
|
|
||||||
self._state = getattr(self._car, self._attr, None)
|
|
||||||
if self._unit_of_measurement == "miles":
|
|
||||||
self._state = round(self._state)
|
|
||||||
for attr in self._extra_attrs:
|
|
||||||
self._state_attributes[attr] = getattr(self._car, attr)
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self):
|
|
||||||
"""Return the state."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self):
|
|
||||||
"""Return all the state attributes."""
|
|
||||||
return self._state_attributes
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_unit_of_measurement(self):
|
|
||||||
"""Return the unit of measurement the state is expressed in."""
|
|
||||||
return self._unit_of_measurement
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""Return the polling state."""
|
|
||||||
return False
|
|
@ -1034,9 +1034,6 @@ mutagen==1.45.1
|
|||||||
# homeassistant.components.mutesync
|
# homeassistant.components.mutesync
|
||||||
mutesync==0.0.1
|
mutesync==0.0.1
|
||||||
|
|
||||||
# homeassistant.components.mychevy
|
|
||||||
mychevy==2.1.1
|
|
||||||
|
|
||||||
# homeassistant.components.mycroft
|
# homeassistant.components.mycroft
|
||||||
mycroftapi==2.0
|
mycroftapi==2.0
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user