Collecting data

Writing Plugins

To integrate a new device, you have to program your own plugin.

Each user-plugin must be stored in the user-directory ~/.RTOC/devices/. Each plugin must has its own folder.

Plugins are written in Python3 and need to follow some rules:

from LoggerPlugin import LoggerPlugin # contains all plugin-functions

class Plugin(LoggerPlugin):  # This must be the main class of your function
      def __init__(self, *args, **kwargs):
        super(Plugin, self).__init__(*args, **kwargs))

        # start your code here

The above lines must be copied exactly into the plugin!

All functions and parameters defined in the main class are available for scripts. To prevent them from being displayed in the Script Help (and Telegram-bot), parameters and functions must begin with ‘_’.

Refer to LoggerPlugin for a full list of available functions.

The following example plugin sends data to RTOC every second and loads an empty GUI

Template.py

"""
This template shows, how to implement plugins in RTOC

RTOC version 2.0

A plugin needs to import RTOC.LoggerPlugin to be recognized by RTOC.
"""
try:
    from LoggerPlugin import LoggerPlugin
except ImportError:
    from RTOC.LoggerPlugin import LoggerPlugin

import sys
import time
from PyQt5 import uic
from PyQt5 import QtWidgets
import numpy as np

DEVICENAME = "Template"
"""Definition of the devicename outside of plugin-class"""

AUTORUN = True
"""If true, the thread to collect data will run right after initializing this plugin"""
SAMPLERATE = 1
"""The thread,which is supposed to collect data will be executed with 1 Hz"""


class Plugin(LoggerPlugin):
    def __init__(self, *args, **kwargs):
        super(Plugin, self).__init__(*args, **kwargs)
        """Call this to initialize RTOC.LoggerPlugin"""

        self.setDeviceName(DEVICENAME)
        """
        Set a default devicename.
        This will be used for all signals sent by this plugin as default
        """

        self.smallGUI = True
        """This plugin has a GUI, which is small. GUI can be shown in two different ways."""

        self._firstrun = True

        self.setPerpetualTimer(self._updateT, samplerate=SAMPLERATE)
        """You will need to collect data periodically in many applications. You need to start that in a seperate thread.

        RTOC provides a simple way to start a repeated thread with :py:meth:`.LoggerPlugin.setPerpetualTimer`. The first parameter is the function, which collects data and sends it to RTOC. You can define a ``samplerate`` or an ``interval`` to set the samplerate.

        You can still use normal threads to do the same thing, but in this way, the plugin can be stopped properly. If you are using normal threads, make sure, to have a loop limited by '
        ``self.run`` with ``while self.run:``.
        """

        if AUTORUN:
            self.start()
            """
            Start the configured perpetualTimer. You can stop it with ``self.cancel()``. If you want to start data collection, when this plugin is started, you need to call ``self.start()`` in the plugin-initialization.
            """

    def _updateT(self):
        """
        This function is called periodically after calling ``self.start()``.

        This example will generate a sinus and a cosinus curve. And send them to RTOC.


        """
        y1 = np.sin(time.time())
        y2 = np.cos(time.time())

        self.stream([y1, y2], snames=['Sinus', 'Cosinus'], unit=["kg", "m"])
        """
        Use this function to send data to RTOC: :py:meth:`.LoggerPlugin.stream`
        """

        self.plot([-10, 0], [2, 1], sname='Plot', unit='Wow')
        """
        Use this function to send data to RTOC: :py:meth:`.LoggerPlugin.plot`
        """
        if self._firstrun:
            self.event('Test event', sname='Plot', id='testID')
            """
            Use this function to send an event to RTOC: :py:meth:`.LoggerPlugin.event`
            """
            self._firstrun = False

    def loadGUI(self):
        """
        This function is used to initialize the Plugin-GUI, which will be available in :doc:`GUI`.

        This is optional.

        Returns:
            PyQt5.QWidget: A widget containing optional plugin-GUI
        """
        self.widget = QtWidgets.QWidget()
        """
        Create an empty QWidget
        """
        packagedir = self.getDir(__file__)
        """Get filepath of this file"""
        uic.loadUi(packagedir+"/Template/template.ui", self.widget)
        """
        This example will load a QWidget designed with QDesigner
        """
        self.widget.teleMessageButton.clicked.connect(self._teleMessageAction)
        self.widget.telePhotoButton.clicked.connect(self._telePhotoAction)
        self.widget.teleFileButton.clicked.connect(self._teleFileAction)
        """
        Connect GUI-buttons with python-functions
        """
        return self.widget  # This function needs to return a QWidget

    def _teleMessageAction(self):
        text = 'Hello world!'
        self.telegram_send_message(text, onlyAdmin=False)

    def _telePhotoAction(self):
        path = self.getDir(__file__)+'/examplePhoto.png'
        self.telegram_send_photo(path, onlyAdmin=False)

    def _teleFileAction(self):
        path = self.getDir(__file__)+'/examplePhoto.png'
        self.telegram_send_document(path, onlyAdmin=False)



