Example #1
0
 def on_message(self, headers, msg):
     global stop_simulation
     message = {}
     try:
         message_str = 'received message '+str(msg)
         
         if fncs.is_initialized():
             _send_simulation_status('RUNNING', message_str, 'DEBUG')
         else:
             _send_simulation_status('STARTED', message_str, 'DEBUG')
         json_msg = yaml.safe_load(str(msg))
         print("\n{}\n".format(json_msg['command']))
         if json_msg['command'] == 'isInitialized':
             message_str = 'isInitialized check: '+str(is_initialized)
             if fncs.is_initialized():
                 _send_simulation_status('RUNNING', message_str, 'DEBUG')
             else:
                 _send_simulation_status('STARTED', message_str, 'DEBUG')
             message['command'] = 'isInitialized'
             message['response'] = str(is_initialized)
             if (simulation_id != None):
                 message['output'] = _get_fncs_bus_messages(simulation_id)
             message_str = 'Added isInitialized output, sending message '+str(message)+' connection '+str(goss_connection)
             if fncs.is_initialized():
                 _send_simulation_status('RUNNING', message_str, 'DEBUG')
             else:
                 _send_simulation_status('STARTED', message_str, 'DEBUG')
             message['timestamp'] = datetime.utcnow().microsecond
             goss_connection.send(output_to_simulation_manager , json.dumps(message))
         elif json_msg['command'] == 'update':
             message['command'] = 'update'
             _publish_to_fncs_bus(simulation_id, json.dumps(json_msg['input'])) #does not return
         elif json_msg['command'] == 'nextTimeStep':
             message['command'] = 'nextTimeStep'
             current_time = json_msg['currentTime']
             message_str = 'incrementing to '+str(current_time + 1)
             _send_simulation_status('RUNNING', message_str, 'DEBUG')
             _done_with_time_step(current_time) #current_time is incrementing integer 0 ,1, 2.... representing seconds
             message_str = 'done with timestep '+str(current_time)
             _send_simulation_status('RUNNING', message_str, 'DEBUG')
             message['output'] = _get_fncs_bus_messages(simulation_id)
             message['timestamp'] = datetime.utcnow().microsecond
             response_msg = json.dumps(message)
             goss_connection.send(output_to_goss_topic + "{}".format(simulation_id) , response_msg)
         elif json_msg['command'] == 'stop':
             message_str = 'Stopping the simulation'
             _send_simulation_status('CLOSED', message_str, 'INFO')
             stop_simulation = True
             fncs.finalize()
             
     
     except Exception as e:
         message_str = 'Error in command '+str(e)
         _send_simulation_status('ERROR', message_str, 'ERROR')
         stop_simulation = True
         if fncs.is_initialized():
             fncs.die()
Example #2
0
 def on_error(self, headers, message):
     global stop_simulation
     message_str = 'Error in goss listener '+str(message)
     _send_simulation_status('ERROR', message_str, 'ERROR')
     stop_simulation = True
     if fncs.is_initialized():
         fncs.die()
Example #3
0
    def __register_federate(self):
        self.__raise_if_not_installed()
        cfg = """name = {0[name]}
time_delta = {0[time_delta]}
broker = {0[broker]}
""".format(
            dict(name=self._federate_name,
                 broker=self._broker,
                 time_delta=self._time_delta))

        if self._registered_fncs_topics:
            cfg += "values"
            for k, v in self._registered_fncs_topics.items():
                cfg += "\n\t{}\n\t\ttopic = {}\n".format(k, v['fncs_topic'])
                if v.get("default"):
                    cfg += "\t\tdefault = {}\n".format(v.get('default'))
                if v.get("data_type"):
                    cfg += "\t\ttype = {}\n".format(v.get('data_type'))
                if v.get("list"):
                    cfg += "\t\tlist = true\n"
        _log.debug(cfg)
        cfg = cfg.replace("\t", "    ")
        fncs.initialize(cfg)
        _log.debug("After initialized!")
        if not fncs.is_initialized():
            raise RuntimeError("Intialization error for fncs.")
