restructure code and use frappy.client for SECoP
- separation of SECoP part from webserver - use frappy client instead of own code for SECoP communication
This commit is contained in:
130
influxgraph.py
130
influxgraph.py
@ -4,24 +4,33 @@ from colors import assign_colors_to_curves
|
||||
import json
|
||||
import io
|
||||
from chart_config import ChartConfig
|
||||
from base import Instrument
|
||||
|
||||
|
||||
class InfluxGraph:
|
||||
"""
|
||||
Class implementing the logic of the different routes that are called by the client to retrieve graph data with InfluxDB.
|
||||
Class implementing the logic of the different routes that are called by
|
||||
the client to retrieve graph data with InfluxDB.
|
||||
|
||||
Global constants :
|
||||
HISTORICAL (int) : value that represents the "historical" visualization mode, meaning that the most recent point is not in the visualisation window (no live data is sent).
|
||||
ACTUAL (int) : value that represents the "actual" visualization mode, wihch is an intermediate state used before going for live mode (the requested time window includes now)
|
||||
LIVE (int) : value that represents the "live" visualization mode, meaning that new points are sent to the client.
|
||||
HISTORICAL (int) : value that represents the "historical" visualization mode, meaning that the
|
||||
most recent point is not in the visualisation window (no live data is sent).
|
||||
ACTUAL (int) : value that represents the "actual" visualization mode, wihch is an intermediate
|
||||
state used before going for live mode (the requested time window includes now)
|
||||
LIVE (int) : value that represents the "live" visualization mode, meaning that new points are
|
||||
sent to the client.
|
||||
|
||||
Attributes :
|
||||
influx_data_getter (InfluxDataGetter) : the InfluxDataGetter instance that allows to get data out of InfluxDB.
|
||||
chart_configs ([ChartConfig]) : an array of chart configuration to apply when /getvars is called
|
||||
livemode (int) : the type of visualization the user is currently in. Can be HISTORICAL, ACTUAL or LIVE.
|
||||
end_query (int) : the unix timestamp in seconds of the most recent requested point in time of the last query or update.
|
||||
lastvalues ({(str):((int), (float))}) : a dictionnary where the keys are the variable names, and the values are tuples, where the first
|
||||
value is the unix timestamp of the most recent value known for this variable, and the second value its corresponding value
|
||||
variables ({(str):(str)}) : a dictionnary of the current available variables requested by the client. The key is the InfluxDB name of the curve, and the value is its label in the GUI.
|
||||
end_query (int) : the unix timestamp in seconds of the most recent requested point in time of the last query
|
||||
or update.
|
||||
lastvalues ({(str):((int), (float))}) : a dictionnary where the keys are the variable names, and the values
|
||||
are tuples, where the first value is the unix timestamp of the most recent value known for this variable,
|
||||
and the second value its corresponding value
|
||||
variables ({(str):(str)}) : a dictionnary of the current available variables requested by the client.
|
||||
The key is the InfluxDB name of the curve, and the value is its label in the GUI.
|
||||
"""
|
||||
HISTORICAL = 0
|
||||
ACTUAL = 1
|
||||
@ -33,13 +42,12 @@ class InfluxGraph:
|
||||
self.livemode = self.HISTORICAL
|
||||
self.end_query = 0
|
||||
self.lastvalues = {}
|
||||
self.variables = {} # name:label
|
||||
|
||||
self.variables = {} # name:label
|
||||
|
||||
def get_abs_time(self, times):
|
||||
"""
|
||||
Gets the absolute times for the given pontential relative times. If the given timestamps are less than one year, then the value is relative
|
||||
and converted into an asbolute timestamps
|
||||
Gets the absolute times for the given potential relative times. If a given timestamp is less than
|
||||
one year, then the value is relative and converted into an absolute timestamp
|
||||
|
||||
Parameters :
|
||||
times([(float)]) : an array of unix timestamps or relative duration (< 1 year) as floats
|
||||
@ -58,7 +66,7 @@ class InfluxGraph:
|
||||
|
||||
Parameters :
|
||||
result ({(str):[[(int),(float)]]}) : a dictionnary with the variable names as key, and an array of points,
|
||||
which are an array containing the timestamp as their first value, and the y-value in float as their second one.
|
||||
which are a tuple (timestamp, y-value as float)
|
||||
endtime (int) : the unix timestamp in seconds of the time we want to have data until
|
||||
"""
|
||||
for var, c in result.items():
|
||||
@ -75,12 +83,14 @@ class InfluxGraph:
|
||||
|
||||
Parameters :
|
||||
variables (str) : a comma separataed value string of variable names (influx names) to retrieve
|
||||
time (str) : a commma separated value string (range) of seconds. They are treated as relative from now if they are lesser than one year.
|
||||
time (str) : a commma separated value string (range) of seconds. They are treated as relative from now
|
||||
if they are lesser than one year.
|
||||
interval (str) : the interval (resolution) of the values to get (string in milliseconds)
|
||||
|
||||
Returns :
|
||||
{"type":"graph-draw", "graph":{(str):[[(int),(float)]]}} : a dictionnary with its "graph-draw" type (so it can be processed by the client), and a "graph" dictionnary with the variable names as key, and an array of points,
|
||||
which are an array containing the timestamp as their first value, and the y-value in float as their second one.
|
||||
{"type":"graph-draw", "graph":{(str):[[(int),(float)]]}} : a dictionnary with its "graph-draw" type
|
||||
(so it can be processed by the client), and a "graph" dictionnary with the variable names as key,
|
||||
and an array of points as a tuple (timestamp, y-value as float)
|
||||
"""
|
||||
time = [float(t) for t in time.split(',')]
|
||||
start, end, now = self.get_abs_time(time + [0])
|
||||
@ -103,11 +113,12 @@ class InfluxGraph:
|
||||
Called when the route /gettime is reached.
|
||||
|
||||
Parameters :
|
||||
time (str="-1800,0") : the given point in time represented by a string, which is a comma separated unix timestamp values list (in seconds). They are treated as relative from now if they are lesser than one year.
|
||||
time (str="-1800,0") : the given point in time represented by a string, which is a comma separated unix
|
||||
timestamp values list (in seconds). They are treated as relative from now if they are lesser than one year.
|
||||
|
||||
Returns :
|
||||
{"type":"time", "time":(int)} : a dictionnary with its "time" type (so the data can be processed by the client) and the server unix timestamp in seconds corresponding
|
||||
to the time asked by the client
|
||||
{"type":"time", "time":(int)} : a dictionnary with its "time" type (so the data can be processed by the
|
||||
client) and the server unix timestamp in seconds corresponding to the time asked by the client
|
||||
"""
|
||||
time = [float(t) for t in time.split(',')]
|
||||
return dict(type='time', time= self.get_abs_time(time))
|
||||
@ -118,13 +129,17 @@ class InfluxGraph:
|
||||
Called when the route /getvars is reached.
|
||||
|
||||
Parameters :
|
||||
time (str) : the given point in time represented by a string, which is a unix timestamp in seconds. It is treated as relative from now if it is lesser than one year.
|
||||
time (str) : the given point in time represented by a string, which is a unix timestamp in seconds.
|
||||
It is treated as relative from now if it is lesser than one year.
|
||||
userconfiguration (str|None) : the JSON string representing the user configuration
|
||||
|
||||
Returns :
|
||||
{"type":"var_list", "device":(str), "blocks":[{"tag":(str),"unit":(str), "curves":[{"name":(str), "label":(str), "color":(str), "original_color":(str)}]}]} :
|
||||
a dictionnary with its "var_list" type (so the data can be processed by the client), the device that was currently set at that time, and the available curves with the name of the internal variable,
|
||||
the color to display for this curve, its original color in SEA, grouped by their tag (which is a category or unit if absent) and their unit (in "blocks")
|
||||
{"type":"var_list", "device":(str), "blocks":[{"tag":(str),"unit":(str), "curves":
|
||||
[{"name":(str), "label":(str), "color":(str), "original_color":(str)}]}]}:
|
||||
a dictionnary with its "var_list" type (so the data can be processed by the client), the device that
|
||||
was currently set at that time, and the available curves with the name of the internal variable,
|
||||
the color to display for this curve, its original color in SEA, grouped by their tag (which is a
|
||||
category or unit if absent) and their unit (in "blocks")
|
||||
"""
|
||||
|
||||
time = [float(t) for t in time.split(',')]
|
||||
@ -148,7 +163,8 @@ class InfluxGraph:
|
||||
Sets the current visualisation mode to LIVE if not in HISTORICAL mode.
|
||||
Called when the route /updategraph is reached.
|
||||
Returns :
|
||||
{"type":"accept-graph", "live": bool} : a dict with its "accept-graph" type and a "live" value telling if the server could change its visualization mode to live
|
||||
{"type":"accept-graph", "live": bool} : a dict with its "accept-graph" type and a "live"
|
||||
value telling if the server could change its visualization mode to live
|
||||
"""
|
||||
logging.info("UPD GRAPH %d", self.livemode)
|
||||
if self.livemode == self.HISTORICAL:
|
||||
@ -188,12 +204,16 @@ class InfluxGraph:
|
||||
|
||||
def graphpoll(self):
|
||||
"""
|
||||
Polls the last known values for all the available variables, and returns only those whose polled values are more recent than the most recent displayed one.
|
||||
Every plain minute, all the variables are returned with a point having their last known value at the current timestamp to synchronize all the curves on the GUI.
|
||||
Polls the last known values for all the available variables, and returns only those whose polled values
|
||||
are more recent than the most recent displayed one.
|
||||
Every plain minute, all the variables are returned with a point having their last known value at the current
|
||||
timestamp to synchronize all the curves on the GUI.
|
||||
|
||||
Returns :
|
||||
{"type":"graph-update", "time":(int), "graph":{(str):[[(int),(float)]]}} | None : a dictionnary with its "graph-update" type
|
||||
(so it can be processed by the client), and a "graph" dictionnary with the variable names as key, and an array of points, which are an array containing the timestamp
|
||||
{"type":"graph-update", "time":(int), "graph":{(str):[[(int),(float)]]}} | None :
|
||||
a dictionnary with its "graph-update" type
|
||||
(so it can be processed by the client), and a "graph" dictionnary with the variable names as key,
|
||||
and an array of points, which are an array containing the timestamp
|
||||
as their first value, and the y-value in float as their second one
|
||||
"""
|
||||
if self.livemode != self.LIVE:
|
||||
@ -203,7 +223,8 @@ class InfluxGraph:
|
||||
result = self.influx_data_getter.poll_last_values(list(self.variables.keys()), self.lastvalues, now)
|
||||
for variable, values in list(result.items()):
|
||||
tlast = self.lastvalues.get(variable, (0,))[0]
|
||||
# removes points older than the last known point (queries are in seconds and might return points already displayed)
|
||||
# removes points older than the last known point
|
||||
# (queries are in seconds and might return points already displayed)
|
||||
while values and values[0][0] <= tlast:
|
||||
values.pop(0)
|
||||
if values and values[-1][0] > tlast:
|
||||
@ -219,3 +240,54 @@ class InfluxGraph:
|
||||
if len(result) > 0:
|
||||
return dict(type='graph-update', time=now, graph=result)
|
||||
return None
|
||||
|
||||
|
||||
class InfluxInstrument(Instrument):
|
||||
|
||||
def __init__(self, instr_name, inst_config=None):
|
||||
self.db = InfluxDB()
|
||||
self.influx_data_getter = InfluxDataGetter(self.db, inst_name)
|
||||
self.clients = {}
|
||||
self.title = instr_name
|
||||
self.device = self.influx_data_getter.get_device_name(int(datetime.now().timestamp()))
|
||||
|
||||
def new_client(self):
|
||||
return self.register(InfluxClient())
|
||||
|
||||
|
||||
class InfluxParams:
|
||||
"""Class with dummy routes, in case client side is started with the right part init commands"""
|
||||
def __init__(self):
|
||||
self.id = uuid.uuid4().hex[0:15]
|
||||
self.queue = []
|
||||
|
||||
def poll(self):
|
||||
messages = self.queue
|
||||
self.queue = []
|
||||
msg = self.graphpoll()
|
||||
if msg:
|
||||
messages.append(msg)
|
||||
return messages
|
||||
|
||||
def info(self):
|
||||
return ["na"]
|
||||
|
||||
def w_getblock(self, path):
|
||||
return dict(type='draw', title="graph", path=path, components=[])
|
||||
|
||||
def w_updateblock(self, path):
|
||||
return dict(type='accept-block')
|
||||
|
||||
def w_console(self):
|
||||
return dict(type='accept-console')
|
||||
|
||||
def w_sendcommand(self, command):
|
||||
return dict(type='accept-command')
|
||||
|
||||
|
||||
class InfluxClient(InfluxParams, InfluxGraph):
|
||||
def __init__(self):
|
||||
InfluxParams.__init__(self)
|
||||
InfluxGraph.__init__(self, instrument.influx_data_getter, instrument.title)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user