docs: async def _request(
              self,
              method: str,
              url: str,
              *,
              access_token: str = None,
              access_token_expiration: datetime = None,
              headers: dict = None,
              params: dict = None,
              json: dict = None,
              ssl: bool = True) -> dict:
          """Make a request against the RainMachine device."""
          if (access_token_expiration
                  and datetime.now() >= access_token_expiration):
              raise TokenExpiredError('Long-lived access token has expired')
  
          if not headers:
              headers = {}
          headers.update({'Content-Type': 'application/json'})
  
          if not params:
              params = {}
          if access_token:
              params.update({'access_token': access_token})
  
          try:
              async with async_timeout.timeout(self.request_timeout):
                  async with self._websession.request(
                          method, url, headers=headers, params=params, json=json,
                          ssl=ssl) as resp:
                      resp.raise_for_status()
                      data = await resp.json(content_type=None)
                      _raise_for_remote_status(url, data)
          except ClientError as err:
              raise RequestError(
                  'Error requesting data from {0}: {1}'.format(url, err))
          except asyncio.TimeoutError:
              raise RequestError('Timeout during request: {0}'.format(url))
  
          return data