Example #4
0
    def _fncs_loop(self):
        _log.info("Starting fncs loop")
        self._simulation_started = True
        while self._current_step < self._simulation_length:
            # Block until the work is done here.
            subKeys = fncs.get_events()
            self._raise_if_error("After get_events")
            self._current_values.clear()

            for x in subKeys:
                fncs_topic = self._registered_fncs_topics[x].get('fncs_topic')
                self._current_values[fncs_topic] = fncs.get_value(x)
                if not fncs.is_initialized():
                    fncs.die()
                    raise RuntimeError("FNCS unexpected error after get_values")

            self._work_callback()

            subKeys = fncs.get_events()

            if len(subKeys) > 0:
                for x in subKeys:
                    subkeyvalue = fncs.get_value(x)
                    volttron_topic = self._registered_fncs_topics[x].get('volttron_topic')
                    if volttron_topic:
                        self.pubsub().publish('pubsub', topic=volttron_topic, message=subkeyvalue)

            # This allows other event loops to run
            gevent.sleep(0.000000001)

        self._simulation_complete = True
        fncs.finalize()
        if self._stop_agent_when_sim_complete:
            self.core().stop()
Example #5
0
    def start_simulation(self):
        """ Begin the main fncs loop

        :return:
        """
        self.__raise_if_not_installed()
        if not fncs.is_initialized():
            raise ValueError("intialized must be called before starting simulation")
        gevent.spawn(self._fncs_loop)
        # Allow the spawned greenlet to run.
        gevent.sleep(0.1)
 def register_with_fncs(self):
     fncs_configuration = {
         "name": "PythonListener{}".format(self.sim_id),
         "time_delta": "1s",
         "broker": self.broker_location,
         "values": {
             "{}".format(self.sim_id): {
                 "topic": self.subscription_topic,
                 "default": "{}",
                 "type": "JSON",
                 "list": "false"
             }
         }
     }
     configuration_zpl = (
         'name = {0}\n'.format(fncs_configuration['name']) +
         'time_delta = {0}\n'.format(fncs_configuration['time_delta']) +
         'broker = {0}\nvalues'.format(fncs_configuration['broker']))
     for x in fncs_configuration['values'].keys():
         configuration_zpl += '\n    {0}'.format(x)
         configuration_zpl += '\n        topic = {0}'.format(
             fncs_configuration['values'][x]['topic'])
         configuration_zpl += '\n        default = {0}'.format(
             fncs_configuration['values'][x]['default'])
         configuration_zpl += '\n        type = {0}'.format(
             fncs_configuration['values'][x]['type'])
         configuration_zpl += '\n        list = {0}'.format(
             fncs_configuration['values'][x]['list'])
     try:
         fncs.initialize(configuration_zpl)
         if not fncs.is_initialized():
             raise RuntimeError(
                 "fncs.initialize(configuration_zpl) failed!\nconfiguration_zpl = {}"
                 .format(configuration_zpl))
     except Exception as e:
         if fncs.is_initialized():
             fncs.die()
         raise
 def run_simulation(self):
     try:
         current_time = 0
         while current_time <= self.sim_length:
             sim_message_topics = fncs.get_events()
             if self.sim_id in sim_message_topics:
                 message = fncs.get_value(self.sim_id)
             time_request = current_time + 1
             if time_request > self.sim_length:
                 fncs.finalize()
                 break
             time_approved = fncs.time_request(time_request)
             if time_approved != time_request:
                 raise RuntimeError(
                     "The time approved from the fncs broker is not the time requested.\ntime_request = {}.\ntime_approved = {}"
                     .format(time_request, time_approved))
             current_time += 1
     except Exception as e:
         if fncs.is_initialized():
             fncs.die()
         raise
