1
mirror of https://github.com/home-assistant/core synced 2024-10-07 10:13:38 +02:00

Add Linky sensors : yesterday + months + years (#23726)

* Add Linky sensors : yesterday + months + years

- SCAN_INTERVAL to 4 hours
- Always close_session after getting the data
- Add username attr
- Fix not updating Linky sensor when Enedis API fails

* Fix @balloob review: remove monitored_conditions
This commit is contained in:
Quentame 2019-06-11 19:18:41 +02:00 committed by Paulus Schoutsen
parent 8fcfcc40fc
commit 7559e70027
3 changed files with 115 additions and 39 deletions

View File

@ -143,6 +143,7 @@ homeassistant/components/life360/* @pnbruckner
homeassistant/components/lifx/* @amelchio homeassistant/components/lifx/* @amelchio
homeassistant/components/lifx_cloud/* @amelchio homeassistant/components/lifx_cloud/* @amelchio
homeassistant/components/lifx_legacy/* @amelchio homeassistant/components/lifx_legacy/* @amelchio
homeassistant/components/linky/* @tiste @Quentame
homeassistant/components/linux_battery/* @fabaff homeassistant/components/linux_battery/* @fabaff
homeassistant/components/liveboxplaytv/* @pschmitt homeassistant/components/liveboxplaytv/* @pschmitt
homeassistant/components/logger/* @home-assistant/core homeassistant/components/logger/* @home-assistant/core

View File

@ -6,5 +6,8 @@
"pylinky==0.3.3" "pylinky==0.3.3"
], ],
"dependencies": [], "dependencies": [],
"codeowners": [] "codeowners": [
"@tiste",
"@Quentame"
]
} }

View File

@ -1,21 +1,41 @@
"""Support for Linky.""" """Support for Linky."""
import logging
import json
from datetime import timedelta from datetime import timedelta
import json
import logging
from pylinky.client import DAILY, MONTHLY, YEARLY, LinkyClient, PyLinkyError
import voluptuous as vol import voluptuous as vol
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, CONF_TIMEOUT,
ENERGY_KILO_WATT_HOUR)
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.helpers.entity import Entity from homeassistant.const import (
from homeassistant.util import Throttle ATTR_ATTRIBUTION, CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME,
ENERGY_KILO_WATT_HOUR)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import track_time_interval
import homeassistant.util.dt as dt_util
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(minutes=10) SCAN_INTERVAL = timedelta(hours=4)
ICON_ENERGY = "mdi:flash"
CONSUMPTION = "conso"
TIME = "time"
INDEX_CURRENT = -1
INDEX_LAST = -2
ATTRIBUTION = "Data provided by Enedis"
DEFAULT_TIMEOUT = 10 DEFAULT_TIMEOUT = 10
SENSORS = {
"yesterday": ("Linky yesterday", DAILY, INDEX_LAST),
"current_month": ("Linky current month", MONTHLY, INDEX_CURRENT),
"last_month": ("Linky last month", MONTHLY, INDEX_LAST),
"current_year": ("Linky current year", YEARLY, INDEX_CURRENT),
"last_year": ("Linky last year", YEARLY, INDEX_LAST)
}
SENSORS_INDEX_LABEL = 0
SENSORS_INDEX_SCALE = 1
SENSORS_INDEX_WHEN = 2
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_USERNAME): cv.string,
@ -30,28 +50,73 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
password = config[CONF_PASSWORD] password = config[CONF_PASSWORD]
timeout = config[CONF_TIMEOUT] timeout = config[CONF_TIMEOUT]
from pylinky.client import LinkyClient, PyLinkyError account = LinkyAccount(hass, add_entities, username, password, timeout)
client = LinkyClient(username, password, None, timeout) add_entities(account.sensors, True)
try:
client.login()
client.fetch_data()
except PyLinkyError as exp:
_LOGGER.error(exp)
client.close_session()
return
devices = [LinkySensor('Linky', client)]
add_entities(devices, True) class LinkyAccount:
"""Representation of a Linky account."""
def __init__(self, hass, add_entities, username, password, timeout):
"""Initialise the Linky account."""
self._username = username
self.__password = password
self._timeout = timeout
self._data = None
self.sensors = []
self.update_linky_data(dt_util.utcnow())
self.sensors.append(
LinkySensor("Linky yesterday", self, DAILY, INDEX_LAST))
self.sensors.append(
LinkySensor("Linky current month", self, MONTHLY, INDEX_CURRENT))
self.sensors.append(
LinkySensor("Linky last month", self, MONTHLY, INDEX_LAST))
self.sensors.append(
LinkySensor("Linky current year", self, YEARLY, INDEX_CURRENT))
self.sensors.append(
LinkySensor("Linky last year", self, YEARLY, INDEX_LAST))
track_time_interval(hass, self.update_linky_data, SCAN_INTERVAL)
def update_linky_data(self, event_time):
"""Fetch new state data for the sensor."""
client = LinkyClient(self._username, self.__password, None,
self._timeout)
try:
client.login()
client.fetch_data()
self._data = client.get_data()
_LOGGER.debug(json.dumps(self._data, indent=2))
except PyLinkyError as exp:
_LOGGER.error(exp)
finally:
client.close_session()
@property
def username(self):
"""Return the username."""
return self._username
@property
def data(self):
"""Return the data."""
return self._data
class LinkySensor(Entity): class LinkySensor(Entity):
"""Representation of a sensor entity for Linky.""" """Representation of a sensor entity for Linky."""
def __init__(self, name, client): def __init__(self, name, account: LinkyAccount, scale, when):
"""Initialize the sensor.""" """Initialize the sensor."""
self._name = name self._name = name
self._client = client self.__account = account
self._state = None self._scale = scale
self.__when = when
self._username = account.username
self.__time = None
self.__consumption = None
@property @property
def name(self): def name(self):
@ -61,28 +126,35 @@ class LinkySensor(Entity):
@property @property
def state(self): def state(self):
"""Return the state of the sensor.""" """Return the state of the sensor."""
return self._state return self.__consumption
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement.""" """Return the unit of measurement."""
return ENERGY_KILO_WATT_HOUR return ENERGY_KILO_WATT_HOUR
@Throttle(SCAN_INTERVAL) @property
def icon(self):
"""Return the icon of the sensor."""
return ICON_ENERGY
@property
def device_state_attributes(self):
"""Return the state attributes of the sensor."""
return {
ATTR_ATTRIBUTION: ATTRIBUTION,
'time': self.__time,
CONF_USERNAME: self._username
}
def update(self): def update(self):
"""Fetch new state data for the sensor.""" """Retreive the new data for the sensor."""
from pylinky.client import PyLinkyError data = self.__account.data[self._scale][self.__when]
try: self.__consumption = data[CONSUMPTION]
self._client.fetch_data() self.__time = data[TIME]
except PyLinkyError as exp:
_LOGGER.error(exp)
self._client.close_session()
return
_LOGGER.debug(json.dumps(self._client.get_data(), indent=2)) if self._scale is not YEARLY:
year_index = INDEX_CURRENT
if self._client.get_data(): if self.__time.endswith("Dec"):
# get the last past day data year_index = INDEX_LAST
self._state = self._client.get_data()['daily'][-2]['conso'] self.__time += ' ' + self.__account.data[YEARLY][year_index][TIME]
else:
self._state = None