mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Remove hydroquebec integration (ADR-0004) (#27407)
This commit is contained in:
parent
7e91677362
commit
2e9e8a16bd
@ -1 +0,0 @@
|
|||||||
"""The hydroquebec component."""
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "hydroquebec",
|
|
||||||
"name": "Hydroquebec",
|
|
||||||
"documentation": "https://www.home-assistant.io/integrations/hydroquebec",
|
|
||||||
"requirements": [
|
|
||||||
"pyhydroquebec==2.2.2"
|
|
||||||
],
|
|
||||||
"dependencies": [],
|
|
||||||
"codeowners": []
|
|
||||||
}
|
|
@ -1,227 +0,0 @@
|
|||||||
"""
|
|
||||||
Support for HydroQuebec.
|
|
||||||
|
|
||||||
Get data from 'My Consumption Profile' page:
|
|
||||||
https://www.hydroquebec.com/portail/en/group/clientele/portrait-de-consommation
|
|
||||||
|
|
||||||
For more details about this platform, please refer to the documentation at
|
|
||||||
https://home-assistant.io/components/sensor.hydroquebec/
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
|
||||||
from homeassistant.const import (
|
|
||||||
CONF_USERNAME,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
ENERGY_KILO_WATT_HOUR,
|
|
||||||
CONF_NAME,
|
|
||||||
CONF_MONITORED_VARIABLES,
|
|
||||||
TEMP_CELSIUS,
|
|
||||||
)
|
|
||||||
from homeassistant.helpers.entity import Entity
|
|
||||||
from homeassistant.util import Throttle
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
KILOWATT_HOUR = ENERGY_KILO_WATT_HOUR
|
|
||||||
PRICE = "CAD"
|
|
||||||
DAYS = "days"
|
|
||||||
CONF_CONTRACT = "contract"
|
|
||||||
|
|
||||||
DEFAULT_NAME = "HydroQuebec"
|
|
||||||
|
|
||||||
REQUESTS_TIMEOUT = 15
|
|
||||||
MIN_TIME_BETWEEN_UPDATES = timedelta(hours=1)
|
|
||||||
SCAN_INTERVAL = timedelta(hours=1)
|
|
||||||
|
|
||||||
SENSOR_TYPES = {
|
|
||||||
"balance": ["Balance", PRICE, "mdi:square-inc-cash"],
|
|
||||||
"period_total_bill": ["Period total bill", PRICE, "mdi:square-inc-cash"],
|
|
||||||
"period_length": ["Period length", DAYS, "mdi:calendar-today"],
|
|
||||||
"period_total_days": ["Period total days", DAYS, "mdi:calendar-today"],
|
|
||||||
"period_mean_daily_bill": ["Period mean daily bill", PRICE, "mdi:square-inc-cash"],
|
|
||||||
"period_mean_daily_consumption": [
|
|
||||||
"Period mean daily consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"period_total_consumption": [
|
|
||||||
"Period total consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"period_lower_price_consumption": [
|
|
||||||
"Period lower price consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"period_higher_price_consumption": [
|
|
||||||
"Period higher price consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"yesterday_total_consumption": [
|
|
||||||
"Yesterday total consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"yesterday_lower_price_consumption": [
|
|
||||||
"Yesterday lower price consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"yesterday_higher_price_consumption": [
|
|
||||||
"Yesterday higher price consumption",
|
|
||||||
KILOWATT_HOUR,
|
|
||||||
"mdi:flash",
|
|
||||||
],
|
|
||||||
"yesterday_average_temperature": [
|
|
||||||
"Yesterday average temperature",
|
|
||||||
TEMP_CELSIUS,
|
|
||||||
"mdi:thermometer",
|
|
||||||
],
|
|
||||||
"period_average_temperature": [
|
|
||||||
"Period average temperature",
|
|
||||||
TEMP_CELSIUS,
|
|
||||||
"mdi:thermometer",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Required(CONF_MONITORED_VARIABLES): vol.All(
|
|
||||||
cv.ensure_list, [vol.In(SENSOR_TYPES)]
|
|
||||||
),
|
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
|
||||||
vol.Required(CONF_PASSWORD): cv.string,
|
|
||||||
vol.Required(CONF_CONTRACT): cv.string,
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
HOST = "https://www.hydroquebec.com"
|
|
||||||
HOME_URL = f"{HOST}/portail/web/clientele/authentification"
|
|
||||||
PROFILE_URL = "{}/portail/fr/group/clientele/" "portrait-de-consommation".format(HOST)
|
|
||||||
MONTHLY_MAP = (
|
|
||||||
("period_total_bill", "montantFacturePeriode"),
|
|
||||||
("period_length", "nbJourLecturePeriode"),
|
|
||||||
("period_total_days", "nbJourPrevuPeriode"),
|
|
||||||
("period_mean_daily_bill", "moyenneDollarsJourPeriode"),
|
|
||||||
("period_mean_daily_consumption", "moyenneKwhJourPeriode"),
|
|
||||||
("period_total_consumption", "consoTotalPeriode"),
|
|
||||||
("period_lower_price_consumption", "consoRegPeriode"),
|
|
||||||
("period_higher_price_consumption", "consoHautPeriode"),
|
|
||||||
)
|
|
||||||
DAILY_MAP = (
|
|
||||||
("yesterday_total_consumption", "consoTotalQuot"),
|
|
||||||
("yesterday_lower_price_consumption", "consoRegQuot"),
|
|
||||||
("yesterday_higher_price_consumption", "consoHautQuot"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
|
||||||
"""Set up the HydroQuebec sensor."""
|
|
||||||
# Create a data fetcher to support all of the configured sensors. Then make
|
|
||||||
# the first call to init the data.
|
|
||||||
|
|
||||||
username = config.get(CONF_USERNAME)
|
|
||||||
password = config.get(CONF_PASSWORD)
|
|
||||||
contract = config.get(CONF_CONTRACT)
|
|
||||||
|
|
||||||
httpsession = hass.helpers.aiohttp_client.async_get_clientsession()
|
|
||||||
hydroquebec_data = HydroquebecData(username, password, httpsession, contract)
|
|
||||||
contracts = await hydroquebec_data.get_contract_list()
|
|
||||||
if not contracts:
|
|
||||||
return
|
|
||||||
_LOGGER.info("Contract list: %s", ", ".join(contracts))
|
|
||||||
|
|
||||||
name = config.get(CONF_NAME)
|
|
||||||
|
|
||||||
sensors = []
|
|
||||||
for variable in config[CONF_MONITORED_VARIABLES]:
|
|
||||||
sensors.append(HydroQuebecSensor(hydroquebec_data, variable, name))
|
|
||||||
|
|
||||||
async_add_entities(sensors, True)
|
|
||||||
|
|
||||||
|
|
||||||
class HydroQuebecSensor(Entity):
|
|
||||||
"""Implementation of a HydroQuebec sensor."""
|
|
||||||
|
|
||||||
def __init__(self, hydroquebec_data, sensor_type, name):
|
|
||||||
"""Initialize the sensor."""
|
|
||||||
self.client_name = name
|
|
||||||
self.type = sensor_type
|
|
||||||
self._name = SENSOR_TYPES[sensor_type][0]
|
|
||||||
self._unit_of_measurement = SENSOR_TYPES[sensor_type][1]
|
|
||||||
self._icon = SENSOR_TYPES[sensor_type][2]
|
|
||||||
self.hydroquebec_data = hydroquebec_data
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the sensor."""
|
|
||||||
return f"{self.client_name} {self._name}"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self):
|
|
||||||
"""Return the state of the sensor."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unit_of_measurement(self):
|
|
||||||
"""Return the unit of measurement of this entity, if any."""
|
|
||||||
return self._unit_of_measurement
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self):
|
|
||||||
"""Icon to use in the frontend, if any."""
|
|
||||||
return self._icon
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Get the latest data from Hydroquebec and update the state."""
|
|
||||||
await self.hydroquebec_data.async_update()
|
|
||||||
if self.hydroquebec_data.data.get(self.type) is not None:
|
|
||||||
self._state = round(self.hydroquebec_data.data[self.type], 2)
|
|
||||||
|
|
||||||
|
|
||||||
class HydroquebecData:
|
|
||||||
"""Get data from HydroQuebec."""
|
|
||||||
|
|
||||||
def __init__(self, username, password, httpsession, contract=None):
|
|
||||||
"""Initialize the data object."""
|
|
||||||
from pyhydroquebec import HydroQuebecClient
|
|
||||||
|
|
||||||
self.client = HydroQuebecClient(
|
|
||||||
username, password, REQUESTS_TIMEOUT, httpsession
|
|
||||||
)
|
|
||||||
self._contract = contract
|
|
||||||
self.data = {}
|
|
||||||
|
|
||||||
async def get_contract_list(self):
|
|
||||||
"""Return the contract list."""
|
|
||||||
# Fetch data
|
|
||||||
ret = await self._fetch_data()
|
|
||||||
if ret:
|
|
||||||
return self.client.get_contracts()
|
|
||||||
return []
|
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
|
||||||
async def _fetch_data(self):
|
|
||||||
"""Fetch latest data from HydroQuebec."""
|
|
||||||
from pyhydroquebec.client import PyHydroQuebecError
|
|
||||||
|
|
||||||
try:
|
|
||||||
await self.client.fetch_data()
|
|
||||||
except PyHydroQuebecError as exp:
|
|
||||||
_LOGGER.error("Error on receive last Hydroquebec data: %s", exp)
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Return the latest collected data from HydroQuebec."""
|
|
||||||
await self._fetch_data()
|
|
||||||
self.data = self.client.get_data(self._contract)[self._contract]
|
|
@ -1231,9 +1231,6 @@ pyhomematic==0.1.60
|
|||||||
# homeassistant.components.homeworks
|
# homeassistant.components.homeworks
|
||||||
pyhomeworks==0.0.6
|
pyhomeworks==0.0.6
|
||||||
|
|
||||||
# homeassistant.components.hydroquebec
|
|
||||||
pyhydroquebec==2.2.2
|
|
||||||
|
|
||||||
# homeassistant.components.ialarm
|
# homeassistant.components.ialarm
|
||||||
pyialarm==0.3
|
pyialarm==0.3
|
||||||
|
|
||||||
|
@ -419,9 +419,6 @@ pyheos==0.6.0
|
|||||||
# homeassistant.components.homematic
|
# homeassistant.components.homematic
|
||||||
pyhomematic==0.1.60
|
pyhomematic==0.1.60
|
||||||
|
|
||||||
# homeassistant.components.hydroquebec
|
|
||||||
pyhydroquebec==2.2.2
|
|
||||||
|
|
||||||
# homeassistant.components.ipma
|
# homeassistant.components.ipma
|
||||||
pyipma==1.2.1
|
pyipma==1.2.1
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
"""Tests for the hydroquebec component."""
|
|
@ -1,102 +0,0 @@
|
|||||||
"""The test for the hydroquebec sensor platform."""
|
|
||||||
import asyncio
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
from unittest.mock import MagicMock
|
|
||||||
|
|
||||||
from homeassistant.bootstrap import async_setup_component
|
|
||||||
from homeassistant.components.hydroquebec import sensor as hydroquebec
|
|
||||||
from tests.common import assert_setup_component
|
|
||||||
|
|
||||||
|
|
||||||
CONTRACT = "123456789"
|
|
||||||
|
|
||||||
|
|
||||||
class HydroQuebecClientMock:
|
|
||||||
"""Fake Hydroquebec client."""
|
|
||||||
|
|
||||||
def __init__(self, username, password, contract=None, httpsession=None):
|
|
||||||
"""Fake Hydroquebec client init."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_data(self, contract):
|
|
||||||
"""Return fake hydroquebec data."""
|
|
||||||
return {CONTRACT: {"balance": 160.12}}
|
|
||||||
|
|
||||||
def get_contracts(self):
|
|
||||||
"""Return fake hydroquebec contracts."""
|
|
||||||
return [CONTRACT]
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def fetch_data(self):
|
|
||||||
"""Return fake fetching data."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class HydroQuebecClientMockError(HydroQuebecClientMock):
|
|
||||||
"""Fake Hydroquebec client error."""
|
|
||||||
|
|
||||||
def get_contracts(self):
|
|
||||||
"""Return fake hydroquebec contracts."""
|
|
||||||
return []
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def fetch_data(self):
|
|
||||||
"""Return fake fetching data."""
|
|
||||||
raise PyHydroQuebecErrorMock("Fake Error")
|
|
||||||
|
|
||||||
|
|
||||||
class PyHydroQuebecErrorMock(BaseException):
|
|
||||||
"""Fake PyHydroquebec Error."""
|
|
||||||
|
|
||||||
|
|
||||||
class PyHydroQuebecClientFakeModule:
|
|
||||||
"""Fake pyfido.client module."""
|
|
||||||
|
|
||||||
PyHydroQuebecError = PyHydroQuebecErrorMock
|
|
||||||
|
|
||||||
|
|
||||||
class PyHydroQuebecFakeModule:
|
|
||||||
"""Fake pyfido module."""
|
|
||||||
|
|
||||||
HydroQuebecClient = HydroQuebecClientMockError
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_hydroquebec_sensor(loop, hass):
|
|
||||||
"""Test the Hydroquebec number sensor."""
|
|
||||||
sys.modules["pyhydroquebec"] = MagicMock()
|
|
||||||
sys.modules["pyhydroquebec.client"] = MagicMock()
|
|
||||||
sys.modules["pyhydroquebec.client.PyHydroQuebecError"] = PyHydroQuebecErrorMock
|
|
||||||
import pyhydroquebec.client
|
|
||||||
|
|
||||||
pyhydroquebec.HydroQuebecClient = HydroQuebecClientMock
|
|
||||||
pyhydroquebec.client.PyHydroQuebecError = PyHydroQuebecErrorMock
|
|
||||||
config = {
|
|
||||||
"sensor": {
|
|
||||||
"platform": "hydroquebec",
|
|
||||||
"name": "hydro",
|
|
||||||
"contract": CONTRACT,
|
|
||||||
"username": "myusername",
|
|
||||||
"password": "password",
|
|
||||||
"monitored_variables": ["balance"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
with assert_setup_component(1):
|
|
||||||
yield from async_setup_component(hass, "sensor", config)
|
|
||||||
state = hass.states.get("sensor.hydro_balance")
|
|
||||||
assert state.state == "160.12"
|
|
||||||
assert state.attributes.get("unit_of_measurement") == "CAD"
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_error(hass, caplog):
|
|
||||||
"""Test the Hydroquebec sensor errors."""
|
|
||||||
caplog.set_level(logging.ERROR)
|
|
||||||
sys.modules["pyhydroquebec"] = PyHydroQuebecFakeModule()
|
|
||||||
sys.modules["pyhydroquebec.client"] = PyHydroQuebecClientFakeModule()
|
|
||||||
|
|
||||||
config = {}
|
|
||||||
fake_async_add_entities = MagicMock()
|
|
||||||
yield from hydroquebec.async_setup_platform(hass, config, fake_async_add_entities)
|
|
||||||
assert fake_async_add_entities.called is False
|
|
Loading…
x
Reference in New Issue
Block a user