Added live data functionnality + some docs in Python and JS code
This commit is contained in:
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# SEAWeb
|
||||
|
||||
The WEB GUI client of SEA.
|
||||
|
||||
This repository contains the code of the server for the control and graphical parts, plus the client code (HTML, CSS, JS)
|
||||
|
||||
## Server
|
||||
|
||||
## Client
|
||||
|
||||
### External libraries
|
||||
|
||||
| Name | Version | Website |
|
||||
| -------------------------- | ------- | -------------------------------------- |
|
||||
| AlertifyJS | v1.8.0 | http://alertifyjs.com |
|
||||
| ChartJS | v2.9.4 | https://www.chartjs.org |
|
||||
| \+ Zoom plugin for ChartJS | v0.7.3 | https://www.chartjs.org |
|
||||
| EventSource | unknown | https://github.com/Yaffle/EventSource/ |
|
||||
| Hammer.JS | v2.0.7 | http://hammerjs.github.io/ |
|
||||
| Swipper | v4.5.0 | http://www.idangero.us/swiper/ |
|
@ -78,20 +78,20 @@ function handleUpdateMessage(src, message) {
|
||||
}
|
||||
clientID = message.id;
|
||||
if ("device" in message) {
|
||||
if (message.device == "_inst_select") {
|
||||
clientTitle = "select instrument";
|
||||
console.log('IDselect')
|
||||
pushInitCommand("getblock?path=_inst_select&", "instrument selection");
|
||||
menuMode = true;
|
||||
sizeChange();
|
||||
} else {
|
||||
clientTitle = message.instrument + " " + message.device;
|
||||
console.log('loadBlocks', message);
|
||||
loadFirstBlocks();
|
||||
}
|
||||
document.title = "SEA "+clientTitle;
|
||||
if (message.device == "_inst_select") {
|
||||
clientTitle = "select instrument";
|
||||
console.log('IDselect')
|
||||
pushInitCommand("getblock?path=_inst_select&", "instrument selection");
|
||||
menuMode = true;
|
||||
sizeChange();
|
||||
} else {
|
||||
clientTitle = message.instrument + " " + message.device;
|
||||
console.log('loadBlocks', message);
|
||||
loadFirstBlocks();
|
||||
}
|
||||
document.title = "SEA "+clientTitle;
|
||||
} else {
|
||||
document.title = "SEA "+clientTitle + " " + message.title;
|
||||
document.title = "SEA "+clientTitle + " " + message.title;
|
||||
}
|
||||
var header = document.getElementById("header");
|
||||
header.style.width = 'auto';
|
||||
|
@ -28,6 +28,7 @@ in loops called gr
|
||||
chart = Chart(...): the chartjs chart
|
||||
*/
|
||||
|
||||
// Unused ?
|
||||
function Timer(){
|
||||
let start = window.performance.now();
|
||||
return function(x = "timer"){
|
||||
@ -35,7 +36,7 @@ function Timer(){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sets the graph background at loading
|
||||
window.addEventListener('load', function(){
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
if(urlParams.has('white')){
|
||||
@ -58,6 +59,11 @@ function delClass(obj, cls){
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function used to make AJAX request, with three nested functions (POST, GET with returned JSON data, GET)
|
||||
* @param {string} addr - The endpoint
|
||||
* @returns This
|
||||
*/
|
||||
function AJAX(addr){
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
@ -108,6 +114,14 @@ function AJAX(addr){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a callback on double tap (defined as two taps less than 500ms and in a window of +-40px in x and y directions)
|
||||
*
|
||||
* Timeout things maight be useless...
|
||||
*
|
||||
* @param {*} callback - The callback to execute
|
||||
* @returns - Never used
|
||||
*/
|
||||
function doubleTap(callback){
|
||||
var timeout;
|
||||
var lastTap = 0, lastX=NaN, lastY=NaN;
|
||||
@ -135,7 +149,13 @@ function doubleTap(callback){
|
||||
window.addEventListener('touchend', handler);
|
||||
return {stop: function(){ window.removeEventListener('touchend', handler) }}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the highest value out of a time interval in a set of points
|
||||
* @param {*} array - The array we want to look the highest value for
|
||||
* @param {*} tmin - The lower bound of the time interval
|
||||
* @param {*} tmax - The upper boud of the time interval
|
||||
* @returns The highest found value (y value)
|
||||
*/
|
||||
function maxAr(array, tmin, tmax){
|
||||
return Math.max.apply(Math, array.map(function(o) {
|
||||
if (o.y == null || o.x < tmin || o.x > tmax) return -1e99;
|
||||
@ -143,6 +163,13 @@ function maxAr(array, tmin, tmax){
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lowest value out of a time interval in a set of points
|
||||
* @param {*} array - The array we want to look the lowest value for
|
||||
* @param {*} tmin - The lower bound of the time interval
|
||||
* @param {*} tmax - The upper boud of the time interval
|
||||
* @returns The lowest found value (y value)
|
||||
*/
|
||||
function minAr(array, tmin, tmax){
|
||||
return Math.min.apply(Math, array.map(function(o) {
|
||||
if (o.y == null || o.x < tmin || o.x > tmax) return 1e99;
|
||||
@ -150,6 +177,12 @@ function minAr(array, tmin, tmax){
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the values to display (especially the exponentials)
|
||||
* @param {*} val - The value to format
|
||||
* @param {number} significant_digits - The max number of digits to display
|
||||
* @returns The formatted value as a string
|
||||
*/
|
||||
function strFormat(val, significant_digits=13) {
|
||||
if (val == null) return '';
|
||||
evalue = val.toExponential(significant_digits-1).replace(/0*e/, 'e').replace(/\.e/, 'e').replace("e+", "e");
|
||||
@ -161,21 +194,21 @@ function strFormat(val, significant_digits=13) {
|
||||
}
|
||||
|
||||
let graphs = (function (){
|
||||
let dataset_to_graph_map = {};
|
||||
let dataset_to_graph_map = {}; // a dictionnary mapping a variable name to a two values array, containing its graph index and its position inside the graph
|
||||
let blocks, liveMode=true, top_vars=[], bottom_vars=[];
|
||||
let legendFlag = false, currentZoomMode = isTouchDevice ? 'xy' : 'x';
|
||||
let prevTime = null, prevMin = null, prevMax = null, prevGraph = null; // zoom speed limitation
|
||||
let cursorLinePos = null;
|
||||
let cursorLinePos = null; // the position of the cursor line (given by its x value)
|
||||
|
||||
let type = 'linear';
|
||||
let type = 'linear'; // type of graphs axis to display
|
||||
|
||||
let ngraphs = 0; // current number of graphs
|
||||
|
||||
let graph_array = [];
|
||||
let graph_elm_array = [];
|
||||
let vars_array = [];
|
||||
let prev_blk = {};
|
||||
let tag_dict = {};
|
||||
let graph_array = []; // an array of Graph objects
|
||||
let graph_elm_array = []; // an array of HTML divs (with appropriate classes) containing the corresponding Graph objects of graph_array
|
||||
let vars_array = []; // an array of arrays of curve names, each curve names array is positionned at its graph id
|
||||
let prev_blk = {};
|
||||
let tag_dict = {}; // a dictionnary of graph indexes (corresponding to the three indexes of the above arrays), indexed by the tag of the graphs
|
||||
|
||||
let currentMinTime = 0, currentMaxTime = 0; // the currently displayed time range
|
||||
let startTime; // time of query on server
|
||||
@ -186,11 +219,15 @@ let graphs = (function (){
|
||||
let container = document.createElement('div');
|
||||
container.classList.add("graphs-container");
|
||||
|
||||
/** The current time corrected for server time */
|
||||
function now(){
|
||||
// the current time corrected for server time
|
||||
return startTime + (performance.now()-recvTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a graph (meaning it deletes the datasets for the corresponding Graph object, set the Graph Object to undefined and empties the HTML container) at the given index
|
||||
* @param {number} gindex - The graph index to clear
|
||||
*/
|
||||
function clear(gindex){
|
||||
let graph_elm = graph_elm_array[gindex];
|
||||
let graph = graph_array[gindex];
|
||||
@ -207,6 +244,11 @@ let graphs = (function (){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} gindex
|
||||
*/
|
||||
function createSelection(gindex){
|
||||
let graph_elm = graph_elm_array[gindex];
|
||||
clear(gindex);
|
||||
@ -262,8 +304,11 @@ let graphs = (function (){
|
||||
|
||||
let gotoNowElm = document.createElement('div');
|
||||
|
||||
/**
|
||||
* Sets live mode and enable/disable 'go to now' button
|
||||
* @param {boolean} mode - Tells if we are in live mode or not
|
||||
*/
|
||||
function setLiveMode(mode=null) {
|
||||
// set live mode and enable/disable 'go to now' button
|
||||
if (mode !== null) liveMode = mode;
|
||||
if (liveMode && cursorLinePos === null)
|
||||
gotoNowElm.innerHTML = '';
|
||||
@ -274,7 +319,7 @@ let graphs = (function (){
|
||||
function createGraph(gindex, block){
|
||||
clear(gindex);
|
||||
tag_dict[block.tag] = gindex;
|
||||
let dict = {}
|
||||
let dict = {} //
|
||||
for (let curve of block.curves) {
|
||||
if (curve.show !== false) {
|
||||
vars_array[gindex].push(curve.name);
|
||||
@ -314,17 +359,30 @@ let graphs = (function (){
|
||||
showLegends(legendFlag, false);
|
||||
if (legendFlag) adjustLegends();
|
||||
|
||||
result = AJAX( "http://" + hostPort +
|
||||
"/updategraph?variables=" + variables() +
|
||||
"&id=" + clientID).getJSON().then(function(data) {
|
||||
setLiveMode(data.live);
|
||||
console.log('LIVE create', liveMode)
|
||||
})
|
||||
//console.log('UPDATE LIVE', result);
|
||||
// result = AJAX( "http://" + hostPort +
|
||||
// "/updategraph?variables=" + variables() +
|
||||
// "&id=" + clientID).getJSON().then(function(data) {
|
||||
// setLiveMode(data.live);
|
||||
// console.log('LIVE create', liveMode)
|
||||
// })
|
||||
|
||||
// result = AJAX( "http://" + hostPort +
|
||||
// "/updategraph?" +
|
||||
// "id=" + clientID).getJSON().then(function(data) {
|
||||
// setLiveMode(data.live);
|
||||
// console.log('LIVE create', liveMode)
|
||||
// })
|
||||
// //console.log('UPDATE LIVE', result);
|
||||
})
|
||||
}
|
||||
|
||||
// add dataset to graph with graph_id
|
||||
/**
|
||||
* Adds dataset to the Graph object at gindex position
|
||||
* @param {number} gindex - The index of the Graph object to add dataset to
|
||||
* @param {string} key - The curve name (variable)
|
||||
* @param {*} data - The corresponding data points for this curve
|
||||
* @param {*} opts - Some options for the curve (color, label)
|
||||
*/
|
||||
function addDataset(gindex, key, data, data_opts){
|
||||
let graph = graph_array[gindex];
|
||||
dataset_to_graph_map[key] = [gindex, graph.addDataset(key, data, data_opts)];
|
||||
@ -392,6 +450,11 @@ let graphs = (function (){
|
||||
axis.max = axis.ticks.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current viewing window to min and max for each graph
|
||||
* @param {number} min - The minimum timestamp in milliseconds of the viewing window
|
||||
* @param {number} max - The maximum timestamp in milliseconds of the viewing window
|
||||
*/
|
||||
function setMinMax(min, max){
|
||||
currentMaxTime = max;
|
||||
currentMinTime = min;
|
||||
@ -400,7 +463,8 @@ let graphs = (function (){
|
||||
}
|
||||
}
|
||||
|
||||
// responsible for new data being displayed on chart
|
||||
/**
|
||||
* Responsible for new data being displayed on chart */
|
||||
function newDataHandler(key, data){
|
||||
if(!(key in dataset_to_graph_map))
|
||||
return
|
||||
@ -468,12 +532,20 @@ let graphs = (function (){
|
||||
}
|
||||
console.log("RELOAD")
|
||||
// AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // activate updates
|
||||
result = AJAX("http://" + hostPort +
|
||||
"/updategraph?variables=" + variables() +
|
||||
"&id=" + clientID).getJSON().then(function(data) {
|
||||
setLiveMode(data.live);
|
||||
console.log('LIVE reload', liveMode)
|
||||
})
|
||||
// result = AJAX("http://" + hostPort +
|
||||
// "/updategraph?variables=" + variables() +
|
||||
// "&id=" + clientID).getJSON().then(function(data) {
|
||||
// setLiveMode(data.live);
|
||||
// console.log('LIVE reload', liveMode)
|
||||
// })
|
||||
|
||||
|
||||
// result = AJAX("http://" + hostPort +
|
||||
// "/updategraph?"+
|
||||
// "id=" + clientID).getJSON().then(function(data) {
|
||||
// setLiveMode(data.live);
|
||||
// console.log('LIVE reload', liveMode)
|
||||
// })
|
||||
updateAuto(false);
|
||||
//update();
|
||||
});
|
||||
@ -629,6 +701,8 @@ let graphs = (function (){
|
||||
|
||||
createGraphs();
|
||||
|
||||
activateUpdates();
|
||||
|
||||
container.parentNode.querySelector('.panel').classList.add('graphics');
|
||||
|
||||
gotoNowElm.addEventListener('click', gotoNow);
|
||||
@ -691,6 +765,20 @@ let graphs = (function (){
|
||||
container.parentNode.querySelector('.panel span').appendChild(gotoMainElm);
|
||||
}
|
||||
|
||||
/**
|
||||
* New function to activate the graph updates
|
||||
*/
|
||||
function activateUpdates(){
|
||||
|
||||
result = AJAX( "http://" + hostPort +
|
||||
"/updategraph?" +
|
||||
"id=" + clientID).getJSON().then(function(data) {
|
||||
setLiveMode(data.live);
|
||||
console.log('LIVE create', liveMode)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function getBlocks(){
|
||||
return blocks;
|
||||
}
|
||||
@ -1180,6 +1268,13 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
||||
chart.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a dataset (curve) to the current graph, and manages the legend for it
|
||||
* @param {string} key - The curve name (variable)
|
||||
* @param {*} data - The corresponding data points for this curve
|
||||
* @param {*} opts - Some options for the curve (color, label)
|
||||
* @returns The index of this curve in its chart
|
||||
*/
|
||||
function addDataset(key, data, opts){
|
||||
let dataset_index = chart.data.datasets.length;
|
||||
chart.data.datasets.push({data: data, label: opts.label, key: key,
|
||||
@ -1283,6 +1378,11 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
||||
chart.data.datasets[index].data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current viewing window to min and max
|
||||
* @param {number} min - The minimum timestamp in milliseconds of the viewing window
|
||||
* @param {number} max - The maximum timestamp in milliseconds of the viewing window
|
||||
*/
|
||||
function setMinMax(min, max){
|
||||
let ax = chart.options.scales.xAxes[0];
|
||||
let ay = chart.options.scales.yAxes[0];
|
||||
@ -1447,6 +1547,11 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when new data is received from the server.
|
||||
* Appends new data to the corresponding curves' datasets
|
||||
* @param {*} graph - The graph response from the server
|
||||
*/
|
||||
function updateCharts2(graph){
|
||||
if(!graphs.doUpdates()) {
|
||||
console.log('graphs.doUpdates skipped');
|
||||
@ -1464,6 +1569,7 @@ function updateCharts2(graph){
|
||||
// graphs.update();
|
||||
}
|
||||
|
||||
/** Useless (called in graph-draw response case in SEAWebClientCommunication) */
|
||||
function createCharts2(arg) {
|
||||
console.log('C2', arg)
|
||||
}
|
||||
|
90
influxdb.py
90
influxdb.py
@ -85,11 +85,41 @@ class InfluxDataGetter:
|
||||
"""
|
||||
res = {}
|
||||
for variable in variables:
|
||||
if variable.endswith(".target"):
|
||||
variable_name_for_query = variable[:-len(".target")]
|
||||
res[variable] = self._get_curve(variable_name_for_query, True, time)
|
||||
else:
|
||||
res[variable] = self._get_curve(variable, False, time)
|
||||
|
||||
variable_name_for_query = variable
|
||||
is_target = False
|
||||
if variable_name_for_query.endswith(".target"):
|
||||
variable_name_for_query = variable_name_for_query[:-len(".target")]
|
||||
is_target = True
|
||||
|
||||
curve = self._get_curve(variable_name_for_query, is_target, time)
|
||||
if len(curve) > 0:
|
||||
res[variable] = curve
|
||||
|
||||
return res
|
||||
|
||||
def poll_last_value(self, variables, time):
|
||||
"""
|
||||
Polls the last value for the given variables that are not more recent that time[1].
|
||||
|
||||
Parameters :
|
||||
variables ([(str)]) : an array of variable names (Influx) to get the last known values for
|
||||
time ([int]) : the current asked timerange in the calling polling function (only second value used). It consists of two values which are Unix timestamps in seconds, first included, second excluded.
|
||||
|
||||
Returns :
|
||||
{(str):[[(int), (float)]]} : a dictionnary of points. The key is the name of the influx variable, and the value is an array of one pair (also array), the first value being the Unix timestamp in second (x), the seconds being the value (y).
|
||||
"""
|
||||
res = {}
|
||||
for variable in variables:
|
||||
|
||||
variable_name_for_query = variable
|
||||
is_target = False
|
||||
if variable_name_for_query.endswith(".target"):
|
||||
variable_name_for_query = variable_name_for_query[:-len(".target")]
|
||||
is_target = True
|
||||
|
||||
point = self._get_last_value(variable_name_for_query, is_target, time)
|
||||
res[variable] = point
|
||||
return res
|
||||
|
||||
# ----- PRIVATE METHODS
|
||||
@ -219,7 +249,8 @@ class InfluxDataGetter:
|
||||
|
||||
Returns :
|
||||
|
||||
[{"tag":(str), "unit":(str), "curves":[{"name":(str), }]]
|
||||
[{"tag":(str), "unit":(str), "curves":[{"name":(str), "label":(str), "color":(str)}]] : a list of dictionnaries, each one representing
|
||||
a block of curves with their name, their label and their color to display, grouped by their tag (which can be the unit augmented with an index) and their unit.
|
||||
"""
|
||||
groups = {}
|
||||
|
||||
@ -299,10 +330,10 @@ class InfluxDataGetter:
|
||||
except:
|
||||
value = None
|
||||
res.append([t, value])
|
||||
|
||||
return self._insert_last_know_value(variable, is_target, res, time)
|
||||
|
||||
return self._insert_last_known_value(variable, is_target, res, time)
|
||||
|
||||
def _insert_last_know_value(self, variable, is_target, curve, time):
|
||||
def _insert_last_known_value(self, variable, is_target, curve, time):
|
||||
"""
|
||||
Adds the last known value as the first point in the curve if the last known value is outside the viewing window.
|
||||
|
||||
@ -313,7 +344,7 @@ class InfluxDataGetter:
|
||||
time ([(int)]) : the timerange we want the values in. It consists of two values which are Unix timestamps in seconds, first included, second excluded.
|
||||
|
||||
Returns :
|
||||
[[(int), (float)]] : the curve parameter, updated with a potential new first point
|
||||
[[(int), (float)]] : the curve of the parameter, updated with a potential new first point
|
||||
"""
|
||||
|
||||
if len(curve) == 0 or curve[0][0] != time[0]:
|
||||
@ -333,4 +364,41 @@ class InfluxDataGetter:
|
||||
except:
|
||||
value = None
|
||||
curve.insert(0, [time[0], value])
|
||||
return curve
|
||||
return curve
|
||||
|
||||
def _get_last_value(self, variable, is_target, time):
|
||||
"""
|
||||
Gets the last value for the given variable that are not more recent that time[1].
|
||||
|
||||
Parameters :
|
||||
variable (str) : the name (Influx) of the variable we want the last value of.
|
||||
is_target (bool) : tells if the given variable is a target, or not (if variable is "nicos/se_t_chip.target", then is_target has to be set to True)
|
||||
time ([int]) : the current asked timerange in the calling polling function (only second value used). It consists of two values which are Unix timestamps in seconds, first included, second excluded.
|
||||
|
||||
Returns :
|
||||
[[(int), (float)]] : a point encapsuled in an array. The first value is the Unix timestamp in second (x), the seconds is the value (y)
|
||||
"""
|
||||
|
||||
res = []
|
||||
query = f"""
|
||||
from(bucket: "{self._bucket}")
|
||||
|> range(start: 0, stop: {time[1] + 1})
|
||||
|> filter(fn : (r) => r._measurement == "{variable}")
|
||||
|> filter(fn : (r) => r._field == "{"target_float" if is_target else "value_float"}")
|
||||
|> last()
|
||||
|> keep(columns: ["_time","_value"])
|
||||
|> yield(name: "res")
|
||||
"""
|
||||
|
||||
# this loop might be simplified, but it has to be kept to catch the case when there is unavailable data
|
||||
tables = self._db.query(query)
|
||||
for table in tables:
|
||||
for record in table.records:
|
||||
t = int(datetime.timestamp(record.get_time()))
|
||||
value = record.get_value()
|
||||
try:
|
||||
value = PrettyFloat(value)
|
||||
except:
|
||||
value = None
|
||||
res.append([t, value])
|
||||
return res
|
@ -32,6 +32,7 @@ class InfluxGraph:
|
||||
self.livemode = self.HISTORICAL
|
||||
self.time = [0, 0]
|
||||
self.lastvalues = {}
|
||||
self.variables = []
|
||||
|
||||
def get_abs_time(self, times):
|
||||
"""
|
||||
@ -60,7 +61,7 @@ class InfluxGraph:
|
||||
# if self.livemode == self.LIVE:
|
||||
for c in result.values():
|
||||
while c:
|
||||
lastt, lastx = c[-1]
|
||||
lastt, _ = c[-1]
|
||||
if lastt <= self.time[1]:
|
||||
break
|
||||
c.pop()
|
||||
@ -144,6 +145,10 @@ class InfluxGraph:
|
||||
end_time = int(self.get_abs_time(time)[-1])
|
||||
|
||||
blocks = self.influx_data_getter.get_available_variables_at_time(end_time)
|
||||
|
||||
# updates the self.variables attribute to keep track of the available variables
|
||||
self.variables = [variable["name"] for block in blocks for variable in block["curves"]]
|
||||
|
||||
assign_colors_to_curves(blocks)
|
||||
result = dict(type='var_list')
|
||||
result['blocks'] = blocks
|
||||
@ -151,19 +156,48 @@ class InfluxGraph:
|
||||
|
||||
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.
|
||||
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
|
||||
"""
|
||||
|
||||
return dict(type='accept-graph', live=False)
|
||||
logging.info("UPD GRAPH %d", self.livemode)
|
||||
if self.livemode == self.HISTORICAL:
|
||||
return dict(type='accept-graph', live=False)
|
||||
else:
|
||||
self.livemode = self.LIVE
|
||||
return dict(type='accept-graph', live=True)
|
||||
|
||||
def graphpoll(self):
|
||||
"""
|
||||
TODO : method needed for live data update. See example in seaweb.py : SeaGraph
|
||||
Polls the last known values for all the available variables, and returns only those whose polled value is more recent than the nost 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", "reduced":(bool), "time":(int), "graph":{(str):[[(int),(float)]]}} | None : a dictionnary with its "graph-update" 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
|
||||
"""
|
||||
if self.livemode == self.LIVE:
|
||||
self.time[1], = self.get_abs_time([0])
|
||||
else:
|
||||
self.time[1] = self.time[0] # Do not update (the current requested value is the last)
|
||||
if self.time[1] > self.time[0]:
|
||||
result = self.influx_data_getter.poll_last_value(self.variables, self.time)
|
||||
|
||||
for variable in self.lastvalues.keys():
|
||||
if result[variable][-1][0] > self.lastvalues[variable][0]:
|
||||
self.lastvalues[variable] = (result[variable][-1][0], result[variable][-1][1])
|
||||
else:
|
||||
del result[variable]
|
||||
|
||||
if int(self.time[1] / 60) != int(self.time[0] / 60):
|
||||
# Update unchanged values every plain minute
|
||||
for var, (_, lastx) in self.lastvalues.items():
|
||||
if var not in result:
|
||||
result[var] = [(self.time[1], lastx)]
|
||||
self.time[0] = self.time[1]
|
||||
if len(result) > 0:
|
||||
return dict(type='graph-update', reduced=False, time=self.time[1], graph=result)
|
||||
return None
|
@ -66,7 +66,7 @@ def get_update(path=None):
|
||||
logging.info('UPDATE %s %s', client.id, socket.getfqdn(flask.request.remote_addr.split(':')[-1]))
|
||||
#msg = dict(type='id', id=client.id, title=instrument.title);
|
||||
#yield to_json_sse(msg)
|
||||
msg = dict(type='id', id=client.id, instrument=instrument.title, device=instrument.device);
|
||||
msg = dict(type='id', id=client.id, instrument=instrument.title, device=instrument.device)
|
||||
yield to_json_sse(msg)
|
||||
try:
|
||||
lastmsg = time.time()
|
||||
@ -498,6 +498,7 @@ class SeaGraph:
|
||||
self.livemode = self.HISTORICAL
|
||||
self.time = [0, 0]
|
||||
self.lastvalues = {}
|
||||
self.variables = []
|
||||
|
||||
def strip_future(self, result):
|
||||
'strip future points (happens only on dummy test_day)'
|
||||
@ -527,13 +528,13 @@ class SeaGraph:
|
||||
self.last_t = 0
|
||||
start, end, now = seagraph.get_abs_time(time + [0])
|
||||
self.time = [start, end]
|
||||
self.variables = variables.split(',')
|
||||
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)
|
||||
self.scanner = seagraph.NumericScanner(instrument.logger_dir, instrument.test_day)
|
||||
#result = self.scanner.get_message(self.variables, self.time)
|
||||
#self.time[0] = self.time[1]
|
||||
result = self.scanner.get_message(self.variables, self.time, show_empty=True)
|
||||
result = self.scanner.get_message(variables, self.time, show_empty=True)
|
||||
self.strip_future(result)
|
||||
#for var in ('treg.set.reg', 'mf'):
|
||||
# curve = result.get(var,[(0,0)])
|
||||
@ -557,6 +558,8 @@ class SeaGraph:
|
||||
scanner = seagraph.VarsScanner(instrument.logger_dir, instrument.test_day)
|
||||
result = dict(type='var_list')
|
||||
result['blocks'] = list(scanner.get_message(time[-1]).values())
|
||||
# updates the self.variables attribute to keep track of the available variables
|
||||
self.variables = [variable["name"] for block in result['blocks'] for variable in block["curves"]]
|
||||
return result
|
||||
|
||||
def w_updategraph(self):
|
||||
|
Reference in New Issue
Block a user