Пример #1
0
    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))
Пример #2
0
 def update_array_for_point(self, point_value):
     """A received point belongs to a PointArray. Update it."""
     if point_value.point_def.is_array_head_point:
         self._current_array = PointArray(point_value.point_def)
     elif self._current_array is None:
         raise DNP3Exception('Array point received, but there is no current Array.')
     elif not self._current_array.contains_index(point_value.index):
         raise DNP3Exception('Received Array point outside of current Array.')
     self._current_array.add_point_value(point_value)
Пример #3
0
    def get_configured_points(self):
        """
            Look up the most-recently-received value of each configured point.

        @return: A dictionary of point values, indexed by their point names.
        """
        if self.volttron_points is None:
            raise DNP3Exception('DNP3 points have not been configured')

        _log.info('Getting all DNP3 configured point values')
        try:
            return {name: self._get_point(self.dnp3_point_name(name)) for name in self.volttron_points}
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #4
0
    def get_selector_block(self, point_name, edit_selector):
        """
            Return a dictionary of point values for a given selector block.

        :param point_name: Name of the first point in the selector block.
        :param edit_selector: The index (edit selector) of the block.
        :return: A dictionary of point values.
        """
        _log.info('Get point values for selector block {}, index {}'.format(point_name, edit_selector))
        point_values = {}
        try:
            # Create a dictionary of all point values in the block, indexed by name. Expand any arrays.
            for pt in self._get_selector_block_points(point_name, edit_selector):
                point_def = pt.point_def
                point_value = pt.unwrapped_value()
                if point_def.is_array_point:
                    head_point_def = self.point_definitions.point_named(pt.name)
                    # Construct array JSON
                    row = 0 if point_def.is_array_head_point else point_def.row
                    col = 0 if point_def.is_array_head_point else point_def.column
                    col_name = head_point_def.array_points[col]['name']
                    # Expand the JSON structure as needed
                    if pt.name not in point_values:
                        point_values[pt.name] = []
                    if row + 1 > len(point_values[pt.name]):
                        point_values[pt.name].append({})
                    point_values[pt.name][row][col_name] = point_value
                else:
                    point_values[pt.name] = point_value
        except Exception as e:
            raise DNP3Exception(e.message)
        return point_values
Пример #5
0
    def get_point_definitions(self, point_name_list):
        """
            For each DNP3 point name in point_name_list, return a dictionary with each of the point definitions.

            The returned dictionary looks like this:

            {
                "point_name1": {
                    "property1": "property1_value",
                    "property2": "property2_value",
                    ...
                },
                "point_name2": {
                    "property1": "property1_value",
                    "property2": "property2_value",
                    ...
                }
            }

            If a definition cannot be found for a point name, it is omitted from the returned dictionary.

        :param point_name_list: A list of point names.
        :return: A dictionary of point definitions.
        """
        _log.info('Fetching a list of DNP3 point definitions for {}'.format(point_name_list))
        try:
            response = {}
            for name in point_name_list:
                point_def = self.point_definitions.get_point_named(self.dnp3_point_name(name))
                if point_def is not None:
                    response[name] = point_def.as_json()
            return response
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #6
0
    def load_point_definitions(self):
        """
            Load and cache a dictionary of PointDefinitions from a json list.

            Index the dictionary by point_type and point index.
        """
        _log.debug('Loading DNP3 point definitions.')
        try:
            if type(self.points) == str:
                # There's something odd here. The point and function definitions are defined in the
                # config file using a 'config://' entry (previously used only by MasterDriveAgent).
                # It seems like this should have been resolved to the registry entry at which the
                # 'config://' entry points, and in that case 'self.points' should already be
                # a json structure. But instead, it's still the string 'config://mesa_points.config'.
                # The call to get_from_config_store() below works around the issue by fetching the linked
                # registry entry.
                point_defs = self.get_from_config_store(self.points)
            else:
                point_defs = self.points
            self.point_definitions = PointDefinitions()
            self.point_definitions.load_points(point_defs)
        except (AttributeError, TypeError) as err:
            if self._local_point_definitions_path:
                _log.warning("Attempting to load point definitions from local path.")
                self.point_definitions = PointDefinitions(point_definitions_path=self._local_point_definitions_path)
            else:
                raise DNP3Exception("Failed to load point definitions from config store: {}".format(err))
Пример #7
0
    def dnp3_point_name(self, point_name):
        """
            Return a point's DNP3 point name, mapped from its VOLTTRON point name if necessary.

            If VOLTTRON point names were configured (by the DNP device driver), map them to DNP3 point names.
        """
        dnp3_point_name = self.volttron_points.get(point_name, '') if self.volttron_points else point_name
        if not dnp3_point_name:
            raise DNP3Exception('No configured point for {}'.format(point_name))
        return dnp3_point_name
