RealTime OpenControl’s documentation¶
Welcome to RealTime OpenControl’s documentation¶
RealTime OpenControl (RTOC) is a free software for recording measurement data of various measuring instruments. It offers the following components
RTLogger backend¶
The core element of RTOC. More information here: Backend Source-code
Expandable with plugins¶
You can write plugins by your own or use a plugin from the repository. More information here: Collecting data
Telegram-Bot¶
The Telegram-Bot offers access to RTOC from any device with Telegram installed. More information here: Telegram Communication
Websocket-Server¶
Communication with RTLogger from other processes or devices. Suitable for embedded devices with graphical user interface. More information here: /Websocket
Graphical user interface (RTOC-GUI)¶
Used, when running RTOC on computers/laptops to view and edit data. More information here Graphical user interface.
Scripting/Automation¶
You can write scripts and run/edit and stop them during runtime. You have full access to all data stored in RTOC and access to all plugins. A event/action system gives a simple solution for very custom automisations. More information here: Controlling and automation
Getting started¶
Follow one of the installation-instructions (pip, builds, source): Installation
See this Example: Embedded to get an idea of the capabilities of RTOC.
Have a look at the plugin-documentation: Collecting data
RTOC will create a directory in the home-directory, where all user-data is stored. More information here: Userdata
FAQ¶
- How can I get plugins from the community? Plugin repository
- How do I import new data from CSV, Wave, Excel, ODF, Matlab? Import/Export signals/sessions
- How do I connect a new plugin? Collecting data
- How do I create a sub-GUI for a device? Writing Plugins
- How do I create my first script? Controlling and automation
- What does the trigger mean? Trigger-System
- RTOC library and default functions for scripts:
RTLogger.scriptLibrary
- Can I access the data from any device? Telegram Communication or Websocket
- How do I use the graphical user interface? Graphical user interface
- How do I create a telegram bot? Telegram-Bot setup
- How do I control an RTOC server via Websocket in the network? Remote-control via Websocket
- Where can I find examples for plugins? RTOC repository
Feel free to buy me some coffee with milk
Indices and tables¶
Table of contents¶
Installation¶
Python3 needs to be installed on your target-computer. Download python3 from the official website: www.python.org
After installing python3, you are able to run python in a terminal. (cmd.exe
on windows)
.. code-block:: bash
$ python3 –version Python 3.6.3
Installing with Python3 (recommended)¶
RTOC is available in the Python package manager PIP:
pip3 install RTOC
This will download the basic RTOC without the dependencies needed for the GUI, Websockets and Telegram. The default RTOC setup is suitable for running RTOC on embedded devices.
There are also different variations available to install:
pip3 install RTOC[GUI] # Includes all packages for GUI
pip3 install RTOC[Telegram] # Includes all packages for Telegram
pip3 install RTOC[ALL] # Includes all packages
Installing from builds¶
Download the latest release builds for Windows here.
Extract the .zip file into a directory. RTOC is started by double-clicking on “RTOC.exe”. Alternatively via command line:
// local RTOC-instance including GUI
./RTOC
Install manually¶
To use the basic RTOC, the following dependencies must be installed:
pip3 install numpy pycryptodomex requests python-nmap whaaaaat prompt_toolkit psycopg2
If you want to use the GUI you must also install the following packages:
pip3 install pyqt5 pyqtgraph markdown2 xlsxwriter scipy pandas ezodf pyGithub
If you want full functionality, then you still need the following packages (for telegram bot):
pip3 install python-telegram-bot matplotlib
You can use different stylesheets for the GUI if you want. Just install one of these with pip: ‘QDarkStyle’, ‘qtmodern’, ‘qdarkgraystyle’.
The RTOC repository can then be cloned with:
git clone git@github.com:Haschtl/RealTimeOpenControl.git
Long-time measurements in postgreSQL database (optional)¶
If you want to store measurements for a long period of time, I would recommend to use RTOC with a postgreSQL database. Therefore you need to setup postgreSQL on your system and change the postgresql parameters in your config.json file.
Setup postgreSQL on linux
- Open a terminal window
- Issue the command
sudo apt install postgresql
- Follow the instructions to change the default postgresql-password.
- Add a new user. You need to switch to the root user to create a new postgres-user
$ sudo bash
$ su - postgres
$ createuser --interactive --pwprompt
$ Enter name of role to add: <NEWUSERNAME>
$ Enter password for new role: <PASSWORD>
$ Enter it again: <PASSWORD>
$ Shall the new role be a superuser? (y/n) n
$ Shall the new role be allowed to create databases? (y/n) y
$ Shall the new role be allowed to create more new roles? (y/n) n
$ exit // to return to root user
$ exit // to return to your user
- Create a database
$ createdb -O <NEWUSERNAME> <DATABASE_NAME>
- Enter your postgresql username, port, database and password in your config.json file.
Setup postgreSQL on windows
- Download postgresql one-click installer from this website
- Double click on the downloaded file and follow the setup instructions.
- Add a new user and create a database (google for that)
- Enter your postgresql username, port, database and password in your config.json file.
First steps¶
First run¶
After installing RTOC, you can run it with:
// local RTOC-instance including GUI
python3 -m RTOC
// local RTOC-instance without GUI
// I would recommend starting RTOC as a service and not to use this.
python3 -m RTOC.RTLogger -s start/stop
// local RTOC-Configuration from Console
python3 -m RTOC.RTLogger -c
// remote RTOC-instance with GUI
python3 -m RTOC -r <ADRESS>
// explicit local RTOC GUI (even if database is enabled)
python3 -m RTOC -l
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:
- Install RTOC (pip3 install RTOC) - You will need to run RTOC once
- Copy the folder of the desired plugin to your RTOC-Userpath: ~/.RTOC/devices/
- 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¶
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
- 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.
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

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
Heliotherm¶
GUI: Yes

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:
Userdata¶
Document-Tree¶
- User data is stored in the home directory of the current user
- home/USER/.RTOC/ on linux
- C:\user\USER\ .RTOC\ on windows
It contains the following files
.RTOC
├── backup
│ ├── localBackup1.json
│ ├── ...
├── devices
│ ├── Template
│ ├── ├── ...
│ ├── ...
├── autorun_devices
├── config.json
├── globalActions.json
├── globalEvents.json
├── plotStyles.json
├── telegramActions.json
├── telegram_clients.json
backup (directory)¶
Used only, if backup is active and postgresql is not active. Currently this type of backup is not implemented.
devices (directory)¶
Place your plugins inside this folder! Each plugin must be in a folder, which should be named like the main-module of your plugin. For more information on how to make a plugin, click here: Collecting data
autorun_devices¶
Write plugin-names in each line of this file. These plugins will start with RTOC automatically (make sure the plugin-Thread is started in your __init__).
config.json¶
This file contains all RTOC configurations. Its separated in different topics:
global¶
Entry | Default | Type | Information |
---|---|---|---|
language | “en” | “en”,”de” | Selected language |
recordLength | 500000 | int | Local recording limit |
name | “RTOC-Remote” | str | Name displayed in Telegram |
documentfolder | “~/.RTOC” | str | ! Do not change ! |
globalActionsActivated | False | bool | Global actions (in-)active |
globalEventsActivated | False | bool | Global events (in-)active |
postgresql¶
Entry | Default | Type | Information |
---|---|---|---|
active | False | bool | De/activate PostgreSQL database |
user | “postgres” | str | PostgreSQL Username |
password | “” | str | User’s password |
host | “127.0.0.1” | str | Host of PostgreSQL-server |
port | 5432 | int | PostgreSQL port |
database | “postgres” | str | Name of PostgreSQL database |
onlyPush | True | bool | Only push data automatically, if backup active |
GUI¶
Entry | Default | Type | Information |
---|---|---|---|
darkmode | True | bool | De/activate darkmode (inactive) |
scriptWidget | True | bool | Show/hide scriptWidget on startup |
deviceWidget | True | bool | Show/hide deviceWidget on startup |
deviceRAWWidget | True | bool | Show/hide deviceRAWWidget on startup |
pluginsWidget | False | bool | Show/hide pluginsWidget on startup |
eventWidget | True | bool | Show/hide eventWidget on startup |
restoreWidgetPosition | False | bool | Save and restore window and widget positions |
newSignalSymbols | True | bool | (inactive) |
plotLabelsEnabled | True | bool | Show/hide signal-labels in graph |
plotGridEnabled | True | bool | Show/hide grid in graph |
showEvents | True | bool | Show/hide events in graph |
grid”: | [True, True, 1.0] | list | Grid configuration: [X-lines, Y-lines, linewidth] |
plotLegendEnabled | False | bool | Show/hide legend in graph |
blinkingIdentifier | False | bool | Show/hide blue blinking of signal-labels, when they are updated |
plotRate | 8 | float | Updaterate of graph in Hz |
plotInverted | False | bool | Invert plot (black-white/white-black) |
xTimeBase | True | bool | Plot x-axis values as difference from actual timestamp |
timeAxis | True | bool | Use time-ticks for x-axis |
systemTray | False | bool | Dis/enable close to systemTray |
signalInactivityTimeout | 2 | float | Time in seconds after Signal-Label turns yellow |
autoShowGraph | False | bool | Automatically show new signals |
antiAliasing | True | bool | Dis/Enable AntiAliasing |
openGL | True | bool | Dis/Enable OpenGL |
useWeave | True | bool | Dis/Enable Weave |
csv_profiles | {} | dict | Allocation of imported signals is stored here |
telegram¶
Entry | Default | Type Information | |
---|---|---|---|
active | False | bool | De/activate telegram-bot |
token | “” | str | Your telegram bot-token |
default_eventlevel | 0 | 0,1 or 2 | Default eventlevel for new users |
default_permission | ‘blocked’ | ‘blocked’,’read’, ‘write’ or ‘admin’ | Default user permissions for new users. First user is always admin! |
inlineMenu | False | bool | Make the telegram menu inline or in KeyboardMarkup |
onlyAdmin | False | bool | If True, only admins will be able to access the bot |
websockets¶
Entry | Default | Type | Information |
---|---|---|---|
active | False | bool | De/activate Websocket-server |
port | 5050 | int | Websocket-port |
password | ‘’ | str | Optional password for Websocket-encryption (AES) |
knownHosts | {} | dict | Recent Websocket-hosts for remote connection are stored here |
backup¶
Entry | Default | Type | Information |
---|---|---|---|
active | False | bool | De/activate backup-thread |
path | ‘~/.RTOC/backup’ | str | Backup-directory (does not affect backup, if postgreSQL is active!) |
clear | False | bool | Automatically clear local data after backup |
autoIfFull | True | bool | Automatically backup, if local recordLength is reached |
autoOnClose | True | bool | Automatically backup after closing RTOC |
loadOnOpen | True | bool | Automatically load data after starting RTOC (if False, signals are still shown to make sure that IDs are allocated correctly) |
intervall | 240 | float | Set backup-intervall in seconds |
resample | 0 | float | If != 0, signals will be resampled with given samplerate before creating backup |
globalActions.json¶
This file contains all global actions. Read more about the event/action system here: Event/Action system
globalEvents.json¶
This file contains all global events. Read more about the event/action system here: Event/Action system
plotStyles.json¶
This file contains all signal styles, which are used by the GUI. Delete it, to reset all signal styles.
telegramActions.json¶
Use this file to add main-menu-entries in the telegram-bot. More information here: Telegram Custom-menu
telegram_clients.json¶
Information about telegram-clients is stored here: clientID = {eventlevel = 0, shortcuts = [[],[]], first_name = "NAME", last_name = "NAME", permission = "admin", menu = "menu"}
Telegram Communication¶
Telegram-Bot setup¶
Create a new Telegram-Bot¶
- Telegram must be installed on Smartphone/PC,…
- Open the following website: https://telegram.me/BotFather
- Click on ‘SEND MESSAGE’ (Telegram should open and create a new contact ‘BotFather’)
- Create a new bot with the command ‘/newbot
- Enter a name for the bot
- Enter a username for the bot
- You will receive a token which has to be entered in RTOC (looks like this: 123456789:AABBAABB66AA11_uGG22GH44AA55_3)
Configure RTOC for Telegram¶
You can eather configure it in the settings of the RTOC GUI or edit the config.json file by yourself. Enter your Bot-Token there and activate it (active=True
).
User permissions¶
By default any new client connected to this bot will have no permissions. You can change the default behavior in config.json.
The first client connected to the bot will automatically be admin. The admin has the permission to change the permissions of all users.
- blocked: No permissions at all
- custom: Can only call user-specifig shortcuts, cannot receive event-notifications
- read: Can receive event-notifications and plot signals
- write: Can create global Events/Actions, send Events/Signals, access devices
- admin: Full permissions. Can delete signals, access settings menu

