def get_readings_from_api(self):

        # Fetch data from remote API.
        log.info('Requesting luftdaten.info live API at {}'.format(self.uri))
        payload = self.session.get(self.uri).content.decode('utf-8')
        data = json.loads(payload)
        #pprint(data)

        # Mungle timestamp to be formally in ISO 8601 format (UTC).
        timestamp = self.convert_timestamp(data[0]['timestamp'])
        log.info('Timestamp of first record: {}'.format(timestamp))

        # Apply data filter.
        data = self.apply_filter(data)

        # Transform live API items to actual readings while optionally
        # applying a number of transformation and enrichment steps.
        for item in self.wrap_progress(data):
            try:
                reading = self.make_reading(item)
                if reading is None:
                    continue

                if not self.make_observations_from_api(item, reading):
                    continue

                log.debug(f'API reading:\n{json.dumps(reading, indent=2)}')

                yield reading

            except Exception as ex:
                log.warning('Could not make reading from {}.\n{}'.format(
                    item, exception_traceback()))
示例#2
0
    def request_live_data(self):

        log.info('Requesting Live API at {}'.format(self.uri))
        payload = self.session.get(self.uri).content.decode('utf-8')
        data = json.loads(payload)
        #pprint(data)

        timestamp = self.convert_timestamp(data[0]['timestamp'])
        log.info('Timestamp of first record: {}'.format(timestamp))

        iterator = data
        if self.progressbar:
            iterator = tqdm(data)

        for item in iterator:
            try:

                reading = self.make_reading(item)
                if reading is None:
                    continue
                yield reading

            except Exception as ex:
                log.warning('Could not make reading from {}.\n{}'.format(
                    item, exception_traceback()))
    def get_current_measurement_readings(self):
        """
        Acquire data from the "measurements" API.
        https://docs.openaq.org/#api-Measurements
        """

        # Fetch data from remote API.
        log.info('Requesting measurement data from OpenAQ')

        api = openaq.OpenAQ()

        params = {}
        if self.filter and 'country' in self.filter:
            params['country'] = self.filter['country']

        # TODO: What to do with readings which do not have any geographic information?
        # TODO: Raise limit by introducing result paging.
        date_from = self.last_hour()
        status, response = api.measurements(date_from=date_from,
                                            has_geo=True,
                                            limit=10000,
                                            include_fields=['attribution'],
                                            **params)
        data = response['results']

        if not data:
            log.warning('No records found beginning {} with filter {}'.format(
                date_from, params))
            return

        # Mungle timestamp to be formally in ISO 8601 format (UTC).
        timestamp = data[0]['date']['utc']
        log.info('Timestamp of first record: {}'.format(timestamp))

        # Apply data filter.
        #data = self.apply_filter(data)

        # Transform live API items to actual readings while optionally
        # applying a number of transformation and enrichment steps.
        readings = {}
        for item in self.wrap_progress(data):
            try:
                self.process_measurement(readings, item)

            except Exception as ex:
                log.warning('Could not use observation from {}.\n{}'.format(
                    item, exception_traceback()))

        for reading in readings.values():
            has_data = False
            for observation in reading.observations:
                if observation['data']:
                    has_data = True
                    break
            if has_data:
                yield reading
示例#4
0
    def enrich_station(self, station):

        # Sanity checks.
        if ('latitude' not in station.position or 'longitude' not in station.position) or \
            (station.position.latitude is None or station.position.longitude is None):
            # TODO: Just emit this message once per X.
            log.warning(
                'Incomplete station position, skipping geospatial enrichment. Station: {}'
                .format(station))
            return

        # Compute geohash.
        station.position.geohash = geohash_encode(station.position.latitude,
                                                  station.position.longitude)

        # Compute human readable location name.
        if self.reverse_geocode:

            try:

                # Reverse-geocode position.
                station.location = resolve_location(
                    latitude=station.position.latitude,
                    longitude=station.position.longitude,
                    geohash=station.position.geohash,
                    country_code=station.position.country,
                )

                # Improve location information.
                improve_location(station.location)

                # Format address into single label.
                station.name = format_address(station.location)

                try:
                    if station.name.lower() == station.position.country.lower(
                    ):
                        del station['name']
                except:
                    pass

            except Exception as ex:
                log.error(
                    u'Problem with reverse geocoder for station {}: {}\n{}'.
                    format(station, ex, exception_traceback()))

            if 'name' not in station:
                station.name = u'Station #{}'.format(station.station_id)
                try:
                    station.name += ', ' + station.position.country
                except:
                    pass
    def get_latest_readings(self):
        """
        Acquire data from the "latest" API.
        https://docs.openaq.org/#api-Latest
        """

        # Fetch data from remote API.
        log.info('Requesting latest data from OpenAQ')

        api = openaq.OpenAQ()

        # Example.
        #res = api.latest(city='Delhi', parameter='pm25', df=True)
        #print(res.columns)

        params = {}
        if self.filter and 'country' in self.filter:
            params['country'] = self.filter['country']

        # TODO: What to do with readings which do not have any geographic information?
        # TODO: Raise limit by introducing result paging.
        status, response = api.latest(
            has_geo=True,
            limit=10000,
            include_fields=['attribution', 'averagingPeriod', 'sourceName'],
            **params)
        data = response['results']

        # Mungle timestamp to be formally in ISO 8601 format (UTC).
        timestamp = data[0]['measurements'][0]['lastUpdated']
        log.info('Timestamp of first record: {}'.format(timestamp))

        # Apply data filter.
        #data = self.apply_filter(data)

        # Transform live API items to actual readings while optionally
        # applying a number of transformation and enrichment steps.
        for item in self.wrap_progress(data):
            try:
                reading = self.make_reading_from_latest(item)
                if reading is None:
                    continue

                log.debug(f'API reading:\n{json.dumps(reading, indent=2)}')

                yield reading

            except Exception as ex:
                log.warning('Could not make reading from {}.\n{}'.format(
                    item, exception_traceback()))
示例#6
0
    def csv_reader(self, csvpath, fieldnames):

        payload = None
        if self.quick_mode:
            try:
                payload = open(csvpath).read(256)
                payload = '\n'.join(payload.split('\n')[:2])
            except:
                pass
        else:
            payload = open(csvpath).read()

        if payload is None:
            log.error('Could not read CSV file %s', csvpath)
            return

        # Read CSV file into tablib's Dataset and cast to dictionary representation.
        imported_data = Dataset().load(payload, format='csv', delimiter=';')
        records = imported_data.dict

        # Iterate all CSV records.
        for record in records:

            item = self.make_item(record)
            try:
                reading = self.make_reading(item)
                if reading is None:
                    continue

                if not self.csvdata_to_reading(record, reading, fieldnames):
                    continue

                yield reading

            except Exception as ex:
                log.warning('Could not make reading from {}.\n{}'.format(
                    item, exception_traceback()))