Skip to content

Commit 5cfe15d

Browse files
author
Sebastian
committed
!!! Changed plugin initialization !!! Please view documentation for more information
added telegram admin preview modes added example in documentation added script functions added script support in plugins added full access to RTOC-data for plugins added telegram_send_plot for plugins
1 parent da9e3b2 commit 5cfe15d

16 files changed

+490
-56
lines changed

RTOC/LoggerPlugin.py

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# LoggerPlugin v2.6
1+
# LoggerPlugin v2.7
22
import traceback
33
import time
44
import sys
@@ -10,31 +10,36 @@
1010

1111
try:
1212
from . import jsonsocket
13+
from .RTLogger import scriptLibrary as rtoc
1314
except (SystemError, ImportError):
1415
import jsonsocket
16+
import RTLogger.scriptLibrary as rtoc
1517

1618
lock = Lock()
1719

1820

1921
class LoggerPlugin:
2022
"""
21-
22-
2323
Args:
24-
stream (method): The callback-method for the stream-method
25-
plot (method): The callback-method for the plot-method
26-
event (method): The callback-method for the event-method
27-
telegramBot (object): Object for telegram-methods
28-
24+
logger (RTLogger): The parent RTLogger-instance
2925
"""
30-
def __init__(self, stream=None, plot=None, event=None, telegramBot=None, *args, **kwargs):
26+
def __init__(self, logger=None, *args, **kwargs):
3127
# Plugin setup
3228
# self.setDeviceName()
3329
self._devicename = "noDevice"
34-
self._cb = stream
35-
self._ev = event
36-
self._plt = plot
37-
self._bot = telegramBot
30+
self.rtoc = rtoc
31+
if logger is not None:
32+
self.logger = logger
33+
self._cb = logger.database.addDataCallback
34+
self._ev = logger.database.addNewEvent
35+
self._plt = logger.database.plot
36+
self._bot = logger.telegramBot
37+
else:
38+
self._logger = None
39+
self._cb = None
40+
self._ev = None
41+
self._plt = None
42+
self._bot = None
3843
self._sock = None
3944
self._tcppassword = ''
4045
self._tcpport = 5050
@@ -532,7 +537,7 @@ def __updateT(self, func):
532537

533538
def telegram_send_message(self, text, priority=0, permission='write'):
534539
"""
535-
Sends a message to all clients (or only admins).
540+
Sends a message to all clients with given permission and higher permission.
536541
537542
Args:
538543
text (str): Text to be send to the clients.
@@ -546,7 +551,7 @@ def telegram_send_message(self, text, priority=0, permission='write'):
546551

547552
def telegram_send_photo(self, path, priority=0, permission='write'):
548553
"""
549-
Sends the picture at a given path to all clients (or only admins).
554+
Sends the picture at a given path to all clients with given permission and higher permission.
550555
551556
Args:
552557
path (str): Path to the picture to send.
@@ -560,7 +565,7 @@ def telegram_send_photo(self, path, priority=0, permission='write'):
560565