Пример #8
0
 def publish_data(self, topic, msg):
     """Publish a payload to the message bus."""
     try:
         self.vip.pubsub.publish(peer='pubsub',
                                 topic=topic,
                                 headers={headers.TIMESTAMP: utils.format_timestamp(utils.get_aware_utc_now())},
                                 message=msg)
     except Exception as err:
         if os.environ.get('UNITTEST', False):
             _log.debug('Disregarding publish_data exception during unit test')
         else:
             raise DNP3Exception('Error publishing topic {}, message {}: {}'.format(topic, msg, err))
Пример #9
0
    def get_points(self, point_list):
        """
            Look up the most-recently-received value of each configured output point.

        @param point_list: A list of point names.
        @return: A dictionary of point values, indexed by their point names.
        """
        _log.info('Getting values for the following points: {}'.format(point_list))
        try:
            return {name: self._get_point(self.dnp3_point_name(name)) for name in point_list}
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #10
0
    def set_points(self, point_dict):
        """
            Set point values for a dictionary of points.

        @param point_dict: A dictionary of {point_name: value} for a list of DNP3 points to set.
        """
        _log.info('Setting DNP3 point values: {}'.format(point_dict))
        try:
            for point_name, value in point_dict.iteritems():
                self.update_input_point(self.get_point_named(self.dnp3_point_name(point_name)), value)
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #11
0
    def _get_point_by_index(self, group, index):
        """
            (Internal) Look up the most-recently-received value for a given point (no debug trace).

        @param group: The group number of a DNP3 point.
        @param index: The index of a DNP3 point.
        @return: The (unwrapped) value of a received point.
        """
        try:
            point_value = self.get_current_point_value(PointDefinition.point_type_for_group(group), index)
            return point_value.unwrapped_value() if point_value else None
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #12
0
    def set_point(self, point_name, value):
        """
            Set the value of a given input point.

        @param point_name: The 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.
        """
        _log.info('Setting DNP3 {} point value = {}'.format(point_name, value))
        try:
            self.update_input_point(self.get_point_named(self.dnp3_point_name(point_name)), value)

        except Exception as e:
            raise DNP3Exception(e.message)
Пример #13
0
    def _get_point(self, point_name):
        """
            (Internal) Look up the most-recently-received value for a given point (no debug trace).

        @param point_name: The name of a DNP3 PointDefinition.
        @return: The (unwrapped) value of a received point.
        """
        try:
            point_def = self.point_definitions.get_point_named(point_name)
            point_value = self.get_current_point_value(point_def.point_type, point_def.index)
            return point_value.unwrapped_value() if point_value else None
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #14
0
    def get_point_by_index(self, data_type, index):
        """
            Look up the most-recently-received value for a given point.

        @param data_type: The data_type of a DNP3 point.
        @param index: The index of a DNP3 point.
        @return: The (unwrapped) value of a received point.
        """
        _log.info('Getting point value for data_type {} and index {}'.format(
            data_type, index))
        try:
            point_value = self.get_current_point_value(data_type, index)
            return point_value.unwrapped_value() if point_value else None
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #15
0
    def get_point(self, point_name):
        """
            Look up the most-recently-received value for a given output point.

        @param point_name: The point name of a DNP3 PointDefinition.
        @return: The (unwrapped) value of a received point.
        """
        _log.info('Getting point value for {}'.format(point_name))
        try:
            point_name = self.dnp3_point_name(point_name)
            point_def = self.point_definitions.get_point_named(point_name)
            point_value = self.get_current_point_value(point_def.data_type,
                                                       point_def.index)
            return point_value.unwrapped_value() if point_value else None
        except Exception as e:
            raise DNP3Exception(e.message)
Пример #16
0
    def load_point_definitions(self):
        """
            Load and cache a dictionary of PointDefinitions from a json list.

            Index the dictionary by point_type and point index.
        """
        _log.debug('Loading DNP3 point definitions.')
        try:
            self.point_definitions = PointDefinitions()
            self.point_definitions.load_points(self.points)
        except (AttributeError, TypeError) as err:
            if self._local_point_definitions_path:
                _log.warning(
                    "Attempting to load point definitions from local path.")
                self.point_definitions = PointDefinitions(
                    point_definitions_path=self._local_point_definitions_path)
            else:
                raise DNP3Exception(
                    "Failed to load point definitions from config store: {}".
                    format(err))
Пример #17
0
    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)