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

Every block always defines a class together with its parameters. When pyobs loads this file, it instantiates the given class and passes the remaining keys as keyword arguments to its constructor.

In this example, the module is of type StandAlone, which logs a message repeatedly at a given interval. Its implementation looks like this:

import asyncio
import logging
from typing import Any
from pyobs.modules import Module

log = logging.getLogger(__name__)


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, **kwargs: Any):
        Module.__init__(self, **kwargs)
        self._message = message
        self._interval = interval
        self.add_background_task(self._message_func)

    async def _message_func(self) -> None:
        while True:
            log.info(self._message)
            await asyncio.sleep(self._interval)

The constructor calls Module.__init__ (forwarding **kwargs so that comm, vfs, and other shared parameters are handled automatically) and registers a background task using add_background_task(). Background tasks are async coroutines that run concurrently while the module is open. The task here loops indefinitely, logging the message and then sleeping.

If the configuration file is saved as standalone.yaml, start it with:

pyobs standalone.yaml

The program shuts down gracefully when it receives an interrupt (Ctrl+c).

For a deeper look at how Object and Module work, see Objects (pyobs.object) and Modules (pyobs.modules).

Modules

A Module defines a single process in pyobs, as defined in Module. Modules can work completely independently of each other, but usually they communicate with and call methods on other modules. The functionality that a module exports for remote calling is defined by its interfaces — classes derived from Interface. See Interfaces (pyobs.interfaces) for the full list.

Location of observatory

Many modules need to know where the telescope is located and what the local time is. This is configured at the top level of any module configuration file:

timezone: Africa/Johannesburg
location:
  longitude: 20.810808
  latitude: -32.375823
  elevation: 1798.

From these values, pyobs automatically builds an Observer object, which is available inside any module via the observer property. The location itself is accessible via location, and the timezone via timezone:

async def open(self) -> None:
    await Module.open(self)
    print(self.observer.location)

Communication between modules

For a module to communicate with others, it needs a Comm object, defined in the configuration like this:

comm:
  class: pyobs.comm.xmpp.XmppComm
  jid: some_module@my.domain.com

Once configured, other modules on the network can be reached via a proxy:

telescope = await self.proxy("telescope", ITelescope)
await telescope.move_radec(ra=83.8, dec=-5.4)

More details about this can be found in the Communication between modules (pyobs.comm) section.

Virtual File System

In a pyobs system, modules are typically distributed across several computers. To make file exchange straightforward, pyobs has a built-in virtual file system (VFS) that maps logical file paths to real locations transparently.

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 maps every filename beginning with cache to the path /path/to/data on the local file system. Opening /cache/test.txt for writing via vfs.open_file('/cache/test.txt', 'w') actually writes to /path/to/data/test.txt.

The same path on a different machine can be mapped over SSH:

vfs:
  class: pyobs.vfs.VirtualFileSystem
  roots:
    cache:
      class: pyobs.vfs.SSHFile
      hostname: othercomputer
      username: xxx
      password: xxx
      root: /path/to/data

Both machines use the same vfs.open_file('/cache/test.txt', ...) call — the VFS handles the transport transparently. See Virtual File System (pyobs.vfs) for more information.

Events

In addition to calling each other’s methods, pyobs modules can send and receive events asynchronously. See Events (pyobs.events) for details.