Custom permission¶
The custom permission has a special role. A user with ‘custom’ permission will not receive notifications for events and will only see shortcuts, created for this user. Thereby you can provide a very simple bot to users, which will only be able to call selected functions or modify parameters. For example a bot with only two buttons to control the heating in the livingroom: ‘Set Temperature’ and ‘Enable/Disable’
User Shortcuts¶
Any Telegram client can define his own shortcuts to plugin-functions and parameters. These shortcuts will be displayed in the main menu.
To define a new shortcut, you can either modify the shortcuts manually in the telegram_clients.json file.
Clients with ‘write’ or ‘admin’ permission can create shortcuts right in the Telegram bot. You can press the ‘Create shortcut’ button in every plugin-parameter or function submenu.
**Important: ** Every telegram function (telegram_send_message,…) inside a plugin-function will send the message, file or image only to the client, who called the shortcut.
Controlling and automation¶
Overview¶
Own scripts can be used during the runtime:
- modify the measurement data
- Adjusting plugin parameters and calling functions
- Create new signals
- manual and automatic controlling, …
In general, you write a Python script like any other, you can import libraries, etc. However, you should pay attention to performance.
RTOC provides an own library for scripts: RTLogger.scriptLibrary
There are three places, where custom scripting is possible.
- Run scripts in GUI
- Telegram-menu-entries: Telegram Communication
- Event/Action system
Available functions and libraries¶
Python libraries¶
There are several python libraries automatically imported in scripts
import math
import numpy as np
import sys
import scipy as sp
from .RTLogger import scriptLibrary as rtoc
Functions to interact with RTOC¶
Access to plugin parameters and signals in scripts¶
All signals can be references in scripts in these ways
[x],[y] = Device.Signalname
[x] = Device.Signalname.x
[y] = Device.Signalname.y
c = Device.Signalname.latest
plugin parameters and functions can be accessed in this way
Device.FUNCTION(...)
Device.PARAMETER = ...
Access to telegram functions¶
You can send messages, pictures, files and graphs with the following functions. (e.g. telegram.send_message_to_all('Hi')
):
Special stuff¶
The actual timestamp is available in the global variable clock
.
You can use the default print()
function for text-output in console, GUI and telegram.
You can define variables global. This ensures, this variable will remain until the next call of this script. Example
global VARNAME = 0
If-else conditions aren’t always suitable for real-time operations. You cannot trigger rising/falling for example. Therefore you can use a trigger to call the code inside a condition only once
trig CONDITION:
print('Hello')
This example will only print ‘Hello’, if CONDITION changes from False
to True
.
RTOC library¶
Event/Action system¶
The Event/Action System allows Python code to be executed when events occur. These pieces of code have the same possibilities as scripts.
Global actions¶
Global actions are stored in the file globalActions.json.
Example
{
"action2": {
"listenID": ["testID"],
"parameters": "",
"script": "Generator.gen_level = 1",
"active": False
}
}
This JSON-file contains dicts - each describing one action.
Parameter | Datatype | Definition |
---|---|---|
listenID |
list |
The event-IDs of events, which will trigger this action |
parameters |
str |
Unused |
script |
str |
The script, which will be executed |
active |
bool |
If True, this action will be active |
Global events¶
Global events are stored in the file globalEvents.json unlike events created in plugins.
Example
{
"myevent": {
"cond": "Generator.Square.latest >= 2",
"text": "It is big",
"return": " ",
"priority": 0,
"id": "testID",
'trigger': 'rising',
'sname': '',
'dname': '',
'active': True
}
}
This JSON-file contains dicts - each describing one event.
Parameter | Datatype | Definition |
---|---|---|
cond |
str |
The condition triggering the event. |
trigger |
str |
Change trigger-mode. rising , falling , both ,``true``, false . If rising , the event will be triggered if cond changes from False to True . If falling , the other way around. both for rising and falling. true for always, if condition is true. false for always, if condition is false. |
active |
bool |
If True, this event will be active. |
id |
str |
The event-ID used to trigger actions. |
return |
str |
Unused |
text |
str |
See LoggerPlugin.event() |
dname |
str |
… |
sname |
str |
|
priority |
0,1 or 2 |
Global actions and events can also be configured during runtime in the telegram-bot.
Graphical user interface¶

