Implemented connection with InfluxDB

This commit is contained in:
l_samenv
2024-07-22 15:51:51 +02:00
parent 0c0662b0b1
commit aa29d89a18
10 changed files with 1017 additions and 5 deletions

169
influxgraph.py Normal file
View File

@ -0,0 +1,169 @@
from influxdb import InfluxDB, InfluxDataGetter
import time
import logging
from colors import assign_colors_to_curves
import json
class InfluxGraph:
"""
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" visualisation mode, meaning that the most recent point is not in the visualisation window.
ACTUAL (int) : value that represents the "actual" visualisation mode, meaning that the curves stay in place, but new data is being added to the right (expansion in the future).
LIVE (int) : value that represents the "live" visualisation mode, meaning that the curves move with the most recent point always at the same place.
Attributes :
db (InfluxDB) : the InfluxDB instance that holds the connection with InfluxDB.
influx_data_getter (InfluxDataGetter) : the InfluxDataGetter instance that allows to get data out of InfluxDB.
livemode (int) : the type of visualisation the user is currently in. Can be HISTORICAL, ACTUAL or LIVE.
time ([(int)]) : an array of unix timestamp in seconds, where the first value is the last most recent requested point in time,
and the second value is the current most recent requested point in time.
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
"""
HISTORICAL = 0
ACTUAL = 1
LIVE = 2
def __init__(self):
self.db = InfluxDB()
self.influx_data_getter = InfluxDataGetter(self.db, json.load(open("./graphs/lab4.json", "r"))["influx"])
self.livemode = self.HISTORICAL
self.time = [0, 0]
self.lastvalues = {}
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
Parameters :
times([(float)]) : an array of unix timestamps or relative duration (< 1 year) as floats
Returns :
[(float)] : an array of absolute unix timestamps as floats
"""
now = int(time.time() + 0.999)
oneyear = 365 * 24 * 3600
return [t + now if t < oneyear else t for t in times]
def strip_future(self, result):
"""
OLD : strip future points (happens only on dummy test_day)
Removes points more recent that the last requested point in time
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.
"""
# if self.livemode == self.LIVE:
for c in result.values():
while c:
lastt, lastx = c[-1]
if lastt <= self.time[1]:
break
c.pop()
def complete_to_end(self, result, endtime):
"""
Completes the data until the last requested point in time by adding the last known y-value at the end point.
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.
endtime (int) : the unix timestamp in seconds of the time we want to have data until
"""
for var, c in result.items():
if c:
lastt, lastx = c[-1]
if lastt < endtime:
c.append((endtime, lastx))
self.lastvalues[var] = (endtime, lastx)
def w_graph(self, variables, time="-1800,0"):
"""
Gets the curves given by variables in the time range "time"
Called when the route /graph is reached.
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.
Returns :
{"type":"graph-draw", "reduced":(bool), "graph":{(str):[[(int),(float)]]}} : a dictionnary with its "graph-draw" type (so it can be processed by the client), a "reduced" value
indicating if the data is reduced or not (meaning the data is sampled to be lighter for data viewing), 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.
"""
time = [float(t) for t in time.split(',')]
start, end, now = self.get_abs_time(time + [0])
start, end, now = int(start), int(end), int(now)
self.time = [start, end]
self.variables = variables.split(',')
self.livemode = self.ACTUAL if end >= now else self.HISTORICAL
logging.info('LIVE %g %g %d %d', end, now, end >= now, self.livemode)
result = self.influx_data_getter.get_curves_in_timerange(self.variables, self.time)
self.strip_future(result)
self.complete_to_end(result, end)
self.time[0] = self.time[1]
# reduction not yet implemented
return dict(type='graph-draw', reduced=False, graph=result)
def w_gettime(self, time):
"""
Gets the server time for the give time.
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.
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
"""
time = [float(t) for t in time.split(',')]
return dict(type='time', time= self.get_abs_time(time))
def w_getvars(self, time):
"""
Gets the curve names available at a given point in time.
Called when the route /getvars is reached.
Parameters :
time (str) : 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":"var_list", "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) 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 unit augmented with an index) and their unit ("in blocks")
"""
time = [float(t) for t in time.split(',')]
end_time = int(self.get_abs_time(time)[-1])
blocks = self.influx_data_getter.get_available_variables_at_time(end_time)
assign_colors_to_curves(blocks)
result = dict(type='var_list')
result['blocks'] = blocks
return result
def w_updategraph(self):
"""
TODO : method needed for live data update. See example in seaweb.py : SeaGraph
OLD : update live values - seems not to work
Sets the current visualisation mode to LIVE.
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
"""
return dict(type='accept-graph', live=False)
def graphpoll(self):
"""
TODO : method needed for live data update. See example in seaweb.py : SeaGraph
"""
return None