It is quite usual in a statechart to rely on some notion of time.
To cope with this, the built-in evaluator (see PythonEvaluator) has support for
time events after(x) and idle(x), meaning that a transition can be triggered after a certain amount of time.

When it comes to interpreting statecharts, Sismic deals with time using an internal clock whose value is exposed
by the time property of an Interpreter.
Basically, this clock does nothing by itself except for being available for an
Evaluator instance.
If your statechart needs to rely on a time value, you have to set it by yourself.

Sismic provides a discrete step-by-step interpreter for statecharts.
It seems natural in a discrete simulation to rely on simulated time.

The following example illustrates a statechart modeling the behavior of a simple elevator.
If the elevator is sent to the 4th floor, according to the YAML definition of this statechart,
the elevator should automatically go back to the ground floor after 10 seconds.

-target:doorsClosedguard:after(10)andcurrent>0action:destination=0

Rather than waiting for 10 seconds, one can simulate this.
First, one should load the statechart and initialize the interpreter:

If a statechart needs to be aware of a real clock, the simplest way to achieve this is by using
the time.time() function of Python.
In a nutshell, the idea is to synchronize interpreter.time with a real clock.
Let us first initialize an interpreter using one of our statechart example, the elevator:

The interpreter initially sets its clock to 0.
As we are interested in a real-time simulation of the statechart,
we need to set the internal clock of our interpreter.
We import from time a real clock,
and store its value into a starttime variable.

importtimestarttime=time.time()

We can now execute the statechart by sending a floorSelected event, and wait for the output.
For our example, we first ask the statechart to send to elevator to the 4th floor.

At this point, the elevator is on the 4th floor and is waiting for another input event.
The internal clock value is still 0.

Current floor: 4
Current time: 0

We should inform our interpreter of the new current time.
Of course, as our interpreter follows a discrete simulation, nothing really happens until we call
execute() or execute_once().

interpreter.time=time.time()-starttime# Does nothing if (time.time() - starttime) is less than 10!interpreter.execute()

Assuming you quickly wrote these lines of code, nothing happened.
But if you wait a little bit, and update the clock again, it should move the elevator to the ground floor.

interpreter.time=time.time()-starttimeinterpreter.execute()

And voilà!

As it is not very convenient to manually set the clock each time you want to execute something, it is best to
put it in a loop. To avoid the use of a starttime variable, you can set the initial time of an interpreter
using the initial_time parameter of its constructor.
This is illustrated in the following example.

fromsismic.ioimportimport_from_yamlfromsismic.interpreterimportInterpreterfromsismic.modelimportEventimporttime# Load statechart and create an interpreterwithopen('examples/elevator.yaml')asf:statechart=import_from_yaml(f)# Set the initial timeinterpreter=Interpreter(statechart)interpreter.time=time.time()# Send an initial eventinterpreter.queue(Event('floorSelected',floor=4))whilenotinterpreter.final:interpreter.time=time.time()ifinterpreter.execute():print('something happened at time {}'.format(interpreter.time))time.sleep(0.5)# 500ms

Here, we called the sleep() function to slow down the loop (optional).
The output should look like:

Notice from previous example that using a loop makes it impossible to send events to the interpreter.
For convenience, sismic provides a sismic.interpreter.helpers.run_in_background()
function that run an interpreter in a thread, and does the job of synchronizing the clock for you.

Note

An optional argument callback can be passed to run_in_background().
It must be a callable that accepts the (possibly empty) list of MacroStep returned by
the underlying call to execute().