You can use the GUI to control your plugins, manipulate your measurements, try scripts, import data and configure your settings. You can also view and control RTOC-servers remotely and subscribe to signals, which will then be casted to your device.
Titlebar¶
Systembar-structure
Systembar
├── File
│ ├── Load session
│ ├── Save session
│ ├── Import data
│ ├── Export data
│ ├── Minimize to system tray
│ ├── Settings
| ├── Quit
├── Devices
│ ├── Add/Remove devices
├── Network
│ ├── Websocket-Server
│ ├── ├── Active
│ ├── ├── Password-Protection
│ ├── ├── Port: 5050
│ ├── Telegram-Bot
│ ├── ├── Active
│ ├── ├── Bot-Token
│ ├── Connect to remote host
│ ├── ├── New host
│ ├── ├── ...
│ ├── Active connections
│ ├── ├── ...
│ ├── Update-Rate: 1Hz
│ ├── Search RTOC-Server
├── Database
│ ├── Save local data in database
│ ├── Reset local data with data from database
│ ├── Export database
├── Subwindows
│ ├── Devices
│ ├── Plugins
│ ├── Script
│ ├── Events
│ ├── DevicesRAW
├── Language
│ ├── German
│ ├── English
├── Help
│ ├── Clear cache
│ ├── RTOC Help
│ ├── Plugin-repository
│ ├── Check for updates
│ ├── About
Subtitlebar
- Number-Edit for local recordLength
- Delete data: Deletes all existing data.
- Open new plot window. You can simply drag’n’drop signals from one window into another.
Device Widget¶
The device widget (left) holds all plugins. Each plugin is represented by a button. You can start/stop plugins with these buttons. If the plugin has a GUI and smallGUI
is True, the gui will be available as a button-dropdown.
Signal Widget¶
The signal widget (right) hold all signals. You can toggle each signal by clicking it (red=hidden, green=visible). Next to the button is the latest value.
Each signal also has a dropdown-menu

