diff --git a/client/components/dates_popup/dates_popup.css b/client/components/dates_popup/dates_popup.css
index cd68d37..6d14e47 100644
--- a/client/components/dates_popup/dates_popup.css
+++ b/client/components/dates_popup/dates_popup.css
@@ -57,6 +57,6 @@
margin-top: 10px;
}
-.jump-button-all, .jump-button-end{
+.jump-button-all, .jump-button-time{
width: 200px;
}
\ No newline at end of file
diff --git a/client/components/dates_popup/dates_popup.js b/client/components/dates_popup/dates_popup.js
index 6d34c2f..ec6b902 100644
--- a/client/components/dates_popup/dates_popup.js
+++ b/client/components/dates_popup/dates_popup.js
@@ -1,6 +1,6 @@
class DatesPopup extends HTMLElement{
- static END = 0;
+ static TIME = 0;
static ALL = 1;
static DAY = new Date(24*60*60*1000);
@@ -24,10 +24,10 @@ class DatesPopup extends HTMLElement{
this.jumpCallback(dateTimeInput[0], dateTimeInput[1], DatesPopup.ALL);
}
- doJumpEndCallback(){
+ doJumpTimeCallback(){
let dateTimeInput = this.getDateTimeInput();
this.hide();
- this.jumpCallback(dateTimeInput[0], dateTimeInput[1], DatesPopup.END);
+ this.jumpCallback(dateTimeInput[0], dateTimeInput[1], DatesPopup.TIME);
}
convertTimeStringToTimestamp(formattedTime){
@@ -62,7 +62,7 @@ class DatesPopup extends HTMLElement{
this.hide();
this.getElementsByTagName("img")[0].onclick = () => {this.hide();};
this.getElementsByClassName("go-to-now-button")[0].onclick = () => {this.doGoToNowCallback();};
- this.getElementsByClassName("jump-button-end")[0].onclick = () => {this.doJumpEndCallback();};
+ this.getElementsByClassName("jump-button-time")[0].onclick = () => {this.doJumpTimeCallback();};
this.getElementsByClassName("jump-button-all")[0].onclick = () => {this.doJumpAllCallback();};
}
@@ -85,17 +85,15 @@ class DatesPopup extends HTMLElement{
diff --git a/client/components/states_indicator/dates/dates.js b/client/components/states_indicator/dates/dates.js
index 4b08874..0d88d10 100644
--- a/client/components/states_indicator/dates/dates.js
+++ b/client/components/states_indicator/dates/dates.js
@@ -40,7 +40,6 @@ class DateIndicator extends HTMLElement{
}
showPopup(){
- console.log("clicked");
this.datePopup.show();
}
diff --git a/client/jsFiles/SEAWebClientCommunication.js b/client/jsFiles/SEAWebClientCommunication.js
index f76f1fa..bbae654 100644
--- a/client/jsFiles/SEAWebClientCommunication.js
+++ b/client/jsFiles/SEAWebClientCommunication.js
@@ -345,7 +345,7 @@ function successHandler(s, message) {
begin = timeRange[0] - timeRange[1];
select.value = begin;
// Server-request for variable-list.*/
- reqJSON(0, "http://" + hostPort + "/getvars?time=" + timeRange + "&id="
+ reqJSON(0, "http://" + hostPort + "/getvars?time=" + timeRange + "&all=False&id="
+ clientID, successHandler, errorHandler);
break;
// Response to a "getvars"-server-request.
@@ -365,7 +365,8 @@ function successHandler(s, message) {
} else {
nextInitCommand();
}*/
- graphs.receivedVars(message.blocks);
+ // graphs.receivedVars(message.blocks);
+ graphs.initGraphs(message.blocks);
nextInitCommand();
break;
// Response to a "graph"-server-request.
diff --git a/client/jsFiles/SEAWebClientGraphics.js b/client/jsFiles/SEAWebClientGraphics.js
index ae81280..ea633db 100644
--- a/client/jsFiles/SEAWebClientGraphics.js
+++ b/client/jsFiles/SEAWebClientGraphics.js
@@ -446,7 +446,7 @@ let graphs = (function (){
}*/
}
}
- graph.setMinMax(minTime,maxTime);
+ graph.setMinMax(currentMinTime,currentMaxTime);
graph.autoScaleIf();
graph.update();
showLegends(legendFlag, false);
@@ -804,11 +804,49 @@ let graphs = (function (){
}
function jumpToDate(dateTimestampMs, timeValueMs, mode){
- let msLeftTimestamp = dateTimestampMs + timeValueMs;
- let msRightTimestamp = msLeftTimestamp + 24*60*60*1000;
- if (liveMode && msRightTimestamp < lastTime) setLiveMode(false);
- setMinMax(msLeftTimestamp, msRightTimestamp);
- updateAuto();
+
+ cursorLine(null);
+
+ let msLeftTimestampGetVars = 0, msLeftTimestampGetGraph = 0 , msRightTimestampGetVars = 0, msRightTimestampGetGraph = 0;
+
+ msLeftTimestampGetVars = dateTimestampMs;
+ msLeftTimestampGetGraph = dateTimestampMs;
+
+ if(mode == DatesPopup.TIME){
+ msRightTimestampGetVars = dateTimestampMs + timeValueMs;
+ }
+ else if(mode == DatesPopup.ALL){ // we ignore time
+ msRightTimestampGetVars = dateTimestampMs + 24*60*60*1000 - 1000; // we exclude the very beginning of the next day
+ }
+
+ msRightTimestampGetGraph = dateTimestampMs + 24*60*60*1000 - 1000;
+
+ AJAX("http://" + hostPort + "/getvars?time=" + msLeftTimestampGetVars/1000 + "," + msRightTimestampGetVars/1000 + "&all=" +allQueryParameterRepresentation(mode) + "&id="+ clientID).getJSON().then(function(data){
+ blocks = data.blocks;
+
+ maxTime = msRightTimestampGetGraph;
+ minTime = msLeftTimestampGetGraph;
+
+ currentMaxTime = maxTime + 60000;
+ currentMinTime = minTime;
+
+ globalIndicators.getIndicatorsMap()[datesKey].update(currentMinTime);
+
+ ngraphs = 0; // forces all the graphs to reset
+ createGraphs();
+
+ if (liveMode && msRightTimestampGetGraph < lastTime) setLiveMode(false);
+ });
+
+ }
+
+ function allQueryParameterRepresentation(mode){
+ if(mode == DatesPopup.ALL){
+ return "True";
+ }
+ else {
+ return "False";
+ }
}
function shiftOlder(){
@@ -881,15 +919,28 @@ let graphs = (function (){
}
/**
- * Removes the cursor, sets the window visualisation to [now-previousDelta, now], goes for live mode and updates
+ * Removes the cursor, gets the var + graphs for now (window visualisation to [now-30min, now]) and ask for updates
*/
function gotoNow() {
- cursorLine(null);
- if (!liveMode) {
- setMinMax(graphs.now() - (currentMaxTime - currentMinTime), graphs.now());
- }
- setLiveMode(true);
- updateAuto();
+ let msRightTimestamp = graphs.now();
+ let msLeftTimestamp = msRightTimestamp - 30*60*1000;
+ cursorLine(null);
+
+ AJAX("http://" + hostPort + "/getvars?time=" + msLeftTimestamp/1000 + "," + msRightTimestamp/1000 + "&all=False&id="+ clientID).getJSON().then(function(data){
+ currentMaxTime = msRightTimestamp + 60000;
+ currentMinTime = msLeftTimestamp;
+
+ maxTime = msRightTimestamp;
+ minTime = msLeftTimestamp;
+
+ blocks = data.blocks;
+
+ ngraphs = 0;
+ createGraphs();
+ globalIndicators.getIndicatorsMap()[datesKey].update(currentMinTime);
+ activateUpdates();
+
+ });
}
/*
@@ -906,6 +957,62 @@ let graphs = (function (){
}
*/
+ function buildGraphicsUI(){
+
+ let f = 0;
+ insertSlide(f, " ", "graphics", container);
+
+ let currentSwiper = swiper[f];
+
+ function setSlidingMode(mode) {
+ currentSwiper.params.noSwipingClass = mode ? "allow-swipe" : "swiper-slide-main";
+ }
+
+ currentSwiper.enableSwiping(false);
+ currentSwiper.on('reachBeginning', function () {
+ currentSwiper.enableSwiping(false);
+ })
+
+ let graphicsPanel = container.parentNode.querySelector('.panel')
+ graphicsPanel.classList.add('graphics');
+ graphicsPanel.childNodes[0].style.visibility = "hidden"; // hides the span added by the swippers
+ // The cross to display "main" panel at the location of the graphs
+ let gotoMainElm = document.createElement('div');
+ gotoMainElm.innerHTML = "×";
+ gotoMainElm.addEventListener('click', function () {
+ currentSwiper.enableSwiping(true);
+ console.log("MAIN")
+ currentSwiper.slideNext();
+ });
+
+ globalIndicators.loadIndicators(graphicsPanel);
+ globalControls.loadControls(graphicsPanel);
+ loadGraphicsMenu(graphicsPanel);
+ graphicsPanel.appendChild(gotoMainElm);
+ gotoMainElm.style.marginTop = "auto";
+ gotoMainElm.style.marginBottom = "auto";
+ gotoMainElm.style.marginRight = "6px";
+ gotoMainElm.style.color = "white";
+ gotoMainElm.style.cursor = "pointer";
+ created = true;
+
+ if (isTouchDevice) {
+ doubleTap(removeCursor);
+ } else {
+ window.addEventListener('dblclick', removeCursor);
+ showLegends(true, false);
+ adjustLegends();
+ }
+ }
+
+ function initGraphs(blocks){
+ if(!created){
+ buildGraphicsUI();
+ created = true;
+ }
+ receivedVars(blocks);
+ }
+
/**
* Holds the received variables from the /getvars call, gets the server time, insert slide (?),
* create the graphs, activate SSE graph-update messages, sets the different event listeners
@@ -920,104 +1027,18 @@ let graphs = (function (){
}
AJAX("http://" + hostPort + "/gettime?time=-1800,0&id="+ clientID).getJSON().then(function(data){
startTime = data.time[1]*1000;
- maxTime = startTime + 60000;
- console.log('MAXTIME', maxTime - Date.now());
+ maxTime = startTime;
+ currentMaxTime = maxTime + 60000;
+ // console.log('MAXTIME', currentMaxTime - Date.now());
minTime = data.time[0]*1000;
recvTime = performance.now();
+
+ blocks = blocks_arg;
+
+ createGraphs();
+
+ activateUpdates();
});
-
-
- // g_varlist = getVarlist(nblocks)
- let f = 0;
- insertSlide(f, " ", "graphics", container);
- blocks = blocks_arg;
-
- createGraphs();
-
- activateUpdates();
-
- let graphicsPanel = container.parentNode.querySelector('.panel')
- graphicsPanel.classList.add('graphics');
- graphicsPanel.childNodes[0].style.visibility = "hidden"; // hides the span added by the swippers
- // The cross to display "main" panel at the location of the graphs
- let gotoMainElm = document.createElement('div');
- gotoMainElm.innerHTML = "×";
- gotoMainElm.addEventListener('click', function () {
- currentSwiper.enableSwiping(true);
- console.log("MAIN")
- currentSwiper.slideNext();
- });
-
- if(!created){
- globalIndicators.loadIndicators(graphicsPanel);
- globalControls.loadControls(graphicsPanel);
- loadGraphicsMenu(graphicsPanel);
- graphicsPanel.appendChild(gotoMainElm);
- gotoMainElm.style.marginTop = "auto";
- gotoMainElm.style.marginBottom = "auto";
- gotoMainElm.style.marginRight = "6px";
- gotoMainElm.style.color = "white";
- gotoMainElm.style.cursor = "pointer";
- created = true;
- }
-
- // gotoNowElm.addEventListener('click', gotoNow);
- //gotoNowElm.innerHTML = "go to now";
- // container.parentNode.querySelector('.panel span').appendChild(gotoNowElm);
-
- // Removes the cursor then applies the changes
- // function removeCursor(evt=null) {
- // graphs.cursorLine(null);
- // graphs.update();
- // }
- if (isTouchDevice) {
- doubleTap(removeCursor);
- } else {
- window.addEventListener('dblclick', removeCursor);
- showLegends(true, false);
- adjustLegends();
- // let zoomMode = document.createElement('div');
- /**
- * Sets the HTML button for the y-zoom depending on the current mode
- */
- // function setInnerZoomMode(){
- // if (currentZoomMode == 'y') {
- // zoomMode.innerHTML = "☒ y-zoom";
- // } else {
- // zoomMode.innerHTML = "☐ y-zoom";
- // }
- // prevTime = null; // reset zoom speed time
- // }
- // setInnerZoomMode();
- /**
- * Inverts the zoom mode (x<->y)
- */
- // function toggleZoomMode(){
- // if (currentZoomMode == 'y')
- // currentZoomMode = 'x';
- // else
- // currentZoomMode = 'y';
- // setInnerZoomMode();
- // for (let gr of graph_array) {
- // if (gr) gr.setZoomMode(currentZoomMode);
- // }
- // }
- // zoomMode.addEventListener('click', toggleZoomMode);
- // container.parentNode.querySelector('.panel span').appendChild(zoomMode);
- }
-
- let currentSwiper = swiper[f];
-
- function setSlidingMode(mode) {
- currentSwiper.params.noSwipingClass = mode ? "allow-swipe" : "swiper-slide-main";
- }
-
- currentSwiper.enableSwiping(false);
- currentSwiper.on('reachBeginning', function () {
- currentSwiper.enableSwiping(false);
- })
-
- // container.parentNode.querySelector('.panel span').appendChild(gotoMainElm);
}
@@ -1261,6 +1282,7 @@ let graphs = (function (){
shiftOlder: shiftOlder,
shiftNewer: shiftNewer,
jumpToDate: jumpToDate,
+ initGraphs: initGraphs,
}
})();
diff --git a/influxdb.py b/influxdb.py
index 3663438..7bd8145 100644
--- a/influxdb.py
+++ b/influxdb.py
@@ -52,22 +52,24 @@ class InfluxDataGetter:
# ----- PUBLIC METHODS
- def get_available_variables_at_time(self, time):
+ def get_available_variables_at_time(self, times, all=False):
"""
Gets the available variables (those that we can have a value for since the device has been installed on the instrument) at the given point in time.
+ We can get the last available variables at the given point in time or all the known variables for the day corresponding to the timestamp.
Parameters :
- time (int) : the unix timestamp in seconds of the given point in time
-
+ times ([int]) : the unix timestamps in seconds of the range. The first value can be unused. The last can represent the point in time.
+ all (bool) : indicates if we want all the variables for the given times[1] timestamp (all the day)
+
Returns :
[{"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.
"""
- all_setup_info = self._get_all_setup_info_as_dict(time)
+ all_setup_info = self._get_all_setup_info_as_dict(times, all)
available_variables = self._extract_variables(all_setup_info)
- available_variables = self._remove_variables_without_value_float(available_variables, time)
- available_variables = self._set_variables_with_target(available_variables, time)
+ available_variables = self._remove_variables_without_value_float(available_variables, times)
+ available_variables = self._set_variables_with_target(available_variables, times)
res = self._group_variables_by_unit(available_variables)
return res
@@ -126,12 +128,14 @@ class InfluxDataGetter:
# ----- PRIVATE METHODS
- def _get_all_setup_info_as_dict(self, time):
+ def _get_all_setup_info_as_dict(self, times, all=False):
"""
Gets the value of the field setup_info in the measurements nicos/se_main, nicos/se_stick, nicos/se_addons as an array of Python dicts.
+ Takes the last setup_info dict (for each measurement) known at times[1], or all the dicts for this day + the previous known (also for each)
Parameters
- time (int) : the Unix timestamp in seconds we want to look the availability of variables for.
+ times ([int]) : the unix timestamps in seconds of the range. The first value can be unused. The last can represent the point in time.
+ all (bool) : indicates if we want all the variables for the given times[1] timestamp (all the day)
Returns :
[{(str):((str), {...})}]: an array of the parsed "setup_info dict" of each measurements. The key is the secop_module prefixed with "se_", and the value is a tuple with its first value
@@ -141,21 +145,34 @@ class InfluxDataGetter:
measurements = ["nicos/se_main", "nicos/se_stick", "nicos/se_addons"]
res = []
for measurement in measurements:
- to_add = {}
+ to_add = []
query = f"""
from(bucket: "{self._bucket}")
- |> range(start: 0, stop: {time + 1})
+ |> range(start: {times[0] if all else 0}, stop: {times[1] + 1})
|> filter(fn: (r) => r._measurement == "{measurement}")
|> filter(fn: (r) => r._field == "setup_info")
- |> last()
+ {"" if all else "|> last()"}
|> yield(name: "res")
"""
-
tables = self._db.query(query)
for table in tables:
for record in table.records:
- to_add = ast.literal_eval(record.get_value())
- res.append(to_add)
+ to_add.append(ast.literal_eval(record.get_value()))
+
+ if all:
+ query = f"""
+ from(bucket: "{self._bucket}")
+ |> range(start: 0, stop: {times[0]+1})
+ |> filter(fn: (r) => r._measurement == "{measurement}")
+ |> filter(fn: (r) => r._field == "setup_info")
+ |> last()
+ |> yield(name: "res")
+ """
+ tables = self._db.query(query)
+ for table in tables:
+ for record in table.records:
+ to_add.append(ast.literal_eval(record.get_value()))
+ res.extend(to_add)
return res
def _extract_variables(self, all_setup_info_dict):
@@ -172,17 +189,21 @@ class InfluxDataGetter:
"""
available_varirables = []
+ added_names = []
for setup_info_dict in all_setup_info_dict:
for (setup_info_variable_name, content) in setup_info_dict.items():
if content[0] != "nicos.devices.secop.devices.SecopDevice":
- available_varirables.append(
- {
- "name":self._transform_setup_info_variable_name_to_influx(setup_info_variable_name),
- "label":content[1]["secop_module"],
- "unit":content[1]["unit"],
- "has_potential_target": "target_datainfo" in content[1].keys()
- }
- )
+ name = self._transform_setup_info_variable_name_to_influx(setup_info_variable_name)
+ if name not in added_names:
+ available_varirables.append(
+ {
+ "name":name,
+ "label":content[1]["secop_module"],
+ "unit":content[1]["unit"],
+ "has_potential_target": "target_datainfo" in content[1].keys()
+ }
+ )
+ added_names.append(name)
return available_varirables
def _transform_setup_info_variable_name_to_influx(self, setup_info_name):
@@ -197,14 +218,14 @@ class InfluxDataGetter:
"""
return self._influx_instrument_config["measurement_prefix"] + setup_info_name.lower()[len(self._influx_instrument_config["setup_info_prefix"]):]
- def _remove_variables_without_value_float(self, available_variables, time):
+ def _remove_variables_without_value_float(self, available_variables, times):
"""
Removes some of the previously identified available_variables if they effectively do not have a value_float field in InfluxDB.
Parameters :
available_variables ([{"name":(str), "label":(str), "unit":(str), "has_potential_target":(bool)}]) : an array of dictionnaries, each containing the Influx name of the corresponding variable out of the setup_info dict,
the label to display in the Web GUI, its unit and a boolean value indicating if the variable has a potential target available.
- time (int): the unix timestamp in seconds at which we want to get the available variables (for the target).
+ times ([int]): (only second value used) the unix timestamps in seconds of the range at which we want to get the available variables (for the value).
Returns :
[{"name":(str), "label":(str), "unit":(str), "has_potential_target":(bool)}] : an array of dictionnaries (updated), each containing the Influx name of the corresponding variable out of the setup_info dict,
@@ -214,7 +235,7 @@ class InfluxDataGetter:
for variable in available_variables:
query = f"""
import "influxdata/influxdb/schema"
- schema.measurementFieldKeys(bucket: "{self._bucket}", measurement: "{variable["name"]}", start:0, stop: {time + 1})
+ schema.measurementFieldKeys(bucket: "{self._bucket}", measurement: "{variable["name"]}", start:0, stop: {times[1] + 1})
|> yield(name: "res")
"""
records = self._db.query(query)[0].records
@@ -223,14 +244,14 @@ class InfluxDataGetter:
return res
- def _set_variables_with_target(self, available_variables, time):
+ def _set_variables_with_target(self, available_variables, times):
"""
Determines if the previously identified available_variables have effectively a target or not (meaning it has a target_float field in Influx).
Parameters :
available_variables ([{"name":(str), "label":(str), "unit":(str), "has_potential_target":(bool)}]) : an array of dictionnaries, each containing the Influx name of the corresponding variable out of the setup_info dict,
the label to display in the Web GUI, its unit and a boolean value indicating if the variable has a potential target available.
- time (int): the unix timestamp in seconds at which we want to get the available variables (for the target).
+ times ([int]): (only second value used) the unix timestamps in seconds of the range at which we want to get the available variables (for the target).
Returns :
[{"name":(str), "label":(str), "unit":(str), "has_potential_target":(bool)}] : an array of dictionnaries, each containing the Influx name of the corresponding variable out of the setup_info dict,
@@ -241,7 +262,7 @@ class InfluxDataGetter:
if variable["has_potential_target"]:
query = f"""
import "influxdata/influxdb/schema"
- schema.measurementFieldKeys(bucket: "{self._bucket}", measurement: "{variable["name"]}", start:0, stop: {time + 1})
+ schema.measurementFieldKeys(bucket: "{self._bucket}", measurement: "{variable["name"]}", start:0, stop: {times[1] + 1})
|> yield(name: "res")
"""
records = self._db.query(query)[0].records
diff --git a/influxgraph.py b/influxgraph.py
index 0d7425f..4f80080 100644
--- a/influxgraph.py
+++ b/influxgraph.py
@@ -139,7 +139,7 @@ class InfluxGraph:
time = [float(t) for t in time.split(',')]
return dict(type='time', time= self.get_abs_time(time))
- def w_getvars(self, time):
+ def w_getvars(self, time, all=False):
"""
Gets the curve names available at a given point in time.
Called when the route /getvars is reached.
@@ -154,9 +154,10 @@ class InfluxGraph:
"""
time = [float(t) for t in time.split(',')]
+ start_time = int(self.get_abs_time(time)[0])
end_time = int(self.get_abs_time(time)[-1])
- blocks = self.influx_data_getter.get_available_variables_at_time(end_time)
+ blocks = self.influx_data_getter.get_available_variables_at_time([start_time, end_time], all)
# 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"]]