Esempio n. 1
0
    def __init__(self, instance_name, time, engine, update_callback, context,
                 params):
        super(Expect, self).__init__(instance_name, time, engine,
                                     update_callback, context, params)
        tf = params["expect"]["timefunction"]
        self.expected_timefunction = importer.get_class(
            "timefunction",
            tf.keys()[0])(engine, self, tf[tf.keys()[0]])
        self.expected_event_name = params["expect"]["event_name"]
        self.expected_instance_name = context["instance_name"]
        self.expected_ignore_start = isodate.parse_duration(
            params["expect"].get("ignore_start", "PT0S")).total_seconds()
        self.expected_required_score_percent = params["expect"].get(
            "required_score_percent", None)
        if not Expect.initialised:
            self.engine.register_event_in(REPORT_PERIOD_S,
                                          self.tick_send_report, self, self)
            Expect.initialised = True

        self.seen_event_in_this_window = False

        t = engine.get_now()
        t_next = self.expected_timefunction.next_change(t)
        if self.expected_timefunction.state(t):
            self.engine.register_event_at(t_next, self.tick_window_end, self,
                                          self)
        else:
            self.engine.register_event_at(t_next, self.tick_window_start, self,
                                          self)
Esempio n. 2
0
def compose_class(class_names):
    """Create a composite class from a list of class names."""
    classes = []
    classes.append(Basic)   # Class is the root of inheritance
    for class_name in class_names:
        if class_name != "basic":   # Normally this is not explicitly specified, so is implicit, but even it is explicit we want to ensure that it's the last class added
            classes.append(importer.get_class('device', class_name))
    classes.reverse()   # In each device class constructor, the first thing we do is to call super(). This means that (in terms of the order of execution of all the init code AFTER that call to super()), the last shall be first
    return type("compositeDeviceClass", tuple(classes), {})
Esempio n. 3
0
 def render_smart_properties(self, elem):
     new_props = {}
     if "properties" in elem:
         for n, v in elem["properties"].copy().items():
             if type(v) == dict:
                 model = importer.get_class('model', n)
                 model(self.context, v, new_props)
                 del elem["properties"][n]  # Delete smart property
         elem["properties"].update(new_props)
Esempio n. 4
0
 def __init__(self, instance_name, time, engine, update_callback, context,
              params):
     """A button which gets pressed according to some time function"""
     super(Button, self).__init__(instance_name, time, engine,
                                  update_callback, context, params)
     tf = params["button"]["timefunction"]
     self.button_timefunction = importer.get_class(
         "timefunction",
         tf.keys()[0])(engine, self, tf[tf.keys()[0]])
     engine.register_event_at(self.button_timefunction.next_change(),
                              self.tick_button, self, self)
Esempio n. 5
0
 def __init__(self, instance_name, time, engine, update_callback, context,
              params):
     """Take Comms up and down according to some time function"""
     tf = params["commswave"]["timefunction"]
     self.comms_timefunction = importer.get_class(
         "timefunction",
         list(tf.keys())[0])(engine, self, tf[list(tf.keys())[0]])
     self.comms_tf_threshold = params["commswave"].get("threshold", None)
     self.messages_sent = 0
     self.messages_attempted = 0
     super(Commswave, self).__init__(instance_name, time, engine,
                                     update_callback, context, params)
