Close
0%
0%

Remote control terminal

A program to present a terminal interface to the user, in which any hardware controlling software could be controlled or monitored.

Public Chat
Similar projects worth following
The aim of this project was to create a program, which presents a terminal interface to the user, in which he could control or monitor any form of ‘instrument’ running on his Raspberry Pi, or similar device. The terminal interface being best for a headless GUI-less, device, to which you can connect by SSH.

By instrument, I mean a Python program you have written, or may be thinking of writing that controls GPIO pins or attached hardware.

A specification exists ‘INDI’ – which defines a simple protocol for transmitting instrument data, such as switch controls, or measured numeric values, to an attached client.

As the client learns everything from the presented protocol, it can be general purpose, the same client being able to connect to any INDI service. This project provides both a client - a terminal interface, and a package with classes which can be used to create and serve drivers, which can be imported and used in your own programs.

The INDI specification and protocol is widely used in the astronomical world for controlling telescopes, however it is a general purpose protocol and can be used for any form of instrumentation. It defines the data to be divided into ‘switches’, ‘lights’, ‘numbers’, ‘text’ and ‘BLOBs’ (binary large objects), which covers a wide swathe of typical uses.

The basic idea is that a driver has to be written, interfacing to your own instrument code and organising any data you present into a standard format which includes things such as labels and numeric format strings. This is then served on a port to which a client can connect. The client could be remote, or could run locally.

The client uses the labels and names to present the data, and to send controlling information, such as switch On or Off. The client can be anything from an automating script, terminal client, distributed displays or anything which can be written which understands the protocol. In my case I was aiming at a terminal display.

As the client learns everything from the presented protocol, it can be general purpose, the same client being able to connect to any INDI service. It could also be written to control a specific instrument if required.

So the project turned into three Python programs:

indipydriver

This provides classes you use to create a driver which sets, updates and reads data, with a further class to serve your driver (or multiple drivers) on a port.

indipyterm

This is the general purpose terminal client, it is simply run, connects to a port, and displays and controls the instrument parameters it learns. There is no user programming involved.

indipyclient

This is a Python package that most users will not run directly, it is used by indipyterm to decode the INDI protocol and present the received data as Python classes. This code could have been an integral part of indipyterm, but I separated it into its own package as it could be useful if a user wants to create his own clients or scripts for automated remote control.

Installing

All three packages are available on Pypi, indipydriver is typically installed into a project virtual environment, and your own code will import it and use its classes.

Installing indipyterm will automatically install and use indipyclient, together with the ‘textual’ package – and its dependencies, which is a library for creating terminals.

If you use the uv tool, indipyterm can be very simply loaded from Pypi and run with the single command:

uvx indipyterm

For full details of the indipydriver package and its classes, together with examples, follow the readthedocs link.

  • 1
    Example driver

    The following summarises how a driver could be structured, it uses the 'hello world' hardware example describing an LED control on a Raspberry Pi.

    Indipydriver provides classes of 'members', 'vectors' and 'devices', where members hold instrument values, such as switch and number values. Vectors group members together, with labels and group strings, which inform the client how to display the values. 'Devices' hold a number of vectors, so a single device can display several groups of controls.

    The 'IPyDriver' class holds one or more devices, and provides methods you can use to send and receive data, which you would use to interface with your own code.

    You would create a subclass of IPyDriver and override the following methods.

    async def rxevent(self, event)

    This is automatically called whenever data is received from the client to set an instrument parameter. The event object describes the received data, and you provide the code which then controls your instrument.

    async def hardware(self)

    This is called when the driver starts, and as default does nothing, typically it could be a contuously running coroutine which you can use to operate your instruments, and if required send updates to the client.

    async def snoopevent(self, event)

    This is only used if the device is monitoring (snooping) on other devices.

    The indipydriver package also includes an IPyServer class. Having created an instance of your IPyDriver subclass, you would serve this, and any other drivers with an IPyServer object:

    server = IPyServer(*drivers, host="localhost", port=7624, maxconnections=5)
    await server.asyncrun()

    A connected client, such as indipyterm, can then control all the drivers. 



  • 2
    Install indipydriver

    Generally you would install from Pypi into a virtual environment.

    If you are trying this on a Raspberry pi, you may want to use your system gpiozero package. In which case, when creating the virtual environment, use the --system-site-packages option to allow your script to use system packages:

    python3 -m venv --system-site-packages my_env_directory
    
    source my_env_directory/bin/activate
    
    pip install indipydriver
  • 3
    Define your instrumentation objects

    You would initially start the script by defining your own classes. In this example an LED will be controlled:

    import asyncio
    import indipydriver as ipd
    
    # from gpiozero import LED
    
    # If trying this on a raspberrypi, uncomment the line above
    # and comment out or delete this simulated LED class definition
    
    class LED:
        "A class to simulate gpiozero.LED"
    
        def __init__(self, pin):
            self.pin = pin
            self.is_lit = False
    
        def on(self):
            self.is_lit = True
    
        def off(self):
            self.is_lit = False

View all 8 instructions

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates