diff --git a/custom_components/rbfa/API.py b/custom_components/rbfa/API.py index fd7ad85..b339553 100644 --- a/custom_components/rbfa/API.py +++ b/custom_components/rbfa/API.py @@ -7,7 +7,7 @@ from homeassistant.util import dt as dt_util from homeassistant.components import persistent_notification -from .const import * +from .const import DOMAIN, VARIABLES, HASHES, REQUIRED, TZ _LOGGER = logging.getLogger(__name__) @@ -17,9 +17,7 @@ class TeamApp(object): def __init__(self, hass, team): self.teamdata = None - self.upcoming = None self.matchdata = {'upcoming': None, 'lastmatch': None} - self.lastmatch = None self.hass = hass self.team = team self.collections = []; @@ -76,6 +74,20 @@ def __get_ranking(self): response = self.__get_url('GetSeriesRankings', self.series) return response + async def ranking_position(self, home, away): + result = {ranking: [], 'home': None, 'away': None} + r = await self.hass.async_add_executor_job(self.__get_ranking) + if r != None: + for rank in r['data']['seriesRankings']['rankings'][0]['teams']: + rankteam = {'position': rank['position'], 'team': rank['name'], 'id': rank['teamId']} + result['ranking'].append(rankteam) + if rank['teamId'] == home: + result['home'] = rank['position'] + if rank['teamId'] == away: + result['away'] = rank['position'] + return result + + async def update(self): _LOGGER.debug('Updating match details using Rest API') @@ -87,11 +99,11 @@ async def update(self): r = await self.hass.async_add_executor_job(self.__get_data) if r != None: - upcoming = None + upcoming = False + previous = None self.collections = [] - ranking = [] - position = None + ranking = None for item in r['data']['teamCalendar']: self.match = item['id'] @@ -109,7 +121,6 @@ async def update(self): naive_dt = datetime.strptime(item['startTime'], '%Y-%m-%dT%H:%M:%S') starttime = naive_dt.replace(tzinfo = ZoneInfo(TZ)) - matchdata = { 'uid': item['id'], 'team': self.team, @@ -121,32 +132,28 @@ async def update(self): 'hometeamlogo': item['homeTeam']['logo'], 'hometeamgoals': item['outcome']['homeTeamGoals'], 'hometeampenalties': item['outcome']['homeTeamPenaltiesScored'], + 'hometeamposition': None, 'awayteam': item['awayTeam']['name'], 'awayteamlogo': item['awayTeam']['logo'], 'awayteamgoals': item['outcome']['awayTeamGoals'], 'awayteampenalties': item['outcome']['awayTeamPenaltiesScored'], + 'awayteamposition': None, 'series': item['series']['name'], 'seriesid': item['series']['id'], 'ranking': ranking, - 'position': position, } - if starttime >= now and self.upcoming == None: + if starttime + timedelta(hours=1) >= now and not upcoming: self.series = item['series']['id'] - r = await self.hass.async_add_executor_job(self.__get_ranking) - if r != None: - for rank in r['data']['seriesRankings']['rankings'][0]['teams']: - rankteam = {'position': rank['position'], 'team': rank['name'], 'id': rank['teamId']} - ranking.append(rankteam) - if rank['teamId'] == self.team: - matchdata['position'] = rank['position'] - matchdata['ranking'] = ranking - _LOGGER.debug('position: %r', position) + +# rankpos = self.ranking_position(item['homeTeam']['id'], item['awayTeam']['id']) +# matchdata['ranking'] = rankpos['ranking'] +# matchdata['hometeamposition'] = rankpos['home'] +# matchdata['awayteamposition'] = rankpos['away'] - self.upcoming = matchdata - self.lastmatch = previous - self.matchdata = {'upcoming': matchdata, 'lastmatch': previous} + upcoming = True + self.matchdata = {'upcoming': previous, 'lastmatch': previous} summary = '[' + item['state'] + '] ' + item['homeTeam']['name'] + ' - ' + item['awayTeam']['name'] @@ -169,3 +176,7 @@ async def update(self): self.collections.append(collection) previous = matchdata + + if not upcoming: + _LOGGER.debug('previous=last') + self.matchdata['lastmatch'] = previous \ No newline at end of file diff --git a/custom_components/rbfa/calendar.py b/custom_components/rbfa/calendar.py index 7131ca8..a6dc593 100644 --- a/custom_components/rbfa/calendar.py +++ b/custom_components/rbfa/calendar.py @@ -1,19 +1,18 @@ import logging -from datetime import datetime -from datetime import timedelta +from datetime import datetime, timedelta from typing import Optional, List -#from .API import TeamData - -from homeassistant.const import CONF_RESOURCES -from homeassistant.components.calendar import CalendarEntity, CalendarEvent +#from homeassistant.const import CONF_RESOURCES from homeassistant.core import HomeAssistant - -from .const import DOMAIN, CONF_TEAM - +from homeassistant.components.calendar import CalendarEntity, CalendarEvent from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.config_entries import ConfigEntry +from .const import DOMAIN +from .coordinator import MyCoordinator +from .entity import RbfaEntity + + _LOGGER = logging.getLogger(__name__) @@ -32,18 +31,19 @@ async def async_setup_entry( )] ) -class TeamCalendar(CalendarEntity): +class TeamCalendar(RbfaEntity, CalendarEntity): """Defines a RBFA Team Calendar.""" _attr_icon = "mdi:soccer" def __init__( self, - TeamData, + coordinator, config, ) -> None: + super().__init__(coordinator) """Initialize the RBFA Team entity.""" - self.TeamData = TeamData + self.TeamData = coordinator self.config = config team = config.data['team'] _LOGGER.debug('team: %r', team) @@ -55,19 +55,29 @@ def __init__( @property def event(self) -> Optional[CalendarEvent]: """Return the next upcoming event.""" - _LOGGER.debug('set upcoming event') + upcoming = self.TeamData.matchdata().get('upcoming') + lastmatch = self.TeamData.matchdata().get('lastmatch') - if self.TeamData.upcoming() != None: - team_items = self.TeamData.upcoming() - _LOGGER.debug('name: %r', team_items['teamname']) - self._attr_name = f"{team_items['clubname']} | {team_items['teamname']}" + if upcoming != None: + _LOGGER.debug('upcoming teamname: %r', upcoming['teamname']) + self._attr_name = f"{upcoming['clubname']} | {upcoming['teamname']}" + return CalendarEvent( + uid = upcoming['uid'], + summary = upcoming['hometeam'] + ' - ' + upcoming['awayteam'], + start = upcoming['date'], + end = upcoming['date'] + timedelta(hours=1), + location = upcoming['location'], + description = upcoming['series'], + ) + elif lastmatch != None: + self._attr_name = f"{lastmatch['clubname']} | {lastmatch['teamname']}" return CalendarEvent( - uid = team_items['uid'], - summary = team_items['hometeam'] + ' - ' + team_items['awayteam'], - start = team_items['date'], - end = team_items['date'] + timedelta(hours=1), - location = team_items['location'], - description = team_items['series'], + uid = lastmatch['uid'], + summary = lastmatch['hometeam'] + ' - ' + lastmatch['awayteam'], + start = lastmatch['date'], + end = lastmatch['date'] + timedelta(hours=1), + location = lastmatch['location'], + description = lastmatch['series'], ) async def async_get_events( diff --git a/custom_components/rbfa/config_flow.py b/custom_components/rbfa/config_flow.py new file mode 100644 index 0000000..0dee9ab --- /dev/null +++ b/custom_components/rbfa/config_flow.py @@ -0,0 +1,29 @@ +from homeassistant import config_entries +from .const import DOMAIN +import voluptuous as vol + + +class ExampleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + """Example config flow.""" + # The schema version of the entries that it creates + # Home Assistant will call your migrate method if the version changes + VERSION = 1 + MINOR_VERSION = 1 + + + async def async_step_user(self, user_input): + + if user_input is not None: + team = user_input.get('team') + + await self.async_set_unique_id(f"{team}") + self._abort_if_unique_id_configured() + + return self.async_create_entry(title=f"{team}", data=user_input) + + + + return self.async_show_form( + step_id="user", + data_schema=vol.Schema({vol.Required('team'): str}), + ) diff --git a/custom_components/rbfa/coordinator.py b/custom_components/rbfa/coordinator.py index c1c6eb3..b2253c6 100644 --- a/custom_components/rbfa/coordinator.py +++ b/custom_components/rbfa/coordinator.py @@ -1,12 +1,11 @@ - +import logging +from datetime import timedelta from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from datetime import timedelta from .const import DOMAIN -import logging from .API import TeamApp _LOGGER = logging.getLogger(__name__) @@ -14,23 +13,21 @@ class MyCoordinator(DataUpdateCoordinator): - """Class to manage fetching Elgato data.""" + """Class to manage fetching RBFA data.""" def __init__(self, hass: HomeAssistant, my_api) -> None: """Initialize the coordinator.""" - team = '283884' - team = '300872' self.collector = TeamApp(hass, my_api.data['team']) super().__init__( hass, _LOGGER, name=f"{DOMAIN}", - update_interval=timedelta(seconds=30), + update_interval=timedelta(minutes=5), ) async def _async_update_data(self): - """Fetch data from the Elgato device.""" + """Fetch data from the RBFA service.""" _LOGGER.debug('fetch data coordinator') await self.collector.update() @@ -39,10 +36,4 @@ def collections(self): return self.collector.collections def matchdata(self): - return self.collector.matchdata - - def upcoming(self): - return self.collector.upcoming - - def lastmatch(self): - return self.collector.lastmatch + return self.collector.matchdata \ No newline at end of file diff --git a/custom_components/rbfa/entity.py b/custom_components/rbfa/entity.py new file mode 100644 index 0000000..53b876b --- /dev/null +++ b/custom_components/rbfa/entity.py @@ -0,0 +1,14 @@ + +from __future__ import annotations +from homeassistant.helpers.update_coordinator import CoordinatorEntity +from .coordinator import MyCoordinator + + +class RbfaEntity(CoordinatorEntity[MyCoordinator]): + """Defines an Elgato entity.""" + + _attr_has_entity_name = True + + def __init__(self, coordinator: MyCoordinator) -> None: + """Initialize an Elgato entity.""" + super().__init__(coordinator=coordinator) diff --git a/custom_components/rbfa/sensor.py b/custom_components/rbfa/sensor.py index df509cd..13d5a6b 100644 --- a/custom_components/rbfa/sensor.py +++ b/custom_components/rbfa/sensor.py @@ -1,7 +1,7 @@ """Platform for sensor integration.""" from __future__ import annotations -from collections.abc import Callable -from dataclasses import dataclass +#from collections.abc import Callable +#from dataclasses import dataclass from homeassistant.components.sensor import ( SensorDeviceClass, @@ -13,51 +13,51 @@ #from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType #from homeassistant.const import Platform -from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN, CONF_TEAM #from .API import TeamData from .coordinator import MyCoordinator +from .entity import RbfaEntity import logging _LOGGER = logging.getLogger(__name__) -@dataclass(frozen=True, kw_only=True) -class RbfaSensorEntityDescription(SensorEntityDescription): - """A class that describes AEMET OpenData sensor entities.""" - - keys: list[str] | None = None - value_fn: Callable[[str], datetime | float | int | str | None] = lambda value: value +# @dataclass(frozen=True, kw_only=True) +# class RbfaSensorEntityDescription(SensorEntityDescription): +# """A class that describes AEMET OpenData sensor entities.""" +# +# keys: list[str] | None = None +# value_fn: Callable[[str], datetime | float | int | str | None] = lambda value: value -SENSORS = [ - RbfaSensorEntityDescription( +SENSORS = ( + SensorEntityDescription( key="date", translation_key="date", device_class = SensorDeviceClass.TIMESTAMP, ), - RbfaSensorEntityDescription( + SensorEntityDescription( key="hometeam", translation_key="hometeam", ), - RbfaSensorEntityDescription( + SensorEntityDescription( key="awayteam", translation_key="awayteam", ), - RbfaSensorEntityDescription( + SensorEntityDescription( key="location", translation_key="location", icon="mdi:map-marker", ), - RbfaSensorEntityDescription( + SensorEntityDescription( key="series", translation_key="series", ), - RbfaSensorEntityDescription( - key="position", - translation_key="position", - ), +# SensorEntityDescription( +# key="position", +# translation_key="position", +# ), # RbfaSensorEntityDescription( # key="hometeamgoals", # translation_key="hometeamgoals", @@ -68,7 +68,7 @@ class RbfaSensorEntityDescription(SensorEntityDescription): # translation_key="awayteamgoals", # icon = "mdi:scoreboard" # ), -] +) async def async_setup_entry( hass: HomeAssistant, @@ -100,15 +100,6 @@ async def async_setup_entry( all_sensors ) -class RbfaEntity(CoordinatorEntity[MyCoordinator]): - """Defines an Elgato entity.""" - - _attr_has_entity_name = True - - def __init__(self, coordinator: MyCoordinator) -> None: - """Initialize an Elgato entity.""" - super().__init__(coordinator=coordinator) - class RbfaSensor(RbfaEntity, SensorEntity): """Representation of a Sensor.""" @@ -128,174 +119,37 @@ def __init__( self.team = entry.data.get('team') self._attr_unique_id = f"{DOMAIN}_{collection}_{description.key}_{self.team}" - if description.key == 'hometeam' or description.key == 'awayteam': - self._attr_entity_picture = self.TeamData[description.key + 'logo'] - self.extra_attributes = { - 'goals': self.TeamData[description.key + 'goals'], - 'penalties': self.TeamData[description.key + 'penalties'], - } + if self.TeamData != None: + + if description.key == 'hometeam' or description.key == 'awayteam': + self._attr_entity_picture = self.TeamData[description.key + 'logo'] + self.extra_attributes = { + 'goals': self.TeamData[description.key + 'goals'], + 'penalties': self.TeamData[description.key + 'penalties'], + 'position': self.TeamData[description.key + 'position'], + } + if description.key == 'series': + self.extra_attributes = { + 'ranking': self.TeamData['ranking'], + } @property def native_value(self): - return self.TeamData[self.entity_description.key] + if self.TeamData != None: + return self.TeamData[self.entity_description.key] @property def extra_state_attributes(self): """Return attributes for sensor.""" - basic_attributes = { - 'team': self.TeamData['teamname'], - 'date': self.TeamData['date'], - } - - if self.entity_description.key == 'position': - self.extra_attributes = { - 'ranking': self.TeamData['ranking'], + if self.TeamData != None: + basic_attributes = { + 'team': self.TeamData['teamname'], + 'date': self.TeamData['date'], } - return basic_attributes | self.extra_attributes - -class HomeSensor(SensorEntity): - """Representation of a Sensor.""" - def __init__( - self, - TeamData, - config, - ) -> None: - - self._attr_unique_id = f"{DOMAIN}_home_team_{config[CONF_TEAM]}" - self.TeamData = TeamData - - _attr_has_entity_name = True - - @property - def translation_key(self): - return "home_team" - - def update(self) -> None: - """Fetch new state data for the sensor.""" - teamdata = self.TeamData.teamdata() - item = self.TeamData.upcoming() - - self._attr_native_value = item['hometeam'] - self._attr_entity_picture = item['homelogo'] - self._attr_extra_state_attributes = { - 'Team': teamdata['name'], - 'Series': item['series'], - 'MatchID': item['uid'], - 'Date': item['date'], - } - - -class AwaySensor(SensorEntity): - """Representation of a Sensor.""" - def __init__( - self, - TeamData, - config, - ) -> None: - - self._attr_unique_id = f"{DOMAIN}_away_team_{config[CONF_TEAM]}" - self.TeamData = TeamData - - _attr_has_entity_name = True - - @property - def translation_key(self): - return "away_team" - - def update(self) -> None: - """Fetch new state data for the sensor.""" - teamdata = self.TeamData.teamdata() - item = self.TeamData.upcoming() - - self._attr_native_value = item['awayteam'] - self._attr_entity_picture = item['awaylogo'] - self._attr_extra_state_attributes = { - 'Team': teamdata['name'], - 'Series': item['series'], - 'MatchID' : item['uid'], - 'Date': item['date'], - } - -class LocationSensor(SensorEntity): - """Representation of a Sensor.""" - _attr_icon = "mdi:soccer" - - def __init__( - self, - TeamData, - config, - ) -> None: - - self._attr_unique_id = f"{DOMAIN}_location_{config[CONF_TEAM]}" - self.TeamData = TeamData - - _attr_has_entity_name = True - - @property - def translation_key(self): - return "location" - - def update(self) -> None: - """Fetch new state data for the sensor.""" - teamdata = self.TeamData.teamdata() - - item = self.TeamData.upcoming() - self._attr_native_value = item['location'] - self._attr_extra_state_attributes = { - 'Team': teamdata['name'], - 'Series': item['series'], - 'MatchID' : item['uid'], - 'Date': item['date'], - } - - -class LastDateSensor(SensorEntity): - """Representation of a Sensor.""" - _attr_device_class = SensorDeviceClass.TIMESTAMP - - def __init__( - self, - TeamData, - config, - ) -> None: - - self._attr_name = f"Previous {config[CONF_TEAM]}" - self._attr_unique_id = f"{DOMAIN}_previous_datetime_{config[CONF_TEAM]}" - self.TeamData = TeamData - - def update(self) -> None: - """Fetch new state data for the sensor.""" - item = self.TeamData.lastmatch() - self._attr_name = f"{item['hometeam']} - {item['awayteam']}" - self._attr_native_value = item['date'] - self._attr_extra_state_attributes = { - 'Series': item['series'], - 'MatchID' : item['uid'], - } - -class ResultSensor(SensorEntity): - """Representation of a Sensor.""" - _attr_icon = "mdi:scoreboard" - - def __init__( - self, - TeamData, - config, - ) -> None: - - self._attr_name = f"Result {config[CONF_TEAM]}" - self._attr_unique_id = f"{DOMAIN}_result_{config[CONF_TEAM]}" - self.TeamData = TeamData - - def update(self) -> None: - """Fetch new state data for the sensor.""" - item = self.TeamData.lastmatch() - self._attr_name = f"{item['hometeam']} - {item['awayteam']}" - self._attr_native_value = item['result'] - self._attr_extra_state_attributes = { - 'Series': item['series'], - 'MatchID' : item['uid'], - 'Ranking': item['ranking'], - 'TeamID': item['team'], - } + + if self.entity_description.key == 'position': + self.extra_attributes = { + 'ranking': self.TeamData['ranking'], + } + return basic_attributes | self.extra_attributes \ No newline at end of file