Esempio n. 6
0
        def create_var(params):
            self.my_random = random.Random(
            )  # We use our own random-number generator, one per variable per device
            rp = params.get("randomness_property", None)
            if rp is None:
                self.my_random.seed(
                    self.get_property("$id"))  # Seed each device uniquely
            else:
                self.my_random.seed(hash(self.get_property(rp)))

            var_name = params["name"]

            if "value" in params:
                var_value = params["value"]
                if type(var_value) == list:
                    var_value = self.my_random.choice(var_value)
                variables[var_name] = var_value
            elif "timefunction" in params:
                tf_name = list(
                    params["timefunction"].keys())[0]  # We know there's only 1
                var_value = importer.get_class("timefunction", tf_name)(
                    engine, self, params["timefunction"][tf_name])
                variables[var_name] = var_value.state()
                next_change = var_value.next_change()
                engine.register_event_at(next_change, self.tick_variable,
                                         (var_name, var_value), self)
            elif "random_lower" in params:
                lower = float(params["random_lower"])
                upper = float(params["random_upper"])
                precision = params.get("precision", 1)
                var_value = lower + self.my_random.random() * (upper - lower)
                var_value = int(var_value * precision) / float(precision)
                variables[var_name] = var_value
            elif "randstruct" in params:
                var_value = randstruct.evaluate(params["randstruct"],
                                                self.my_random)
                variables[var_name] = var_value
            elif "series" in params:
                series = params["series"]
                if var_name not in Variable.device_indices:
                    Variable.device_indices[var_name] = 0
                idx = Variable.device_indices[var_name]
                var_value = series[idx % len(series)]
                variables[var_name] = var_value
            else:
                assert False, "variable " + var_name + " must have either value, timefunction, random_lower/upper, randstruct or series"
Esempio n. 7
0
    def __init__(self, engine, device, params):
        self.engine = engine
        self.device = device
        self.mix_operator = params["operator"]
        self.mix_timefunctions = []
        for f in params["timefunctions"]:
            tf = importer.get_class("timefunction",
                                    f.keys()[0])(engine, device,
                                                 f[f.keys()[0]])
            self.mix_timefunctions.append(tf)

        self.operators = {
            "add": self.operator_add,
            "and": self.operator_and,
            "mul": self.operator_mul
        }

        self.initial_state = {"add": 0.0, "and": 1.0, "mul": 1.0}
Esempio n. 8
0
def main():
    global g_get_sim_time
    global g_instance_name
    
    def postWebEvent(webParams):    # CAUTION: Called asynchronously from the web server thread
        if "action" in webParams:
            if webParams["action"] == "event":
                if webParams["headers"]["Instancename"] == g_instance_name:
                    engine.register_event_in(0, device_factory.external_event, webParams, None)
            elif webParams["action"] == "announce":
                logging.log(webParams["severity"], "[broadcast message] "+webParams["message"])

    def event_count_callback():
        return events.event_count

    logging.getLogger().setLevel(logging.INFO)
    os.makedirs("../synth_logs", exist_ok = True)
    os.makedirs("../synth_accounts", exist_ok = True)
    params = get_params()
    assert g_instance_name is not None, "Instance name has not been defined, but this is required for logfile naming"
    init_logging(params)
    logging.info("*** Synth starting at real time "+str(datetime.now())+" ***")
    logging.info("Parameters:\n"+json.dumps(params, sort_keys=True, indent=4, separators=(',', ': ')))
    post_to_slack("Started")

    Tstart = time.time()
    random.seed(12345)  # Ensure reproduceability

    if not "client" in params:
        logging.error("No client defined to receive simulation results")
        return
    client = importer.get_class('client', params['client']['type'])(g_instance_name, params, params['client'])

    if not "engine" in params:
        logging.error("No simulation engine defined")
        return
    engine = importer.get_class('engine', params['engine']['type'])(params['engine'], client.enter_interactive, event_count_callback)
    g_get_sim_time = engine.get_now_no_lock

    if not "events" in params:
        logging.warning("No events defined")
    events = Events(client, engine, g_instance_name, params, params["events"])

    zeromq_rx.init(postWebEvent)

    logging.info("Simulation starts")

    err_str = ""
    try:
        while engine.events_to_come():
            engine.next_event()
            client.tick()
        device_factory.close()
    except:
        err_str = traceback.format_exc()  # Report any exception, but continue to clean-up anyway
        logging.error("Error at real time "+str(datetime.now())+" (local)")
        logging.error(err_str)

    logging.info("Simulation ends")
    logging.info("Ending device logging ("+str(len(device_factory.g_devices))+" devices were emulated)")
    events.flush()
    client.close()

    logging.info("Elapsed real time: "+str(int(time.time()-Tstart))+" seconds")

    if err_str=="":
        post_to_slack("Finished OK")
        exit(0)
    post_to_slack(err_str)
    exit(-1)