Check out each menu-entry by yourself, please.
Event Widget¶

The event widget shows a list with all events. You can filter the events by text or hide specific priorities. On the right top is a button to delete all events.
Script Widget¶

This widget is a simple text-editor for scripts. If you want to learn more about scripts, check out Controlling and automation.
Run scripts in GUI¶
Click on one of the buttons at the top of this widget to run the code either once or repeated.
You can also load/save scripts from/to file.
At the right top is a help window with lists for all signals, parameters and functions.
Trigger-System¶

Scripts are executed in two different ways (can be selected from the “Start” button’s drop-down menu in the ScriptWidget):
- Samplerate-Triggered: script is executed periodically
- Signal-Triggered: Script is executed, if a new signaldata is received. You can select multiple trigger-signals. In this case, the latest xy-pairs of the triggered signals can still be modified.
Import/Export signals/sessions¶
Import session¶
- Open “File”->”Load session” in the menubar
- Select a file you want to import
or
- Drag’n’Drop a file or copied data into RTOC
Import XLSX, MATLAB, CSV¶

On the left side is the data-table. You can modify it to your needs.
On the right side you can define signals, that will be taken from the data-table. 1. Click (+) to add a new signal. 2. Set a signal and devicename (not needed) 3. Select columns for X and Y data. If X-Column is 0, X-data will be generated automatically 4. The color on the right of each signal indicates, if this signal can be imported (mouse-over gives more information on failure) 5. Click “Import data” to load the signals to RTOC. Invalid signals will be skipped
Remote-control via Websocket¶