hasGUI = True  # If your plugin has a widget do this

if __name__ == "__main__":
    """
    Sometimes you want to use plugins standalone also. This is very useful for testing.
    """
    if hasGUI:
        app = QtWidgets.QApplication(sys.argv)
        myapp = QtWidgets.QMainWindow()

    widget = Plugin()

    if hasGUI:
        widget.loadGUI()
        myapp.setCentralWidget(widget.widget)

        myapp.show()
        app.exec_()

    widget.run = False

    sys.exit()

Plugin repository

This repository contains some plugins for RealTime OpenControl (RTOC).

Installing plugins

You can either install plugins manually or - if you are using the GUI - you can install it with the built-in installer: Plugin-Downloader

Manually

To add a plugin to RTOC you need to do the following steps:

  1. Install RTOC (pip3 install RTOC) - You will need to run RTOC once
  2. Copy the folder of the desired plugin to your RTOC-Userpath: ~/.RTOC/devices/
  3. Now restart RTOC (python3 -m RTOC)

List of plugins

  • Template: An example, showing how to create a simple plugin to send data to RTOC
  • DPS5020: Plugin for DPS powersupplies. It can monitor all data and you can set Voltage, Current and switch it on/off. Uses USB to read data.
  • Funktionsgenerator: Default-plugin of RTOC. Generates common signals.
  • holdPeak_VC820: Plugin for VC820 multimeters. It can monitor the measured values with correct units. Uses USB/Minimalmodbus to read data.
  • INA219_Modul: Plugin for INA219 solar module. Monitors voltage, current, power and shunt_voltage
  • Octotouch: Plugin for 3D-printer-software Octotouch. It can just monitor the temperatures. Uses HTTP/JSON to read data.
  • PIKO_Solarmodules: Plugin for PIKO solar modules. Monitors voltage, current and power
  • System: Plugin to monitor system-information like CPU, Memory, …
  • ReflowOfen/ReflowPlatte: Plugin, which reads data from local network-devices HTTP-address.
  • Heliotherm: Plugin, which reads data from Heliotherm heat pump using TCP/Modbus.
  • Futtertrocknung: Embedded-Plugin. Plugin, which is used to run on a RaspberryPi. Monitors some sensor-data.

Plugin descriptions

Template

GUI: Yes, if you want to

_images/template.png

Dependencies: -

Info: Use this plugin as a starting point

DPS5020

GUI: Yes

Dependencies: pip3 install minimalmodbus

Target system: Each OS (connected to DPS with USB)

Info:

  • You can set a parameters in file DPS5020.py
default_device = '/dev/ttyUSB0'
SERIAL_BAUDRATE = 9600
SERIAL_BYTESIZE = 8
SERIAL_TIMEOUT = 2

Generator

GUI: Yes

_images/generator.png

Dependencies: -

Target system: Each OS

Info:

holdPeak_VC820

GUI: Yes

Dependencies: pip3 install serial

Target system: Each OS (connected to VC820 with USB)

Info:

  • You can set a parameters in file HoldPeak VC820.py: - default_device = ‘COM7’ - SERIAL_BAUDRATE = 2400 - SERIAL_BYTESIZE = 8 - SERIAL_TIMEOUT = 1
  • You will need to run RTOC as root unless you set devices rules. See [this tutorial](http://ask.xmodulo.com/change-usb-device-permission-linux.html) for how to set device rules.

INA219_Modul

GUI: No

Dependencies: pip3 install pi-ina219

Target system: RaspberryPi (connected to INA219 via I2C)

Info:

  • You can set a parameters in file INA219_Modul.py:
    • SHUNT_OHMS = 0.1
    • MAX_EXPECTED_AMPS = 0.2
    • SAMPLERATE = 1/60# frequency in Hz (1/sec)
    • I2C_ADDRESS = 0x41

Octotouch

GUI: Yes

_images/octotouch.png

Dependencies: -

Target system: Each OS (In same network as Octotouch-server)

Info:

You can set a parameters in file OctoTouch.py:

  • devicename = “Octotouch”
  • apikey = “”
  • SAMPLERATE = 1

PIKO_Solarmodules

GUI: No

Dependencies: pip3 install lxml

Target system: Each OS (In same network as PIKO modules)

Info:

  • You can set a parameters in file INA219_Modul.py: - SAMPLERATE = 1/60# frequency in Hz (1/sec) - ADRESSES = [“IP1”, “IP2”, …] #You can specify multiple adresses

System

GUI: Yes

_images/systemPlugin.png

Dependencies: -

Target system: Each OS

Info:

ReflowOfen/ReflowPlatte

GUI: Yes

_images/reflowOven.png

Dependencies: -

Target system: Each OS

Info:

Heliotherm

GUI: Yes

_images/heliotherm.png

Dependencies: pip3 install pyModbusTCP

Target system: Each OS (In same network as Heliotherm heat pump)

Info:

Futtertrocknung

GUI: No

Dependencies: pip3 install adafruit_CCS811 adafruit_DHT board busio

Target system: RaspberryPi

Info: