def _apply_point_update(point_def, point_index, value): """ Set an input point in the outstation database. This may send its PointValue to the Master. :param point_def: A PointDefinition. :param point_index: A numeric index for the point. :param value: A value to send (unwrapped, simple data type). """ data_type = point_def.data_type if data_type == DATA_TYPE_ANALOG_INPUT: wrapped_val = opendnp3.Analog(float(value)) if isinstance(value, bool) or not isinstance(value, numbers.Number): # Invalid data type raise DNP3Exception('Received {} value for {}.'.format(type(value), point_def)) elif data_type == DATA_TYPE_BINARY_INPUT: wrapped_val = opendnp3.Binary(value) if not isinstance(value, bool): # Invalid data type raise DNP3Exception('Received {} value for {}.'.format(type(value), point_def)) else: # The agent supports only DNP3's Analog and Binary point types at this time. raise DNP3Exception('Unsupported point type {}'.format(data_type)) if wrapped_val is not None: DNP3Outstation.apply_update(wrapped_val, point_index) _log.debug('Sent DNP3 point {}, value={}'.format(point_def, wrapped_val.value))
def _apply_point_update(point_def, point_index, value): """ Set an input point in the outstation database. This may send its PointValue to the Master. :param point_def: A PointDefinition. :param point_index: A numeric index for the point. :param value: A value to send (unwrapped, simple data type). """ data_type = point_def.data_type if data_type == DATA_TYPE_ANALOG_INPUT: wrapped_val = opendnp3.Analog(float(value)) if isinstance(value, bool) or not isinstance(value, numbers.Number): # Invalid data type raise DNP3Exception('Received {} value for {}.'.format( type(value), point_def)) elif data_type == DATA_TYPE_BINARY_INPUT: wrapped_val = opendnp3.Binary(value) if not isinstance(value, bool): # Invalid data type raise DNP3Exception('Received {} value for {}.'.format( type(value), point_def)) else: # The agent supports only DNP3's Analog and Binary point types at this time. raise DNP3Exception('Unsupported point type {}'.format(data_type)) if wrapped_val is not None: DNP3Outstation.apply_update(wrapped_val, point_index) _log.debug('Sent DNP3 point {}, value={}'.format( point_def, wrapped_val.value))
def _configure_parameters(self, contents): """ Initialize/Update the DNP3 agent configuration. DNP3Agent configuration parameters (the MesaAgent subclass has some more): points: (string) A JSON structure of point definitions to be loaded. point_topic: (string) Message bus topic to use when publishing DNP3 point values. Default: mesa/point. outstation_status_topic: (string) Message bus topic to use when publishing outstation status. Default: mesa/outstation_status. local_ip: (string) Outstation's host address (DNS resolved). Default: 0.0.0.0. port: (integer) Outstation's port number - the port that the remote endpoint (Master) is listening on. Default: 20000. outstation_config: (dictionary) Outstation configuration parameters. All are optional. Parameters include: database_sizes: (integer) Size of each DNP3 database buffer. Default: 10000. event_buffers: (integer) Size of the database event buffers. Default: 10. allow_unsolicited: (boolean) Whether to allow unsolicited requests. Default: True. link_local_addr: (integer) Link layer local address. Default: 10. link_remote_addr: (integer) Link layer remote address. Default: 1. log_levels: List of bit field names (OR'd together) that filter what gets logged by DNP3. Default: [NORMAL]. Possible values: ALL, ALL_APP_COMMS, ALL_COMMS, NORMAL, NOTHING. threads_to_allocate: (integer) Threads to allocate in the manager's thread pool. Default: 1. """ config = self.default_config.copy() config.update(contents) self.points = config.get('points', []) self.point_topic = config.get('point_topic', DEFAULT_POINT_TOPIC) self.outstation_status_topic = config.get('outstation_status_topic', DEFAULT_OUTSTATION_STATUS_TOPIC) self.local_ip = config.get('local_ip', DEFAULT_LOCAL_IP) self.port = int(config.get('port', DEFAULT_PORT)) self.outstation_config = config.get('outstation_config', {}) _log.debug('DNP3Agent configuration parameters:') _log.debug('\tpoints type={}'.format(type(self.points))) _log.debug('\tpoint_topic={}'.format(self.point_topic)) _log.debug('\toutstation_status_topic={}'.format(self.outstation_status_topic)) _log.debug('\tlocal_ip={}'.format(self.local_ip)) _log.debug('\tport={}'.format(self.port)) _log.debug('\toutstation_config={}'.format(self.outstation_config)) self.load_point_definitions() DNP3Outstation.set_agent(self) return config
def start_outstation(self): """Start the DNP3Outstation instance, kicking off communication with the DNP3 Master.""" _log.info('Starting DNP3Outstation') self.publish_outstation_status('starting') self.application = DNP3Outstation(self.local_ip, self.port, self.outstation_config) self.application.start() self.publish_outstation_status('running')
def onstart(self, sender, **kwargs): """Start the DNP3Outstation instance, kicking off communication with the DNP3 Master.""" self._configure_parameters(self.default_config) _log.info('Starting DNP3Outstation') self.publish_outstation_status('starting') self.application = DNP3Outstation(self.local_ip, self.port, self.outstation_config) self.application.start() self.publish_outstation_status('running')
def _set_point(self, point_name, value): """ (Internal) Set the value of a given input point (no debug trace). @param point_name: The VOLTTRON point name of a DNP3 PointDefinition. @param value: The value to set. The value's data type must match the one in the DNP3 PointDefinition. """ point_properties = self.volttron_points.get(point_name, {}) data_type = point_properties.get('data_type', None) index = point_properties.get('index', None) try: if data_type == DATA_TYPE_ANALOG_INPUT: wrapped_value = opendnp3.Analog(value) elif data_type == DATA_TYPE_BINARY_INPUT: wrapped_value = opendnp3.Binary(value) else: raise Exception('Unexpected data type for DNP3 point named {0}'.format(point_name)) DNP3Outstation.apply_update(wrapped_value, index) except Exception as e: raise DNP3Exception(e.message)
def _set_point(self, point_name, value): """ (Internal) Set the value of a given input point (no debug trace). @param point_name: The VOLTTRON point name of a DNP3 PointDefinition. @param value: The value to set. The value's data type must match the one in the DNP3 PointDefinition. """ point_properties = self.volttron_points.get(point_name, {}) group = point_properties.get('group', None) index = point_properties.get('index', None) point_type = PointDefinition.point_type_for_group(group) try: if point_type == POINT_TYPE_ANALOG_INPUT: wrapped_value = opendnp3.Analog(value) elif point_type == POINT_TYPE_BINARY_INPUT: wrapped_value = opendnp3.Binary(value) else: raise Exception('Unexpected data type for DNP3 point named {0}'.format(point_name)) DNP3Outstation.apply_update(wrapped_value, index) except Exception as e: raise DNP3Exception(e.message)