Ejemplo n.º 1
0
 async def rt_connect(self, loop):
     """Start subscription manager for real time data."""
     if self.sub_manager is not None:
         return
     self.sub_manager = SubscriptionManager(
         loop, "token={}".format(self._access_token), SUB_ENDPOINT)
     self.sub_manager.start()
Ejemplo n.º 2
0
class Tibber:
    """Class to comunicate with the Tibber api."""

    # pylint: disable=too-many-instance-attributes

    def __init__(
        self,
        access_token=DEMO_TOKEN,
        timeout=DEFAULT_TIMEOUT,
        websession=None,
        time_zone=None,
    ):
        """Initialize the Tibber connection."""
        if websession is None:

            async def _create_session():
                return aiohttp.ClientSession()

            loop = asyncio.get_event_loop()
            self.websession = loop.run_until_complete(_create_session())
        else:
            self.websession = websession
        self._timeout = timeout
        self._access_token = access_token
        self.time_zone = time_zone or pytz.utc
        self._name = None
        self._home_ids = []
        self._all_home_ids = []
        self._homes = {}
        self.sub_manager = None

    async def close_connection(self):
        """Close the Tibber connection."""
        await self.websession.close()

    def sync_close_connection(self):
        """Close the Tibber connection."""
        loop = asyncio.get_event_loop()
        task = loop.create_task(self.close_connection())
        loop.run_until_complete(task)

    async def rt_connect(self, loop):
        """Start subscription manager for real time data."""
        if self.sub_manager is not None:
            return
        self.sub_manager = SubscriptionManager(
            loop, "token={}".format(self._access_token), SUB_ENDPOINT)
        self.sub_manager.start()

    async def rt_disconnect(self):
        """Stop subscription manager."""
        if self.sub_manager is None:
            return
        await self.sub_manager.stop()

    async def execute(self, document, variable_values=None):
        """Execute gql."""
        res = await self._execute(document, variable_values)
        if res is None:
            return None
        return res.get("data")

    async def _execute(self, document, variable_values=None, retry=2):
        """Execute gql."""
        payload = {"query": document, "variables": variable_values or {}}

        post_args = {
            "headers": {
                "Authorization": "Bearer " + self._access_token
            },
            "data": payload,
        }

        try:
            with async_timeout.timeout(self._timeout):
                resp = await self.websession.post(API_ENDPOINT, **post_args)
            if resp.status != 200:
                _LOGGER.error("Error connecting to Tibber, resp code: %s",
                              resp.status)
                return None
            result = await resp.json()
        except aiohttp.ClientError as err:
            if retry > 0:
                return await self._execute(document, variable_values,
                                           retry - 1)
            _LOGGER.error("Error connecting to Tibber: %s ",
                          err,
                          exc_info=True)
            raise
        except asyncio.TimeoutError:
            if retry > 0:
                return await self._execute(document, variable_values,
                                           retry - 1)
            _LOGGER.error("Timed out when connecting to Tibber")
            raise
        errors = result.get("errors")
        if errors:
            _LOGGER.error("Received non-compatible response %s", errors)
        return result

    def sync_update_info(self, *_):
        """Update home info."""
        loop = asyncio.get_event_loop()
        task = loop.create_task(self.update_info())
        loop.run_until_complete(task)

    async def update_info(self, *_):
        """Update home info async."""
        query = """
        {
          viewer {
            name
            homes {
              subscriptions {
                status
              }
              id
            }
          }
        }
        """

        res = await self._execute(query)
        if res is None:
            return
        errors = res.get("errors", [])
        if errors:
            msg = errors[0].get("message", "failed to login")
            _LOGGER.error(msg)
            raise InvalidLogin(msg)

        data = res.get("data")
        if not data:
            return
        viewer = data.get("viewer")
        if not viewer:
            return
        self._name = viewer.get("name")
        homes = viewer.get("homes", [])
        self._home_ids = []
        for _home in homes:
            home_id = _home.get("id")
            self._all_home_ids += [home_id]
            subs = _home.get("subscriptions")
            if subs:
                status = subs[0].get("status", "ended").lower()
                if not home_id or status != "running":
                    continue
            self._home_ids += [home_id]

    @property
    def name(self):
        """Return name of user."""
        return self._name

    @property
    def home_ids(self):
        """Return list of home ids."""
        return self.get_home_ids(only_active=True)

    def get_home_ids(self, only_active=True):
        """Return list of home ids."""
        if only_active:
            return self._home_ids
        return self._all_home_ids

    def get_homes(self, only_active=True):
        """Return list of Tibber homes."""
        return [
            self.get_home(home_id)
            for home_id in self.get_home_ids(only_active)
        ]

    def get_home(self, home_id):
        """Retun an instance of TibberHome for given home id."""
        if home_id not in self._all_home_ids:
            _LOGGER.error("Could not find any Tibber home with id: %s",
                          home_id)
            return None
        if home_id not in self._homes.keys():
            self._homes[home_id] = TibberHome(home_id, self)
        return self._homes[home_id]

    async def send_notification(self, title, message):
        """Send notification."""
        query = """
        mutation{
          sendPushNotification(input: {
            title: "%s",
            message: "%s",
          }){
            successful
            pushedToNumberOfDevices
          }
        }
        """ % (
            title,
            message,
        )

        res = await self.execute(query)
        if not res:
            return False
        noti = res.get("sendPushNotification", {})
        successful = noti.get("successful", False)
        pushed_to_number_of_devices = noti.get("pushedToNumberOfDevices", 0)
        _LOGGER.debug(
            "send_notification: status %s, send to %s devices",
            successful,
            pushed_to_number_of_devices,
        )
        return successful