"""Component providing HA sensor support for Travis CI framework.""" from datetime import timedelta import logging from typing import Any, override from travispy import TravisPy from travispy.errors import TravisError import voluptuous as vol from homeassistant.components import persistent_notification from homeassistant.components.sensor import ( PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA, SensorEntity, SensorEntityDescription, ) from homeassistant.const import ( CONF_API_KEY, CONF_MONITORED_CONDITIONS, CONF_SCAN_INTERVAL, UnitOfTime, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType _LOGGER = logging.getLogger(__name__) CONF_BRANCH = "branch" CONF_REPOSITORY = "repository" DEFAULT_BRANCH_NAME = "master" SCAN_INTERVAL = timedelta(seconds=30) SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( SensorEntityDescription( key="last_build_id", name="Last Build ID", icon="mdi:card-account-details", ), SensorEntityDescription( key="last_build_duration", name="Last Build Duration", native_unit_of_measurement=UnitOfTime.SECONDS, icon="mdi:timelapse", ), SensorEntityDescription( key="last_build_finished_at", name="Last Build Finished At", icon="mdi:timetable", ), SensorEntityDescription( key="last_build_started_at", name="Last Build Started At", icon="mdi:timetable", ), SensorEntityDescription( key="last_build_state", name="Last Build State", icon="mdi:github", ), SensorEntityDescription( key="state", name="State", icon="mdi:github", ), ) SENSOR_KEYS: list[str] = [desc.key for desc in SENSOR_TYPES] NOTIFICATION_ID = "travisci" NOTIFICATION_TITLE = "Travis CI Sensor Setup" PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend( { vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_MONITORED_CONDITIONS, default=SENSOR_KEYS): vol.All( cv.ensure_list, [vol.In(SENSOR_KEYS)] ), vol.Required(CONF_BRANCH, default=DEFAULT_BRANCH_NAME): cv.string, vol.Optional(CONF_REPOSITORY, default=[]): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_SCAN_INTERVAL, default=SCAN_INTERVAL): cv.time_period, } ) def setup_platform( hass: HomeAssistant, config: ConfigType, add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the Travis CI sensor.""" token = config[CONF_API_KEY] repositories = config[CONF_REPOSITORY] branch = config[CONF_BRANCH] try: travis = TravisPy.github_auth(token) user = travis.user() except TravisError as ex: _LOGGER.error("Unable to connect to Travis CI service: %s", str(ex)) persistent_notification.create( hass, f"Error: {ex}
You will need to restart hass after fixing.", title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID, ) return # non specific repository selected, then show all associated if not repositories: all_repos = travis.repos(member=user.login) repositories = [repo.slug for repo in all_repos] entities = [] monitored_conditions = config[CONF_MONITORED_CONDITIONS] for repo in repositories: if "/" not in repo: repo = f"{user.login}/{repo}" entities.extend( [ TravisCISensor(travis, repo, user, branch, description) for description in SENSOR_TYPES if description.key in monitored_conditions ] ) add_entities(entities, True) class TravisCISensor(SensorEntity): """Representation of a Travis CI sensor.""" _attr_attribution = "Information provided by https://travis-ci.org/" def __init__( self, data, repo_name, user, branch, description: SensorEntityDescription ) -> None: """Initialize the sensor.""" self.entity_description = description self._build = None self._data = data self._repo_name = repo_name self._user = user self._branch = branch self._attr_name = f"{repo_name} {description.name}" @property @override def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" attrs: dict[str, Any] = {} if self._build and self._attr_native_value is not None: if self._user and self.entity_description.key == "state": attrs["Owner Name"] = self._user.name attrs["Owner Email"] = self._user.email else: attrs["Committer Name"] = self._build.commit.committer_name attrs["Committer Email"] = self._build.commit.committer_email attrs["Commit Branch"] = self._build.commit.branch attrs["Committed Date"] = self._build.commit.committed_at attrs["Commit SHA"] = self._build.commit.sha return attrs def update(self) -> None: """Get the latest data and updates the states.""" _LOGGER.debug("Updating sensor %s", self.name) repo = self._data.repo(self._repo_name) self._build = self._data.build(repo.last_build_id) if self._build: if (sensor_type := self.entity_description.key) == "state": branch_stats = self._data.branch(self._branch, self._repo_name) self._attr_native_value = branch_stats.state else: param = sensor_type.replace("last_build_", "") self._attr_native_value = getattr(self._build, param)