async def _exec_plugin_poll(self) -> None: """Executes poll type plugin """ _LOGGER.info('Started South Plugin: {}'.format(self._name)) try_count = 1 # pollInterval is expressed in milliseconds if int(self._plugin_handle['pollInterval']['value']) <= 0: self._plugin_handle['pollInterval']['value'] = '1000' _LOGGER.warning( 'Plugin {} pollInterval must be greater than 0, defaulting to {} ms' .format(self._name, self._plugin_handle['pollInterval']['value'])) sleep_seconds = int( self._plugin_handle['pollInterval']['value']) / 1000.0 _TIME_TO_WAIT_BEFORE_RETRY = sleep_seconds while self._plugin and try_count <= _MAX_RETRY_POLL: try: t1 = self._event_loop.time() data = self._plugin.plugin_poll(self._plugin_handle) if len(data) > 0: if isinstance(data, list): for reading in data: asyncio.ensure_future( Ingest.add_readings( asset=reading['asset'], timestamp=reading['timestamp'], key=reading['key'], readings=reading['readings'])) elif isinstance(data, dict): asyncio.ensure_future( Ingest.add_readings(asset=data['asset'], timestamp=data['timestamp'], key=data['key'], readings=data['readings'])) delta = self._event_loop.time() - t1 # If delta somehow becomes > sleep_seconds, then ignore delta sleep_for = sleep_seconds - delta if delta < sleep_seconds else sleep_seconds await asyncio.sleep(sleep_for) except asyncio.CancelledError: pass except KeyError as ex: try_count = 2 _LOGGER.exception('Key error plugin {} : {}'.format( self._name, str(ex))) except exceptions.QuietError: try_count = 2 await asyncio.sleep(_TIME_TO_WAIT_BEFORE_RETRY) except (Exception, RuntimeError, exceptions.DataRetrievalError) as ex: try_count = 2 _LOGGER.error('Failed to poll for plugin {}'.format( self._name)) _LOGGER.debug('Exception poll plugin {}'.format(str(ex))) await asyncio.sleep(_TIME_TO_WAIT_BEFORE_RETRY) _LOGGER.warning('Stopped all polling tasks for plugin: {}'.format( self._name))
async def _exec_plugin_poll(self) -> None: """Executes poll type plugin """ _LOGGER.info('Started South Plugin: {}'.format(self._name)) try_count = 1 while self._plugin and try_count <= _MAX_RETRY_POLL: try: data = self._plugin.plugin_poll(self._plugin_handle) if len(data) > 0: if isinstance(data, list): for reading in data: asyncio.ensure_future( Ingest.add_readings( asset=reading['asset'], timestamp=reading['timestamp'], key=reading['key'], readings=reading['readings'])) elif isinstance(data, dict): asyncio.ensure_future( Ingest.add_readings(asset=data['asset'], timestamp=data['timestamp'], key=data['key'], readings=data['readings'])) # pollInterval is expressed in milliseconds sleep_seconds = int( self._plugin_handle['pollInterval']['value']) / 1000.0 await asyncio.sleep(sleep_seconds) # If successful, then set retry count back to 1, meaning that # only in case of 3 successive failures, exit. try_count = 1 except KeyError as ex: _LOGGER.exception('Key error plugin {} : {}'.format( self._name, str(ex))) except (Exception, RuntimeError, exceptions.DataRetrievalError) as ex: try_count += 1 _LOGGER.exception( 'Failed to poll for plugin {}, retry count: {}'.format( self._name, try_count)) await asyncio.sleep(_TIME_TO_WAIT_BEFORE_RETRY) _LOGGER.exception( 'Max retries exhausted in starting South plugin: {}'.format( self._name))
async def _exec_plugin_poll(self, config) -> None: """Executes poll type plugin """ await Ingest.start(self._core_management_host, self._core_management_port) max_retry = 3 try_count = 1 while True and try_count <= max_retry: try: data = self._plugin.plugin_poll(self._plugin_handle) if len(data) > 0: if isinstance(data, list): for reading in data: asyncio.ensure_future( Ingest.add_readings( asset=reading['asset'], timestamp=reading['timestamp'], key=reading['key'], readings=reading['readings'])) elif isinstance(data, dict): asyncio.ensure_future( Ingest.add_readings(asset=data['asset'], timestamp=data['timestamp'], key=data['key'], readings=data['readings'])) # pollInterval is expressed in milliseconds sleep_seconds = int(config['pollInterval']['value']) / 1000.0 await asyncio.sleep(sleep_seconds) # If successful, then set retry count back to 1, meaning that only in case of 3 successive failures, exit. try_count = 1 except KeyError as ex: _LOGGER.exception('Keyerror plugin {} : {}'.format( self._name, str(ex))) except Exception as ex: try_count += 1 _LOGGER.exception( 'Failed to poll for plugin {}, retry count: {}'.format( self._name, try_count)) await asyncio.sleep(2)
def on_message(client, userdata, msg): global _callback_event_loop #_LOGGER.info('{} has a message.'.format(_PLUGIN_NAME)) try: if not Ingest.is_available(): _LOGGER.error("Ingest is not availabe") else: inboundPayload = sparkplug_b_pb2.Payload() inboundPayload.ParseFromString(msg.payload) time_stamp = utils.local_timestamp() if _callback_event_loop is None: _LOGGER.debug("Message processing event doesn't yet exist - creating new event loop.") asyncio.set_event_loop(asyncio.new_event_loop()) _callback_event_loop = asyncio.get_event_loop() for metric in inboundPayload.metrics: readingKey = str(uuid.uuid4()) data = { 'asset' : metric.name, 'timestamp' : time_stamp, #metric.timestamp, 'key' : readingKey, 'readings' : { "value": metric.float_value, } } #_LOGGER.info("UUID: " + readingKey) #_LOGGER.info("Metric Name: " + str(metric.name)) #_LOGGER.info(metric) _callback_event_loop.run_until_complete(save_data(data)) #_LOGGER.info('Exiting message callback.') except Exception as e: _LOGGER.error(e)
async def render_post(request): """Store sensor readings from CoAP to FogLAMP Args: request: The payload is a cbor-encoded array that decodes to JSON similar to the following: .. code-block:: python { "timestamp": "2017-01-02T01:02:03.23232Z-05:00", "asset": "pump1", "key": "80a43623-ebe5-40d6-8d80-3f892da9b3b4", "readings": { "velocity": "500", "temperature": { "value": "32", "unit": "kelvin" } } } """ # aiocoap handlers must be defensive about exceptions. If an exception # is raised out of a handler, it is permanently disabled by aiocoap. # Therefore, Exception is caught instead of specific exceptions. # TODO: The payload is documented at # https://docs.google.com/document/d/1rJXlOqCGomPKEKx2ReoofZTXQt9dtDiW_BHU7FYsj-k/edit# # and will be moved to a .rst file code = aiocoap.numbers.codes.Code.VALID # TODO: Decide upon the correct format of message message = '' try: if not Ingest.is_available(): message = '{"busy": true}' raise aiocoap.error.CommunicationKilled(message) try: payload = cbor2.loads(request.payload) except Exception: raise ValueError('Payload must be a dictionary') asset = payload['asset'] timestamp = payload['timestamp'] key = payload['key'] # readings or sensor_values are optional try: readings = payload['readings'] except KeyError: readings = payload[ 'sensor_values'] # sensor_values is deprecated # if optional then # TODO: confirm, do we want to check this? if not isinstance(readings, dict): raise ValueError('readings must be a dictionary') await Ingest.add_readings(asset=asset, timestamp=timestamp, key=key, readings=readings) except (KeyError, ValueError, TypeError) as e: Ingest.increment_discarded_readings() _LOGGER.exception("%d: %s", aiocoap.numbers.codes.Code.BAD_REQUEST, str(e)) raise aiocoap.error.BadRequest(str(e)) except Exception as ex: Ingest.increment_discarded_readings() _LOGGER.exception("%d: %s", aiocoap.numbers.codes.Code.INTERNAL_SERVER_ERROR, str(ex)) raise aiocoap.error.ConstructionRenderableError(str(ex)) return aiocoap.Message(payload=message.encode('utf-8'), code=code)
async def render_post(request): """Store sensor readings from CoAP to FogLAMP Args: request: The payload decodes to JSON similar to the following: .. code-block:: python { "timestamp": "2017-01-02T01:02:03.23232Z-05:00", "asset": "pump1", "key": "80a43623-ebe5-40d6-8d80-3f892da9b3b4", "readings": { "velocity": "500", "temperature": { "value": "32", "unit": "kelvin" } } } Example: curl -X POST http://localhost:6683/sensor-reading -d '{"timestamp": "2017-01-02T01:02:03.23232Z-05:00", "asset": "pump1", "key": "80a43623-ebe5-40d6-8d80-3f892da9b3b4", "readings": {"velocity": "500", "temperature": {"value": "32", "unit": "kelvin"}}}' """ # TODO: The payload is documented at # https://docs.google.com/document/d/1rJXlOqCGomPKEKx2ReoofZTXQt9dtDiW_BHU7FYsj-k/edit# # and will be moved to a .rst file increment_discarded_counter = False # TODO: Decide upon the correct format of message message = {'result': 'success'} code = web.HTTPOk.status_code try: if not Ingest.is_available(): increment_discarded_counter = True message = {'busy': True} else: payload = await request.json() if not isinstance(payload, dict): raise ValueError('Payload must be a dictionary') asset = payload.get('asset') timestamp = payload.get('timestamp') key = payload.get('key') # readings and sensor_readings are optional try: readings = payload.get('readings') except KeyError: readings = payload.get('sensor_values') # sensor_values is deprecated if not isinstance(readings, dict): raise ValueError('readings must be a dictionary') await Ingest.add_readings(asset=asset, timestamp=timestamp, key=key, readings=readings) except (ValueError, TypeError) as e: increment_discarded_counter = True code = web.HTTPBadRequest.status_code message = {'error': str(e)} _LOGGER.exception(str(e)) except Exception as e: increment_discarded_counter = True code = web.HTTPInternalServerError.status_code message = {'error': str(e)} _LOGGER.exception(str(e)) if increment_discarded_counter: Ingest.increment_discarded_readings() # expect keys in response: # (code = 2xx) result Or busy # (code = 4xx, 5xx) error message['status'] = code return web.json_response(message)
async def render_post(request): """Store sensor readings from CoAP to FogLAMP Args: request: The payload decodes to JSON similar to the following: .. code-block:: python { "timestamp": "2017-01-02T01:02:03.23232Z-05:00", "asset": "pump1", "key": "80a43623-ebe5-40d6-8d80-3f892da9b3b4", "readings": {"humidity": 0.0, "temperature": -40.0} } } Example: curl -X POST http://localhost:6683/sensor-reading -d '{"timestamp": "2017-01-02T01:02:03.23232Z-05:00", "asset": "pump1", "key": "80a43623-ebe5-40d6-8d80-3f892da9b3b4", "readings": {"humidity": 0.0, "temperature": -40.0}}' """ # TODO: The payload is documented at # https://docs.google.com/document/d/1rJXlOqCGomPKEKx2ReoofZTXQt9dtDiW_BHU7FYsj-k/edit# # and will be moved to a .rst file # TODO: Decide upon the correct format of message message = {'result': 'success'} try: if not Ingest.is_available(): message = {'busy': True} raise web.HTTPServiceUnavailable(reason=message) try: payload = await request.json() except Exception: raise ValueError('Payload must be a dictionary') asset = payload['asset'] timestamp = payload['timestamp'] key = payload['key'] # readings or sensor_values are optional try: readings = payload['readings'] except KeyError: readings = payload[ 'sensor_values'] # sensor_values is deprecated # if optional then # TODO: confirm, do we want to check this? if not isinstance(readings, dict): raise ValueError('readings must be a dictionary') await Ingest.add_readings(asset=asset, timestamp=timestamp, key=key, readings=readings) except (KeyError, ValueError, TypeError) as e: Ingest.increment_discarded_readings() _LOGGER.exception("%d: %s", web.HTTPBadRequest.status_code, str(e)) raise web.HTTPBadRequest(reason=str(e)) except Exception as ex: Ingest.increment_discarded_readings() _LOGGER.exception("%d: %s", web.HTTPInternalServerError.status_code, str(ex)) raise web.HTTPInternalServerError(reason=str(ex)) return web.json_response(message)
async def render_post(request): """Store sensor readings from CoAP to FogLAMP Args: request: The payload is a cbor-encoded array that decodes to JSON similar to the following: .. code-block:: python { "timestamp": "2017-01-02T01:02:03.23232Z-05:00", "asset": "pump1", "key": "80a43623-ebe5-40d6-8d80-3f892da9b3b4", "readings": { "velocity": "500", "temperature": { "value": "32", "unit": "kelvin" } } } """ # aiocoap handlers must be defensive about exceptions. If an exception # is raised out of a handler, it is permanently disabled by aiocoap. # Therefore, Exception is caught instead of specific exceptions. # TODO: The payload is documented at # https://docs.google.com/document/d/1rJXlOqCGomPKEKx2ReoofZTXQt9dtDiW_BHU7FYsj-k/edit# # and will be moved to a .rst file code = aiocoap.numbers.codes.Code.INTERNAL_SERVER_ERROR increment_discarded_counter = True message = '' try: if not Ingest.is_available(): message = '{"busy": true}' else: payload = cbor2.loads(request.payload) if not isinstance(payload, dict): raise ValueError('Payload must be a dictionary') asset = payload.get('asset') timestamp = payload.get('timestamp') key = payload.get('key') # readings and sensor_readings are optional try: readings = payload['readings'] except KeyError: readings = payload.get( 'sensor_values') # sensor_values is deprecated increment_discarded_counter = False await Ingest.add_readings(asset=asset, timestamp=timestamp, key=key, readings=readings) # Success code = aiocoap.numbers.codes.Code.VALID except (ValueError, TypeError) as e: code = aiocoap.numbers.codes.Code.BAD_REQUEST message = json.dumps({message: str(e)}) except Exception: _LOGGER.exception('Add readings failed') if increment_discarded_counter: Ingest.increment_discarded_readings() return aiocoap.Message(payload=message.encode('utf-8'), code=code)