So we have Raspberry, LCDs, keyboards and all this stuff. Now time to put some live in it.
My idea is to create modular centre.
Main part of system is Core. Its simple program that connect all parts, mainly workers and I/Os. Worker is part of system that do a job. For example keeps track of weather, get sensor readings, checks emails or close window. I/O connect user to system and call workers. Its i2c keyboard manager (push events to core) or LCD display manager (it call workers to get date to display)
So back to core. It import workers and I/Os. Names are in array, and later will be move to config file. Each name is a python package name and worker.py or io.py is searched and imported.
They are imported into core arrays and not into global scope. For worker Worker class is created and for I/O IO class. __init__(self, core) takes one argument: core (each module got access to core, later it will be changed to connector class). Each module must have a few functions: start(), shutdown() and receive_event(e) in I/O.
Main loop in core is very simple, it pop event from event array and send it to all I/Os. After that calculate time to sleep in such way that each loop takes 0.5s.
Event is a simple class with fields: type, code, value, source. Type goes for global type such as keyboard, command, system. More detailed type is in source, for example i2c1 or wiimote.
The Core has two more important functions. Function add_event(self, event) adds event to array. And function work(self, *args) that calls worker. Job is parsed and call is made. All parameters are send to worker. Lets say we call w = self.core.work(‘weather’, ‘forecast’) from one of I/Os. First check is made if weather worker exists. And if does varible worker is ouer worker. Next statement is parsed to worker.forecast(). If we send more than 2 parameters to work() all parameters will be parsed and appended to statement. So if we have self.core.wok(‘myjob’, ‘light’, ‘on’, ‘1’) it will be parsed to worker.light(‘on’, ‘1’) where worker is reference to myjob.
I/Os and worker startup is in start() function. It may start another thread if necessary or do anything required to proper working.
For example weather/worker.py in init create a Weather class which have a thread to ping weather server. It works independently so whenever systems ask for weather its returned from cache. Functions start() and stop() starts and stops Weather thread. Two more functions, weather to return current weather and forecast to return weather forecast for date and we have a fully functional worker. All hard job goes to Weather class.
Now for I/O. Its base job is to take some input (from user or another thread) send request to core, receive response and return it.
Currently I have two such modules that works differently. LCD have a thread that calls workers and display response on lcd. It also react on events (display menu, change active tab). Another one is i2c keyboard. It reads input each 250ms and send keyboard event to core.