You can connect to any remote RTOC in the ‘Network’-menu of the Titlebar.
Plugin-Downloader¶

This tool can automatically download, update and remove signals from the Plugin repository.
Websocket Communication¶
**Websocket Port: 5050, SSL: 443 **
The content is formatted as a JSON file (Python: dict) with the following keys (all optional). For more information: RTLogger.NetworkFunctions
dict-key | Description |
---|---|
``authorize = “hashed_password” | You must always send this command in the beginning (If not password-protected: authorize=True) |
plot = False |
True : x and y data are plotted as one signal. False : x and y data are signals in pairs. See LoggerPlugin.plot() for more information. |
x = [0,1,2,3,4,5] |
X data to be sent. If x is not set and plot = False , time.time() is set as x-value. If plot = True , the indices of the y data are used. See LoggerPlugin.plot() for more information. |
y = [1,2,3,4,5,6] |
Y-data to be sent. See LoggerPlugin.plot() for more information. |
sname = ["signalname"] |
List of signal names with plot = False , only one element with plot = True . See LoggerPlugin.plot() for more information. |
dname = "devicename" |
Device name to be transmitted. See LoggerPlugin.plot() for more information. |
unit = "unit" |
signal unit. See LoggerPlugin.plot() for more information. |
event = {text = "", dname='', sname='', x=clock, priority=0} |
Create an event. See LoggerPlugin.event() for more information. |
getLatest= True |
If getLatest=True , RTOC returns a Dict of the most current measured values. The signal names are the keys. See NetworkFunctions.getLatest() for more information. |
getSignalList = True |
If getSignalList=True , RTOC returns a list of signal names. See NetworkFunctions.getSignalList() for more information. |
getEventList = True |
If getEventList=True , RTOC returns a list of all events. See NetworkFunctions.getEventList() for more information. |
getPluginList = True |
If getPluginList =True , RTOC returns a Dict of the plugins containing the plugin functions, parameters and the status of the plugin. See NetworkFunctions.getPluginList() for more information. |
getEvent = ['Device.Signal',...] |
Server request for the events of a signal. See NetworkFunctions.getEvent() for more information. |
getSignal = ['Device.Signal',...] |
Server request for signal data. See NetworkFunctions.getSignal() for more information. |
getSession = True |
|
remove = ['signal', 'DEVICE.SIGNAL'] |
|
subscribe = ['signal', 'DEVICE.SIGNAL'] |
|
unsubscribe = ['signal', 'DEVICE.SIGNAL'] |
|
subscribeAll = True |
|
unsubscribeAll = True |
|
plugin = {...} |
Access to plugins with Dict. See NetworkFunctions.handleTcpPlugins() for more information. |
logger = {...} |
RTOC default functions. See /RTLogger/RTWebsocketServer() for more information. |
userAction = {...} |
|
automation = {...} |
As response RTOC delivers a dict with the following keys:
dict-key | Description |
---|---|
error = False | If True, an error has occurred in the transmission |
sent = False | Is True if data (x,y) has been transmitted to the server. |
signalList = [] | Contains list of devices, at getSignalList-Request |
pluginList= {} | Dict with plugins, with getPluginList-Request |
signals = {} | Dict with signals, with getSignal-Request |
events = {} | Dict with events, at getEvent-Request |
latest = {} | Dict with latest measured values, at getLatest-Request |
userAction = {} | |
automation = {} | |
logger = {} | |
plugin = {} | |
remove = {} | |
getSession = {} |
Python example (With /RTLogger/RTWebsocketClient
)¶
This example uses the module /RTLogger/RTWebsocketClient
:
import RTWebsocketClient
data = {'x':[0,1,2,3],'y':[1,2,3,4],'dname':'Test','sname':['T1','T2','T3','T4']}
sock = RTWebsocketClient.RTWebsocketClient()
sock.on_message = lambda msg: print(msg)
sock.connect('127.0.0.1', 5050)
sock.send(data)
input('Press enter to quit')
sock.close()
Have a look into the RTWebsocketClient-File to see, which websocket-callbacks are available.
Backend Source-code¶
LoggerPlugin.py¶
This class is imported by any plugin written for RTOC.
It includes all functions to interact with RTOC. Every plugin must inherit this class! Your plugin must look like this
::
from RTOC.LoggerPlugin import LoggerPlugin
class Plugin(LoggerPlugin):
def __init__(self, *args, **kwargs):
LoggerPlugin.__init__(self, *args, **kwargs)
...
...
If you need to pass arguments to your class initialization, use kwargs. (‘stream’, ‘plot’, ‘event’, ‘telegramBot’ cannot be used as kwarg-name)
jsonsocket.py¶
RTOC.RTLogger Submodules¶
RTOC.RTLogger.Daemon module¶
Generic linux daemon base class for python 3.x.
Source: https://web.archive.org/web/20160320091458/http://www.jejik.com/files/examples/daemon3x.py
RTOC.RTLogger.DeviceFunctions module¶
RTOC.RTLogger.EventActionFunctions module¶
-
class
EventActionFunctions
[source]¶ Bases:
object
This class contains all global event/action-specific functions of RTLogger
-
addGlobalAction
(name='testAction', listenID='testID', script='', parameters='', active=True)[source]¶
-
addGlobalEvent
(name='testEvent', cond='', text='TestEvent', priority=0, retur='', id='testID', trigger='rising', sname='', dname='', active=True)[source]¶
-
checkGlobalActions
(actions)[source]¶ Checks if actions are valid. Will add the key ‘errors’ to each event. ‘errors’ will be True, if it’s not valid.
Parameters: actions (dict) – actions to be checked. Returns: Input-actions + ‘errors’-key Return type: actions (dict)
-
checkGlobalEvents
(events)[source]¶ Checks if events are valid. Will add the key ‘errors’ to each event. ‘errors’ will be True, if it’s not valid.
Parameters: events (dict) – events to be checked. Returns: Input-events + ‘errors’-key Return type: events (dict)
-
editGlobalAction
(name='testAction', listenID='testID', script='', parameters='', active=True)[source]¶
-
editGlobalEvent
(name='testEvent', cond='', text='TestEvent', priority=0, retur='', id='testID', trigger='rising', sname='', dname='', active=True)[source]¶
-
loadGlobalActions
()[source]¶ Loads global actions from file and stores them in dict ‘self.globalActions’
-
loadGlobalEvents
()[source]¶ Loads global events from file and stores them in dict ‘self.globalEvents’
-
performGlobalEvents
(y, unit, devicename, signalname, x=None)[source]¶ Performs global events, if their conditions are fullfilled. This function is called any time data is added to signals.
Parameters: - y (float) – y-value of signal (not needed)
- unit (str) – unit of signal (not needed)
- devicename (str) – devicename of signal
- signalname (str) – signalname of signal
- x (float) – x-value of signal (not needed)
-
RTOC.RTLogger.NetworkFunctions module¶
RTOC.RTLogger.RTLogger module¶
RTOC.RTLogger.RTOC_Web module¶
RTOC.RTLogger.RTOC_Web_standalone module¶
RTOC.RTLogger.RTRemote module¶
RTOC.RTLogger.RT_data module¶
RTOC.RTLogger.ScriptFunctions module¶
RTOC.RTLogger.importCode module¶
-
importCode
(code, name, add_to_sys_modules=0)[source]¶ Import dynamically generated code as a module. code is the object containing the code (a string, a file handle or an actual compiled code object, same types as accepted by an exec statement). The name is the name to give to the module, and the final argument says wheter to add it to sys.modules or not. If it is added, a subsequent import statement using name will return this module. If it is not added to sys.modules import will try to load it in the normal fashion.
import foo
is equivalent to
foofile = open(“/path/to/foo.py”) foo = importCode(foofile,”foo”,1)
Returns a newly generated module.
RTOC.RTLogger.loggerlib module¶
RTOC.RTLogger.scriptLibrary module¶
RTOC.RTLogger.telegramBot module¶
GUI - Source-code¶
RTOC.RTOC module¶
RTOC.RTOC_GUI subpackage¶
RTOC.RTOC_GUI.Actions module¶
RTOC.RTOC_GUI.RTPlotActions module¶
RTOC.RTOC_GUI.RTPlotWidget module¶
RTOC.RTOC_GUI.csvSignalWidget module¶
RTOC.RTOC_GUI.define module¶
RTOC.RTOC_GUI.eventWidget module¶
RTOC.RTOC_GUI.globalActionWidget module¶
RTOC.RTOC_GUI.globalEventWidget module¶
RTOC.RTOC_GUI.remoteWidget module¶
RTOC.RTOC_GUI.scriptHelpWidget module¶
RTOC.RTOC_GUI.scriptSubWidget module¶
RTOC.RTOC_GUI.scriptWidget module¶
RTOC.RTOC_GUI.settingsWidget module¶
RTOC.RTOC_GUI.signalEditWidget module¶
RTOC.RTOC_GUI.signalWidget module¶
RTOC.RTOC_GUI.styleMultiPlotGUI module¶
RTOC.RTOC_GUI.stylePlotGUI module¶
RTOC.RTOC.PluginDownloader module¶
RTOC.RTOC.RTOC_Import module¶
Example: Embedded¶
This example uses the following RTOC-features:
- PostgreSQL-database for long-time logging
- Telegram-Bot with different permissions
- Remote-Websocket connection
- Automation (Event-Action-System)
Introduction¶

