Overview
After installing pyobs, you have the new command pyobs
, which creates and
starts pyobs modules from the command line based on a configuration file, written
in YAML.
A simple configuration file (standalone.yaml
) might look like this:
class: pyobs.modules.test.StandAlone
message: Hello world
interval: 10
Basically you always define a class
for a block together with its properties.
In this example, the module is of type StandAlone
, which is a trivial implementation
of a module that does nothing more than logging a given message continuously in a given interval:
class StandAlone(Module):
"""Example module that only logs the given message forever in the given interval."""
def __init__(self, message: str = 'Hello world', interval: int = 10, *args, **kwargs):
"""Creates a new StandAlone object.
Args:
message: Message to log in the given interval.
interval: Interval between messages.
"""
Module.__init__(self, *args, **kwargs)
# add thread func
self._add_thread_func(self._message_func, True)
# store
self._message = message
self._interval = interval
def _message_func(self):
"""Thread function for async processing."""
# loop until closing
while not self.closing.is_set():
# log message
log.info(self._message)
# sleep a little
self.closing.wait(self._interval)
The constructor just calls the constructor of Module
and calls a method
add_background_task()
, which takes a method that is run in an extra thread. In this case,
it is the method thread_func()
, that does some logging in a loop until the program quits.
The class method default_config() defines the default configuration for the module, and open() and close() are called when the module is opened and closed, respectively.
If the configuration file is saved as standalone.yaml
, one can easily start it via the pyobs
command:
pyobs standalone.yaml
The program quits gracefully when it receives an interrupt, so you can stop it by simply pressing Ctrl+c
.
Modules
A Module defines a single process in pyobs, as defined in Module
. Modules can work
completely independent of each other, but usually they want to communicate and call methods on other modules.
The functionality that a module exports for remote calling is defined by its base classe, specifically classes
derived from Interface
.
Location of observatory
There is some functionality that is required in many modules, including those concerning the environment,
especially the location of the telescope and the local time. For this, there is support for an additional object
of type Environment
, which can be defined in the application’s configuration
at top-level like this:
timezone: Africa/Johannesburg
location:
longitude: 20.810808
latitude: -32.375823
elevation: 1798.
Now an object of this type is automatically pushed into the module and can be accessed via the environment
property, e.g.:
def open(self):
Module.open(self)
print(self.environment.location)
Communication between modules
In case the module is supposed to communicate with others, we need another module of type
Comm
, which can be defined in the application’s configuration like this:
comm:
class: pyobs.comm.xmpp.XmppComm
jid: some_module@my.domain.com
More details about this can be found in the Communication between modules (pyobs.comm) section.
Virtual File System
At the telescope the pyobs system usually contains multiple modules that are distributed over several computers. In order to make file exchange es easy as possible, pyobs has a built-in virtual file system (VFS) that dynamically maps file paths to real locations.
A typical VFS setup in a module configuration file looks like this:
vfs:
class: pyobs.vfs.VirtualFileSystem
roots:
cache:
class: pyobs.vfs.LocalFile
root: /path/to/data
This simple case uses a LocalFile
to map every filename beginning with cache
(see the key in the
roots
dictionary) to the path /path/to/data
in the local file system. So opening a file via
vfs.open_file('/cache/test.txt', 'w')
actually opens the file in /path/to/data/test.txt
for writing.
The magic begins when running another module on another computer with this configuration:
vfs:
class: pyobs.vfs.VirtualFileSystem
roots:
cache:
class: pyobs.vfs.SSHFile
hostname: othercomputer
username: xxx
password: xxx
root: /path/to/data
Now on that machine you can read the same file, using the same command vfs.open_file('/cache/test.txt', 'r')
,
via a SSH connection, by specifying SSHFile
as the class for the given root.
See Virtual File System (pyobs.vfs) for more information about the VFS.
Events
In addition to calling each other’s method, pyobs modules can also send and receive events. See more about this in Events (pyobs.events).