561566
def telegram_send_document(self, path, priority=0, permission='write'):
562567
"""
563-
Sends any document at a given path to all clients (or only admins).
568+
Sends any document at a given path to all clients with given permission and higher permission.
564569
565570
Args:
566571
path (str): Path to the file to send.
@@ -572,6 +577,23 @@ def telegram_send_document(self, path, priority=0, permission='write'):
572577
else:
573578
logging.warning('TelegramBot is not enabled or wrong configured! Can not send file "{}"'.format(path))
574579

580+
def telegram_send_plot(self, signals={}, title='', text='', events=[], dpi=300, priority=0, permission='write'):
581+
"""
582+
Sends any document at a given path to all clients with given permission and higher permission.
583+
584+
Args:
585+
signals (dict): Contains multiple sets of x-y data, e.g. ``{'signal1':[1,2,3,4,5],[4,3,6,5,7]}``
586+
title (str): The title displayed above the graph.
587+
text (str): The plot-description text
588+
events (list): A list containing pseudo-events (text+vertical-line), e.g. ``[[10, 'Hello world at x=10']]``
589+
dpi (int): Resolution of plot.
590+
priority (int): Priority to decide, which allow each client to disable notifications (0: Information, 1: Warning, 2: Error)
591+
permission (str): Choose user-permission (blocked, read, write, admin)
592+
"""
593+
if self._bot is not None:
594+
self._bot.send_plot(signals, title, text, events, dpi, priority, permission)
595+
else:
596+
logging.warning('TelegramBot is not enabled or wrong configured! Can not send plot')
575597

576598

577599
class _perpetualTimer():

RTOC/RTLogger/DeviceFunctions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def startPlugin(self, name, remote=True):
8686
# if callback is None:
8787
self.pluginObjects[
8888
name] = importlib.import_module(
89-
fullname).Plugin(stream=self.database.addDataCallback, plot=self.database.plot, event=self.database.addNewEvent, telegramBot=self.telegramBot)
89+
fullname).Plugin(logger=self)
9090
# else:
9191
# self.pluginObjects[name] = importlib.import_module(
9292
# fullname).Plugin(callback, self.addNewEvent)

RTOC/RTLogger/NetworkFunctions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,12 @@ def getPluginDict(self):
343343
dict[name]['parameters'] = []
344344
dict[name]['status'] = False
345345
for fun in self.pluginFunctions.keys():
346-
hiddenFuncs = ["loadGUI", "updateT", "stream", "plot", "event", "createTCPClient", "sendTCP", "close", "cancel", "start", "setSamplerate","setDeviceName",'setPerpetualTimer','setInterval','getDir', 'telegram_send_message', 'telegram_send_photo', 'telegram_send_document']
346+
hiddenFuncs = ["loadGUI", "updateT", "stream", "plot", "event", "createTCPClient", "sendTCP", "close", "cancel", "start", "setSamplerate","setDeviceName",'setPerpetualTimer','setInterval','getDir', 'telegram_send_message', 'telegram_send_photo', 'telegram_send_document', 'telegram_send_plot']
347347

348348
if fun.startswith(name+".") and fun not in [name+'.'+i for i in hiddenFuncs]:
349349
dict[name]['functions'].append(fun.replace(name+".", ''))
350350
for fun in self.pluginParameters.keys():
351-
hiddenParams = ["run", "smallGUI", 'widget', 'samplerate','lockPerpetialTimer']
351+
hiddenParams = ["run", "smallGUI", 'widget', 'samplerate','lockPerpetialTimer','logger']
352352

353353
if fun.startswith(name+".") and fun not in [name+'.'+i for i in hiddenParams]:
354354
value = self.getPluginParameter(name, "get", fun.replace(name+".", ''))

RTOC/RTLogger/ScriptFunctions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def generateCode(self, s, condition=False):
1717
s = self.replacePluginMethods(s)
1818
s = self.replaceSignalNames(s)
1919
s = self.replaceLoggerFunctions(s)
20+
s = self.replaceTelegramFunctions(s)
2021
s, init = self.replaceGlobalVariables(s)
2122
s = s.replace('global.', 'self.')
2223
s = self.replaceLibraryFunctions(s)
@@ -91,6 +92,15 @@ def replaceLoggerFunctions(self, s):
9192
s = s.replace("sendTCP(", "self._sendTCP(")
9293
return s
9394

95+
def replaceTelegramFunctions(self, s):
96+
s = s.replace("telegram.send_photo(", "self.telegramBot.send_photo(")
97+
98+
s = s.replace("telegram.send_document(", "self.telegramBot.send_document(")
99+
s = s.replace("telegram.send_plot(", "self.telegramBot.send_plot(")
100+
101+
s = s.replace("telegram.send_message_to_all(", "self.telegramBot.send_message_to_all(")
102+
return s
103+
94104
def replaceGlobalVariables(self, s):
95105
globals = []
96106
for item in s.split("\n"):

RTOC/RTLogger/scriptLibrary.py

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
log.basicConfig(level=log.INFO)
1414
logging = log.getLogger(__name__)
1515

16+
try:
17+
from statsmodels.tsa.ar_model import AR
18+
from sklearn.metrics import mean_squared_error
19+
except (ImportError, SystemError):
20+
AR = None
21+
logging.info('statsmodels and sklearn is not installed. Cannot use "rtoc.estimate".')
1622

1723
def lsfit(self, x, y, func="linear", x0=None, n=None):
1824
"""
@@ -75,7 +81,7 @@ def resample(self, x, y, n=None):
7581
x (list): x-values (a linspace)
7682
y (list): Interpolated y-values
7783
"""
78-
if n is None:
84+
if n is None and self is not None:
7985
n = self.config['global']['recordLength']
8086
if len(x) == len(y):
8187
x2 = np.linspace(x[0], x[-1], n)
@@ -290,3 +296,128 @@ def norm(x, y, max=1, min=0, oldMin=None, oldMax=None):
290296
y = (y-oldMin)/oldMax
291297
y = y*max+min
292298
return x, y
299+
300+
def predict(coef, history):
301+
"""
302+
Make a prediction give regression coefficients and lag obs
303+
"""
304+
yhat = coef[0]
305+
for i in range(1, len(coef)):
306+
yhat += coef[i] * history[-i]
307+
return yhat
308+
309+
def estimate(x,y, n):
310+
"""
311+
Estimate n values in future for a signal using ARMA. You need to install the following python packages with pip3: ``pip3 install statsmodels scikit-learn scikit-metrics patsy``
312+
313+
Args:
314+
x (list): List of x-values
315+
y (list): List of y-values
316+
n (int): Number of values to be estimated
317+
318+
Returns:
319+
x (list): List of estimated x-values
320+
y (list): List of estimated y-values
321+
"""
322+
if AR is None:
323+
return
324+
325+
x, y = resample(None, x, y, n=len(x))
326+
samplerate = 1/(x[1]-x[0])
327+
328+
#train = np.diff(y)
329+
train = np.array(y)
330+
test = np.linspace(x[-1]+1/samplerate, x[-1]+(1/samplerate)*n, n)
331+
# size = int(len(data) * 0.66)
332+
# train, test = data[0:size], data[size:]
333+
# train autoregression
334+
model = AR(train)
335+
model_fit = model.fit(maxlag=6, disp=False)
336+
window = model_fit.k_ar
337+
coef = model_fit.params
338+
# walk forward over time steps in test
339+
history = [train[i] for i in range(len(train))]
340+
predictions = list()
341+
for t in range(len(test)):
342+
yhat = predict(coef, history)
343+
predictions.append(yhat)
344+
history.append(yhat)
345+
error = mean_squared_error(test, predictions)
346+
print('Test MSE: %.3f' % error)
347+
348+
return test, predictions
349+
350+
def correlate(x1,y1,x2,y2, mode='valid'):
351+
"""
352+
Crosscorrelate two signals using numpy.correlate
353+
354+
Args:
355+
x1 (list): List of x-values of signal 1
356+
y1 (list): List of y-values of signal 1
357+
x1 (list): List of x-values of signal 2
358+
y1 (list): List of y-values of signal 2
359+
mode: {'valid', 'same', 'full') Refer to the convolve docstring. Note that the default is ‘valid’, unlike convolve, which uses ‘full’.
360+
361+
Returns:
362+
x (list): List of x-values
363+
y (list): List of correlated y-values
364+
"""
365+
maxL = max([len(y1), len(y2)])
366+
x,ys = combine(None, [[x1,y1],[x2,y2]], n=maxL)
367+
y = np.correlate(ys[0], ys[1], mode)
368+
369+
return x, y
370+
371+
def forwardEuler(x,y, f, U_0, samplerate, T):
372+
dt = 1/samplerate
373+
N_t = int(round(float(T)/dt))
374+
u = np.zeros(N_t+1)
375+
t = np.linspace(0, N_t*dt, len(u))
376+
u[0] = U_0
377+
for n in range(N_t):
378+
u[n+1] = u[n] + dt*f(u[n], t[n])
379+
return t,u
380+
381+
def CCN():
382+
"""
383+
https://machinelearningmastery.com/how-to-get-started-with-deep-learning-for-time-series-forecasting-7-day-mini-course/
384+
385+
https://machinelearningmastery.com/time-series-prediction-lstm-recurrent-neural-networks-python-keras/
386+
387+
388+
Estimate n values in future for a signal using Convolutional Neural Network model. You need to install the following python packages with pip3: ``pip3 install tensorflow keras``
389+
390+
Args:
391+
x (list): List of x-values
392+
y (list): List of y-values
393+
n (int): Number of values to be estimated
394+
395+
Returns:
396+
x (list): List of estimated x-values
397+
y (list): List of estimated y-values
398+
"""
399+
from keras.models import Sequential
400+
from keras.layers import Dense
401+
from keras.layers import Flatten
402+
from keras.layers.convolutional import Conv1D
403+
from keras.layers.convolutional import MaxPooling1D
404+
# define dataset
405+
X = np.array([[10, 20, 30], [20, 30, 40], [30, 40, 50], [40, 50, 60]])
406+
y = np.array([40, 50, 60, 70])
407+
# reshape from [samples, timesteps] into [samples, timesteps, features]
408+
X = X.reshape((X.shape[0], X.shape[1], 1))
409+
# define model
410+
model = Sequential()
411+
model.add(Conv1D(filters=64, kernel_size=2, activation='relu', input_shape=(3, 1)))
412+
model.add(MaxPooling1D(pool_size=2))
413+
model.add(Flatten())
414+
model.add(Dense(50, activation='relu'))
415+
model.add(Dense(1))
416+
model.compile(optimizer='adam', loss='mse')
417+
# fit model
418+
model.fit(X, y, epochs=1000, verbose=0)
419+
# demonstrate prediction
420+
x_input = np.array([50, 60, 70])
421+
x_input = x_input.reshape((1, 3, 1))
422+
yhat = model.predict(x_input, verbose=0)
423+
print(yhat)

0 commit comments

Comments
 (0)