Merge pull request #62690 from home-assistant/rc

This commit is contained in:
Franck Nijhof 2021-12-23 18:17:49 +01:00 committed by GitHub
commit 4f25e98999
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 637 additions and 3511 deletions

View File

@ -432,7 +432,7 @@ homeassistant/components/recollect_waste/* @bachya
homeassistant/components/recorder/* @home-assistant/core homeassistant/components/recorder/* @home-assistant/core
homeassistant/components/rejseplanen/* @DarkFox homeassistant/components/rejseplanen/* @DarkFox
homeassistant/components/renault/* @epenet homeassistant/components/renault/* @epenet
homeassistant/components/repetier/* @MTrab homeassistant/components/repetier/* @MTrab @ShadowBr0ther
homeassistant/components/rflink/* @javicalle homeassistant/components/rflink/* @javicalle
homeassistant/components/rfxtrx/* @danielhiversen @elupus @RobBie1221 homeassistant/components/rfxtrx/* @danielhiversen @elupus @RobBie1221
homeassistant/components/ridwell/* @bachya homeassistant/components/ridwell/* @bachya

View File

@ -76,6 +76,8 @@ from .helpers import CastStatusListener, ChromecastInfo, ChromeCastZeroconf
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
APP_IDS_UNRELIABLE_MEDIA_INFO = ("Netflix",)
CAST_SPLASH = "https://www.home-assistant.io/images/cast/splash.png" CAST_SPLASH = "https://www.home-assistant.io/images/cast/splash.png"
SUPPORT_CAST = SUPPORT_PLAY_MEDIA | SUPPORT_TURN_OFF SUPPORT_CAST = SUPPORT_PLAY_MEDIA | SUPPORT_TURN_OFF
@ -564,7 +566,10 @@ class CastDevice(MediaPlayerEntity):
if media_status.player_is_idle: if media_status.player_is_idle:
return STATE_IDLE return STATE_IDLE
if self.app_id is not None and self.app_id != pychromecast.IDLE_APP_ID: if self.app_id is not None and self.app_id != pychromecast.IDLE_APP_ID:
return STATE_PLAYING if self.app_id in APP_IDS_UNRELIABLE_MEDIA_INFO:
# Some apps don't report media status, show the player as playing
return STATE_PLAYING
return STATE_IDLE
if self._chromecast is not None and self._chromecast.is_idle: if self._chromecast is not None and self._chromecast.is_idle:
return STATE_OFF return STATE_OFF
return None return None

View File

@ -199,7 +199,7 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
"""Turn on light.""" """Turn on light."""
data: dict[str, bool | float | int | str | tuple[float, float]] = {"on": True} data: dict[str, bool | float | int | str | tuple[float, float]] = {"on": True}
if attr_brightness := kwargs.get(ATTR_BRIGHTNESS): if (attr_brightness := kwargs.get(ATTR_BRIGHTNESS)) is not None:
data["brightness"] = attr_brightness data["brightness"] = attr_brightness
if attr_color_temp := kwargs.get(ATTR_COLOR_TEMP): if attr_color_temp := kwargs.get(ATTR_COLOR_TEMP):
@ -215,16 +215,16 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
if ATTR_XY_COLOR in kwargs: if ATTR_XY_COLOR in kwargs:
data["xy"] = kwargs[ATTR_XY_COLOR] data["xy"] = kwargs[ATTR_XY_COLOR]
if attr_transition := kwargs.get(ATTR_TRANSITION): if (attr_transition := kwargs.get(ATTR_TRANSITION)) is not None:
data["transition_time"] = int(attr_transition * 10) data["transition_time"] = int(attr_transition * 10)
elif "IKEA" in self._device.manufacturer: elif "IKEA" in self._device.manufacturer:
data["transition_time"] = 0 data["transition_time"] = 0
if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH, ""))) is not None: if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH))) is not None:
data["alert"] = alert data["alert"] = alert
del data["on"] del data["on"]
if (effect := EFFECT_TO_DECONZ.get(kwargs.get(ATTR_EFFECT, ""))) is not None: if (effect := EFFECT_TO_DECONZ.get(kwargs.get(ATTR_EFFECT))) is not None:
data["effect"] = effect data["effect"] = effect
await self._device.set_state(**data) await self._device.set_state(**data)
@ -236,11 +236,11 @@ class DeconzBaseLight(DeconzDevice, LightEntity):
data: dict[str, bool | int | str] = {"on": False} data: dict[str, bool | int | str] = {"on": False}
if ATTR_TRANSITION in kwargs: if (attr_transition := kwargs.get(ATTR_TRANSITION)) is not None:
data["brightness"] = 0 data["brightness"] = 0
data["transition_time"] = int(kwargs[ATTR_TRANSITION] * 10) data["transition_time"] = int(attr_transition * 10)
if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH, ""))) is not None: if (alert := FLASH_TO_DECONZ.get(kwargs.get(ATTR_FLASH))) is not None:
data["alert"] = alert data["alert"] = alert
del data["on"] del data["on"]

View File

@ -2,7 +2,12 @@
"domain": "dht", "domain": "dht",
"name": "DHT Sensor", "name": "DHT Sensor",
"documentation": "https://www.home-assistant.io/integrations/dht", "documentation": "https://www.home-assistant.io/integrations/dht",
"requirements": ["adafruit-circuitpython-dht==3.6.0"], "requirements": [
"codeowners": ["@thegardenmonkey"], "adafruit-circuitpython-dht==3.7.0",
"RPi.GPIO==0.7.1a4"
],
"codeowners": [
"@thegardenmonkey"
],
"iot_class": "local_polling" "iot_class": "local_polling"
} }

View File

@ -3,7 +3,7 @@
"name": "Flux LED/MagicHome", "name": "Flux LED/MagicHome",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/flux_led", "documentation": "https://www.home-assistant.io/integrations/flux_led",
"requirements": ["flux_led==0.27.8"], "requirements": ["flux_led==0.27.13"],
"quality_scale": "platinum", "quality_scale": "platinum",
"codeowners": ["@icemanch"], "codeowners": ["@icemanch"],
"iot_class": "local_push", "iot_class": "local_push",

View File

@ -3,6 +3,7 @@ import logging
from fritzconnection.core.exceptions import FritzConnectionException, FritzSecurityError from fritzconnection.core.exceptions import FritzConnectionException, FritzSecurityError
from fritzconnection.core.logger import fritzlogger from fritzconnection.core.logger import fritzlogger
from requests import exceptions
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@ -45,7 +46,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await fritz_tools.async_start(entry.options) await fritz_tools.async_start(entry.options)
except FritzSecurityError as ex: except FritzSecurityError as ex:
raise ConfigEntryAuthFailed from ex raise ConfigEntryAuthFailed from ex
except FritzConnectionException as ex: except (FritzConnectionException, exceptions.ConnectionError) as ex:
raise ConfigEntryNotReady from ex raise ConfigEntryNotReady from ex
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})

View File

@ -117,7 +117,7 @@ class FritzBoxToolsFlowHandler(ConfigFlow, domain=DOMAIN):
self._port = ssdp_location.port self._port = ssdp_location.port
self._name = ( self._name = (
discovery_info.upnp.get(ssdp.ATTR_UPNP_FRIENDLY_NAME) discovery_info.upnp.get(ssdp.ATTR_UPNP_FRIENDLY_NAME)
or self.fritz_tools.model or discovery_info.upnp[ssdp.ATTR_UPNP_MODEL_NAME]
) )
self.context[CONF_HOST] = self._host self.context[CONF_HOST] = self._host

View File

@ -3,13 +3,12 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import Callable from collections.abc import Callable
from http import HTTPStatus
import logging import logging
from typing import Any from typing import Any
from aiohttp import client_exceptions from aiohttp import client_exceptions
from aiohue import HueBridgeV1, HueBridgeV2, LinkButtonNotPressed, Unauthorized from aiohue import HueBridgeV1, HueBridgeV2, LinkButtonNotPressed, Unauthorized
from aiohue.errors import AiohueException from aiohue.errors import AiohueException, BridgeBusy
import async_timeout import async_timeout
from homeassistant import core from homeassistant import core
@ -38,9 +37,6 @@ class HueBridge:
self.config_entry = config_entry self.config_entry = config_entry
self.hass = hass self.hass = hass
self.authorized = False self.authorized = False
self.parallel_updates_semaphore = asyncio.Semaphore(
3 if self.api_version == 1 else 10
)
# Jobs to be executed when API is reset. # Jobs to be executed when API is reset.
self.reset_jobs: list[core.CALLBACK_TYPE] = [] self.reset_jobs: list[core.CALLBACK_TYPE] = []
self.sensor_manager: SensorManager | None = None self.sensor_manager: SensorManager | None = None
@ -83,6 +79,7 @@ class HueBridge:
client_exceptions.ClientOSError, client_exceptions.ClientOSError,
client_exceptions.ServerDisconnectedError, client_exceptions.ServerDisconnectedError,
client_exceptions.ContentTypeError, client_exceptions.ContentTypeError,
BridgeBusy,
) as err: ) as err:
raise ConfigEntryNotReady( raise ConfigEntryNotReady(
f"Error connecting to the Hue bridge at {self.host}" f"Error connecting to the Hue bridge at {self.host}"
@ -115,50 +112,19 @@ class HueBridge:
async def async_request_call( async def async_request_call(
self, task: Callable, *args, allowed_errors: list[str] | None = None, **kwargs self, task: Callable, *args, allowed_errors: list[str] | None = None, **kwargs
) -> Any: ) -> Any:
"""Limit parallel requests to Hue hub. """Send request to the Hue bridge, optionally omitting error(s)."""
try:
The Hue hub can only handle a certain amount of parallel requests, total. return await task(*args, **kwargs)
Although we limit our parallel requests, we still will run into issues because except AiohueException as err:
other products are hitting up Hue. # The (new) Hue api can be a bit fanatic with throwing errors
# some of which we accept in certain conditions
ClientOSError means hub closed the socket on us. # handle that here. Note that these errors are strings and do not have
ContentResponseError means hub raised an error. # an identifier or something.
Since we don't make bad requests, this is on them. if allowed_errors is not None and str(err) in allowed_errors:
""" # log only
max_tries = 5 self.logger.debug("Ignored error/warning from Hue API: %s", str(err))
async with self.parallel_updates_semaphore: return None
for tries in range(max_tries): raise err
try:
return await task(*args, **kwargs)
except AiohueException as err:
# The new V2 api is a bit more fanatic with throwing errors
# some of which we accept in certain conditions
# handle that here. Note that these errors are strings and do not have
# an identifier or something.
if allowed_errors is not None and str(err) in allowed_errors:
# log only
self.logger.debug(
"Ignored error/warning from Hue API: %s", str(err)
)
return None
raise err
except (
client_exceptions.ClientOSError,
client_exceptions.ClientResponseError,
client_exceptions.ServerDisconnectedError,
) as err:
if tries == max_tries:
self.logger.error("Request failed %s times, giving up", tries)
raise
# We only retry if it's a server error. So raise on all 4XX errors.
if (
isinstance(err, client_exceptions.ClientResponseError)
and err.status < HTTPStatus.INTERNAL_SERVER_ERROR
):
raise
await asyncio.sleep(HUB_BUSY_SLEEP * tries)
async def async_reset(self) -> bool: async def async_reset(self) -> bool:
"""Reset this bridge to default state. """Reset this bridge to default state.

View File

@ -3,7 +3,7 @@
"name": "Philips Hue", "name": "Philips Hue",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/hue", "documentation": "https://www.home-assistant.io/integrations/hue",
"requirements": ["aiohue==3.0.7"], "requirements": ["aiohue==3.0.10"],
"ssdp": [ "ssdp": [
{ {
"manufacturer": "Royal Philips Electronics", "manufacturer": "Royal Philips Electronics",

View File

@ -8,6 +8,7 @@ from aiohue.v2.controllers.events import EventType
from aiohue.v2.controllers.scenes import ScenesController from aiohue.v2.controllers.scenes import ScenesController
from aiohue.v2.models.scene import Scene as HueScene from aiohue.v2.models.scene import Scene as HueScene
from homeassistant.components.light import ATTR_TRANSITION
from homeassistant.components.scene import Scene as SceneEntity from homeassistant.components.scene import Scene as SceneEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
@ -16,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .bridge import HueBridge from .bridge import HueBridge
from .const import DOMAIN from .const import DOMAIN
from .v2.entity import HueBaseEntity from .v2.entity import HueBaseEntity
from .v2.helpers import normalize_hue_transition
async def async_setup_entry( async def async_setup_entry(
@ -94,11 +96,9 @@ class HueSceneEntity(HueBaseEntity, SceneEntity):
async def async_activate(self, **kwargs: Any) -> None: async def async_activate(self, **kwargs: Any) -> None:
"""Activate Hue scene.""" """Activate Hue scene."""
transition = kwargs.get("transition") transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
if transition is not None:
# hue transition duration is in milliseconds
transition = int(transition * 1000)
dynamic = kwargs.get("dynamic", self.is_dynamic) dynamic = kwargs.get("dynamic", self.is_dynamic)
await self.bridge.async_request_call( await self.bridge.async_request_call(
self.controller.recall, self.controller.recall,
self.resource.id, self.resource.id,

View File

@ -142,18 +142,21 @@ class HueBaseEntity(Entity):
if self._ignore_availability is not None: if self._ignore_availability is not None:
# already processed # already processed
return return
cur_state = self.resource.on.on if self.device.product_data.certified:
if self._last_state is None: # certified products report their state correctly
self._last_state = cur_state self._ignore_availability = False
return
# some (3th party) Hue lights report their connection status incorrectly # some (3th party) Hue lights report their connection status incorrectly
# causing the zigbee availability to report as disconnected while in fact # causing the zigbee availability to report as disconnected while in fact
# it can be controlled. Although this is in fact something the device manufacturer # it can be controlled. Although this is in fact something the device manufacturer
# should fix, we work around it here. If the light is reported unavailable # should fix, we work around it here. If the light is reported unavailable
# by the zigbee connectivity but the state changesm its considered as a # by the zigbee connectivity but the state changes its considered as a
# malfunctioning device and we report it. # malfunctioning device and we report it.
# while the user should actually fix this issue instead of ignoring it, we # while the user should actually fix this issue instead of ignoring it, we
# ignore the availability for this light from this point. # ignore the availability for this light from this point.
cur_state = self.resource.on.on
if self._last_state is None:
self._last_state = cur_state
return
if zigbee := self.bridge.api.devices.get_zigbee_connectivity(self.device.id): if zigbee := self.bridge.api.devices.get_zigbee_connectivity(self.device.id):
if ( if (
self._last_state != cur_state self._last_state != cur_state
@ -163,7 +166,7 @@ class HueBaseEntity(Entity):
# while it was reported as not connected! # while it was reported as not connected!
self.logger.warning( self.logger.warning(
"Light %s changed state while reported as disconnected. " "Light %s changed state while reported as disconnected. "
"This is an indicator that routing is not working properly for this device. " "This might be an indicator that routing is not working for this device. "
"Home Assistant will ignore availability for this light from now on. " "Home Assistant will ignore availability for this light from now on. "
"Device details: %s - %s (%s) fw: %s", "Device details: %s - %s (%s) fw: %s",
self.name, self.name,

View File

@ -29,6 +29,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from ..bridge import HueBridge from ..bridge import HueBridge
from ..const import CONF_ALLOW_HUE_GROUPS, DOMAIN from ..const import CONF_ALLOW_HUE_GROUPS, DOMAIN
from .entity import HueBaseEntity from .entity import HueBaseEntity
from .helpers import normalize_hue_brightness, normalize_hue_transition
ALLOWED_ERRORS = [ ALLOWED_ERRORS = [
"device (groupedLight) has communication issues, command (on) may not have effect", "device (groupedLight) has communication issues, command (on) may not have effect",
@ -147,17 +148,11 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on.""" """Turn the light on."""
transition = kwargs.get(ATTR_TRANSITION) transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
xy_color = kwargs.get(ATTR_XY_COLOR) xy_color = kwargs.get(ATTR_XY_COLOR)
color_temp = kwargs.get(ATTR_COLOR_TEMP) color_temp = kwargs.get(ATTR_COLOR_TEMP)
brightness = kwargs.get(ATTR_BRIGHTNESS) brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
flash = kwargs.get(ATTR_FLASH) flash = kwargs.get(ATTR_FLASH)
if brightness is not None:
# Hue uses a range of [0, 100] to control brightness.
brightness = float((brightness / 255) * 100)
if transition is not None:
# hue transition duration is in milliseconds
transition = int(transition * 1000)
# NOTE: a grouped_light can only handle turn on/off # NOTE: a grouped_light can only handle turn on/off
# To set other features, you'll have to control the attached lights # To set other features, you'll have to control the attached lights
@ -193,10 +188,7 @@ class GroupedHueLight(HueBaseEntity, LightEntity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off.""" """Turn the light off."""
transition = kwargs.get(ATTR_TRANSITION) transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
if transition is not None:
# hue transition duration is in milliseconds
transition = int(transition * 1000)
# NOTE: a grouped_light can only handle turn on/off # NOTE: a grouped_light can only handle turn on/off
# To set other features, you'll have to control the attached lights # To set other features, you'll have to control the attached lights

View File

@ -0,0 +1,19 @@
"""Helper functions for Philips Hue v2."""
def normalize_hue_brightness(brightness):
"""Return calculated brightness values."""
if brightness is not None:
# Hue uses a range of [0, 100] to control brightness.
brightness = float((brightness / 255) * 100)
return brightness
def normalize_hue_transition(transition):
"""Return rounded transition values."""
if transition is not None:
# hue transition duration is in milliseconds and round them to 100ms
transition = int(round(transition, 1) * 1000)
return transition

View File

@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
from aiohue.v2 import HueBridgeV2 from aiohue.v2 import HueBridgeV2
from aiohue.v2.controllers.events import EventType from aiohue.v2.controllers.events import EventType
from aiohue.v2.models.button import Button from aiohue.v2.models.button import Button, ButtonEvent
from homeassistant.const import CONF_DEVICE_ID, CONF_ID, CONF_TYPE, CONF_UNIQUE_ID from homeassistant.const import CONF_DEVICE_ID, CONF_ID, CONF_TYPE, CONF_UNIQUE_ID
from homeassistant.core import callback from homeassistant.core import callback
@ -27,6 +27,11 @@ async def async_setup_hue_events(bridge: "HueBridge"):
api: HueBridgeV2 = bridge.api # to satisfy typing api: HueBridgeV2 = bridge.api # to satisfy typing
conf_entry = bridge.config_entry conf_entry = bridge.config_entry
dev_reg = device_registry.async_get(hass) dev_reg = device_registry.async_get(hass)
last_state = {
x.id: x.button.last_event
for x in api.sensors.button.items
if x.button is not None
}
# at this time the `button` resource is the only source of hue events # at this time the `button` resource is the only source of hue events
btn_controller = api.sensors.button btn_controller = api.sensors.button
@ -35,6 +40,21 @@ async def async_setup_hue_events(bridge: "HueBridge"):
def handle_button_event(evt_type: EventType, hue_resource: Button) -> None: def handle_button_event(evt_type: EventType, hue_resource: Button) -> None:
"""Handle event from Hue devices controller.""" """Handle event from Hue devices controller."""
LOGGER.debug("Received button event: %s", hue_resource) LOGGER.debug("Received button event: %s", hue_resource)
# guard for missing button object on the resource
if hue_resource.button is None:
return
cur_event = hue_resource.button.last_event
last_event = last_state.get(hue_resource.id)
# ignore the event if the last_event value is exactly the same
# this may happen if some other metadata of the button resource is adjusted
if cur_event == last_event:
return
if cur_event != ButtonEvent.REPEAT:
# do not store repeat event
last_state[hue_resource.id] = cur_event
hue_device = btn_controller.get_device(hue_resource.id) hue_device = btn_controller.get_device(hue_resource.id)
device = dev_reg.async_get_device({(DOMAIN, hue_device.id)}) device = dev_reg.async_get_device({(DOMAIN, hue_device.id)})
@ -44,7 +64,7 @@ async def async_setup_hue_events(bridge: "HueBridge"):
CONF_ID: slugify(f"{hue_device.metadata.name}: Button"), CONF_ID: slugify(f"{hue_device.metadata.name}: Button"),
CONF_DEVICE_ID: device.id, # type: ignore CONF_DEVICE_ID: device.id, # type: ignore
CONF_UNIQUE_ID: hue_resource.id, CONF_UNIQUE_ID: hue_resource.id,
CONF_TYPE: hue_resource.button.last_event.value, CONF_TYPE: cur_event.value,
CONF_SUBTYPE: hue_resource.metadata.control_id, CONF_SUBTYPE: hue_resource.metadata.control_id,
} }
hass.bus.async_fire(ATTR_HUE_EVENT, data) hass.bus.async_fire(ATTR_HUE_EVENT, data)

View File

@ -30,6 +30,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from ..bridge import HueBridge from ..bridge import HueBridge
from ..const import DOMAIN from ..const import DOMAIN
from .entity import HueBaseEntity from .entity import HueBaseEntity
from .helpers import normalize_hue_brightness, normalize_hue_transition
ALLOWED_ERRORS = [ ALLOWED_ERRORS = [
"device (light) has communication issues, command (on) may not have effect", "device (light) has communication issues, command (on) may not have effect",
@ -155,17 +156,11 @@ class HueLight(HueBaseEntity, LightEntity):
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on.""" """Turn the device on."""
transition = kwargs.get(ATTR_TRANSITION) transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
xy_color = kwargs.get(ATTR_XY_COLOR) xy_color = kwargs.get(ATTR_XY_COLOR)
color_temp = kwargs.get(ATTR_COLOR_TEMP) color_temp = kwargs.get(ATTR_COLOR_TEMP)
brightness = kwargs.get(ATTR_BRIGHTNESS) brightness = normalize_hue_brightness(kwargs.get(ATTR_BRIGHTNESS))
flash = kwargs.get(ATTR_FLASH) flash = kwargs.get(ATTR_FLASH)
if brightness is not None:
# Hue uses a range of [0, 100] to control brightness.
brightness = float((brightness / 255) * 100)
if transition is not None:
# hue transition duration is in milliseconds
transition = int(transition * 1000)
await self.bridge.async_request_call( await self.bridge.async_request_call(
self.controller.set_state, self.controller.set_state,
@ -181,11 +176,9 @@ class HueLight(HueBaseEntity, LightEntity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off.""" """Turn the light off."""
transition = kwargs.get(ATTR_TRANSITION) transition = normalize_hue_transition(kwargs.get(ATTR_TRANSITION))
flash = kwargs.get(ATTR_FLASH) flash = kwargs.get(ATTR_FLASH)
if transition is not None:
# hue transition duration is in milliseconds
transition = int(transition * 1000)
await self.bridge.async_request_call( await self.bridge.async_request_call(
self.controller.set_state, self.controller.set_state,
id=self.resource.id, id=self.resource.id,

View File

@ -4,7 +4,7 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/knx", "documentation": "https://www.home-assistant.io/integrations/knx",
"requirements": [ "requirements": [
"xknx==0.18.14" "xknx==0.18.15"
], ],
"codeowners": [ "codeowners": [
"@Julius2342", "@Julius2342",

View File

@ -1,12 +1,15 @@
"""The pvpc_hourly_pricing integration to collect Spain official electric prices.""" """The pvpc_hourly_pricing integration to collect Spain official electric prices."""
from datetime import datetime, timedelta
import logging import logging
from typing import Mapping
from aiopvpc import DEFAULT_POWER_KW, TARIFFS from aiopvpc import DEFAULT_POWER_KW, TARIFFS, PVPCData
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_registry import ( from homeassistant.helpers.entity_registry import (
EntityRegistry, EntityRegistry,
@ -14,6 +17,8 @@ from homeassistant.helpers.entity_registry import (
async_migrate_entries, async_migrate_entries,
) )
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util
from .const import ( from .const import (
ATTR_POWER, ATTR_POWER,
@ -99,6 +104,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await hass.config_entries.async_remove(entry.entry_id) await hass.config_entries.async_remove(entry.entry_id)
return False return False
coordinator = ElecPricesDataUpdateCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
hass.config_entries.async_setup_platforms(entry, PLATFORMS) hass.config_entries.async_setup_platforms(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(async_update_options)) entry.async_on_unload(entry.add_update_listener(async_update_options))
return True return True
@ -119,4 +128,39 @@ async def async_update_options(hass: HomeAssistant, entry: ConfigEntry) -> None:
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
class ElecPricesDataUpdateCoordinator(DataUpdateCoordinator[Mapping[datetime, float]]):
"""Class to manage fetching Electricity prices data from API."""
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Initialize."""
self.api = PVPCData(
session=async_get_clientsession(hass),
tariff=entry.data[ATTR_TARIFF],
local_timezone=hass.config.time_zone,
power=entry.data[ATTR_POWER],
power_valley=entry.data[ATTR_POWER_P3],
)
super().__init__(
hass, _LOGGER, name=DOMAIN, update_interval=timedelta(minutes=30)
)
self._entry = entry
@property
def entry_id(self) -> str:
"""Return entry ID."""
return self._entry.entry_id
async def _async_update_data(self) -> Mapping[datetime, float]:
"""Update electricity prices from the ESIOS API."""
prices = await self.api.async_update_prices(dt_util.utcnow())
self.api.process_state_and_attributes(dt_util.utcnow())
if not prices:
raise UpdateFailed
return prices

View File

@ -3,7 +3,7 @@
"name": "Spain electricity hourly pricing (PVPC)", "name": "Spain electricity hourly pricing (PVPC)",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/pvpc_hourly_pricing", "documentation": "https://www.home-assistant.io/integrations/pvpc_hourly_pricing",
"requirements": ["aiopvpc==2.2.4"], "requirements": ["aiopvpc==3.0.0"],
"codeowners": ["@azogue"], "codeowners": ["@azogue"],
"quality_scale": "platinum", "quality_scale": "platinum",
"iot_class": "cloud_polling" "iot_class": "cloud_polling"

View File

@ -1,73 +1,160 @@
"""Sensor to collect the reference daily prices of electricity ('PVPC') in Spain.""" """Sensor to collect the reference daily prices of electricity ('PVPC') in Spain."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Mapping
from datetime import datetime
import logging import logging
from random import randint
from typing import Any from typing import Any
from aiopvpc import PVPCData from homeassistant.components.sensor import (
SensorEntity,
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME, CURRENCY_EURO, ENERGY_KILO_WATT_HOUR from homeassistant.const import CONF_NAME, CURRENCY_EURO, ENERGY_KILO_WATT_HOUR
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.entity import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_call_later, async_track_time_change from homeassistant.helpers.event import async_track_time_change
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.typing import StateType
import homeassistant.util.dt as dt_util from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import ATTR_POWER, ATTR_POWER_P3, ATTR_TARIFF from . import ElecPricesDataUpdateCoordinator
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
PARALLEL_UPDATES = 1
ATTR_PRICE = "price" SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
ICON = "mdi:currency-eur" SensorEntityDescription(
UNIT = f"{CURRENCY_EURO}/{ENERGY_KILO_WATT_HOUR}" key="PVPC",
icon="mdi:currency-eur",
_DEFAULT_TIMEOUT = 10 native_unit_of_measurement=f"{CURRENCY_EURO}/{ENERGY_KILO_WATT_HOUR}",
state_class=SensorStateClass.MEASUREMENT,
),
)
_PRICE_SENSOR_ATTRIBUTES_MAP = {
"tariff": "tariff",
"period": "period",
"available_power": "available_power",
"next_period": "next_period",
"hours_to_next_period": "hours_to_next_period",
"next_better_price": "next_better_price",
"hours_to_better_price": "hours_to_better_price",
"num_better_prices_ahead": "num_better_prices_ahead",
"price_position": "price_position",
"price_ratio": "price_ratio",
"max_price": "max_price",
"max_price_at": "max_price_at",
"min_price": "min_price",
"min_price_at": "min_price_at",
"next_best_at": "next_best_at",
"price_00h": "price_00h",
"price_01h": "price_01h",
"price_02h": "price_02h",
"price_02h_d": "price_02h_d", # only on DST day change with 25h
"price_03h": "price_03h",
"price_04h": "price_04h",
"price_05h": "price_05h",
"price_06h": "price_06h",
"price_07h": "price_07h",
"price_08h": "price_08h",
"price_09h": "price_09h",
"price_10h": "price_10h",
"price_11h": "price_11h",
"price_12h": "price_12h",
"price_13h": "price_13h",
"price_14h": "price_14h",
"price_15h": "price_15h",
"price_16h": "price_16h",
"price_17h": "price_17h",
"price_18h": "price_18h",
"price_19h": "price_19h",
"price_20h": "price_20h",
"price_21h": "price_21h",
"price_22h": "price_22h",
"price_23h": "price_23h",
# only seen in the evening
"next_better_price (next day)": "next_better_price (next day)",
"hours_to_better_price (next day)": "hours_to_better_price (next day)",
"num_better_prices_ahead (next day)": "num_better_prices_ahead (next day)",
"price_position (next day)": "price_position (next day)",
"price_ratio (next day)": "price_ratio (next day)",
"max_price (next day)": "max_price (next day)",
"max_price_at (next day)": "max_price_at (next day)",
"min_price (next day)": "min_price (next day)",
"min_price_at (next day)": "min_price_at (next day)",
"next_best_at (next day)": "next_best_at (next day)",
"price_next_day_00h": "price_next_day_00h",
"price_next_day_01h": "price_next_day_01h",
"price_next_day_02h": "price_next_day_02h",
"price_next_day_02h_d": "price_next_day_02h_d",
"price_next_day_03h": "price_next_day_03h",
"price_next_day_04h": "price_next_day_04h",
"price_next_day_05h": "price_next_day_05h",
"price_next_day_06h": "price_next_day_06h",
"price_next_day_07h": "price_next_day_07h",
"price_next_day_08h": "price_next_day_08h",
"price_next_day_09h": "price_next_day_09h",
"price_next_day_10h": "price_next_day_10h",
"price_next_day_11h": "price_next_day_11h",
"price_next_day_12h": "price_next_day_12h",
"price_next_day_13h": "price_next_day_13h",
"price_next_day_14h": "price_next_day_14h",
"price_next_day_15h": "price_next_day_15h",
"price_next_day_16h": "price_next_day_16h",
"price_next_day_17h": "price_next_day_17h",
"price_next_day_18h": "price_next_day_18h",
"price_next_day_19h": "price_next_day_19h",
"price_next_day_20h": "price_next_day_20h",
"price_next_day_21h": "price_next_day_21h",
"price_next_day_22h": "price_next_day_22h",
"price_next_day_23h": "price_next_day_23h",
}
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the electricity price sensor from config_entry.""" """Set up the electricity price sensor from config_entry."""
name = config_entry.data[CONF_NAME] coordinator: ElecPricesDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
pvpc_data_handler = PVPCData( name = entry.data[CONF_NAME]
tariff=config_entry.data[ATTR_TARIFF],
power=config_entry.data[ATTR_POWER],
power_valley=config_entry.data[ATTR_POWER_P3],
local_timezone=hass.config.time_zone,
websession=async_get_clientsession(hass),
timeout=_DEFAULT_TIMEOUT,
)
async_add_entities( async_add_entities(
[ElecPriceSensor(name, config_entry.unique_id, pvpc_data_handler)], False [ElecPriceSensor(coordinator, SENSOR_TYPES[0], entry.unique_id, name)]
) )
class ElecPriceSensor(RestoreEntity, SensorEntity): class ElecPriceSensor(CoordinatorEntity, SensorEntity):
"""Class to hold the prices of electricity as a sensor.""" """Class to hold the prices of electricity as a sensor."""
_attr_icon = ICON coordinator: ElecPricesDataUpdateCoordinator
_attr_native_unit_of_measurement = UNIT
_attr_should_poll = False
_attr_state_class = STATE_CLASS_MEASUREMENT
def __init__(self, name, unique_id, pvpc_data_handler): def __init__(
"""Initialize the sensor object.""" self,
self._name = name coordinator: ElecPricesDataUpdateCoordinator,
self._unique_id = unique_id description: SensorEntityDescription,
self._pvpc_data = pvpc_data_handler unique_id: str | None,
self._num_retries = 0 name: str,
) -> None:
"""Initialize ESIOS sensor."""
super().__init__(coordinator)
self.entity_description = description
self._attr_attribution = coordinator.api.attribution
self._attr_unique_id = unique_id
self._attr_name = name
self._attr_device_info = DeviceInfo(
configuration_url="https://www.ree.es/es/apidatos",
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, coordinator.entry_id)},
manufacturer="REE",
name="PVPC (REData API)",
)
self._state: StateType = None
self._attrs: Mapping[str, Any] = {}
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Handle entity which will be added.""" """Handle entity which will be added."""
await super().async_added_to_hass() await super().async_added_to_hass()
if state := await self.async_get_last_state():
self._pvpc_data.state = state.state
# Update 'state' value in hour changes # Update 'state' value in hour changes
self.async_on_remove( self.async_on_remove(
@ -75,86 +162,31 @@ class ElecPriceSensor(RestoreEntity, SensorEntity):
self.hass, self.update_current_price, second=[0], minute=[0] self.hass, self.update_current_price, second=[0], minute=[0]
) )
) )
# Update prices at random time, 2 times/hour (don't want to upset API)
random_minute = randint(1, 29)
mins_update = [random_minute, random_minute + 30]
self.async_on_remove(
async_track_time_change(
self.hass, self.async_update_prices, second=[0], minute=mins_update
)
)
_LOGGER.debug( _LOGGER.debug(
"Setup of price sensor %s (%s) with tariff '%s', " "Setup of price sensor %s (%s) with tariff '%s'",
"updating prices each hour at %s min",
self.name, self.name,
self.entity_id, self.entity_id,
self._pvpc_data.tariff, self.coordinator.api.tariff,
mins_update,
) )
now = dt_util.utcnow()
await self.async_update_prices(now)
self.update_current_price(now)
@property
def unique_id(self) -> str | None:
"""Return a unique ID."""
return self._unique_id
@property
def name(self) -> str:
"""Return the name of the sensor."""
return self._name
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
return self._pvpc_data.state
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._pvpc_data.state_available
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes."""
return self._pvpc_data.attributes
@callback @callback
def update_current_price(self, now): def update_current_price(self, now: datetime) -> None:
"""Update the sensor state, by selecting the current price for this hour.""" """Update the sensor state, by selecting the current price for this hour."""
self._pvpc_data.process_state_and_attributes(now) self.coordinator.api.process_state_and_attributes(now)
self.async_write_ha_state() self.async_write_ha_state()
async def async_update_prices(self, now): @property
"""Update electricity prices from the ESIOS API.""" def native_value(self) -> StateType:
prices = await self._pvpc_data.async_update_prices(now) """Return the state of the sensor."""
if not prices and self._pvpc_data.source_available: self._state = self.coordinator.api.state
self._num_retries += 1 return self._state
if self._num_retries > 2:
_LOGGER.warning(
"%s: repeated bad data update, mark component as unavailable source",
self.entity_id,
)
self._pvpc_data.source_available = False
return
retry_delay = 2 * self._num_retries * self._pvpc_data.timeout @property
_LOGGER.debug( def extra_state_attributes(self) -> Mapping[str, Any] | None:
"%s: Bad update[retry:%d], will try again in %d s", """Return the state attributes."""
self.entity_id, self._attrs = {
self._num_retries, _PRICE_SENSOR_ATTRIBUTES_MAP[key]: value
retry_delay, for key, value in self.coordinator.api.attributes.items()
) if key in _PRICE_SENSOR_ATTRIBUTES_MAP
async_call_later(self.hass, retry_delay, self.async_update_prices) }
return return self._attrs
if not prices:
_LOGGER.debug("%s: data source is not yet available", self.entity_id)
return
self._num_retries = 0
if not self._pvpc_data.source_available:
self._pvpc_data.source_available = True
_LOGGER.warning("%s: component has recovered data access", self.entity_id)
self.update_current_price(now)

View File

@ -5,7 +5,7 @@ from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
import logging import logging
import pyrepetier import pyrepetierng as pyrepetier
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import SensorEntityDescription from homeassistant.components.sensor import SensorEntityDescription

View File

@ -2,7 +2,7 @@
"domain": "repetier", "domain": "repetier",
"name": "Repetier-Server", "name": "Repetier-Server",
"documentation": "https://www.home-assistant.io/integrations/repetier", "documentation": "https://www.home-assistant.io/integrations/repetier",
"requirements": ["pyrepetier==3.0.5"], "requirements": ["pyrepetierng==0.1.0"],
"codeowners": ["@MTrab"], "codeowners": ["@MTrab", "@ShadowBr0ther"],
"iot_class": "local_polling" "iot_class": "local_polling"
} }

View File

@ -1,6 +1,7 @@
"""Entity representing a Sonos power sensor.""" """Entity representing a Sonos power sensor."""
from __future__ import annotations from __future__ import annotations
import logging
from typing import Any from typing import Any
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
@ -16,11 +17,14 @@ from .speaker import SonosSpeaker
ATTR_BATTERY_POWER_SOURCE = "power_source" ATTR_BATTERY_POWER_SOURCE = "power_source"
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Sonos from a config entry.""" """Set up Sonos from a config entry."""
async def _async_create_entity(speaker: SonosSpeaker) -> None: async def _async_create_entity(speaker: SonosSpeaker) -> None:
_LOGGER.debug("Creating battery binary_sensor on %s", speaker.zone_name)
entity = SonosPowerEntity(speaker) entity = SonosPowerEntity(speaker)
async_add_entities([entity]) async_add_entities([entity])

View File

@ -149,7 +149,6 @@ SONOS_CREATE_BATTERY = "sonos_create_battery"
SONOS_CREATE_SWITCHES = "sonos_create_switches" SONOS_CREATE_SWITCHES = "sonos_create_switches"
SONOS_CREATE_LEVELS = "sonos_create_levels" SONOS_CREATE_LEVELS = "sonos_create_levels"
SONOS_CREATE_MEDIA_PLAYER = "sonos_create_media_player" SONOS_CREATE_MEDIA_PLAYER = "sonos_create_media_player"
SONOS_ENTITY_CREATED = "sonos_entity_created"
SONOS_POLL_UPDATE = "sonos_poll_update" SONOS_POLL_UPDATE = "sonos_poll_update"
SONOS_ALARMS_UPDATED = "sonos_alarms_updated" SONOS_ALARMS_UPDATED = "sonos_alarms_updated"
SONOS_FAVORITES_UPDATED = "sonos_favorites_updated" SONOS_FAVORITES_UPDATED = "sonos_favorites_updated"

View File

@ -10,15 +10,11 @@ from soco.core import SoCo
from soco.exceptions import SoCoException from soco.exceptions import SoCoException
import homeassistant.helpers.device_registry as dr import homeassistant.helpers.device_registry as dr
from homeassistant.helpers.dispatcher import ( from homeassistant.helpers.dispatcher import async_dispatcher_connect
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.entity import DeviceInfo, Entity from homeassistant.helpers.entity import DeviceInfo, Entity
from .const import ( from .const import (
DOMAIN, DOMAIN,
SONOS_ENTITY_CREATED,
SONOS_FAVORITES_UPDATED, SONOS_FAVORITES_UPDATED,
SONOS_POLL_UPDATE, SONOS_POLL_UPDATE,
SONOS_STATE_UPDATED, SONOS_STATE_UPDATED,
@ -60,9 +56,6 @@ class SonosEntity(Entity):
self.async_write_ha_state, self.async_write_ha_state,
) )
) )
async_dispatcher_send(
self.hass, f"{SONOS_ENTITY_CREATED}-{self.soco.uid}", self.platform.domain
)
async def async_poll(self, now: datetime.datetime) -> None: async def async_poll(self, now: datetime.datetime) -> None:
"""Poll the entity if subscriptions fail.""" """Poll the entity if subscriptions fail."""

View File

@ -3,7 +3,7 @@
"name": "Sonos", "name": "Sonos",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/sonos", "documentation": "https://www.home-assistant.io/integrations/sonos",
"requirements": ["soco==0.25.0"], "requirements": ["soco==0.25.1"],
"dependencies": ["ssdp"], "dependencies": ["ssdp"],
"after_dependencies": ["plex", "zeroconf"], "after_dependencies": ["plex", "zeroconf"],
"zeroconf": ["_sonos._tcp.local."], "zeroconf": ["_sonos._tcp.local."],

View File

@ -132,6 +132,7 @@ async def async_setup_entry(
@callback @callback
def async_create_entities(speaker: SonosSpeaker) -> None: def async_create_entities(speaker: SonosSpeaker) -> None:
"""Handle device discovery and create entities.""" """Handle device discovery and create entities."""
_LOGGER.debug("Creating media_player on %s", speaker.zone_name)
async_add_entities([SonosMediaPlayerEntity(speaker)]) async_add_entities([SonosMediaPlayerEntity(speaker)])
@service.verify_domain_control(hass, SONOS_DOMAIN) @service.verify_domain_control(hass, SONOS_DOMAIN)

View File

@ -1,6 +1,8 @@
"""Entity representing a Sonos number control.""" """Entity representing a Sonos number control."""
from __future__ import annotations from __future__ import annotations
import logging
from homeassistant.components.number import NumberEntity from homeassistant.components.number import NumberEntity
from homeassistant.const import ENTITY_CATEGORY_CONFIG from homeassistant.const import ENTITY_CATEGORY_CONFIG
from homeassistant.core import callback from homeassistant.core import callback
@ -13,6 +15,8 @@ from .speaker import SonosSpeaker
LEVEL_TYPES = ("bass", "treble") LEVEL_TYPES = ("bass", "treble")
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Sonos number platform from a config entry.""" """Set up the Sonos number platform from a config entry."""
@ -21,6 +25,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
def _async_create_entities(speaker: SonosSpeaker) -> None: def _async_create_entities(speaker: SonosSpeaker) -> None:
entities = [] entities = []
for level_type in LEVEL_TYPES: for level_type in LEVEL_TYPES:
_LOGGER.debug(
"Creating %s number control on %s", level_type, speaker.zone_name
)
entities.append(SonosLevelEntity(speaker, level_type)) entities.append(SonosLevelEntity(speaker, level_type))
async_add_entities(entities) async_add_entities(entities)

View File

@ -1,6 +1,8 @@
"""Entity representing a Sonos battery level.""" """Entity representing a Sonos battery level."""
from __future__ import annotations from __future__ import annotations
import logging
from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor import SensorEntity
from homeassistant.const import ( from homeassistant.const import (
DEVICE_CLASS_BATTERY, DEVICE_CLASS_BATTERY,
@ -14,6 +16,8 @@ from .const import SONOS_CREATE_AUDIO_FORMAT_SENSOR, SONOS_CREATE_BATTERY
from .entity import SonosEntity from .entity import SonosEntity
from .speaker import SonosSpeaker from .speaker import SonosSpeaker
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Sonos from a config entry.""" """Set up Sonos from a config entry."""
@ -22,11 +26,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
def _async_create_audio_format_entity( def _async_create_audio_format_entity(
speaker: SonosSpeaker, audio_format: str speaker: SonosSpeaker, audio_format: str
) -> None: ) -> None:
_LOGGER.debug("Creating audio input format sensor on %s", speaker.zone_name)
entity = SonosAudioInputFormatSensorEntity(speaker, audio_format) entity = SonosAudioInputFormatSensorEntity(speaker, audio_format)
async_add_entities([entity]) async_add_entities([entity])
@callback @callback
def _async_create_battery_sensor(speaker: SonosSpeaker) -> None: def _async_create_battery_sensor(speaker: SonosSpeaker) -> None:
_LOGGER.debug("Creating battery level sensor on %s", speaker.zone_name)
entity = SonosBatteryEntity(speaker) entity = SonosBatteryEntity(speaker)
async_add_entities([entity]) async_add_entities([entity])

View File

@ -20,10 +20,7 @@ from soco.music_library import MusicLibrary
from soco.plugins.sharelink import ShareLinkPlugin from soco.plugins.sharelink import ShareLinkPlugin
from soco.snapshot import Snapshot from soco.snapshot import Snapshot
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -42,7 +39,6 @@ from .const import (
BATTERY_SCAN_INTERVAL, BATTERY_SCAN_INTERVAL,
DATA_SONOS, DATA_SONOS,
DOMAIN, DOMAIN,
PLATFORMS,
SCAN_INTERVAL, SCAN_INTERVAL,
SONOS_CHECK_ACTIVITY, SONOS_CHECK_ACTIVITY,
SONOS_CREATE_ALARM, SONOS_CREATE_ALARM,
@ -51,7 +47,6 @@ from .const import (
SONOS_CREATE_LEVELS, SONOS_CREATE_LEVELS,
SONOS_CREATE_MEDIA_PLAYER, SONOS_CREATE_MEDIA_PLAYER,
SONOS_CREATE_SWITCHES, SONOS_CREATE_SWITCHES,
SONOS_ENTITY_CREATED,
SONOS_POLL_UPDATE, SONOS_POLL_UPDATE,
SONOS_REBOOTED, SONOS_REBOOTED,
SONOS_SPEAKER_ACTIVITY, SONOS_SPEAKER_ACTIVITY,
@ -161,9 +156,6 @@ class SonosSpeaker:
self._share_link_plugin: ShareLinkPlugin | None = None self._share_link_plugin: ShareLinkPlugin | None = None
self.available = True self.available = True
# Synchronization helpers
self._platforms_ready: set[str] = set()
# Subscriptions and events # Subscriptions and events
self.subscriptions_failed: bool = False self.subscriptions_failed: bool = False
self._subscriptions: list[SubscriptionBase] = [] self._subscriptions: list[SubscriptionBase] = []
@ -217,7 +209,6 @@ class SonosSpeaker:
dispatch_pairs = ( dispatch_pairs = (
(SONOS_CHECK_ACTIVITY, self.async_check_activity), (SONOS_CHECK_ACTIVITY, self.async_check_activity),
(SONOS_SPEAKER_ADDED, self.update_group_for_uid), (SONOS_SPEAKER_ADDED, self.update_group_for_uid),
(f"{SONOS_ENTITY_CREATED}-{self.soco.uid}", self.async_handle_new_entity),
(f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted), (f"{SONOS_REBOOTED}-{self.soco.uid}", self.async_rebooted),
(f"{SONOS_SPEAKER_ACTIVITY}-{self.soco.uid}", self.speaker_activity), (f"{SONOS_SPEAKER_ACTIVITY}-{self.soco.uid}", self.speaker_activity),
) )
@ -253,15 +244,11 @@ class SonosSpeaker:
self.hass, self.async_poll_battery, BATTERY_SCAN_INTERVAL self.hass, self.async_poll_battery, BATTERY_SCAN_INTERVAL
) )
dispatcher_send(self.hass, SONOS_CREATE_BATTERY, self) dispatcher_send(self.hass, SONOS_CREATE_BATTERY, self)
else:
self._platforms_ready.update({BINARY_SENSOR_DOMAIN, SENSOR_DOMAIN})
if new_alarms := [ if new_alarms := [
alarm.alarm_id for alarm in self.alarms if alarm.zone.uid == self.soco.uid alarm.alarm_id for alarm in self.alarms if alarm.zone.uid == self.soco.uid
]: ]:
dispatcher_send(self.hass, SONOS_CREATE_ALARM, self, new_alarms) dispatcher_send(self.hass, SONOS_CREATE_ALARM, self, new_alarms)
else:
self._platforms_ready.add(SWITCH_DOMAIN)
dispatcher_send(self.hass, SONOS_CREATE_SWITCHES, self) dispatcher_send(self.hass, SONOS_CREATE_SWITCHES, self)
@ -277,19 +264,11 @@ class SonosSpeaker:
dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self) dispatcher_send(self.hass, SONOS_CREATE_MEDIA_PLAYER, self)
dispatcher_send(self.hass, SONOS_SPEAKER_ADDED, self.soco.uid) dispatcher_send(self.hass, SONOS_SPEAKER_ADDED, self.soco.uid)
self.hass.create_task(self.async_subscribe())
# #
# Entity management # Entity management
# #
async def async_handle_new_entity(self, entity_type: str) -> None:
"""Listen to new entities to trigger first subscription."""
if self._platforms_ready == PLATFORMS:
return
self._platforms_ready.add(entity_type)
if self._platforms_ready == PLATFORMS:
self._resubscription_lock = asyncio.Lock()
await self.async_subscribe()
def write_entity_states(self) -> None: def write_entity_states(self) -> None:
"""Write states for associated SonosEntity instances.""" """Write states for associated SonosEntity instances."""
dispatcher_send(self.hass, f"{SONOS_STATE_UPDATED}-{self.soco.uid}") dispatcher_send(self.hass, f"{SONOS_STATE_UPDATED}-{self.soco.uid}")
@ -405,6 +384,9 @@ class SonosSpeaker:
async def async_resubscribe(self, exception: Exception) -> None: async def async_resubscribe(self, exception: Exception) -> None:
"""Attempt to resubscribe when a renewal failure is detected.""" """Attempt to resubscribe when a renewal failure is detected."""
if not self._resubscription_lock:
self._resubscription_lock = asyncio.Lock()
async with self._resubscription_lock: async with self._resubscription_lock:
if not self.available: if not self.available:
return return

View File

@ -3,7 +3,7 @@
"name": "Tile", "name": "Tile",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/tile", "documentation": "https://www.home-assistant.io/integrations/tile",
"requirements": ["pytile==5.2.4"], "requirements": ["pytile==2021.12.0"],
"codeowners": ["@bachya"], "codeowners": ["@bachya"],
"iot_class": "cloud_polling" "iot_class": "cloud_polling"
} }

View File

@ -16,6 +16,7 @@ from homeassistant.const import (
) )
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util.dt import get_time_zone
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -131,12 +132,15 @@ class TrainSensor(SensorEntity):
self._state = None self._state = None
self._departure_state = None self._departure_state = None
self._delay_in_minutes = None self._delay_in_minutes = None
self._timezone = get_time_zone("Europe/Stockholm")
async def async_update(self): async def async_update(self):
"""Retrieve latest state.""" """Retrieve latest state."""
if self._time is not None: if self._time is not None:
departure_day = next_departuredate(self._weekday) departure_day = next_departuredate(self._weekday)
when = datetime.combine(departure_day, self._time) when = datetime.combine(departure_day, self._time).astimezone(
self._timezone
)
try: try:
self._state = await self._train_api.async_get_train_stop( self._state = await self._train_api.async_get_train_stop(
self._from_station, self._to_station, when self._from_station, self._to_station, when
@ -193,8 +197,8 @@ class TrainSensor(SensorEntity):
"""Return the departure state.""" """Return the departure state."""
if (state := self._state) is not None: if (state := self._state) is not None:
if state.time_at_location is not None: if state.time_at_location is not None:
return state.time_at_location return state.time_at_location.astimezone(self._timezone)
if state.estimated_time_at_location is not None: if state.estimated_time_at_location is not None:
return state.estimated_time_at_location return state.estimated_time_at_location.astimezone(self._timezone)
return state.advertised_time_at_location return state.advertised_time_at_location.astimezone(self._timezone)
return None return None

View File

@ -1,6 +1,7 @@
"""Support for Vallox ventilation units.""" """Support for Vallox ventilation units."""
from __future__ import annotations from __future__ import annotations
import asyncio
from dataclasses import dataclass, field from dataclasses import dataclass, field
import ipaddress import ipaddress
import logging import logging
@ -13,7 +14,7 @@ from vallox_websocket_api.vallox import get_uuid as calculate_uuid
import voluptuous as vol import voluptuous as vol
from homeassistant.const import CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STARTED from homeassistant.const import CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STARTED
from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.core import CoreState, HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.discovery import async_load_platform
from homeassistant.helpers.typing import ConfigType, StateType from homeassistant.helpers.typing import ConfigType, StateType
@ -25,6 +26,7 @@ from .const import (
DEFAULT_FAN_SPEED_HOME, DEFAULT_FAN_SPEED_HOME,
DEFAULT_NAME, DEFAULT_NAME,
DOMAIN, DOMAIN,
INITIAL_COORDINATOR_UPDATE_RETRY_INTERVAL_SECONDS,
METRIC_KEY_PROFILE_FAN_SPEED_AWAY, METRIC_KEY_PROFILE_FAN_SPEED_AWAY,
METRIC_KEY_PROFILE_FAN_SPEED_BOOST, METRIC_KEY_PROFILE_FAN_SPEED_BOOST,
METRIC_KEY_PROFILE_FAN_SPEED_HOME, METRIC_KEY_PROFILE_FAN_SPEED_HOME,
@ -171,7 +173,24 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
hass.data[DOMAIN] = {"client": client, "coordinator": coordinator, "name": name} hass.data[DOMAIN] = {"client": client, "coordinator": coordinator, "name": name}
async def _async_load_platform_delayed(*_: Any) -> None: async def _async_load_platform_delayed(*_: Any) -> None:
await coordinator.async_refresh() # We need a successful update before loading the platforms, because platform init code
# derives the UUIDs from the data the coordinator fetches.
warned_once = False
while hass.state == CoreState.running:
await coordinator.async_refresh()
if coordinator.last_update_success:
break
if not warned_once:
_LOGGER.warning(
"Vallox integration not ready yet; Retrying in background"
)
warned_once = True
await asyncio.sleep(INITIAL_COORDINATOR_UPDATE_RETRY_INTERVAL_SECONDS)
else:
return
hass.async_create_task(async_load_platform(hass, "sensor", DOMAIN, {}, config)) hass.async_create_task(async_load_platform(hass, "sensor", DOMAIN, {}, config))
hass.async_create_task(async_load_platform(hass, "fan", DOMAIN, {}, config)) hass.async_create_task(async_load_platform(hass, "fan", DOMAIN, {}, config))

View File

@ -7,6 +7,7 @@ from vallox_websocket_api import PROFILE as VALLOX_PROFILE
DOMAIN = "vallox" DOMAIN = "vallox"
DEFAULT_NAME = "Vallox" DEFAULT_NAME = "Vallox"
INITIAL_COORDINATOR_UPDATE_RETRY_INTERVAL_SECONDS = 5
STATE_SCAN_INTERVAL = timedelta(seconds=60) STATE_SCAN_INTERVAL = timedelta(seconds=60)
# Common metric keys and (default) values. # Common metric keys and (default) values.

View File

@ -7,7 +7,7 @@ from homeassistant.backports.enum import StrEnum
MAJOR_VERSION: Final = 2021 MAJOR_VERSION: Final = 2021
MINOR_VERSION: Final = 12 MINOR_VERSION: Final = 12
PATCH_VERSION: Final = "4" PATCH_VERSION: Final = "5"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0) REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)

View File

@ -61,6 +61,7 @@ PyViCare==2.13.1
PyXiaomiGateway==0.13.4 PyXiaomiGateway==0.13.4
# homeassistant.components.bmp280 # homeassistant.components.bmp280
# homeassistant.components.dht
# homeassistant.components.mcp23017 # homeassistant.components.mcp23017
# homeassistant.components.rpi_gpio # homeassistant.components.rpi_gpio
# homeassistant.components.rpi_rf # homeassistant.components.rpi_rf
@ -94,7 +95,7 @@ accuweather==0.3.0
adafruit-circuitpython-bmp280==3.1.1 adafruit-circuitpython-bmp280==3.1.1
# homeassistant.components.dht # homeassistant.components.dht
adafruit-circuitpython-dht==3.6.0 adafruit-circuitpython-dht==3.7.0
# homeassistant.components.mcp23017 # homeassistant.components.mcp23017
adafruit-circuitpython-mcp230xx==2.2.2 adafruit-circuitpython-mcp230xx==2.2.2
@ -186,7 +187,7 @@ aiohomekit==0.6.4
aiohttp_cors==0.7.0 aiohttp_cors==0.7.0
# homeassistant.components.hue # homeassistant.components.hue
aiohue==3.0.7 aiohue==3.0.10
# homeassistant.components.imap # homeassistant.components.imap
aioimaplib==0.9.0 aioimaplib==0.9.0
@ -234,7 +235,7 @@ aiopulse==0.4.3
aiopvapi==1.6.19 aiopvapi==1.6.19
# homeassistant.components.pvpc_hourly_pricing # homeassistant.components.pvpc_hourly_pricing
aiopvpc==2.2.4 aiopvpc==3.0.0
# homeassistant.components.webostv # homeassistant.components.webostv
aiopylgtv==0.4.0 aiopylgtv==0.4.0
@ -658,7 +659,7 @@ fjaraskupan==1.0.2
flipr-api==1.4.1 flipr-api==1.4.1
# homeassistant.components.flux_led # homeassistant.components.flux_led
flux_led==0.27.8 flux_led==0.27.13
# homeassistant.components.homekit # homeassistant.components.homekit
fnvhash==0.1.0 fnvhash==0.1.0
@ -1753,7 +1754,7 @@ pyrainbird==0.4.3
pyrecswitch==1.0.2 pyrecswitch==1.0.2
# homeassistant.components.repetier # homeassistant.components.repetier
pyrepetier==3.0.5 pyrepetierng==0.1.0
# homeassistant.components.risco # homeassistant.components.risco
pyrisco==0.3.1 pyrisco==0.3.1
@ -1961,7 +1962,7 @@ python_opendata_transport==0.2.1
pythonegardia==1.0.40 pythonegardia==1.0.40
# homeassistant.components.tile # homeassistant.components.tile
pytile==5.2.4 pytile==2021.12.0
# homeassistant.components.touchline # homeassistant.components.touchline
pytouchline==0.7 pytouchline==0.7
@ -2184,7 +2185,7 @@ smhi-pkg==1.0.15
snapcast==2.1.3 snapcast==2.1.3
# homeassistant.components.sonos # homeassistant.components.sonos
soco==0.25.0 soco==0.25.1
# homeassistant.components.solaredge_local # homeassistant.components.solaredge_local
solaredge-local==0.2.0 solaredge-local==0.2.0
@ -2448,7 +2449,7 @@ xbox-webapi==2.0.11
xboxapi==2.0.1 xboxapi==2.0.1
# homeassistant.components.knx # homeassistant.components.knx
xknx==0.18.14 xknx==0.18.15
# homeassistant.components.bluesound # homeassistant.components.bluesound
# homeassistant.components.fritz # homeassistant.components.fritz

View File

@ -131,7 +131,7 @@ aiohomekit==0.6.4
aiohttp_cors==0.7.0 aiohttp_cors==0.7.0
# homeassistant.components.hue # homeassistant.components.hue
aiohue==3.0.7 aiohue==3.0.10
# homeassistant.components.apache_kafka # homeassistant.components.apache_kafka
aiokafka==0.6.0 aiokafka==0.6.0
@ -164,7 +164,7 @@ aiopulse==0.4.3
aiopvapi==1.6.19 aiopvapi==1.6.19
# homeassistant.components.pvpc_hourly_pricing # homeassistant.components.pvpc_hourly_pricing
aiopvpc==2.2.4 aiopvpc==3.0.0
# homeassistant.components.webostv # homeassistant.components.webostv
aiopylgtv==0.4.0 aiopylgtv==0.4.0
@ -399,7 +399,7 @@ fjaraskupan==1.0.2
flipr-api==1.4.1 flipr-api==1.4.1
# homeassistant.components.flux_led # homeassistant.components.flux_led
flux_led==0.27.8 flux_led==0.27.13
# homeassistant.components.homekit # homeassistant.components.homekit
fnvhash==0.1.0 fnvhash==0.1.0
@ -1172,7 +1172,7 @@ python-twitch-client==0.6.0
python_awair==0.2.1 python_awair==0.2.1
# homeassistant.components.tile # homeassistant.components.tile
pytile==5.2.4 pytile==2021.12.0
# homeassistant.components.traccar # homeassistant.components.traccar
pytraccar==0.10.0 pytraccar==0.10.0
@ -1291,7 +1291,7 @@ smarthab==0.21
smhi-pkg==1.0.15 smhi-pkg==1.0.15
# homeassistant.components.sonos # homeassistant.components.sonos
soco==0.25.0 soco==0.25.1
# homeassistant.components.solaredge # homeassistant.components.solaredge
solaredge==0.0.2 solaredge==0.0.2
@ -1450,7 +1450,7 @@ wolf_smartset==0.1.11
xbox-webapi==2.0.11 xbox-webapi==2.0.11
# homeassistant.components.knx # homeassistant.components.knx
xknx==0.18.14 xknx==0.18.15
# homeassistant.components.bluesound # homeassistant.components.bluesound
# homeassistant.components.fritz # homeassistant.components.fritz

View File

@ -1082,7 +1082,12 @@ async def test_entity_control(hass: HomeAssistant):
chromecast.media_controller.seek.assert_called_once_with(123) chromecast.media_controller.seek.assert_called_once_with(123)
async def test_entity_media_states(hass: HomeAssistant): # Some smart TV's with Google TV report "Netflix", not the Netflix app's ID
@pytest.mark.parametrize(
"app_id, state_no_media",
[(pychromecast.APP_YOUTUBE, "idle"), ("Netflix", "playing")],
)
async def test_entity_media_states(hass: HomeAssistant, app_id, state_no_media):
"""Test various entity media states.""" """Test various entity media states."""
entity_id = "media_player.speaker" entity_id = "media_player.speaker"
reg = er.async_get(hass) reg = er.async_get(hass)
@ -1090,7 +1095,7 @@ async def test_entity_media_states(hass: HomeAssistant):
info = get_fake_chromecast_info() info = get_fake_chromecast_info()
chromecast, _ = await async_setup_media_player_cast(hass, info) chromecast, _ = await async_setup_media_player_cast(hass, info)
_, conn_status_cb, media_status_cb = get_status_callbacks(chromecast) cast_status_cb, conn_status_cb, media_status_cb = get_status_callbacks(chromecast)
connection_status = MagicMock() connection_status = MagicMock()
connection_status.status = "CONNECTED" connection_status.status = "CONNECTED"
@ -1103,6 +1108,15 @@ async def test_entity_media_states(hass: HomeAssistant):
assert state.state == "off" assert state.state == "off"
assert entity_id == reg.async_get_entity_id("media_player", "cast", str(info.uuid)) assert entity_id == reg.async_get_entity_id("media_player", "cast", str(info.uuid))
# App id updated, but no media status
chromecast.app_id = app_id
cast_status = MagicMock()
cast_status_cb(cast_status)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == state_no_media
# Got media status
media_status = MagicMock(images=None) media_status = MagicMock(images=None)
media_status.player_is_playing = True media_status.player_is_playing = True
media_status_cb(media_status) media_status_cb(media_status)
@ -1124,15 +1138,23 @@ async def test_entity_media_states(hass: HomeAssistant):
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "idle" assert state.state == "idle"
media_status.player_is_idle = False # No media status, app is still running
chromecast.is_idle = True media_status_cb(None)
media_status_cb(media_status) await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state.state == state_no_media
# App no longer running
chromecast.app_id = pychromecast.IDLE_APP_ID
cast_status = MagicMock()
cast_status_cb(cast_status)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "off" assert state.state == "off"
# No cast status
chromecast.is_idle = False chromecast.is_idle = False
media_status_cb(media_status) cast_status_cb(None)
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "unknown" assert state.state == "unknown"

View File

@ -399,6 +399,20 @@ async def test_light_state_change(hass, aioclient_mock, mock_deconz_websocket):
"xy": (0.411, 0.351), "xy": (0.411, 0.351),
}, },
), ),
( # Turn on light without transition time
{
"light_on": True,
"service": SERVICE_TURN_ON,
"call": {
ATTR_ENTITY_ID: "light.hue_go",
ATTR_TRANSITION: 0,
},
},
{
"on": True,
"transitiontime": 0,
},
),
( # Turn on light with short color loop ( # Turn on light with short color loop
{ {
"light_on": False, "light_on": False,
@ -453,6 +467,22 @@ async def test_light_state_change(hass, aioclient_mock, mock_deconz_websocket):
"alert": "select", "alert": "select",
}, },
), ),
( # Turn off light without transition time
{
"light_on": True,
"service": SERVICE_TURN_OFF,
"call": {
ATTR_ENTITY_ID: "light.hue_go",
ATTR_TRANSITION: 0,
ATTR_FLASH: FLASH_SHORT,
},
},
{
"bri": 0,
"transitiontime": 0,
"alert": "select",
},
),
( # Turn off light with long flashing ( # Turn off light with long flashing
{ {
"light_on": True, "light_on": True,

View File

@ -25,7 +25,7 @@ async def test_hue_event(hass, mock_bridge_v2, v2_resources_test_data):
# Emit button update event # Emit button update event
btn_event = { btn_event = {
"button": {"last_event": "short_release"}, "button": {"last_event": "initial_press"},
"id": "c658d3d8-a013-4b81-8ac6-78b248537e70", "id": "c658d3d8-a013-4b81-8ac6-78b248537e70",
"metadata": {"control_id": 1}, "metadata": {"control_id": 1},
"type": "button", "type": "button",

View File

@ -110,16 +110,16 @@ async def test_light_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat
assert test_light.attributes["color_mode"] == COLOR_MODE_COLOR_TEMP assert test_light.attributes["color_mode"] == COLOR_MODE_COLOR_TEMP
assert test_light.attributes["brightness"] == 255 assert test_light.attributes["brightness"] == 255
# test again with sending transition # test again with sending transition with 250ms which should round up to 200ms
await hass.services.async_call( await hass.services.async_call(
"light", "light",
"turn_on", "turn_on",
{"entity_id": test_light_id, "brightness_pct": 50, "transition": 6}, {"entity_id": test_light_id, "brightness_pct": 50, "transition": 0.25},
blocking=True, blocking=True,
) )
assert len(mock_bridge_v2.mock_requests) == 2 assert len(mock_bridge_v2.mock_requests) == 2
assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is True assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is True
assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 6000 assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 200
# test again with sending flash/alert # test again with sending flash/alert
await hass.services.async_call( await hass.services.async_call(
@ -170,12 +170,12 @@ async def test_light_turn_off_service(hass, mock_bridge_v2, v2_resources_test_da
await hass.services.async_call( await hass.services.async_call(
"light", "light",
"turn_off", "turn_off",
{"entity_id": test_light_id, "transition": 6}, {"entity_id": test_light_id, "transition": 0.25},
blocking=True, blocking=True,
) )
assert len(mock_bridge_v2.mock_requests) == 2 assert len(mock_bridge_v2.mock_requests) == 2
assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is False assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is False
assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 6000 assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 200
async def test_light_added(hass, mock_bridge_v2): async def test_light_added(hass, mock_bridge_v2):
@ -310,7 +310,7 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
"entity_id": test_light_id, "entity_id": test_light_id,
"brightness_pct": 100, "brightness_pct": 100,
"xy_color": (0.123, 0.123), "xy_color": (0.123, 0.123),
"transition": 6, "transition": 0.25,
}, },
blocking=True, blocking=True,
) )
@ -325,7 +325,7 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["x"] == 0.123 assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["x"] == 0.123
assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["y"] == 0.123 assert mock_bridge_v2.mock_requests[index]["json"]["color"]["xy"]["y"] == 0.123
assert ( assert (
mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 6000 mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 200
) )
# Now generate update events by emitting the json we've sent as incoming events # Now generate update events by emitting the json we've sent as incoming events
@ -374,7 +374,7 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
"turn_off", "turn_off",
{ {
"entity_id": test_light_id, "entity_id": test_light_id,
"transition": 6, "transition": 0.25,
}, },
blocking=True, blocking=True,
) )
@ -384,5 +384,5 @@ async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data):
for index in range(0, 3): for index in range(0, 3):
assert mock_bridge_v2.mock_requests[index]["json"]["on"]["on"] is False assert mock_bridge_v2.mock_requests[index]["json"]["on"]["on"] is False
assert ( assert (
mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 6000 mock_bridge_v2.mock_requests[index]["json"]["dynamics"]["duration"] == 200
) )

View File

@ -77,13 +77,13 @@ async def test_scene_turn_on_service(hass, mock_bridge_v2, v2_resources_test_dat
await hass.services.async_call( await hass.services.async_call(
"scene", "scene",
"turn_on", "turn_on",
{"entity_id": test_entity_id, "transition": 6}, {"entity_id": test_entity_id, "transition": 0.25},
blocking=True, blocking=True,
) )
assert len(mock_bridge_v2.mock_requests) == 2 assert len(mock_bridge_v2.mock_requests) == 2
assert mock_bridge_v2.mock_requests[1]["json"]["recall"] == { assert mock_bridge_v2.mock_requests[1]["json"]["recall"] == {
"action": "active", "action": "active",
"duration": 6000, "duration": 200,
} }

View File

@ -1,4 +1,6 @@
"""Tests for the pvpc_hourly_pricing integration.""" """Tests for the pvpc_hourly_pricing integration."""
from http import HTTPStatus
import pytest import pytest
from homeassistant.components.pvpc_hourly_pricing import ATTR_TARIFF, DOMAIN from homeassistant.components.pvpc_hourly_pricing import ATTR_TARIFF, DOMAIN
@ -11,10 +13,7 @@ from homeassistant.const import (
from tests.common import load_fixture from tests.common import load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker from tests.test_util.aiohttp import AiohttpClientMocker
FIXTURE_JSON_DATA_2019_10_26 = "PVPC_CURV_DD_2019_10_26.json" FIXTURE_JSON_DATA_2021_06_01 = "PVPC_DATA_2021_06_01.json"
FIXTURE_JSON_DATA_2019_10_27 = "PVPC_CURV_DD_2019_10_27.json"
FIXTURE_JSON_DATA_2019_10_29 = "PVPC_CURV_DD_2019_10_29.json"
FIXTURE_JSON_DATA_2021_06_01 = "PVPC_CURV_DD_2021_06_01.json"
def check_valid_state(state, tariff: str, value=None, key_attr=None): def check_valid_state(state, tariff: str, value=None, key_attr=None):
@ -27,7 +26,7 @@ def check_valid_state(state, tariff: str, value=None, key_attr=None):
try: try:
_ = float(state.state) _ = float(state.state)
# safety margins for current electricity price (it shouldn't be out of [0, 0.2]) # safety margins for current electricity price (it shouldn't be out of [0, 0.2])
assert -0.1 < float(state.state) < 0.3 assert -0.1 < float(state.state) < 0.5
assert state.attributes[ATTR_TARIFF] == tariff assert state.attributes[ATTR_TARIFF] == tariff
except ValueError: except ValueError:
pass pass
@ -43,28 +42,22 @@ def check_valid_state(state, tariff: str, value=None, key_attr=None):
@pytest.fixture @pytest.fixture
def pvpc_aioclient_mock(aioclient_mock: AiohttpClientMocker): def pvpc_aioclient_mock(aioclient_mock: AiohttpClientMocker):
"""Create a mock config entry.""" """Create a mock config entry."""
aioclient_mock.get( mask_url = "https://apidatos.ree.es/es/datos/mercados/precios-mercados-tiempo-real"
"https://api.esios.ree.es/archives/70/download_json?locale=es&date=2019-10-26", mask_url += "?time_trunc=hour&geo_ids={0}&start_date={1}T00:00&end_date={1}T23:59"
text=load_fixture(f"{DOMAIN}/{FIXTURE_JSON_DATA_2019_10_26}"),
)
aioclient_mock.get(
"https://api.esios.ree.es/archives/70/download_json?locale=es&date=2019-10-27",
text=load_fixture(f"{DOMAIN}/{FIXTURE_JSON_DATA_2019_10_27}"),
)
# missing day
aioclient_mock.get(
"https://api.esios.ree.es/archives/70/download_json?locale=es&date=2019-10-28",
text='{"message":"No values for specified archive"}',
)
aioclient_mock.get(
"https://api.esios.ree.es/archives/70/download_json?locale=es&date=2019-10-29",
text=load_fixture(f"{DOMAIN}/{FIXTURE_JSON_DATA_2019_10_29}"),
)
# new format for prices >= 2021-06-01 # new format for prices >= 2021-06-01
sample_data = load_fixture(f"{DOMAIN}/{FIXTURE_JSON_DATA_2021_06_01}")
# tariff variant with different geo_ids=8744
aioclient_mock.get(mask_url.format(8741, "2021-06-01"), text=sample_data)
aioclient_mock.get(mask_url.format(8744, "2021-06-01"), text=sample_data)
# simulate missing day
aioclient_mock.get( aioclient_mock.get(
"https://api.esios.ree.es/archives/70/download_json?locale=es&date=2021-06-01", mask_url.format(8741, "2021-06-02"),
text=load_fixture(f"{DOMAIN}/{FIXTURE_JSON_DATA_2021_06_01}"), status=HTTPStatus.BAD_GATEWAY,
text=(
'{"errors":[{"code":502,"status":"502","title":"Bad response from ESIOS",'
'"detail":"There are no data for the selected filters."}]}'
),
) )
return aioclient_mock return aioclient_mock

View File

@ -1,820 +0,0 @@
{
"PVPC": [
{
"Dia": "26/10/2019",
"Hora": "00-01",
"GEN": "114,20",
"NOC": "65,17",
"VHC": "69,02",
"COFGEN": "0,000087148314000000",
"COFNOC": "0,000135978057000000",
"COFVHC": "0,000151138804000000",
"PMHGEN": "59,56",
"PMHNOC": "57,22",
"PMHVHC": "59,81",
"SAHGEN": "1,96",
"SAHNOC": "1,89",
"SAHVHC": "1,97",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,14",
"INTGEN": "0,93",
"INTNOC": "0,90",
"INTVHC": "0,94",
"PCAPGEN": "5,54",
"PCAPNOC": "0,93",
"PCAPVHC": "1,31",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,01",
"CCVNOC": "1,86",
"CCVVHC": "1,95"
},
{
"Dia": "26/10/2019",
"Hora": "01-02",
"GEN": "111,01",
"NOC": "62,10",
"VHC": "59,03",
"COFGEN": "0,000072922194000000",
"COFNOC": "0,000124822445000000",
"COFVHC": "0,000160597191000000",
"PMHGEN": "56,23",
"PMHNOC": "54,03",
"PMHVHC": "52,62",
"SAHGEN": "2,14",
"SAHNOC": "2,05",
"SAHVHC": "2,00",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,56",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,96",
"CCVNOC": "1,82",
"CCVVHC": "1,77"
},
{
"Dia": "26/10/2019",
"Hora": "02-03",
"GEN": "105,17",
"NOC": "56,48",
"VHC": "53,56",
"COFGEN": "0,000064100056000000",
"COFNOC": "0,000117356595000000",
"COFVHC": "0,000158787037000000",
"PMHGEN": "50,26",
"PMHNOC": "48,29",
"PMHVHC": "47,03",
"SAHGEN": "2,35",
"SAHNOC": "2,26",
"SAHVHC": "2,20",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,55",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,87",
"CCVNOC": "1,73",
"CCVVHC": "1,68"
},
{
"Dia": "26/10/2019",
"Hora": "03-04",
"GEN": "102,45",
"NOC": "53,87",
"VHC": "51,02",
"COFGEN": "0,000059549798000000",
"COFNOC": "0,000113408113000000",
"COFVHC": "0,000152391581000000",
"PMHGEN": "47,42",
"PMHNOC": "45,57",
"PMHVHC": "44,38",
"SAHGEN": "2,51",
"SAHNOC": "2,41",
"SAHVHC": "2,35",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,56",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,83",
"CCVNOC": "1,69",
"CCVVHC": "1,65"
},
{
"Dia": "26/10/2019",
"Hora": "04-05",
"GEN": "102,15",
"NOC": "53,58",
"VHC": "50,73",
"COFGEN": "0,000057296575000000",
"COFNOC": "0,000111308472000000",
"COFVHC": "0,000145270809000000",
"PMHGEN": "47,05",
"PMHNOC": "45,21",
"PMHVHC": "44,03",
"SAHGEN": "2,58",
"SAHNOC": "2,48",
"SAHVHC": "2,41",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,56",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,83",
"CCVNOC": "1,69",
"CCVVHC": "1,64"
},
{
"Dia": "26/10/2019",
"Hora": "05-06",
"GEN": "101,62",
"NOC": "53,13",
"VHC": "50,34",
"COFGEN": "0,000057285870000000",
"COFNOC": "0,000111061995000000",
"COFVHC": "0,000141535570000000",
"PMHGEN": "46,55",
"PMHNOC": "44,76",
"PMHVHC": "43,63",
"SAHGEN": "2,60",
"SAHNOC": "2,50",
"SAHVHC": "2,43",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,90",
"INTVHC": "0,87",
"PCAPGEN": "5,54",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,82",
"CCVNOC": "1,68",
"CCVVHC": "1,64"
},
{
"Dia": "26/10/2019",
"Hora": "06-07",
"GEN": "102,36",
"NOC": "53,90",
"VHC": "51,08",
"COFGEN": "0,000060011439000000",
"COFNOC": "0,000113191071000000",
"COFVHC": "0,000139395926000000",
"PMHGEN": "46,58",
"PMHNOC": "44,82",
"PMHVHC": "43,69",
"SAHGEN": "3,32",
"SAHNOC": "3,20",
"SAHVHC": "3,12",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,89",
"INTVHC": "0,87",
"PCAPGEN": "5,51",
"PCAPNOC": "0,92",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,82",
"CCVNOC": "1,69",
"CCVVHC": "1,64"
},
{
"Dia": "26/10/2019",
"Hora": "07-08",
"GEN": "106,73",
"NOC": "58,10",
"VHC": "61,55",
"COFGEN": "0,000067624746000000",
"COFNOC": "0,000113073036000000",
"COFVHC": "0,000130165590000000",
"PMHGEN": "50,24",
"PMHNOC": "48,34",
"PMHVHC": "50,45",
"SAHGEN": "3,98",
"SAHNOC": "3,83",
"SAHVHC": "4,00",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,89",
"INTVHC": "0,93",
"PCAPGEN": "5,50",
"PCAPNOC": "0,92",
"PCAPVHC": "1,30",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,89",
"CCVNOC": "1,75",
"CCVVHC": "1,83"
},
{
"Dia": "26/10/2019",
"Hora": "08-09",
"GEN": "107,75",
"NOC": "59,43",
"VHC": "62,66",
"COFGEN": "0,000083194704000000",
"COFNOC": "0,000083589950000000",
"COFVHC": "0,000069841029000000",
"PMHGEN": "51,74",
"PMHNOC": "50,02",
"PMHVHC": "51,97",
"SAHGEN": "3,62",
"SAHNOC": "3,50",
"SAHVHC": "3,63",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,91",
"PCAPGEN": "5,40",
"PCAPNOC": "0,91",
"PCAPVHC": "1,27",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,89",
"CCVNOC": "1,76",
"CCVVHC": "1,83"
},
{
"Dia": "26/10/2019",
"Hora": "09-10",
"GEN": "110,38",
"NOC": "62,09",
"VHC": "65,34",
"COFGEN": "0,000105869478000000",
"COFNOC": "0,000077963480000000",
"COFVHC": "0,000057355982000000",
"PMHGEN": "55,41",
"PMHNOC": "53,64",
"PMHVHC": "55,65",
"SAHGEN": "2,60",
"SAHNOC": "2,52",
"SAHVHC": "2,61",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,87",
"INTVHC": "0,91",
"PCAPGEN": "5,36",
"PCAPNOC": "0,90",
"PCAPVHC": "1,26",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,92",
"CCVNOC": "1,79",
"CCVVHC": "1,86"
},
{
"Dia": "26/10/2019",
"Hora": "10-11",
"GEN": "108,10",
"NOC": "60,00",
"VHC": "63,02",
"COFGEN": "0,000121833263000000",
"COFNOC": "0,000085468800000000",
"COFVHC": "0,000063770407000000",
"PMHGEN": "53,39",
"PMHNOC": "51,77",
"PMHVHC": "53,58",
"SAHGEN": "2,42",
"SAHNOC": "2,34",
"SAHVHC": "2,42",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,87",
"INTVHC": "0,90",
"PCAPGEN": "5,32",
"PCAPNOC": "0,90",
"PCAPVHC": "1,25",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,88",
"CCVNOC": "1,76",
"CCVVHC": "1,82"
},
{
"Dia": "26/10/2019",
"Hora": "11-12",
"GEN": "104,11",
"NOC": "56,20",
"VHC": "59,04",
"COFGEN": "0,000125947995000000",
"COFNOC": "0,000085228595000000",
"COFVHC": "0,000064070840000000",
"PMHGEN": "50,02",
"PMHNOC": "48,54",
"PMHVHC": "50,20",
"SAHGEN": "1,89",
"SAHNOC": "1,83",
"SAHVHC": "1,90",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,89",
"INTNOC": "0,87",
"INTVHC": "0,90",
"PCAPGEN": "5,31",
"PCAPNOC": "0,90",
"PCAPVHC": "1,25",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,81",
"CCVNOC": "1,70",
"CCVVHC": "1,76"
},
{
"Dia": "26/10/2019",
"Hora": "12-13",
"GEN": "103,61",
"NOC": "55,65",
"VHC": "58,52",
"COFGEN": "0,000128302145000000",
"COFNOC": "0,000082279443000000",
"COFVHC": "0,000063904657000000",
"PMHGEN": "49,50",
"PMHNOC": "47,99",
"PMHVHC": "49,67",
"SAHGEN": "1,90",
"SAHNOC": "1,84",
"SAHVHC": "1,90",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,87",
"INTVHC": "0,90",
"PCAPGEN": "5,32",
"PCAPNOC": "0,90",
"PCAPVHC": "1,25",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,81",
"CCVNOC": "1,69",
"CCVVHC": "1,75"
},
{
"Dia": "26/10/2019",
"Hora": "13-14",
"GEN": "104,03",
"NOC": "122,60",
"VHC": "122,60",
"COFGEN": "0,000134270665000000",
"COFNOC": "0,000080726428000000",
"COFVHC": "0,000063976543000000",
"PMHGEN": "49,98",
"PMHNOC": "50,33",
"PMHVHC": "50,33",
"SAHGEN": "1,85",
"SAHNOC": "1,87",
"SAHVHC": "1,87",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,89",
"INTNOC": "0,90",
"INTVHC": "0,90",
"PCAPGEN": "5,30",
"PCAPNOC": "5,50",
"PCAPVHC": "5,50",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,81",
"CCVNOC": "1,83",
"CCVVHC": "1,83"
},
{
"Dia": "26/10/2019",
"Hora": "14-15",
"GEN": "103,44",
"NOC": "122,00",
"VHC": "122,00",
"COFGEN": "0,000130580837000000",
"COFNOC": "0,000079392022000000",
"COFVHC": "0,000064422150000000",
"PMHGEN": "49,25",
"PMHNOC": "49,60",
"PMHVHC": "49,60",
"SAHGEN": "1,97",
"SAHNOC": "1,98",
"SAHVHC": "1,98",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,90",
"INTVHC": "0,90",
"PCAPGEN": "5,32",
"PCAPNOC": "5,52",
"PCAPVHC": "5,52",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,81",
"CCVNOC": "1,82",
"CCVVHC": "1,82"
},
{
"Dia": "26/10/2019",
"Hora": "15-16",
"GEN": "100,57",
"NOC": "119,16",
"VHC": "119,16",
"COFGEN": "0,000114850139000000",
"COFNOC": "0,000070924506000000",
"COFVHC": "0,000056150579000000",
"PMHGEN": "46,19",
"PMHNOC": "46,55",
"PMHVHC": "46,55",
"SAHGEN": "2,15",
"SAHNOC": "2,17",
"SAHVHC": "2,17",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,36",
"PCAPNOC": "5,57",
"PCAPVHC": "5,57",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,77",
"CCVNOC": "1,79",
"CCVVHC": "1,79"
},
{
"Dia": "26/10/2019",
"Hora": "16-17",
"GEN": "99,90",
"NOC": "118,48",
"VHC": "118,48",
"COFGEN": "0,000105915899000000",
"COFNOC": "0,000065274280000000",
"COFVHC": "0,000051268616000000",
"PMHGEN": "45,44",
"PMHNOC": "45,80",
"PMHVHC": "45,80",
"SAHGEN": "2,25",
"SAHNOC": "2,27",
"SAHVHC": "2,27",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,35",
"PCAPNOC": "5,56",
"PCAPVHC": "5,56",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,76",
"CCVNOC": "1,78",
"CCVVHC": "1,78"
},
{
"Dia": "26/10/2019",
"Hora": "17-18",
"GEN": "102,97",
"NOC": "121,53",
"VHC": "121,53",
"COFGEN": "0,000104178581000000",
"COFNOC": "0,000063611672000000",
"COFVHC": "0,000049947652000000",
"PMHGEN": "48,62",
"PMHNOC": "48,96",
"PMHVHC": "48,96",
"SAHGEN": "2,14",
"SAHNOC": "2,16",
"SAHVHC": "2,16",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,90",
"INTVHC": "0,90",
"PCAPGEN": "5,33",
"PCAPNOC": "5,53",
"PCAPVHC": "5,53",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,80",
"CCVNOC": "1,82",
"CCVVHC": "1,82"
},
{
"Dia": "26/10/2019",
"Hora": "18-19",
"GEN": "107,71",
"NOC": "126,30",
"VHC": "126,30",
"COFGEN": "0,000106669089000000",
"COFNOC": "0,000070000350000000",
"COFVHC": "0,000061100876000000",
"PMHGEN": "53,37",
"PMHNOC": "53,74",
"PMHVHC": "53,74",
"SAHGEN": "2,05",
"SAHNOC": "2,06",
"SAHVHC": "2,06",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,90",
"INTVHC": "0,90",
"PCAPGEN": "5,33",
"PCAPNOC": "5,53",
"PCAPVHC": "5,53",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,87",
"CCVNOC": "1,89",
"CCVVHC": "1,89"
},
{
"Dia": "26/10/2019",
"Hora": "19-20",
"GEN": "118,75",
"NOC": "137,49",
"VHC": "137,49",
"COFGEN": "0,000115010612000000",
"COFNOC": "0,000095780287000000",
"COFVHC": "0,000092687680000000",
"PMHGEN": "64,21",
"PMHNOC": "64,71",
"PMHVHC": "64,71",
"SAHGEN": "2,07",
"SAHNOC": "2,08",
"SAHVHC": "2,08",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,35",
"PCAPNOC": "5,55",
"PCAPVHC": "5,55",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,04",
"CCVNOC": "2,06",
"CCVVHC": "2,06"
},
{
"Dia": "26/10/2019",
"Hora": "20-21",
"GEN": "124,00",
"NOC": "142,78",
"VHC": "142,78",
"COFGEN": "0,000129085428000000",
"COFNOC": "0,000144302922000000",
"COFVHC": "0,000185612441000000",
"PMHGEN": "69,13",
"PMHNOC": "69,67",
"PMHVHC": "69,67",
"SAHGEN": "2,30",
"SAHNOC": "2,32",
"SAHVHC": "2,32",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,36",
"PCAPNOC": "5,56",
"PCAPVHC": "5,56",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,12",
"CCVNOC": "2,14",
"CCVVHC": "2,14"
},
{
"Dia": "26/10/2019",
"Hora": "21-22",
"GEN": "124,16",
"NOC": "143,00",
"VHC": "143,00",
"COFGEN": "0,000133109692000000",
"COFNOC": "0,000151101318000000",
"COFVHC": "0,000197574745000000",
"PMHGEN": "68,50",
"PMHNOC": "69,09",
"PMHVHC": "69,09",
"SAHGEN": "3,05",
"SAHNOC": "3,07",
"SAHVHC": "3,07",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,38",
"PCAPNOC": "5,60",
"PCAPVHC": "5,60",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,13",
"CCVNOC": "2,15",
"CCVVHC": "2,15"
},
{
"Dia": "26/10/2019",
"Hora": "22-23",
"GEN": "120,30",
"NOC": "139,04",
"VHC": "139,04",
"COFGEN": "0,000120157209000000",
"COFNOC": "0,000148137882000000",
"COFVHC": "0,000194906294000000",
"PMHGEN": "64,33",
"PMHNOC": "64,82",
"PMHVHC": "64,82",
"SAHGEN": "3,38",
"SAHNOC": "3,41",
"SAHVHC": "3,41",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,92",
"INTVHC": "0,92",
"PCAPGEN": "5,42",
"PCAPNOC": "5,63",
"PCAPVHC": "5,63",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,08",
"CCVNOC": "2,10",
"CCVVHC": "2,10"
},
{
"Dia": "26/10/2019",
"Hora": "23-24",
"GEN": "118,05",
"NOC": "69,05",
"VHC": "72,93",
"COFGEN": "0,000103870556000000",
"COFNOC": "0,000146233245000000",
"COFVHC": "0,000182184931000000",
"PMHGEN": "61,54",
"PMHNOC": "59,25",
"PMHVHC": "61,80",
"SAHGEN": "3,85",
"SAHNOC": "3,71",
"SAHVHC": "3,87",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,92",
"INTNOC": "0,89",
"INTVHC": "0,93",
"PCAPGEN": "5,49",
"PCAPNOC": "0,92",
"PCAPVHC": "1,29",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,05",
"CCVNOC": "1,91",
"CCVVHC": "2,00"
}
]
}

View File

@ -1,854 +0,0 @@
{
"PVPC": [
{
"Dia": "27/10/2019",
"Hora": "00-01",
"GEN": "115,15",
"NOC": "65,95",
"VHC": "69,94",
"COFGEN": "0,000083408754000000",
"COFNOC": "0,000125204015000000",
"COFVHC": "0,000143740251000000",
"PMHGEN": "59,13",
"PMHNOC": "56,72",
"PMHVHC": "59,37",
"SAHGEN": "3,28",
"SAHNOC": "3,14",
"SAHVHC": "3,29",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,14",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,94",
"PCAPGEN": "5,58",
"PCAPNOC": "0,93",
"PCAPVHC": "1,32",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,03",
"CCVNOC": "1,88",
"CCVVHC": "1,97"
},
{
"Dia": "27/10/2019",
"Hora": "01-02",
"GEN": "109,63",
"NOC": "60,60",
"VHC": "57,48",
"COFGEN": "0,000069962863000000",
"COFNOC": "0,000114629494000000",
"COFVHC": "0,000147622130000000",
"PMHGEN": "53,21",
"PMHNOC": "51,01",
"PMHVHC": "49,61",
"SAHGEN": "3,72",
"SAHNOC": "3,57",
"SAHVHC": "3,47",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,95",
"INTNOC": "0,91",
"INTVHC": "0,88",
"PCAPGEN": "5,61",
"PCAPNOC": "0,94",
"PCAPVHC": "0,73",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,95",
"CCVNOC": "1,80",
"CCVVHC": "1,75"
},
{
"Dia": "27/10/2019",
"Hora": "02-03",
"GEN": "108,41",
"NOC": "59,38",
"VHC": "56,29",
"COFGEN": "0,000065978330000000",
"COFNOC": "0,000111216294000000",
"COFVHC": "0,000145651145000000",
"PMHGEN": "52,09",
"PMHNOC": "49,90",
"PMHVHC": "48,53",
"SAHGEN": "3,62",
"SAHNOC": "3,47",
"SAHVHC": "3,37",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,95",
"INTNOC": "0,91",
"INTVHC": "0,88",
"PCAPGEN": "5,63",
"PCAPNOC": "0,94",
"PCAPVHC": "0,73",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,93",
"CCVNOC": "1,79",
"CCVVHC": "1,73"
},
{
"Dia": "27/10/2019",
"Hora": "03-04",
"GEN": "108,22",
"NOC": "59,31",
"VHC": "56,27",
"COFGEN": "0,000061999708000000",
"COFNOC": "0,000107809474000000",
"COFVHC": "0,000143671560000000",
"PMHGEN": "51,88",
"PMHNOC": "49,78",
"PMHVHC": "48,45",
"SAHGEN": "3,68",
"SAHNOC": "3,53",
"SAHVHC": "3,44",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,59",
"PCAPNOC": "0,93",
"PCAPVHC": "0,73",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,93",
"CCVNOC": "1,78",
"CCVVHC": "1,73"
},
{
"Dia": "27/10/2019",
"Hora": "04-05",
"GEN": "107,03",
"NOC": "58,16",
"VHC": "55,10",
"COFGEN": "0,000057358428000000",
"COFNOC": "0,000103595831000000",
"COFVHC": "0,000139122535000000",
"PMHGEN": "50,53",
"PMHNOC": "48,48",
"PMHVHC": "47,15",
"SAHGEN": "3,85",
"SAHNOC": "3,69",
"SAHVHC": "3,59",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,91",
"INTVHC": "0,88",
"PCAPGEN": "5,60",
"PCAPNOC": "0,93",
"PCAPVHC": "0,73",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,91",
"CCVNOC": "1,76",
"CCVVHC": "1,71"
},
{
"Dia": "27/10/2019",
"Hora": "05-06",
"GEN": "104,79",
"NOC": "56,01",
"VHC": "53,06",
"COFGEN": "0,000055060063000000",
"COFNOC": "0,000101732765000000",
"COFVHC": "0,000134441142000000",
"PMHGEN": "48,28",
"PMHNOC": "46,32",
"PMHVHC": "45,08",
"SAHGEN": "3,91",
"SAHNOC": "3,75",
"SAHVHC": "3,65",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,59",
"PCAPNOC": "0,93",
"PCAPVHC": "0,73",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,87",
"CCVNOC": "1,73",
"CCVVHC": "1,68"
},
{
"Dia": "27/10/2019",
"Hora": "06-07",
"GEN": "104,56",
"NOC": "55,85",
"VHC": "52,94",
"COFGEN": "0,000054511300000000",
"COFNOC": "0,000101250808000000",
"COFVHC": "0,000131206727000000",
"PMHGEN": "48,10",
"PMHNOC": "46,18",
"PMHVHC": "44,98",
"SAHGEN": "3,90",
"SAHNOC": "3,74",
"SAHVHC": "3,65",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,57",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,87",
"CCVNOC": "1,73",
"CCVVHC": "1,68"
},
{
"Dia": "27/10/2019",
"Hora": "07-08",
"GEN": "107,72",
"NOC": "58,93",
"VHC": "55,95",
"COFGEN": "0,000056191283000000",
"COFNOC": "0,000102978398000000",
"COFVHC": "0,000130073563000000",
"PMHGEN": "50,23",
"PMHNOC": "48,26",
"PMHVHC": "47,01",
"SAHGEN": "4,89",
"SAHNOC": "4,70",
"SAHVHC": "4,57",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,56",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,91",
"CCVNOC": "1,77",
"CCVVHC": "1,72"
},
{
"Dia": "27/10/2019",
"Hora": "08-09",
"GEN": "107,80",
"NOC": "59,29",
"VHC": "62,70",
"COFGEN": "0,000060083432000000",
"COFNOC": "0,000100348617000000",
"COFVHC": "0,000118460190000000",
"PMHGEN": "50,94",
"PMHNOC": "49,13",
"PMHVHC": "51,20",
"SAHGEN": "4,38",
"SAHNOC": "4,23",
"SAHVHC": "4,40",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,92",
"INTNOC": "0,89",
"INTVHC": "0,93",
"PCAPGEN": "5,47",
"PCAPNOC": "0,92",
"PCAPVHC": "1,29",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,90",
"CCVNOC": "1,76",
"CCVVHC": "1,84"
},
{
"Dia": "27/10/2019",
"Hora": "09-10",
"GEN": "106,74",
"NOC": "58,40",
"VHC": "61,63",
"COFGEN": "0,000070236674000000",
"COFNOC": "0,000071273888000000",
"COFVHC": "0,000062511624000000",
"PMHGEN": "50,00",
"PMHNOC": "48,29",
"PMHVHC": "50,22",
"SAHGEN": "4,34",
"SAHNOC": "4,20",
"SAHVHC": "4,36",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,92",
"PCAPGEN": "5,42",
"PCAPNOC": "0,91",
"PCAPVHC": "1,28",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,87",
"CCVNOC": "1,74",
"CCVVHC": "1,82"
},
{
"Dia": "27/10/2019",
"Hora": "10-11",
"GEN": "106,13",
"NOC": "57,81",
"VHC": "61,02",
"COFGEN": "0,000089379429000000",
"COFNOC": "0,000066131351000000",
"COFVHC": "0,000053107930000000",
"PMHGEN": "50,32",
"PMHNOC": "48,60",
"PMHVHC": "50,54",
"SAHGEN": "3,43",
"SAHNOC": "3,31",
"SAHVHC": "3,44",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,92",
"PCAPGEN": "5,42",
"PCAPNOC": "0,91",
"PCAPVHC": "1,28",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,86",
"CCVNOC": "1,73",
"CCVVHC": "1,81"
},
{
"Dia": "27/10/2019",
"Hora": "11-12",
"GEN": "105,00",
"NOC": "56,78",
"VHC": "59,91",
"COFGEN": "0,000106229062000000",
"COFNOC": "0,000075658481000000",
"COFVHC": "0,000058816566000000",
"PMHGEN": "50,34",
"PMHNOC": "48,65",
"PMHVHC": "50,56",
"SAHGEN": "2,33",
"SAHNOC": "2,25",
"SAHVHC": "2,34",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,91",
"PCAPGEN": "5,39",
"PCAPNOC": "0,91",
"PCAPVHC": "1,27",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,84",
"CCVNOC": "1,72",
"CCVVHC": "1,79"
},
{
"Dia": "27/10/2019",
"Hora": "12-13",
"GEN": "105,07",
"NOC": "56,79",
"VHC": "59,92",
"COFGEN": "0,000113739886000000",
"COFNOC": "0,000079251893000000",
"COFVHC": "0,000061868784000000",
"PMHGEN": "50,41",
"PMHNOC": "48,69",
"PMHVHC": "50,59",
"SAHGEN": "2,31",
"SAHNOC": "2,23",
"SAHVHC": "2,32",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,91",
"PCAPGEN": "5,40",
"PCAPNOC": "0,91",
"PCAPVHC": "1,27",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,85",
"CCVNOC": "1,72",
"CCVVHC": "1,79"
},
{
"Dia": "27/10/2019",
"Hora": "13-14",
"GEN": "104,67",
"NOC": "123,29",
"VHC": "59,59",
"COFGEN": "0,000116885572000000",
"COFNOC": "0,000077561607000000",
"COFVHC": "0,000061189779000000",
"PMHGEN": "50,08",
"PMHNOC": "50,47",
"PMHVHC": "50,30",
"SAHGEN": "2,29",
"SAHNOC": "2,31",
"SAHVHC": "2,30",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,37",
"PCAPNOC": "5,57",
"PCAPVHC": "1,27",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "2,88",
"CCVGEN": "1,83",
"CCVNOC": "1,85",
"CCVVHC": "1,78"
},
{
"Dia": "27/10/2019",
"Hora": "14-15",
"GEN": "107,41",
"NOC": "126,05",
"VHC": "126,05",
"COFGEN": "0,000122253070000000",
"COFNOC": "0,000076034460000000",
"COFVHC": "0,000059795888000000",
"PMHGEN": "52,87",
"PMHNOC": "53,28",
"PMHVHC": "53,28",
"SAHGEN": "2,20",
"SAHNOC": "2,22",
"SAHVHC": "2,22",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,37",
"PCAPNOC": "5,57",
"PCAPVHC": "5,57",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,87",
"CCVNOC": "1,89",
"CCVVHC": "1,89"
},
{
"Dia": "27/10/2019",
"Hora": "15-16",
"GEN": "108,36",
"NOC": "127,06",
"VHC": "127,06",
"COFGEN": "0,000120316270000000",
"COFNOC": "0,000073732639000000",
"COFVHC": "0,000059483320000000",
"PMHGEN": "53,68",
"PMHNOC": "54,14",
"PMHVHC": "54,14",
"SAHGEN": "2,29",
"SAHNOC": "2,31",
"SAHVHC": "2,31",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,92",
"INTVHC": "0,92",
"PCAPGEN": "5,39",
"PCAPNOC": "5,60",
"PCAPVHC": "5,60",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,89",
"CCVNOC": "1,91",
"CCVVHC": "1,91"
},
{
"Dia": "27/10/2019",
"Hora": "16-17",
"GEN": "106,15",
"NOC": "124,78",
"VHC": "124,78",
"COFGEN": "0,000106276301000000",
"COFNOC": "0,000065442255000000",
"COFVHC": "0,000053614900000000",
"PMHGEN": "51,38",
"PMHNOC": "51,78",
"PMHVHC": "51,78",
"SAHGEN": "2,40",
"SAHNOC": "2,42",
"SAHVHC": "2,42",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,92",
"INTVHC": "0,92",
"PCAPGEN": "5,40",
"PCAPNOC": "5,61",
"PCAPVHC": "5,61",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,86",
"CCVNOC": "1,88",
"CCVVHC": "1,88"
},
{
"Dia": "27/10/2019",
"Hora": "17-18",
"GEN": "105,09",
"NOC": "123,72",
"VHC": "123,72",
"COFGEN": "0,000098092024000000",
"COFNOC": "0,000060340481000000",
"COFVHC": "0,000050280869000000",
"PMHGEN": "51,35",
"PMHNOC": "51,75",
"PMHVHC": "51,75",
"SAHGEN": "1,40",
"SAHNOC": "1,41",
"SAHVHC": "1,41",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,92",
"INTVHC": "0,92",
"PCAPGEN": "5,40",
"PCAPNOC": "5,61",
"PCAPVHC": "5,61",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,85",
"CCVNOC": "1,86",
"CCVVHC": "1,86"
},
{
"Dia": "27/10/2019",
"Hora": "18-19",
"GEN": "108,12",
"NOC": "126,77",
"VHC": "126,77",
"COFGEN": "0,000095857172000000",
"COFNOC": "0,000058545227000000",
"COFVHC": "0,000049936767000000",
"PMHGEN": "54,41",
"PMHNOC": "54,83",
"PMHVHC": "54,83",
"SAHGEN": "1,35",
"SAHNOC": "1,36",
"SAHVHC": "1,36",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,38",
"PCAPNOC": "5,59",
"PCAPVHC": "5,59",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,89",
"CCVNOC": "1,91",
"CCVVHC": "1,91"
},
{
"Dia": "27/10/2019",
"Hora": "19-20",
"GEN": "112,76",
"NOC": "131,51",
"VHC": "131,51",
"COFGEN": "0,000099686581000000",
"COFNOC": "0,000063674261000000",
"COFVHC": "0,000057884599000000",
"PMHGEN": "58,53",
"PMHNOC": "59,03",
"PMHVHC": "59,03",
"SAHGEN": "1,77",
"SAHNOC": "1,79",
"SAHVHC": "1,79",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,92",
"INTVHC": "0,92",
"PCAPGEN": "5,40",
"PCAPNOC": "5,62",
"PCAPVHC": "5,62",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,96",
"CCVNOC": "1,98",
"CCVVHC": "1,98"
},
{
"Dia": "27/10/2019",
"Hora": "20-21",
"GEN": "118,69",
"NOC": "137,48",
"VHC": "137,48",
"COFGEN": "0,000111025948000000",
"COFNOC": "0,000087846097000000",
"COFVHC": "0,000084304207000000",
"PMHGEN": "64,79",
"PMHNOC": "65,35",
"PMHVHC": "65,35",
"SAHGEN": "1,34",
"SAHNOC": "1,35",
"SAHVHC": "1,35",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,92",
"INTVHC": "0,92",
"PCAPGEN": "5,40",
"PCAPNOC": "5,62",
"PCAPVHC": "5,62",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,05",
"CCVNOC": "2,07",
"CCVVHC": "2,07"
},
{
"Dia": "27/10/2019",
"Hora": "21-22",
"GEN": "121,19",
"NOC": "139,94",
"VHC": "139,94",
"COFGEN": "0,000129356812000000",
"COFNOC": "0,000137580750000000",
"COFVHC": "0,000175068439000000",
"PMHGEN": "66,00",
"PMHNOC": "66,51",
"PMHVHC": "66,51",
"SAHGEN": "2,64",
"SAHNOC": "2,66",
"SAHVHC": "2,66",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,38",
"PCAPNOC": "5,58",
"PCAPVHC": "5,58",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,08",
"CCVNOC": "2,10",
"CCVVHC": "2,10"
},
{
"Dia": "27/10/2019",
"Hora": "22-23",
"GEN": "120,21",
"NOC": "138,96",
"VHC": "138,96",
"COFGEN": "0,000132818174000000",
"COFNOC": "0,000143862321000000",
"COFVHC": "0,000185393247000000",
"PMHGEN": "65,72",
"PMHNOC": "66,23",
"PMHVHC": "66,23",
"SAHGEN": "1,94",
"SAHNOC": "1,96",
"SAHVHC": "1,96",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,91",
"INTVHC": "0,91",
"PCAPGEN": "5,38",
"PCAPNOC": "5,59",
"PCAPVHC": "5,59",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,07",
"CCVNOC": "2,09",
"CCVVHC": "2,09"
},
{
"Dia": "27/10/2019",
"Hora": "23-24",
"GEN": "117,85",
"NOC": "68,93",
"VHC": "136,63",
"COFGEN": "0,000117725347000000",
"COFNOC": "0,000138623638000000",
"COFVHC": "0,000180725170000000",
"PMHGEN": "62,92",
"PMHNOC": "60,64",
"PMHVHC": "63,46",
"SAHGEN": "2,28",
"SAHNOC": "2,20",
"SAHVHC": "2,30",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,92",
"INTNOC": "0,89",
"INTVHC": "0,93",
"PCAPGEN": "5,48",
"PCAPNOC": "0,92",
"PCAPVHC": "5,69",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "62,01",
"CCVGEN": "2,05",
"CCVNOC": "1,91",
"CCVVHC": "2,07"
},
{
"Dia": "27/10/2019",
"Hora": "24-25",
"GEN": "118,42",
"NOC": "69,35",
"VHC": "73,34",
"COFGEN": "0,000097485259000000",
"COFNOC": "0,000133828173000000",
"COFVHC": "0,000166082424000000",
"PMHGEN": "63,21",
"PMHNOC": "60,82",
"PMHVHC": "63,52",
"SAHGEN": "2,51",
"SAHNOC": "2,41",
"SAHVHC": "2,52",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,90",
"INTVHC": "0,94",
"PCAPGEN": "5,52",
"PCAPNOC": "0,92",
"PCAPVHC": "1,30",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,07",
"CCVNOC": "1,92",
"CCVVHC": "2,01"
}
]
}

View File

@ -1,820 +0,0 @@
{
"PVPC": [
{
"Dia": "29/10/2019",
"Hora": "00-01",
"GEN": "117,17",
"NOC": "68,21",
"VHC": "72,10",
"COFGEN": "0,000077051997000000",
"COFNOC": "0,000124733002000000",
"COFVHC": "0,000143780107000000",
"PMHGEN": "62,55",
"PMHNOC": "60,23",
"PMHVHC": "62,86",
"SAHGEN": "1,96",
"SAHNOC": "1,89",
"SAHVHC": "1,97",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,89",
"INTVHC": "0,93",
"PCAPGEN": "5,50",
"PCAPNOC": "0,92",
"PCAPVHC": "1,30",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,04",
"CCVNOC": "1,90",
"CCVVHC": "1,99"
},
{
"Dia": "29/10/2019",
"Hora": "01-02",
"GEN": "115,34",
"NOC": "66,27",
"VHC": "63,14",
"COFGEN": "0,000063669626000000",
"COFNOC": "0,000113703738000000",
"COFVHC": "0,000153709241000000",
"PMHGEN": "60,54",
"PMHNOC": "58,17",
"PMHVHC": "56,70",
"SAHGEN": "2,11",
"SAHNOC": "2,02",
"SAHVHC": "1,97",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,90",
"INTVHC": "0,87",
"PCAPGEN": "5,54",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "2,02",
"CCVNOC": "1,88",
"CCVVHC": "1,83"
},
{
"Dia": "29/10/2019",
"Hora": "02-03",
"GEN": "112,37",
"NOC": "63,40",
"VHC": "60,25",
"COFGEN": "0,000057299719000000",
"COFNOC": "0,000107847932000000",
"COFVHC": "0,000151346355000000",
"PMHGEN": "57,42",
"PMHNOC": "55,17",
"PMHVHC": "53,69",
"SAHGEN": "2,27",
"SAHNOC": "2,18",
"SAHVHC": "2,12",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,57",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,98",
"CCVNOC": "1,84",
"CCVVHC": "1,79"
},
{
"Dia": "29/10/2019",
"Hora": "03-04",
"GEN": "111,32",
"NOC": "62,39",
"VHC": "59,27",
"COFGEN": "0,000054631496000000",
"COFNOC": "0,000105135123000000",
"COFVHC": "0,000145712713000000",
"PMHGEN": "55,92",
"PMHNOC": "53,73",
"PMHVHC": "52,29",
"SAHGEN": "2,74",
"SAHNOC": "2,63",
"SAHVHC": "2,56",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,57",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,97",
"CCVNOC": "1,82",
"CCVVHC": "1,77"
},
{
"Dia": "29/10/2019",
"Hora": "04-05",
"GEN": "111,08",
"NOC": "62,17",
"VHC": "59,04",
"COFGEN": "0,000053587732000000",
"COFNOC": "0,000103791403000000",
"COFVHC": "0,000139739507000000",
"PMHGEN": "55,64",
"PMHNOC": "53,46",
"PMHVHC": "52,03",
"SAHGEN": "2,79",
"SAHNOC": "2,68",
"SAHVHC": "2,61",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,14",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,94",
"INTNOC": "0,90",
"INTVHC": "0,88",
"PCAPGEN": "5,56",
"PCAPNOC": "0,93",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,96",
"CCVNOC": "1,82",
"CCVVHC": "1,77"
},
{
"Dia": "29/10/2019",
"Hora": "05-06",
"GEN": "113,57",
"NOC": "64,62",
"VHC": "61,53",
"COFGEN": "0,000054978965000000",
"COFNOC": "0,000104220226000000",
"COFVHC": "0,000135044065000000",
"PMHGEN": "58,23",
"PMHNOC": "55,99",
"PMHVHC": "54,57",
"SAHGEN": "2,69",
"SAHNOC": "2,58",
"SAHVHC": "2,52",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,93",
"INTNOC": "0,90",
"INTVHC": "0,87",
"PCAPGEN": "5,53",
"PCAPNOC": "0,92",
"PCAPVHC": "0,72",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "2,00",
"CCVNOC": "1,85",
"CCVVHC": "1,80"
},
{
"Dia": "29/10/2019",
"Hora": "06-07",
"GEN": "113,48",
"NOC": "64,78",
"VHC": "61,84",
"COFGEN": "0,000063808739000000",
"COFNOC": "0,000109956697000000",
"COFVHC": "0,000134904594000000",
"PMHGEN": "58,13",
"PMHNOC": "56,06",
"PMHVHC": "54,78",
"SAHGEN": "2,80",
"SAHNOC": "2,70",
"SAHVHC": "2,64",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,12",
"INTGEN": "0,92",
"INTNOC": "0,89",
"INTVHC": "0,87",
"PCAPGEN": "5,45",
"PCAPNOC": "0,91",
"PCAPVHC": "0,71",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "0,89",
"CCVGEN": "1,98",
"CCVNOC": "1,84",
"CCVVHC": "1,80"
},
{
"Dia": "29/10/2019",
"Hora": "07-08",
"GEN": "118,40",
"NOC": "69,72",
"VHC": "73,36",
"COFGEN": "0,000086957107000000",
"COFNOC": "0,000119021762000000",
"COFVHC": "0,000131848949000000",
"PMHGEN": "63,73",
"PMHNOC": "61,60",
"PMHVHC": "64,00",
"SAHGEN": "2,12",
"SAHNOC": "2,05",
"SAHVHC": "2,13",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,91",
"PCAPGEN": "5,40",
"PCAPNOC": "0,91",
"PCAPVHC": "1,27",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,05",
"CCVNOC": "1,91",
"CCVVHC": "1,99"
},
{
"Dia": "29/10/2019",
"Hora": "08-09",
"GEN": "117,71",
"NOC": "69,47",
"VHC": "72,71",
"COFGEN": "0,000103659543000000",
"COFNOC": "0,000093080441000000",
"COFVHC": "0,000078478538000000",
"PMHGEN": "63,59",
"PMHNOC": "61,75",
"PMHVHC": "63,81",
"SAHGEN": "1,76",
"SAHNOC": "1,71",
"SAHVHC": "1,77",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,12",
"FOSVHC": "0,13",
"INTGEN": "0,89",
"INTNOC": "0,86",
"INTVHC": "0,89",
"PCAPGEN": "5,27",
"PCAPNOC": "0,89",
"PCAPVHC": "1,24",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "2,01",
"CCVNOC": "1,89",
"CCVVHC": "1,96"
},
{
"Dia": "29/10/2019",
"Hora": "09-10",
"GEN": "115,84",
"NOC": "67,79",
"VHC": "70,80",
"COFGEN": "0,000109607743000000",
"COFNOC": "0,000077907419000000",
"COFVHC": "0,000061476325000000",
"PMHGEN": "62,27",
"PMHNOC": "60,57",
"PMHVHC": "62,44",
"SAHGEN": "1,29",
"SAHNOC": "1,25",
"SAHVHC": "1,29",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,12",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,86",
"INTVHC": "0,88",
"PCAPGEN": "5,23",
"PCAPNOC": "0,88",
"PCAPVHC": "1,23",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,98",
"CCVNOC": "1,86",
"CCVVHC": "1,92"
},
{
"Dia": "29/10/2019",
"Hora": "10-11",
"GEN": "114,70",
"NOC": "66,74",
"VHC": "69,67",
"COFGEN": "0,000115808394000000",
"COFNOC": "0,000078426619000000",
"COFVHC": "0,000062221967000000",
"PMHGEN": "61,05",
"PMHNOC": "59,42",
"PMHVHC": "61,21",
"SAHGEN": "1,41",
"SAHNOC": "1,37",
"SAHVHC": "1,41",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,12",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,86",
"INTVHC": "0,88",
"PCAPGEN": "5,22",
"PCAPNOC": "0,88",
"PCAPVHC": "1,23",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,96",
"CCVNOC": "1,84",
"CCVVHC": "1,90"
},
{
"Dia": "29/10/2019",
"Hora": "11-12",
"GEN": "114,45",
"NOC": "66,51",
"VHC": "69,43",
"COFGEN": "0,000117753360000000",
"COFNOC": "0,000076432674000000",
"COFVHC": "0,000061112533000000",
"PMHGEN": "60,85",
"PMHNOC": "59,23",
"PMHVHC": "61,01",
"SAHGEN": "1,37",
"SAHNOC": "1,34",
"SAHVHC": "1,38",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,12",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,85",
"INTVHC": "0,88",
"PCAPGEN": "5,21",
"PCAPNOC": "0,88",
"PCAPVHC": "1,23",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,95",
"CCVNOC": "1,84",
"CCVVHC": "1,90"
},
{
"Dia": "29/10/2019",
"Hora": "12-13",
"GEN": "114,46",
"NOC": "133,04",
"VHC": "69,45",
"COFGEN": "0,000121492044000000",
"COFNOC": "0,000074703573000000",
"COFVHC": "0,000061457855000000",
"PMHGEN": "60,95",
"PMHNOC": "61,33",
"PMHVHC": "61,11",
"SAHGEN": "1,30",
"SAHNOC": "1,31",
"SAHVHC": "1,31",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,88",
"INTVHC": "0,88",
"PCAPGEN": "5,20",
"PCAPNOC": "5,39",
"PCAPVHC": "1,22",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "2,88",
"CCVGEN": "1,95",
"CCVNOC": "1,97",
"CCVVHC": "1,90"
},
{
"Dia": "29/10/2019",
"Hora": "13-14",
"GEN": "113,37",
"NOC": "131,94",
"VHC": "131,94",
"COFGEN": "0,000126490319000000",
"COFNOC": "0,000074777760000000",
"COFVHC": "0,000060760068000000",
"PMHGEN": "59,86",
"PMHNOC": "60,24",
"PMHVHC": "60,24",
"SAHGEN": "1,32",
"SAHNOC": "1,33",
"SAHVHC": "1,33",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,87",
"INTNOC": "0,88",
"INTVHC": "0,88",
"PCAPGEN": "5,19",
"PCAPNOC": "5,38",
"PCAPVHC": "5,38",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,93",
"CCVNOC": "1,95",
"CCVVHC": "1,95"
},
{
"Dia": "29/10/2019",
"Hora": "14-15",
"GEN": "112,88",
"NOC": "131,46",
"VHC": "131,46",
"COFGEN": "0,000120771211000000",
"COFNOC": "0,000072095790000000",
"COFVHC": "0,000058765117000000",
"PMHGEN": "59,31",
"PMHNOC": "59,68",
"PMHVHC": "59,68",
"SAHGEN": "1,37",
"SAHNOC": "1,38",
"SAHVHC": "1,38",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,88",
"INTVHC": "0,88",
"PCAPGEN": "5,21",
"PCAPNOC": "5,40",
"PCAPVHC": "5,40",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,93",
"CCVNOC": "1,94",
"CCVVHC": "1,94"
},
{
"Dia": "29/10/2019",
"Hora": "15-16",
"GEN": "115,75",
"NOC": "134,41",
"VHC": "134,41",
"COFGEN": "0,000110808247000000",
"COFNOC": "0,000066006577000000",
"COFVHC": "0,000053763013000000",
"PMHGEN": "62,14",
"PMHNOC": "62,58",
"PMHVHC": "62,58",
"SAHGEN": "1,34",
"SAHNOC": "1,35",
"SAHVHC": "1,35",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,89",
"INTVHC": "0,89",
"PCAPGEN": "5,23",
"PCAPNOC": "5,42",
"PCAPVHC": "5,42",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "1,98",
"CCVNOC": "1,99",
"CCVVHC": "1,99"
},
{
"Dia": "29/10/2019",
"Hora": "16-17",
"GEN": "118,08",
"NOC": "136,75",
"VHC": "136,75",
"COFGEN": "0,000107924950000000",
"COFNOC": "0,000063090606000000",
"COFVHC": "0,000052115396000000",
"PMHGEN": "64,48",
"PMHNOC": "64,93",
"PMHVHC": "64,93",
"SAHGEN": "1,31",
"SAHNOC": "1,32",
"SAHVHC": "1,32",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,89",
"INTVHC": "0,89",
"PCAPGEN": "5,22",
"PCAPNOC": "5,42",
"PCAPVHC": "5,42",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,01",
"CCVNOC": "2,03",
"CCVVHC": "2,03"
},
{
"Dia": "29/10/2019",
"Hora": "17-18",
"GEN": "121,32",
"NOC": "139,95",
"VHC": "139,95",
"COFGEN": "0,000111993776000000",
"COFNOC": "0,000063840323000000",
"COFVHC": "0,000053264660000000",
"PMHGEN": "67,88",
"PMHNOC": "68,30",
"PMHVHC": "68,30",
"SAHGEN": "1,10",
"SAHNOC": "1,11",
"SAHVHC": "1,11",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,88",
"INTVHC": "0,88",
"PCAPGEN": "5,22",
"PCAPNOC": "5,41",
"PCAPVHC": "5,41",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,06",
"CCVNOC": "2,07",
"CCVVHC": "2,07"
},
{
"Dia": "29/10/2019",
"Hora": "18-19",
"GEN": "126,19",
"NOC": "144,85",
"VHC": "144,85",
"COFGEN": "0,000117118878000000",
"COFNOC": "0,000072058416000000",
"COFVHC": "0,000066417528000000",
"PMHGEN": "69,04",
"PMHNOC": "69,47",
"PMHVHC": "69,47",
"SAHGEN": "4,73",
"SAHNOC": "4,76",
"SAHVHC": "4,76",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,89",
"INTVHC": "0,89",
"PCAPGEN": "5,22",
"PCAPNOC": "5,42",
"PCAPVHC": "5,42",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,13",
"CCVNOC": "2,15",
"CCVVHC": "2,15"
},
{
"Dia": "29/10/2019",
"Hora": "19-20",
"GEN": "125,34",
"NOC": "144,06",
"VHC": "144,06",
"COFGEN": "0,000128443388000000",
"COFNOC": "0,000098772457000000",
"COFVHC": "0,000100678475000000",
"PMHGEN": "68,61",
"PMHNOC": "69,09",
"PMHVHC": "69,09",
"SAHGEN": "4,31",
"SAHNOC": "4,34",
"SAHVHC": "4,34",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,88",
"INTNOC": "0,89",
"INTVHC": "0,89",
"PCAPGEN": "5,24",
"PCAPNOC": "5,43",
"PCAPVHC": "5,43",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,12",
"CCVNOC": "2,14",
"CCVVHC": "2,14"
},
{
"Dia": "29/10/2019",
"Hora": "20-21",
"GEN": "120,62",
"NOC": "139,31",
"VHC": "139,31",
"COFGEN": "0,000144847952000000",
"COFNOC": "0,000148736569000000",
"COFVHC": "0,000192706770000000",
"PMHGEN": "67,11",
"PMHNOC": "67,58",
"PMHVHC": "67,58",
"SAHGEN": "1,12",
"SAHNOC": "1,12",
"SAHVHC": "1,12",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,89",
"INTNOC": "0,89",
"INTVHC": "0,89",
"PCAPGEN": "5,27",
"PCAPNOC": "5,47",
"PCAPVHC": "5,47",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,06",
"CCVNOC": "2,07",
"CCVVHC": "2,07"
},
{
"Dia": "29/10/2019",
"Hora": "21-22",
"GEN": "120,67",
"NOC": "139,36",
"VHC": "139,36",
"COFGEN": "0,000143400205000000",
"COFNOC": "0,000153448551000000",
"COFVHC": "0,000201113372000000",
"PMHGEN": "66,43",
"PMHNOC": "66,90",
"PMHVHC": "66,90",
"SAHGEN": "1,80",
"SAHNOC": "1,81",
"SAHVHC": "1,81",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,89",
"INTNOC": "0,90",
"INTVHC": "0,90",
"PCAPGEN": "5,30",
"PCAPNOC": "5,50",
"PCAPVHC": "5,50",
"TEUGEN": "44,03",
"TEUNOC": "62,01",
"TEUVHC": "62,01",
"CCVGEN": "2,06",
"CCVNOC": "2,08",
"CCVVHC": "2,08"
},
{
"Dia": "29/10/2019",
"Hora": "22-23",
"GEN": "117,80",
"NOC": "69,35",
"VHC": "136,53",
"COFGEN": "0,000122948482000000",
"COFNOC": "0,000146077289000000",
"COFVHC": "0,000194614149000000",
"PMHGEN": "63,25",
"PMHNOC": "61,28",
"PMHVHC": "63,75",
"SAHGEN": "2,10",
"SAHNOC": "2,03",
"SAHVHC": "2,11",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,90",
"INTNOC": "0,87",
"INTVHC": "0,91",
"PCAPGEN": "5,34",
"PCAPNOC": "0,90",
"PCAPVHC": "5,54",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "62,01",
"CCVGEN": "2,03",
"CCVNOC": "1,90",
"CCVVHC": "2,04"
},
{
"Dia": "29/10/2019",
"Hora": "23-24",
"GEN": "111,95",
"NOC": "63,48",
"VHC": "66,87",
"COFGEN": "0,000098841799000000",
"COFNOC": "0,000139677463000000",
"COFVHC": "0,000176886301000000",
"PMHGEN": "56,97",
"PMHNOC": "55,07",
"PMHVHC": "57,22",
"SAHGEN": "2,52",
"SAHNOC": "2,44",
"SAHVHC": "2,53",
"FOMGEN": "0,03",
"FOMNOC": "0,03",
"FOMVHC": "0,03",
"FOSGEN": "0,13",
"FOSNOC": "0,13",
"FOSVHC": "0,13",
"INTGEN": "0,91",
"INTNOC": "0,88",
"INTVHC": "0,91",
"PCAPGEN": "5,40",
"PCAPNOC": "0,91",
"PCAPVHC": "1,27",
"TEUGEN": "44,03",
"TEUNOC": "2,22",
"TEUVHC": "2,88",
"CCVGEN": "1,95",
"CCVNOC": "1,82",
"CCVVHC": "1,89"
}
]
}

View File

@ -1,604 +0,0 @@
{
"PVPC": [
{
"Dia": "01/06/2021",
"Hora": "00-01",
"PCB": "116,33",
"CYM": "116,33",
"COF2TD": "0,000088075182000000",
"PMHPCB": "104,00",
"PMHCYM": "104,00",
"SAHPCB": "3,56",
"SAHCYM": "3,56",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,57",
"CCVCYM": "2,57",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "01-02",
"PCB": "115,95",
"CYM": "115,95",
"COF2TD": "0,000073094842000000",
"PMHPCB": "103,18",
"PMHCYM": "103,18",
"SAHPCB": "3,99",
"SAHCYM": "3,99",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,58",
"CCVCYM": "2,58",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "02-03",
"PCB": "114,89",
"CYM": "114,89",
"COF2TD": "0,000065114032000000",
"PMHPCB": "101,87",
"PMHCYM": "101,87",
"SAHPCB": "4,25",
"SAHCYM": "4,25",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,56",
"CCVCYM": "2,56",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "03-04",
"PCB": "114,96",
"CYM": "114,96",
"COF2TD": "0,000061272596000000",
"PMHPCB": "102,01",
"PMHCYM": "102,01",
"SAHPCB": "4,19",
"SAHCYM": "4,19",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,57",
"CCVCYM": "2,57",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "04-05",
"PCB": "114,84",
"CYM": "114,84",
"COF2TD": "0,000059563056000000",
"PMHPCB": "101,87",
"PMHCYM": "101,87",
"SAHPCB": "4,21",
"SAHCYM": "4,21",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,56",
"CCVCYM": "2,56",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "05-06",
"PCB": "116,03",
"CYM": "116,03",
"COF2TD": "0,000059907686000000",
"PMHPCB": "103,14",
"PMHCYM": "103,14",
"SAHPCB": "4,11",
"SAHCYM": "4,11",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,58",
"CCVCYM": "2,58",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "06-07",
"PCB": "116,29",
"CYM": "116,29",
"COF2TD": "0,000062818713000000",
"PMHPCB": "103,64",
"PMHCYM": "103,64",
"SAHPCB": "3,88",
"SAHCYM": "3,88",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,57",
"CCVCYM": "2,57",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "07-08",
"PCB": "115,70",
"CYM": "115,70",
"COF2TD": "0,000072575564000000",
"PMHPCB": "103,85",
"PMHCYM": "103,85",
"SAHPCB": "3,10",
"SAHCYM": "3,10",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,00",
"PCAPCYM": "0,00",
"TEUPCB": "6,00",
"TEUCYM": "6,00",
"CCVPCB": "2,55",
"CCVCYM": "2,55",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "08-09",
"PCB": "152,89",
"CYM": "152,89",
"COF2TD": "0,000086825264000000",
"PMHPCB": "105,65",
"PMHCYM": "105,65",
"SAHPCB": "2,36",
"SAHCYM": "2,36",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,34",
"PCAPCYM": "0,34",
"TEUPCB": "41,77",
"TEUCYM": "41,77",
"CCVPCB": "2,57",
"CCVCYM": "2,57",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "09-10",
"PCB": "150,83",
"CYM": "150,83",
"COF2TD": "0,000095768317000000",
"PMHPCB": "103,77",
"PMHCYM": "103,77",
"SAHPCB": "2,24",
"SAHCYM": "2,24",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,34",
"PCAPCYM": "0,34",
"TEUPCB": "41,77",
"TEUCYM": "41,77",
"CCVPCB": "2,53",
"CCVCYM": "2,53",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "10-11",
"PCB": "242,62",
"CYM": "149,28",
"COF2TD": "0,000102672431000000",
"PMHPCB": "102,38",
"PMHCYM": "102,11",
"SAHPCB": "2,38",
"SAHCYM": "2,37",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,01",
"PCAPCYM": "0,34",
"TEUPCB": "133,12",
"TEUCYM": "41,77",
"CCVPCB": "2,54",
"CCVCYM": "2,51",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "11-12",
"PCB": "240,50",
"CYM": "240,50",
"COF2TD": "0,000105691470000000",
"PMHPCB": "100,14",
"PMHCYM": "100,14",
"SAHPCB": "2,52",
"SAHCYM": "2,52",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,02",
"PCAPCYM": "2,02",
"TEUPCB": "133,12",
"TEUCYM": "133,12",
"CCVPCB": "2,51",
"CCVCYM": "2,51",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "12-13",
"PCB": "238,09",
"CYM": "238,09",
"COF2TD": "0,000110462952000000",
"PMHPCB": "97,58",
"PMHCYM": "97,58",
"SAHPCB": "2,71",
"SAHCYM": "2,71",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,02",
"PCAPCYM": "2,02",
"TEUPCB": "133,12",
"TEUCYM": "133,12",
"CCVPCB": "2,47",
"CCVCYM": "2,47",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "13-14",
"PCB": "235,30",
"CYM": "235,30",
"COF2TD": "0,000119052052000000",
"PMHPCB": "94,65",
"PMHCYM": "94,65",
"SAHPCB": "2,89",
"SAHCYM": "2,89",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,02",
"PCAPCYM": "2,02",
"TEUPCB": "133,12",
"TEUCYM": "133,12",
"CCVPCB": "2,43",
"CCVCYM": "2,43",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "14-15",
"PCB": "137,96",
"CYM": "231,28",
"COF2TD": "0,000117990009000000",
"PMHPCB": "89,95",
"PMHCYM": "90,19",
"SAHPCB": "3,37",
"SAHCYM": "3,38",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,34",
"PCAPCYM": "2,03",
"TEUPCB": "41,77",
"TEUCYM": "133,12",
"CCVPCB": "2,34",
"CCVCYM": "2,37",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "15-16",
"PCB": "132,88",
"CYM": "132,88",
"COF2TD": "0,000108598330000000",
"PMHPCB": "84,43",
"PMHCYM": "84,43",
"SAHPCB": "3,89",
"SAHCYM": "3,89",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,34",
"PCAPCYM": "0,34",
"TEUPCB": "41,77",
"TEUCYM": "41,77",
"CCVPCB": "2,26",
"CCVCYM": "2,26",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "16-17",
"PCB": "131,93",
"CYM": "131,93",
"COF2TD": "0,000104114191000000",
"PMHPCB": "83,66",
"PMHCYM": "83,66",
"SAHPCB": "3,73",
"SAHCYM": "3,73",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,34",
"PCAPCYM": "0,34",
"TEUPCB": "41,77",
"TEUCYM": "41,77",
"CCVPCB": "2,25",
"CCVCYM": "2,25",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "17-18",
"PCB": "135,99",
"CYM": "135,99",
"COF2TD": "0,000105171071000000",
"PMHPCB": "88,07",
"PMHCYM": "88,07",
"SAHPCB": "3,31",
"SAHCYM": "3,31",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,34",
"PCAPCYM": "0,34",
"TEUPCB": "41,77",
"TEUCYM": "41,77",
"CCVPCB": "2,31",
"CCVCYM": "2,31",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "18-19",
"PCB": "231,44",
"CYM": "138,13",
"COF2TD": "0,000106417649000000",
"PMHPCB": "90,57",
"PMHCYM": "90,33",
"SAHPCB": "3,16",
"SAHCYM": "3,15",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,16",
"FOSCYM": "0,16",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,02",
"PCAPCYM": "0,34",
"TEUPCB": "133,12",
"TEUCYM": "41,77",
"CCVPCB": "2,37",
"CCVCYM": "2,34",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "19-20",
"PCB": "240,40",
"CYM": "240,40",
"COF2TD": "0,000108017615000000",
"PMHPCB": "99,53",
"PMHCYM": "99,53",
"SAHPCB": "3,00",
"SAHCYM": "3,00",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,04",
"PCAPCYM": "2,04",
"TEUPCB": "133,12",
"TEUCYM": "133,12",
"CCVPCB": "2,52",
"CCVCYM": "2,52",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "20-21",
"PCB": "246,20",
"CYM": "246,20",
"COF2TD": "0,000114631042000000",
"PMHPCB": "104,32",
"PMHCYM": "104,32",
"SAHPCB": "3,90",
"SAHCYM": "3,90",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,05",
"PCAPCYM": "2,05",
"TEUPCB": "133,12",
"TEUCYM": "133,12",
"CCVPCB": "2,61",
"CCVCYM": "2,61",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "21-22",
"PCB": "248,08",
"CYM": "248,08",
"COF2TD": "0,000127585671000000",
"PMHPCB": "107,28",
"PMHCYM": "107,28",
"SAHPCB": "2,78",
"SAHCYM": "2,78",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "2,06",
"PCAPCYM": "2,06",
"TEUPCB": "133,12",
"TEUCYM": "133,12",
"CCVPCB": "2,64",
"CCVCYM": "2,64",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "22-23",
"PCB": "155,91",
"CYM": "249,41",
"COF2TD": "0,000130129026000000",
"PMHPCB": "108,02",
"PMHCYM": "108,39",
"SAHPCB": "2,93",
"SAHCYM": "2,94",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,35",
"PCAPCYM": "2,09",
"TEUPCB": "41,77",
"TEUCYM": "133,12",
"CCVPCB": "2,64",
"CCVCYM": "2,67",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
},
{
"Dia": "01/06/2021",
"Hora": "23-24",
"PCB": "156,50",
"CYM": "156,50",
"COF2TD": "0,000110367990000000",
"PMHPCB": "108,02",
"PMHCYM": "108,02",
"SAHPCB": "3,50",
"SAHCYM": "3,50",
"FOMPCB": "0,03",
"FOMCYM": "0,03",
"FOSPCB": "0,17",
"FOSCYM": "0,17",
"INTPCB": "0,00",
"INTCYM": "0,00",
"PCAPPCB": "0,35",
"PCAPCYM": "0,35",
"TEUPCB": "41,77",
"TEUCYM": "41,77",
"CCVPCB": "2,66",
"CCVCYM": "2,66",
"EDSRPCB": "0,00",
"EDSRCYM": "0,00"
}
]
}

View File

@ -0,0 +1,154 @@
{
"data": {
"type": "Precios mercado peninsular en tiempo real",
"id": "mer13",
"attributes": {
"title": "Precios mercado peninsular en tiempo real",
"last-update": "2021-05-31T20:19:18.000+02:00",
"description": null
},
"meta": {
"cache-control": {
"cache": "MISS"
}
}
},
"included": [
{
"type": "PVPC (\u20ac\/MWh)",
"id": "1001",
"groupId": null,
"attributes": {
"title": "PVPC (\u20ac\/MWh)",
"description": null,
"color": "#ffcf09",
"type": null,
"magnitude": "price",
"composite": false,
"last-update": "2021-05-31T20:19:18.000+02:00",
"values": [
{
"value": 116.33,
"percentage": 1,
"datetime": "2021-06-01T00:00:00.000+02:00"
},
{
"value": 115.95,
"percentage": 1,
"datetime": "2021-06-01T01:00:00.000+02:00"
},
{
"value": 114.89,
"percentage": 1,
"datetime": "2021-06-01T02:00:00.000+02:00"
},
{
"value": 114.96,
"percentage": 1,
"datetime": "2021-06-01T03:00:00.000+02:00"
},
{
"value": 114.84,
"percentage": 1,
"datetime": "2021-06-01T04:00:00.000+02:00"
},
{
"value": 116.03,
"percentage": 1,
"datetime": "2021-06-01T05:00:00.000+02:00"
},
{
"value": 116.29,
"percentage": 1,
"datetime": "2021-06-01T06:00:00.000+02:00"
},
{
"value": 115.7,
"percentage": 1,
"datetime": "2021-06-01T07:00:00.000+02:00"
},
{
"value": 152.89,
"percentage": 1,
"datetime": "2021-06-01T08:00:00.000+02:00"
},
{
"value": 150.83,
"percentage": 1,
"datetime": "2021-06-01T09:00:00.000+02:00"
},
{
"value": 149.28,
"percentage": 1,
"datetime": "2021-06-01T10:00:00.000+02:00"
},
{
"value": 240.5,
"percentage": 1,
"datetime": "2021-06-01T11:00:00.000+02:00"
},
{
"value": 238.09,
"percentage": 1,
"datetime": "2021-06-01T12:00:00.000+02:00"
},
{
"value": 235.3,
"percentage": 1,
"datetime": "2021-06-01T13:00:00.000+02:00"
},
{
"value": 231.28,
"percentage": 1,
"datetime": "2021-06-01T14:00:00.000+02:00"
},
{
"value": 132.88,
"percentage": 1,
"datetime": "2021-06-01T15:00:00.000+02:00"
},
{
"value": 131.93,
"percentage": 1,
"datetime": "2021-06-01T16:00:00.000+02:00"
},
{
"value": 135.99,
"percentage": 1,
"datetime": "2021-06-01T17:00:00.000+02:00"
},
{
"value": 138.13,
"percentage": 1,
"datetime": "2021-06-01T18:00:00.000+02:00"
},
{
"value": 240.4,
"percentage": 1,
"datetime": "2021-06-01T19:00:00.000+02:00"
},
{
"value": 246.2,
"percentage": 1,
"datetime": "2021-06-01T20:00:00.000+02:00"
},
{
"value": 248.08,
"percentage": 1,
"datetime": "2021-06-01T21:00:00.000+02:00"
},
{
"value": 249.41,
"percentage": 1,
"datetime": "2021-06-01T22:00:00.000+02:00"
},
{
"value": 156.5,
"percentage": 1,
"datetime": "2021-06-01T23:00:00.000+02:00"
}
]
}
}
]
}

View File

@ -90,10 +90,9 @@ async def test_config_flow(
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("sensor.test") state = hass.states.get("sensor.test")
check_valid_state(state, tariff=TARIFFS[1]) check_valid_state(state, tariff=TARIFFS[1])
price_pbc = state.state
assert pvpc_aioclient_mock.call_count == 2 assert pvpc_aioclient_mock.call_count == 2
assert state.attributes["period"] == "P2" assert state.attributes["period"] == "P1"
assert state.attributes["next_period"] == "P1" assert state.attributes["next_period"] == "P2"
assert state.attributes["available_power"] == 4600 assert state.attributes["available_power"] == 4600
# check options flow # check options flow
@ -111,10 +110,8 @@ async def test_config_flow(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("sensor.test") state = hass.states.get("sensor.test")
price_cym = state.state
check_valid_state(state, tariff=TARIFFS[0]) check_valid_state(state, tariff=TARIFFS[0])
assert pvpc_aioclient_mock.call_count == 3 assert pvpc_aioclient_mock.call_count == 3
assert state.attributes["period"] == "P2" assert state.attributes["period"] == "P2"
assert state.attributes["next_period"] == "P1" assert state.attributes["next_period"] == "P1"
assert state.attributes["available_power"] == 3000 assert state.attributes["available_power"] == 3000
assert price_cym < price_pbc

View File

@ -11,100 +11,19 @@ from homeassistant.components.pvpc_hourly_pricing import (
TARIFFS, TARIFFS,
) )
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
from homeassistant.core import ATTR_NOW, EVENT_TIME_CHANGED
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .conftest import check_valid_state from .conftest import check_valid_state
from tests.common import MockConfigEntry, date_util, mock_registry from tests.common import (
MockConfigEntry,
async_fire_time_changed,
date_util,
mock_registry,
)
from tests.test_util.aiohttp import AiohttpClientMocker from tests.test_util.aiohttp import AiohttpClientMocker
async def _process_time_step(
hass, mock_data, key_state=None, value=None, tariff="discrimination", delta_min=60
):
state = hass.states.get("sensor.test_dst")
check_valid_state(state, tariff=tariff, value=value, key_attr=key_state)
mock_data["return_time"] += timedelta(minutes=delta_min)
hass.bus.async_fire(EVENT_TIME_CHANGED, {ATTR_NOW: mock_data["return_time"]})
await hass.async_block_till_done()
return state
async def test_sensor_availability(
hass, caplog, legacy_patchable_time, pvpc_aioclient_mock: AiohttpClientMocker
):
"""Test sensor availability and handling of cloud access."""
hass.config.time_zone = dt_util.get_time_zone("Europe/Madrid")
config_entry = MockConfigEntry(
domain=DOMAIN, data={CONF_NAME: "test_dst", ATTR_TARIFF: "discrimination"}
)
config_entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
mock_data = {"return_time": datetime(2019, 10, 27, 20, 0, 0, tzinfo=date_util.UTC)}
def mock_now():
return mock_data["return_time"]
with patch("homeassistant.util.dt.utcnow", new=mock_now):
assert await hass.config_entries.async_setup(config_entry.entry_id)
# check migration
current_entries = hass.config_entries.async_entries(DOMAIN)
assert len(current_entries) == 1
migrated_entry = current_entries[0]
assert migrated_entry.version == 1
assert migrated_entry.data[ATTR_POWER] == migrated_entry.data[ATTR_POWER_P3]
assert migrated_entry.data[ATTR_TARIFF] == TARIFFS[0]
await hass.async_block_till_done()
caplog.clear()
assert pvpc_aioclient_mock.call_count == 2
await _process_time_step(hass, mock_data, "price_21h", 0.13896)
await _process_time_step(hass, mock_data, "price_22h", 0.06893)
assert pvpc_aioclient_mock.call_count == 4
await _process_time_step(hass, mock_data, "price_23h", 0.06935)
assert pvpc_aioclient_mock.call_count == 5
# sensor has no more prices, state is "unavailable" from now on
await _process_time_step(hass, mock_data, value="unavailable")
await _process_time_step(hass, mock_data, value="unavailable")
num_errors = sum(
1
for x in caplog.records
if x.levelno == logging.ERROR and "unknown job listener" not in x.msg
)
num_warnings = sum(1 for x in caplog.records if x.levelno == logging.WARNING)
assert num_warnings == 1
assert num_errors == 0
assert pvpc_aioclient_mock.call_count == 9
# check that it is silent until it becomes available again
caplog.clear()
with caplog.at_level(logging.WARNING):
# silent mode
for _ in range(21):
await _process_time_step(hass, mock_data, value="unavailable")
assert pvpc_aioclient_mock.call_count == 30
assert len(caplog.messages) == 0
# warning about data access recovered
await _process_time_step(hass, mock_data, value="unavailable")
assert pvpc_aioclient_mock.call_count == 31
assert len(caplog.messages) == 1
assert caplog.records[0].levelno == logging.WARNING
# working ok again
await _process_time_step(hass, mock_data, "price_00h", value=0.06821)
assert pvpc_aioclient_mock.call_count == 32
await _process_time_step(hass, mock_data, "price_01h", value=0.06627)
assert pvpc_aioclient_mock.call_count == 33
assert len(caplog.messages) == 1
assert caplog.records[0].levelno == logging.WARNING
async def test_multi_sensor_migration( async def test_multi_sensor_migration(
hass, caplog, legacy_patchable_time, pvpc_aioclient_mock: AiohttpClientMocker hass, caplog, legacy_patchable_time, pvpc_aioclient_mock: AiohttpClientMocker
): ):
@ -139,7 +58,7 @@ async def test_multi_sensor_migration(
assert len(hass.config_entries.async_entries(DOMAIN)) == 2 assert len(hass.config_entries.async_entries(DOMAIN)) == 2
assert len(entity_reg.entities) == 2 assert len(entity_reg.entities) == 2
mock_data = {"return_time": datetime(2019, 10, 27, 20, tzinfo=date_util.UTC)} mock_data = {"return_time": datetime(2021, 6, 1, 21, tzinfo=date_util.UTC)}
def mock_now(): def mock_now():
return mock_data["return_time"] return mock_data["return_time"]
@ -164,3 +83,15 @@ async def test_multi_sensor_migration(
await hass.async_block_till_done() await hass.async_block_till_done()
assert pvpc_aioclient_mock.call_count == 2 assert pvpc_aioclient_mock.call_count == 2
# check state and availability
state = hass.states.get("sensor.test_pvpc_1")
check_valid_state(state, tariff=TARIFFS[0], value=0.1565)
mock_data["return_time"] += timedelta(minutes=60)
async_fire_time_changed(hass, mock_data["return_time"])
await list(hass.data[DOMAIN].values())[0].async_refresh()
await hass.async_block_till_done()
state = hass.states.get("sensor.test_pvpc_1")
check_valid_state(state, tariff=TARIFFS[0], value="unavailable")
assert pvpc_aioclient_mock.call_count == 3