Minimal working setup for pyobs inside a Jupyter notebook
Introduction
This is a short introduction to using pyobs inside a Jupyter notebook. If you are already familiar with pyobs, you will find that the only big difference is the setup process and how you interact with and manage your own module. If you are new to pyobs, this notebook should give you a good first introduction for writing code which interacts with pyobs.
Setup
Preparations
The following code (and pyobs in general) depends on the asyncio
event loop running. If the following code returns False
you will
need to upgrade your Jupyter version, as older versions don’t support
asyncio
.
import asyncio
asyncio.get_event_loop().is_running()
Before we start with the actual setup, we have to redirect the loggin
output to stdout
, so that is displayed inside the cell output. If
you want to disable error/warning messages, you can skip this step.
import logging
import sys
logging.basicConfig(stream=sys.stdout)
Credentials
This is not specific to pyobs itself, but is general advice: NEVER
commit credentials to a git repository. In the case of the normal pyobs
yaml
configuration files pyobs allows other config files config
files to be imported, in which the credentials can be stored, while the
config file containing the credentials can be added to the
.gitignore
file. In the case of Jupyter notebooks I recommend using
.env
files, which can be simmilarly excluded from the repo by adding
them to the .gitignore
file. This also allow you to share the
credentials between multiple notebooks in the same probject.
For this to work, simply add a .env
file to your project root and
add the following lines:
COMM_JID = "[USERNAME]@iag50srv.astro.physik.uni-goettingen.de"
COMM_PWD = "[PASSWORD]"
You want to replace the username and password with your credentials and
if you are not at the IAG, replace the address after the @
with the
one of your institute. After adding this, the load_dotenv()
below,
shoud return True
import os
from dotenv import load_dotenv
load_dotenv()
COMM_JID = os.getenv('COMM_JID')
COMM_PWD = os.getenv('COMM_PWD')
Comm
For our pyobs module to work, it needs a valid comm
module
to communicate with other modules (telescopes, cameras, etc.). In a
production environment, XMPP is used for this communication, so a
XmppComm
module is created with the credentials, that where
previously loaded.
from pyobs.comm.xmpp import XmppComm
comm = XmppComm(jid=COMM_JID, password=COMM_PWD, use_tls=True)
Open Comms
Open a channel, lieutenant.
By opening the comm module, we connect it to the pyobs network, so that we can communicate with the other modules on the network.
await comm.open()
If everything works and if other modules are connected to the network, the following command should return the names of these modules:
comm.clients
Closing Comms
At the end of a session, the comm module should be closed again. This signals to the rest of the network, that the module is not longer available.
await comm.close()
Virtual File System (VFS)
If you want to work with a camera, the module also needs access to the pyobs virtual filesystem. Again if you are not at the IAG, you will need to replace the download address below, with your own address.
from pyobs.vfs import VirtualFileSystem
vfs = VirtualFileSystem(
roots={
"cache":
{
"class": "pyobs.vfs.HttpFile",
"download": "https://iag50srv.astro.physik.uni-goettingen.de/pyobs/filecache/"
}})
Usage
Telescope
The module can now be used to control other modules on the network.
First we create a proxy object for a telescope. The proxy object is a
local representation of the remote module, but can be controlled using
its usual methods. The proxy
method needs the “username” of the
module which it is proxying, in this case, the name of the telescope.
from pyobs.interfaces import ITelescope
TELESCOPE_NAME = "telescope"
telescope = await comm.proxy(TELESCOPE_NAME, ITelescope)
The proxy telescope then can be used to get the orientation of the telescope…
await telescope.get_radec(), await telescope.get_altaz()
and to move it in altaz coordinates…
await telescope.move_altaz(alt=60, az=180)
or radec coordiantes (both in degrees).
await telescope.move_radec(ra=60, dec=25)
Camera
A camera can be used in the same way, as a telescope. First, we create a
proxy for a module with the “username” "sbig6303e"
as the camera.
from pyobs.interfaces import ICamera
CAMERA_NAME = "sbig6303e"
camera = await comm.proxy(CAMERA_NAME, ICamera)
With the proxy object, we then can set the exposure time and image type.
from pyobs.interfaces import IExposureTime
from pyobs.interfaces import IImageType
from pyobs.utils.enums import ImageType
if isinstance(camera, IExposureTime):
await camera.set_exposure_time(2)
if isinstance(camera, IImageType):
await camera.set_image_type(ImageType.OBJECT)
grab_data
then starts the exposure and returns the path to the image
in the virtual filesystem. This path is then supplied to the vfs
module to retrieve the image.
image_name = await camera.grab_data(broadcast=False)
img = await vfs.read_image(image_name)
Now we can look at the header…
img.header
and at the image itself.
import matplotlib.pyplot as plt
plt.imshow(img.data, cmap="gray")
plt.show()
We can also save the image as a file.
img.writeto("image_test.fits")