This example will show, how to connect a heatpump or any other heating system with an RTOC-server. This will allow remote control and long-time-measurements. (And events,… all RTOC-Features)
Person A and B are administrators of the RTOC-server. Person A from outside the local network using the Telegram-Bot and Person B in the same network with the RTOC-server using a PC.
Person C is a user, who just wants to control the heating system (Smart Home). He/she will be able to set the room-temperature or any other custom functions with the telegramBot.
Person D is just interested in your heating’s long-time-measurements (e.g. a technician) and has access with the telegramBot.
Prerequirement¶
- Raspberry Pi
- Heating system/heat pump with remote control capability
- RTOC-Plugin to interact with the heating system (e.g. Heliotherm from RTOC_repo)
Setup¶
- Install RTOC: Installation
- Setup PostgreSQL Database: Long-time measurements in postgreSQL database (optional)
- Setup Telegram-Bot: Telegram-Bot setup
- You should also set a websocket-password in config.json
- Download/program a plugin. Refer to Plugin repository and Writing Plugins.
- Add the plugin to autorun_devices.
- Start RTOC with python3 -m RTOC. Use loggerServer.py to run RTOC as a service on linux.
Remote access¶
Remote-Websocket-Client (Person B)¶
Person B uses a computer with RTOC installed. Have a look at the Graphical user interface-Documentation for more information. He can view all of the data in the database of the RTOC-server and has access to all functions and parameters from the heating system. He can manipulate the data with the RTOC-GUI. Person B can instead also use the RTOC_Remote Android App
Admin-Telegram-Client (Person A)¶
Person A uses the Telegram-Bot to access the heating system. He has also access to all functions and parameters from the heating system and can view and edit all of the data. He can also modify the event-action (automation).
Custom-Telegram-Client (Person C)¶
Person C just wants to set the room temperature for example. But does not want to use the complexe structure of the Telegram-Bot to do this (Devices->Heatpump->Functions->SetTemp). Therefore the telegram administators can set the permissions for Person C to ‘custom’. Then Person C will only see shortcuts, which have been created for only this user. This can be done in two ways: 1. Set the permission of Person C to ‘Write’ and create shortcuts for the desired functions/parameters and change the permission to ‘Custom’ afterwards. 2. Edit the client-shortcuts in telegram_clients.json.
Read-Telegram-Client (Person D)¶
Person D just wants to view the measurements. Therefore an administrator can set his permission to ‘Read’.
Submit your plugin¶
If you want to publish your plugin in my repository, send me a an email: kellersebastian@protonmail.com