Search code examples
volttron

volttron set_multiple_points actuator agent rpc call


Can I get a tip on how to use the actuator agent set_multiple_points?

In the actuator agent code, I can see the method:

def set_multiple_points(self, requester_id, topics_values, **kwargs):
    """RPC method
    Set multiple points on multiple devices. Makes a single
    RPC call to the platform driver per device.
    :param requester_id: Ignored, VIP Identity used internally
    :param topics_values: List of (topic, value) tuples
    :param \*\*kwargs: Any driver specific parameters
    :returns: Dictionary of points to exceptions raised.
              If all points were set successfully an empty
              dictionary will be returned.
    .. warning:: calling without previously scheduling *all* devices
                 and not within the time allotted will raise a LockError
    """

In my CSV agent driver that I am experimenting with, I have 4 devices defined in the init, as well as a point_topic that is the same across all devices, and a change_setpoint to apply to all of the devices.

def __init__(self, csv_topic="", **kwargs):
    # Configure the base agent
    super(Csvdriveragent, self).__init__(**kwargs)
    _log.debug("vip_identity: " + self.core.identity)

    # This agent is for testing purposes, so we'll default our ID
    self.agent_id = "csv_actuation_agent"
    
    # Get the topic that the Driver will publish to from the configuration file
    devices = {device1:'201201',
                device2:'201202',
                device3:'201203',
                device4:'201204' 
    }      

    self.point_topic = self.topic + "/" + "RmTmpSpt"

    # This value will be used to send requests to the Driver to set a point on the device with an alternating value
    self.change_setpoint = 85

Can I get a tip on what the rpc call would look like for set_multiple_points?

I know the comments state in a dictionary format, is this at all close below for how to put the rpc call together?

result = self.vip.rpc.call(
    'platform.actuator', 'set_multiple_points', devices, point_topic, self.change_setpoint).get(
    timeout=4)

Any tips for how to revert_multiple points back also greatly appreciated too. For example if a timer expires (gevent.sleep()) how would I revert all the point back to prior values?


Solution

  • The set_multiple_points RPC call requires a requester_id string and a list of tuples defining pairs of topic to value-to-set combinations (topic_values).

    The basic form of an RPC call to the actuator is as follows:

    # use the agent's VIP connection to make an RPC call to the actuator agent 
    result = self.vip.rpc.call('platform.actuator', <RPC exported function>, <args>).get(timeout=<seconds>)
    

    Because we're working with devices, we need to know which devices we're interested in, and what their topics are.

    device_map = {
      'device1': '201201',
      'device2': '201202',
      'device3': '201203',
      'device4': '201204', 
    }
    
    building_topic = 'campus/building'      
    

    Before setting one or more points, it is required that the requester establish a schedule period for sending control signals - this is done by creating a schedule data structure and sending that to the actuator along with some other metadata.

    schedule_request = []
    
    # create start and end timestamps
    _now = get_aware_utc_now()
    str_start = format_timestamp(_now)
    _end = _now + td(seconds=10)
    str_end = format_timestamp(_end)
    
    # wrap the topic and timestamps up in a list and add it to the schedules list
    for device in device_map.values():
        topic = '/'.join([building_topic, device])
        schedule_request.append([topic, str_start, str_end])
    
    # send the request to the actuator
    result = self.vip.rpc.call('platform.actuator', 'request_new_schedule', self.core.identity, 'my_schedule', 'LOW', schedule_request).get(timeout=3)
    

    Now we can send our set_multiple_points request during the scheduled period - within the next 10 seconds.

    # start by creating our topic_values
    topic_values = []
    
    for device in device_map.values();
       topic = '/'.join([building_topic, device])
       # swap get_value_for_device with your logic
       value = self.get_value_for_device(device)
       # create a (topic, value) tuple and add it to our topic values
       topic_values.append((topic, value,))
    
    # now we can send our set_multiple_points request, use the basic form with our additional params
    result = self.vip.rpc.call('platform.actuator', 'set_multiple_points', self.core.identity, topic_values).get(timeout=3)
    
    # TODO: handle the response here
    

    To revert a point, create a schedule for the point following the above examples but for a single point, then send an RPC request to the Actuator for the 'revert_point' method. This requires that you've set a default value in your driver's registry config.

    response = self.vip.rpc.call('platform.actuator', 'revert_point', self.core.identity, '/'.join([building_topic, device], point_name).get(timeout=3)