Esempio n. 9
0
def main():
    global g_get_sim_time
    global g_instance_name
    global g_asked_to_pause

    def incomingAsyncEvent(
            packet
    ):  # CAUTION: Called asynchronously from the ZeroMQ rx thread
        logging.info("incoming async event " + str(packet))
        if "action" in packet:
            if packet["action"] == "event":
                if packet["headers"]["Instancename"] == g_instance_name:
                    logging.info("Matches this instance name, so dispatching")
                    engine.register_event_in(0, device_factory.external_event,
                                             packet, None)
            elif packet["action"] == "announce":
                logging.log(packet["severity"],
                            "[broadcast message] " + packet["message"])
            elif packet["action"] == "command":
                if packet["headers"]["Instancename"] == g_instance_name:
                    argv = packet["argv"]
                    logging.info("Received async command " + str(argv))
                    if len(argv) > 0:
                        client.async_command(argv)

    def event_count_callback():
        return events.event_count

    logging.getLogger().setLevel(logging.INFO)
    os.makedirs("../synth_logs", exist_ok=True)
    os.makedirs("../synth_accounts", exist_ok=True)

    params = get_params()
    assert g_instance_name is not None, "Instance name has not been defined, but this is required for logfile naming"
    init_logging(params)
    logging.info("*** Synth starting at real time " + str(datetime.now()) +
                 " ***")
    logging.info(
        "Parameters:\n" +
        json.dumps(params, sort_keys=True, indent=4, separators=(',', ': ')))
    post_to_slack("Started")

    install_signal_catcher()

    Tstart = time.time()  # Human time
    Tstart_process = time.process_time()  # Time CPU usage
    random.seed(12345)  # Ensure reproduceability

    if not "client" in params:
        logging.error("No client defined to receive simulation results")
        return
    client = importer.get_class('client',
                                params['client']['type'])(g_instance_name,
                                                          params,
                                                          params['client'])

    if not "engine" in params:
        logging.error("No simulation engine defined")
        return
    engine = importer.get_class('engine', params['engine']['type'])(
        params['engine'], client.enter_interactive, event_count_callback)
    g_get_sim_time = engine.get_now_no_lock

    if not "events" in params:
        logging.warning("No events defined")
    events = Events(client, engine, g_instance_name, params, params["events"])

    zeromq_rx.init(incomingAsyncEvent, emit_logging=True)
    zeromq_tx.init(emit_logging=True)

    logging.info("Simulation starts")

    faulthandler.dump_traceback_later(
        600, repeat=True
    )  # TEMP - every 10 minutes emit a stack trace for every thread - to diagnose hanging issue
    err_str = ""
    try:
        while engine.events_to_come():
            engine.next_event()
            client.tick()
            if g_asked_to_pause:
                g_asked_to_pause = False
                logging.info("Paused")
                signal.pause(
                )  # Suspend this process. Receiving any signal will then cause us to resume
                logging.info("Resuming")
        device_factory.close()
    except:
        err_str = traceback.format_exc(
        )  # Report any exception, but continue to clean-up anyway
        logging.error("Error at real time " + str(datetime.now()) + " (local)")
        logging.error(err_str)

    logging.info("Simulation ends")
    logging.info("Ending device logging (" +
                 str(len(device_factory.g_devices)) +
                 " devices were emulated)")
    events.flush()
    client.close()

    logging.info("Elapsed real time: " + str(int(time.time() - Tstart)) +
                 " seconds.")
    logging.info("CPU time used: " +
                 str(int(time.process_time() - Tstart_process)) + " seconds.")

    if err_str == "":
        post_to_slack("Finished OK")
        exit(0)
    post_to_slack(err_str)
    exit(-1)