def create_observation(self, data: Dict[str, Any]) -> Observation: """Creates an observation object. Args: data: The observation data. """ data['id'] = Observation.get_new_id() data['sensorName'] = self._name data['sensorType'] = self._type # Character '\' is escaped in the JSON configuration file. Encoded # bytes have to be decoded. for set_name, request_set in data.get('requestSets').items(): if request_set.get('request'): request_set['request'] = codecs.decode( request_set.get('request'), 'unicode_escape') if request_set.get('responseDelimiter'): request_set['responseDelimiter'] = codecs.decode( request_set.get('responseDelimiter'), 'unicode_escape') if request_set.get('responsePattern'): request_set['responsePattern'] = codecs.decode( request_set.get('responsePattern'), 'unicode_escape') return Observation(data)
def listen(self, obs_draft: Observation) -> None: """Threaded method for passive mode. Reads incoming data from serial port. Used for sensors which start streaming data without prior request. Args: obs_draft: The observation draft with the response pattern. """ while self._is_running and self._is_passive: if not obs_draft: self.logger.warning(f'No draft observation set for passive ' f'listener on port "{self.name}"') break if not self._serial: self._create() if self._serial is None: self.logger.error(f'Can\'t access port ' f'"{self._serial_port_config.port}" for ' f'passive listening') return if not self._serial.is_open: self.logger.info(f'Re-opening port ' f'"{self._serial_port_config.port}" for ' f'passive listening ...') self._serial.open() self._serial.reset_input_buffer() obs = copy.deepcopy(obs_draft) obs.set('id', Observation.get_new_id()) obs.set('portName', self.name) draft = obs.get('requestSets').get('draft') timeout = draft.get('timeout', 1.0) response_delimiter = draft.get('responseDelimiter', '') length = draft.get('responseLength', 0) request = draft.get('request') if request: self._write(request) response = self._read(eol=response_delimiter, length=length, timeout=timeout) if response: self.logger.verbose( f'Received "{self.sanitize(response)}" ' f'from sensor "{obs.get("sensorName")}" on ' f'port "{self._name}"') draft['response'] = response obs.set('timestamp', str(arrow.utcnow())) self.publish_observation(obs)
def run(self) -> None: """Iterates trough the observation set and sends observations to an external callback function.""" # Return if observation is disabled. if not self._obs.get('enabled'): return # Disable the observation if it should run one time only. if self._obs.get('onetime'): self._obs.set('enabled', False) # Make a deep copy, since we don't want to do any changes to the # observation in our observation set. obs_copy = copy.deepcopy(self._obs) # Set IDs. obs_copy.set('id', Observation.get_new_id()) obs_copy.set('pid', self._project_id) obs_copy.set('nid', self._node_id) # Insert the name of the port module or the virtual sensor at the # beginning of the receivers list. receivers = obs_copy.get('receivers') receivers.insert(0, self._port_name) obs_copy.set('receivers', receivers) # Set the next receiver to the module following the port. obs_copy.set('nextReceiver', 1) self.logger.info(f'Starting job "{self._obs.get("name")}" for port ' f'"{self._port_name}" ...') # Get the sleep time of the whole observation. sleep_time = obs_copy.get('sleepTime', 0) # Create target, header, and payload in order to send the observation. target = self._port_name header = Observation.get_header() header['from'] = 'job' payload = obs_copy.data # Fire and forget the observation. self._uplink(target, header, payload) # Sleep until the next observation. self.logger.debug(f'Next observation starts in {sleep_time} s') time.sleep(sleep_time)