Example #8
0
    def __register_federate(self):
        self.__raise_if_not_installed()
        cfg = """name = {0[name]}
time_delta = {0[time_delta]}
broker = {0[broker]}
""".format(dict(name=self._federate_name, broker=self._broker, time_delta=self._time_delta))

        if self._registered_fncs_topics:
            cfg += "values"
            for k, v in self._registered_fncs_topics.items():
                cfg += "\n\t{}\n\t\ttopic = {}\n".format(k, v['fncs_topic'])
                if v.get("default"):
                    cfg += "\t\tdefault = {}\n".format(v.get('default'))
                if v.get("data_type"):
                    cfg += "\t\ttype = {}\n".format(v.get('data_type'))
                if v.get("list"):
                    cfg += "\t\tlist = true\n"
        _log.debug(cfg)
        cfg = cfg.replace("\t", "    ")
        fncs.initialize(cfg)
        if not fncs.is_initialized():
            raise RuntimeError("Intialization error for fncs.")
Example #9
0
def _publish_to_fncs_bus(simulation_id, goss_message):
    """publish a message received from the GOSS bus to the FNCS bus.
    
    Function arguments:
        simulation_id -- Type: string. Description: The simulation id. 
            It must not be an empty string. Default: None.
        goss_message -- Type: string. Description: The message from the GOSS bus
            as a json string. It must not be an empty string. Default: None.
    Function returns:
        None.
    Function exceptions:
        RuntimeError()
        ValueError()
    """
    message_str = 'translating following message for fncs simulation '+simulation_id+' '+str(goss_message)
    _send_simulation_status('RUNNING', message_str, 'DEBUG')
    print(message_str)

    if simulation_id == None or simulation_id == '' or type(simulation_id) != str:
        raise ValueError(
            'simulation_id must be a nonempty string.\n'
            + 'simulation_id = {0}'.format(simulation_id))
    if goss_message == None or goss_message == '' or type(goss_message) != str:
        raise ValueError(
            'goss_message must be a nonempty string.\n'
            + 'goss_message = {0}'.format(goss_message))
    if not fncs.is_initialized():
        raise RuntimeError(
            'Cannot publish message as there is no connection'
            + ' to the FNCS message bus.')
    try:
        test_goss_message_format = yaml.safe_load(goss_message)
        if type(test_goss_message_format) != dict:
            raise ValueError(
                'goss_message is not a json formatted string.'
                + '\ngoss_message = {0}'.format(goss_message))
        fncs_input_topic = '{0}/fncs_input'.format(simulation_id)
        fncs_input_message = {"{}".format(simulation_id) : {}}
        forward_differences_list = test_goss_message_format["message"]["forward_differences"]
        for x in forward_differences_list:
            object_name = (object_mrid_to_name.get(x.get("object"))).get("name")
            object_phases = (object_mrid_to_name.get(x.get("object"))).get("phases")
            object_total_phases = (object_mrid_to_name.get(x.get("object"))).get("total_phases")
            object_type = (object_mrid_to_name.get(x.get("object"))).get("type")
            object_name_prefix = ((difference_attribute_map.get(x.get("attribute"))).get(object_type)).get("prefix")
            cim_attribute = x.get("attribute")
            object_property_list = ((difference_attribute_map.get(x.get("attribute"))).get(object_type)).get("property")
            phase_in_property = ((difference_attribute_map.get(x.get("attribute"))).get(object_type)).get("phase_sensitive",False)
            if (object_name_prefix + object_name) not in fncs_input_message["{}".format(simulation_id)].keys():
                fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name] = {}
            if cim_attribute == "RegulatingControl.mode":
                val = x.get("value")
                if val == 0:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "VOLT"
                elif val == 2:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "VAR"
                elif val == 3:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "CURRENT"
                else:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "MANUAL"
                    _send_simulation_status("RUNNING", "Unsupported capacitor control mode requested. The only supported control modes for capacitors are voltage, VAr, volt/VAr, and current. Setting control mode to MANUAL.","WARN")
            elif cim_attribute == "RegulatingControl.targetDeadband":
                for y in difference_attribute_map[cim_attribute][object_type]["property"]:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][y] = "{}".format(x.get("value"))
            elif cim_attribute == "RegulatingControl.targetValue":
                for y in difference_attribute_map[cim_attribute][object_type]["property"]:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][y] = "{}".format(x.get("value"))    
            elif cim_attribute == "ShuntCompensator.aVRDelay":
                for y in difference_attribute_map[cim_attribute][object_type]["property"]:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][y] = "{}".format(x.get("value"))
            elif cim_attribute == "ShuntCompensator.sections":
                if x.get("value") == 1:
                    val = "CLOSED"
                else:
                    val = "OPEN"
                for y in object_phases:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = "{}".format(val)
            elif cim_attribute == "Switch.open":
                if x.get("value") == 1:
                    val = "OPEN"
                else:
                    val = "CLOSED"
                for y in object_total_phases:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = "{}".format(val)
            elif cim_attribute == "TapChanger.initialDelay":
                for y in object_property_list:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][y] = "{}".format(x.get("value"))
            elif cim_attribute == "TapChanger.step":
                for y in object_phases:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = "{}".format(x.get("value"))
            elif cim_attribute == "TapChanger.lineDropCompensation":
                if x.get("value") == 1:
                    val = "LINE_DROP_COMP"
                else:
                    val = "MANUAL"
                fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0]] = "{}".format(val)
            elif cim_attribute == "TapChanger.lineDropR":
                for y in object_phases:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = "{}".format(x.get("value"))
            elif cim_attribute == "TapChanger.lineDropX":
                for y in object_phases:
                    fncs_input_message["{}".format(simulation_id)][object_name_prefix + object_name][object_property_list[0].format(y)] = "{}".format(x.get("value"))
            else:
                _send_simulation_status("RUNNING", "Attribute, {}, is not a supported attribute in the simulator at this current time. ignoring difference.", "WARN")
            
                
        goss_message_converted = json.dumps(fncs_input_message)
        _send_simulation_status("RUNNING", "Sending the following message to the simulator. {}".format(goss_message_converted),"INFO")
        if fncs.is_initialized():
		fncs.publish_anon(fncs_input_topic, goss_message_converted)
    except ValueError as ve:
        raise ValueError(ve)
    except Exception as ex:
	_send_simulation_status("ERROR","An error occured while trying to translate the update message received","ERROR")
