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_cloud/* @amelchio
homeassistant/components/lifx_legacy/* @amelchio
homeassistant/components/linky/* @tiste @Quentame
homeassistant/components/linux_battery/* @fabaff
homeassistant/components/liveboxplaytv/* @pschmitt
homeassistant/components/logger/* @home-assistant/core

View File

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

View File

@ -1,21 +1,41 @@
"""Support for Linky."""
import logging
import json
from datetime import timedelta
import json
import logging
from pylinky.client import DAILY, MONTHLY, YEARLY, LinkyClient, PyLinkyError
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.helpers.entity import Entity
from homeassistant.util import Throttle
from homeassistant.const import (
ATTR_ATTRIBUTION, CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME,
ENERGY_KILO_WATT_HOUR)
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__)
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
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({
vol.Required(CONF_USERNAME): cv.string,
@ -30,28 +50,73 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
password = config[CONF_PASSWORD]
timeout = config[CONF_TIMEOUT]
from pylinky.client import LinkyClient, PyLinkyError
client = LinkyClient(username, password, None, timeout)
try:
client.login()
client.fetch_data()
except PyLinkyError as exp:
_LOGGER.error(exp)
client.close_session()
return
account = LinkyAccount(hass, add_entities, username, password, timeout)
add_entities(account.sensors, True)
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):
"""Representation of a sensor entity for Linky."""
def __init__(self, name, client):
def __init__(self, name, account: LinkyAccount, scale, when):
"""Initialize the sensor."""
self._name = name
self._client = client
self._state = None
self.__account = account
self._scale = scale
self.__when = when
self._username = account.username
self.__time = None
self.__consumption = None
@property
def name(self):
@ -61,28 +126,35 @@ class LinkySensor(Entity):
@property
def state(self):
"""Return the state of the sensor."""
return self._state
return self.__consumption
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
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):
"""Fetch new state data for the sensor."""
from pylinky.client import PyLinkyError
try:
self._client.fetch_data()
except PyLinkyError as exp:
_LOGGER.error(exp)
self._client.close_session()
return
"""Retreive the new data for the sensor."""
data = self.__account.data[self._scale][self.__when]
self.__consumption = data[CONSUMPTION]
self.__time = data[TIME]
_LOGGER.debug(json.dumps(self._client.get_data(), indent=2))
if self._client.get_data():
# get the last past day data
self._state = self._client.get_data()['daily'][-2]['conso']
else:
self._state = None
if self._scale is not YEARLY:
year_index = INDEX_CURRENT
if self.__time.endswith("Dec"):
year_index = INDEX_LAST
self.__time += ' ' + self.__account.data[YEARLY][year_index][TIME]