예제 #1
0
 def wait_for_rate_limit_reset(self):
     utc_now = pd.Timestamp.utcnow()
     timedelta_to_wait = self.rate_limit_reset_time - utc_now
     timedelta_to_wait += timedelta(minutes=3)  # Just for safety
     secs_to_wait = timedelta_to_wait.total_seconds()
     retry_time_utc = utc_now + timedelta_to_wait
     _print_and_log('Waiting {:.0f} seconds.  Will retry at {}'.format(
         secs_to_wait, retry_time_utc))
     time.sleep(secs_to_wait)
예제 #2
0
    def _api_query(self,
                   service: str,
                   api_params: Dict,
                   wait_if_rate_limit_exceeded: bool = False,
                   use_data_service: bool = False) -> str:
        """Send API request to PVOutput.org and return content text.

        Args:
            service: string, e.g. 'search' or 'getstatus'
            api_params: dict
            wait_if_rate_limit_exceeded: bool
            use_data_service: bool

        Raises:
            NoStatusFound
            RateLimitExceeded
        """
        get_response_func = (self._get_data_service_response
                             if use_data_service else self._get_api_response)

        try:
            response = get_response_func(service, api_params)
        except Exception as e:
            _LOG.exception(e)
            raise

        try:
            return self._process_api_response(response)
        except RateLimitExceeded:
            msg = ("PVOutput.org API rate limit exceeded!"
                   "  Rate limit will be reset at {}".format(
                       self.rate_limit_reset_time))
            _print_and_log(msg)
            if wait_if_rate_limit_exceeded:
                self.wait_for_rate_limit_reset()
                return self._api_query(service,
                                       api_params,
                                       wait_if_rate_limit_exceeded=False)

            raise RateLimitExceeded(response, msg)
예제 #3
0
    def get_batch_status(self,
                         pv_system_id: int,
                         date_to: Optional[Union[str, datetime]] = None,
                         max_retries: Optional[int] = 1000,
                         **kwargs) -> Union[None, pd.DataFrame]:
        """Get batch PV system status (e.g. power generation).

        The returned DataFrame will be empty if the PVOutput API
        returns 'status 400: No status found'.

        Data returned is limited to the last 366 days per request.
        To retrieve older data, use the date_to parameter.

        The PVOutput getbatchstatus API is asynchronous.  When it's first
        called, it replies to say 'accepted'.  This function will then
        wait a minute and call the API again to see if the data is ready.
        Set `max_retries` to 1 if you want to return immediately, even
        if data isn't ready yet (and hence this function will return None)

        https://pvoutput.org/help.html#dataservice-getbatchstatus

        Args:
            pv_system_id: int
            date_to: str in format YYYYMMDD; or datetime
                (localtime of the PV system).  The returned timeseries will
                include 366 days of data: from YYYY-1MMDD to YYYYMMDD inclusive
            max_retries: int, number of times to retry after receiving
                a '202 Accepted' request.  Set `max_retries` to 1 if you want
                to return immediately, even if data isn't ready yet (and hence
                this function will return None).

        Returns:
            None (if data isn't ready after retrying max_retries times) or
            pd.DataFrame:
                index: datetime (DatetimeIndex, localtime of the PV system)
                columns:  (all np.float64):
                    cumulative_energy_gen_Wh,
                    instantaneous_power_gen_W,
                    temperature_C,
                    voltage
        """
        api_params = {'sid1': pv_system_id}

        _set_date_param(date_to, api_params, 'dt')

        for retry in range(max_retries):
            try:
                pv_system_status_text = self._api_query(
                    service='getbatchstatus',
                    api_params=api_params,
                    use_data_service=True,
                    **kwargs)
            except NoStatusFound:
                _LOG.info('system_id %d: No status found for date_to %s',
                          pv_system_id, date_to)
                pv_system_status_text = ""
                break

            if 'Accepted 202' in pv_system_status_text:
                if retry == 0:
                    _print_and_log('Request accepted.')
                if retry < max_retries - 1:
                    _print_and_log('Sleeping for 1 minute.')
                    time.sleep(60)
                else:
                    _print_and_log(
                        'Call get_batch_status again in a minute to see if'
                        ' results are ready.')
            else:
                break
        else:
            return

        return _process_batch_status(pv_system_status_text)