Example #10
0
def _register_with_fncs_broker(broker_location='tcp://localhost:5570'):
    """Register with the fncs_broker and return.
    
    Function arguments:
        broker_location -- Type: string. Description: The ip location and port
            for the fncs_broker. It must not be an empty string.
            Default: 'tcp://localhost:5570'.
    Function returns:
        None.
    Function exceptions:
        RuntimeError()
        ValueError()
    """
    global is_initialized
    global stop_simulation
    configuration_zpl = ''
    try:
        message_str = 'Registering with FNCS broker '+str(simulation_id)+' and broker '+broker_location
        ('STARTED', message_str, 'INFO')
        
        message_str = 'still connected to goss 1 '+str(goss_connection.is_connected())
        _send_simulation_status('STARTED', message_str, 'INFO')
        if simulation_id == None or simulation_id == '' or type(simulation_id) != str:
            raise ValueError(
                'simulation_id must be a nonempty string.\n'
                + 'simulation_id = {0}'.format(simulation_id))
    
        if (broker_location == None or broker_location == ''
                or type(broker_location) != str):
            raise ValueError(
                'broker_location must be a nonempty string.\n' 
                + 'broker_location = {0}'.format(broker_location))
        fncs_configuration = {
            'name' : 'FNCS_GOSS_Bridge_' + simulation_id,
            'time_delta' : '1s',
            'broker' : broker_location,
            'values' : {
                simulation_id : {
                    'topic' : simulation_id + '/fncs_output',
                    'default' : '{}',
                    'type' : 'JSON',
                    'list' : 'false'
                }
            }
        }  
    
        
        configuration_zpl = ('name = {0}\n'.format(fncs_configuration['name'])
            + 'time_delta = {0}\n'.format(fncs_configuration['time_delta'])
            + 'broker = {0}\nvalues'.format(fncs_configuration['broker']))
        for x in fncs_configuration['values'].keys():
            configuration_zpl += '\n    {0}'.format(x)
            configuration_zpl += '\n        topic = {0}'.format(
                fncs_configuration['values'][x]['topic'])
            configuration_zpl += '\n        default = {0}'.format(
                fncs_configuration['values'][x]['default'])
            configuration_zpl += '\n        type = {0}'.format(
                fncs_configuration['values'][x]['type'])
            configuration_zpl += '\n        list = {0}'.format(
                fncs_configuration['values'][x]['list'])
        fncs.initialize(configuration_zpl)
        
        is_initialized = fncs.is_initialized()
        if is_initialized:
            message_str = 'Registered with fncs '+str(is_initialized)
            _send_simulation_status('RUNNING', message_str, 'INFO')
    
    
    except Exception as e:
        message_str = 'Error while registering with fncs broker '+str(e)
        _send_simulation_status('ERROR', message_str, 'ERROR')
        stop_simulation = True
        if fncs.is_initialized():
            fncs.die()

    if not fncs.is_initialized():
        message_str = 'fncs.initialize(configuration_zpl) failed!\n' + 'configuration_zpl = {0}'.format(configuration_zpl)
        _send_simulation_status('ERROR', message_str, 'ERROR')
        stop_simulation = True
        if fncs.is_initialized():
            fncs.die()
        raise RuntimeError(
            'fncs.initialize(configuration_zpl) failed!\n'
            + 'configuration_zpl = {0}'.format(configuration_zpl))
