Basic program side setup
Learn how to easily setup program side.
In this tutorial, we are going to learn how we can setup the program side, and link simulation to it.
First, we will learn some basic concepts before we begin.
Queue & Tick
This section is not necessary for you to understand to use it, since the queue state is automatically managed for you. But it is a good idea to read through.
Ideally, your algorithm should finish processing any changes triggered by user actions instantly. But this is not the case in reality. Your program are most likely running on complex logic, and has the possibility to runs slower than user. This brings complications of state management, and a new concept of processing state, since the current state is not your processing state if your program are more than one step behind. The framework solve this problem by tracking a queue of state, and manage your sleep schedule for you:
- Queue management: the framework always keeps the data safely for you under multiprocessing contexts.
- Access processing state: your program will always be able to get correct processing states with very high speed.
- Tick management: your program always wake up at the right time, and put to sleep at the right time.
Setup your tick
In this example, we are going to setup a simple tick that doing nothing but read data from it. Simply write your own tick class, and import start function from listener package.
The following code will keep waiting for listener, until you have one running. Do not worry! We will teach you how to setup one in a bit. So DO NOT RUN the code yet!
Bear with us
In this section, we will only talk about setup communication on one side. For your program side, the rest of tutorial will take care of it. It may seems confused a little bit since we are only build one side in this tutorial, but it will not after you walk through all of them, bear with us.
from time import sleep
from random import random
def tick(data_manager):
sleep(random()*2) # simulate time costs for ur program, 0-2 secs
from algotron.listener import Listener
listener = Listener(loc='localhost', port=33333)
listener.start(tick)
In this case, we defined a simple tick function that listen to the program side, and every time the program side has a change, the tick function will get called.
Notice that tick function has to have a signature of one parameter: data_manager. For the next example we are going to teach you how to use it.
Tip for unstack from "waiting for watchdogs"
If for some reason, you are unable to setup simulation side, the program side will be waiting forever. The listener has this consideration in mind. While you are waiting for the socket, you can exit by ctrl-c.
Data_manager
Data manager is your good friend, it can get the new changes, and any physical / sensor data you want with high speed. Under the surface data_manager do more than store and fetch data, it also keeps data thread safe, and manage your sleep schedule for you.
As an example to ask change or data, we can change the tick function to following:
def tick(data_manager):
sleep(random()*2) # simulate time costs for ur program, 0-2 secs
print '---- TICK ----'
print 'current change: {}'.format(data_manager.get_change())
print 'chair1: {}'.format(data_manager.get_object(name='chair1'))
print 'chair2: {}'.format(data_manager.get_object(name='chair2'))
print 'c1 pressure sensor: {}'.format(data_manager.get_sensor_state(obj_name='chair1', state='pressure'))
print 'c2 pressure sensor: {}'.format(data_manager.get_sensor_state(obj_name='chair2', state='pressure'))
print 'door1 sensor: {}'.format(data_manager.get_sensor_state(obj_name='door1', state='opened'))
The data manager has many functions.
- "get_change" gets the newest change;
- "get_sensor_state" gets any sensor attached to a physical state
- "get_object" gets any object state
What if you made a bug in your code? No worries! Data manager also protect you from it in multi-threading environment. If bug happened it can capture it, print the error, and clean up system resources.
Attach your program to simulation
So far, you have setup a minimal version of simulation and a listener for your program. Your algorithm (or program) will be on the other side of the simulation, in a different location, receive new changes in the environment, access the sensor states, and reasoning based on them. This requires the simulation side knows the location of your running program.
The algotron provides you simple interface that allows you connect to your program. Simply add those at the beginning and end of the actions your human performed, so your program receives any new changes triggered in simulation, and have access to states in simulation as well:
# at the beginning of jackman
from algotron.watchdog import Sergeant
sergeant = Sergeant(client_addr=('localhost', 33333),
sim=myhome,
#ignores=['physics']
).ready()
# after the last action of jackman
sergeant.detach()
In this setup, it tells the simulation there is a program running on the same machine, at port 44444, listening to any changes triggered by "myhome" simulation. By the time it call ready, it will try to communicate with the other side, and if success, push all the new changes (notification) to the other side.
By default, it push all changes happened. But if you only want sensor states change, you can uncomment the "ignores" line to ignore any physics state.
Remember to call "detach" to close the communication and clean it up nicely.
So what are watchdogs?
You may or may not notice, we are using sergent class from watchdog package. This package contains all kind of program implement listener pattern, their job is to watch any change made in scope and report to the other side. In smart home environment we set up two kind of watchdogs, one called "sergeant", attach to one smart home and report all changes. Sergeant is designed to intelligently limit the traffic by managing socket and determine which state change is important, and marshalling messages. The other one called "doorman", by contrast attached to a device in environment, only report change relative to a much smaller scope, designed to tradeoff communication efficiency to running speed. In this version, doorman is not very robust and not recommended to use.
Try it!
As a simple example, can u try to add chair2, a second pressure sensor to it? Try it! The answer is in the next section.
Congratulations
Congratulations, you have just finished developer tutorial.
Updated over 8 years ago