Example #11
0
 def on_disconnected(self):
     global stop_simulation
     stop_simulation = True
     if fncs.is_initialized():
         fncs.die()
Example #12
0
    def initialize(self,
                   sim_start_time,
                   sim_length,
                   topic_mapping,
                   work_callback,
                   federate_name=None,
                   broker_location="tcp://localhost:5570",
                   time_delta="1s",
                   stop_agent_when_sim_complete=False):
        """ Configure the agent to act as a federated connection to FNCS

        sim_start_time - Wall clock time for the simulation start time (This is not used at present time other
                         than to be available)

        sim_length - Time for the simulation to run.  Should be formatted as <number><unit> i.e. 60s.

        topic_mapping - Maps fncs topics onto volttron topics.

        federate_name - MUST be unique to the broker.  If None, then will be the
                        identity of the current agent process.

        broker - tcp location of the fncs broker (defaults to tcp://localhost:5570)

        time_delta - Minimum timestep supported for the federate.

        stop_agent_when_sim_complete - Should we stop the agent when the simulation is completed.

        :param sim_start_time:
        :param sim_length:
        :param topic_mapping:
        :param work_callback:
        :param federate_name:
        :param broker_location:
        :param time_delta:
        :param poll_timeout:
        :return:
        """
        self.__raise_if_not_installed()

        if fncs.is_initialized():
            raise RuntimeError(
                "Invalid state, fncs has alreayd been initialized")

        if not topic_mapping:
            raise ValueError(
                "Must supply a topic mapping with topics to map onto.")

        if not sim_start_time:
            raise ValueError("sim_start_time must be specified.")

        if not sim_length:
            raise ValueError("sim_length must be specified.")

        if not time_delta:
            raise ValueError("time_delta must be specified.")

        if not federate_name:
            raise ValueError("federate_name must be specified.")

        if not broker_location:
            raise ValueError("broker_location must be specified.")

        if not work_callback:
            raise ValueError("work_callback must be specified.")

        if not isinstance(sim_start_time, datetime):
            raise ValueError("sim_start_time must be a datetime object.")

        self._broker = broker_location
        self._time_delta = time_delta
        self._current_simulation_time = self._simulation_start_time = sim_start_time
        self._simulation_delta = self.parse_time(time_delta)
        self._simulation_length = self.parse_time(sim_length)
        if federate_name:
            self._federate_name = federate_name
        self._work_callback = work_callback

        for k, v in topic_mapping.items():
            if not v.get('fncs_topic'):
                raise ValueError(
                    "Invalid fncs_topic specified in key {}.".format(k))

            entry = dict(fncs_topic=v.get('fncs_topic'))
            if 'volttron_topic' in v:
                entry['volttron_topic'] = v['volttron_topic']

            self._registered_fncs_topics[k] = entry

        self.__register_federate()
        self._simulation_started = False
        self._simulation_complete = False
        self._stop_agent_when_sim_complete = stop_agent_when_sim_complete
Example #13
0
 def _raise_if_error(self, location):
     if not fncs.is_initialized():
         fncs.die()
         raise RuntimeError("FNCS unexpected error: {}".format(location))
Example #14
0
    def initialize(self, sim_start_time, sim_length, topic_maping, work_callback, federate_name=None,
                   broker_location="tcp://localhost:5570", time_delta="1s", stop_agent_when_sim_complete=False):
        """ Configure the agent to act as a federated connection to FNCS

        sim_start_time - Wall clock time for the simulation start time (This is not used at present time other
                         than to be available)

        sim_length - Time for the simulation to run.  Should be formatted as <number><unit> i.e. 60s.

        topic_mapping - Maps fncs topics onto volttron topics.

        federate_name - MUST be unique to the broker.  If None, then will be the
                        identity of the current agent process.

        broker - tcp location of the fncs broker (defaults to tcp://localhost:5570)

        time_delta - Minimum timestep supported for the federate.

        stop_agent_when_sim_complete - Should we stop the agent when the simulation is completed.

        :param sim_start_time:
        :param sim_length:
        :param topic_maping:
        :param work_callback:
        :param federate_name:
        :param broker_location:
        :param time_delta:
        :param poll_timeout:
        :return:
        """
        self.__raise_if_not_installed()

        if fncs.is_initialized():
            raise RuntimeError("Invalid state, fncs has alreayd been initialized")

        if not topic_maping:
            raise ValueError("Must supply a topic mapping with topics to map onto.")

        if not sim_start_time:
            raise ValueError("sim_start_time must be specified.")

        if not sim_length:
            raise ValueError("sim_length must be specified.")

        if not time_delta:
            raise ValueError("time_delta must be specified.")

        if not federate_name:
            raise ValueError("federate_name must be specified.")

        if not broker_location:
            raise ValueError("broker_location must be specified.")

        if not work_callback:
            raise ValueError("work_callback must be specified.")

        if not isinstance(sim_start_time, datetime):
            raise ValueError("sim_start_time must be a datetime object.")

        self._broker = broker_location
        self._time_delta = time_delta
        self._current_simulation_time = self._simulation_start_time = sim_start_time
        self._simulation_delta = self.parse_time(time_delta)
        self._simulation_length = self.parse_time(sim_length)
        if federate_name:
            self._federate_name = federate_name
        self._work_callback = work_callback

        for k, v in topic_maping.items():
            if not v.get('fncs_topic'):
                raise ValueError("Invalid fncs_topic specified in key {}.".format(k))

            entry = dict(fncs_topic=v.get('fncs_topic'))
            if 'volttron_topic' in v.keys():
                entry['volttron_topic'] = v['volttron_topic']

            self._registered_fncs_topics[k] = entry

        self.__register_federate()
        self._simulation_started = False
        self._simulation_complete = False
        self._stop_agent_when_sim_complete = stop_agent_when_sim_complete
Example #15
0
 def _raise_if_error(self, location):
     if not fncs.is_initialized():
         fncs.die()
         raise RuntimeError("FNCS unexpected error: {}".format(location))