make web client work

This commit is contained in:
2020-12-10 16:58:59 +01:00
parent 9e1d3b4e07
commit 1de819cd26
7 changed files with 380 additions and 209 deletions

View File

@ -86,7 +86,7 @@ function handleUpdateMessage(src, message) {
sizeChange(); sizeChange();
} else { } else {
clientTitle = message.instrument + " " + message.device; clientTitle = message.instrument + " " + message.device;
console.log('loadBlocks') console.log('loadBlocks', message);
loadFirstBlocks(); loadFirstBlocks();
} }
document.title = "SEA "+clientTitle; document.title = "SEA "+clientTitle;
@ -155,7 +155,6 @@ function handleUpdateMessage(src, message) {
case "graph-update": case "graph-update":
//if (getUpdatesGraphics) { //if (getUpdatesGraphics) {
//timeServer = message.time; //timeServer = message.time;
console.log("graph-update");
updateCharts2(message.graph); updateCharts2(message.graph);
//} //}
break; break;
@ -207,11 +206,12 @@ function updateValues(message, src) {
} else if (type == "input") { } else if (type == "input") {
var row = matches[j].parentNode.parentNode.parentNode; var row = matches[j].parentNode.parentNode.parentNode;
row.style.backgroundColor = "white"; row.style.backgroundColor = "white";
var oldValue = matches[j].getAttribute("oldValue") var mval = matches[j].value;
|| matches[j].value; var oldValue = matches[j].getAttribute("oldValue");
if (value != matches[j].value && value != oldValue) { if (oldValue === null) oldValue = mval;
if (value != mval && parseFloat(value) != parseFloat(mval) && value != oldValue) {
if (matches[j] == document.activeElement if (matches[j] == document.activeElement
|| oldValue != matches[j].value) { || oldValue != mval) {
row.style.backgroundColor = "orange"; row.style.backgroundColor = "orange";
} else { } else {
matches[j].value = value; matches[j].value = value;

View File

@ -106,51 +106,20 @@ function doubleTap(callback){
return {stop: function(){ window.removeEventListener('touchend', handler) }} return {stop: function(){ window.removeEventListener('touchend', handler) }}
} }
function maxAr(array){ function maxAr(array, tmin, tmax){
return Math.max.apply(Math, array.map(function(o) { return Math.max.apply(Math, array.map(function(o) {
if (o.y == null) return -1e99; if (o.y == null || o.x < tmin || o.x > tmax) return -1e99;
return o.y; return o.y;
})); }));
} }
function minAr(array){ function minAr(array, tmin, tmax){
return Math.min.apply(Math, array.map(function(o) { return Math.min.apply(Math, array.map(function(o) {
if (o.y == null) return 1e99; if (o.y == null || o.x < tmin || o.x > tmax) return 1e99;
return o.y; return o.y;
})); }));
} }
function autoScale(chart) {
axis = chart.options.scales.yAxes[0]
datasets = chart.data.datasets;
let max = -1e99;
let min = 1e99;
for (testwidth = 1; testwidth >= 0; testwidth--) {
for(let i = 0; i < datasets.length; i++){
ds = datasets[i];
if (ds.borderWidth == testwidth) continue;
let lmax = maxAr(ds.data);
let lmin = minAr(ds.data);
if(lmax > max)
max = lmax;
if(lmin < min)
min = lmin;
}
if (min < max) {
break;
} else if (min == max) {
max = min + 0.5;
min = max - 1.0;
break;
}
}
//console.log('autoScale', min, max);
axis.ticks.min = min - (max - min) * 0.05;
axis.ticks.max = max + (max - min) * 0.01;
axis.min = axis.ticks.min;
axis.max = axis.ticks.max;
}
function strFormat(str, significant_digits) { function strFormat(str, significant_digits) {
if (str == null) return ''; if (str == null) return '';
evalue = str.toExponential(significant_digits-1).replace(/0*e/, 'e').replace(/\.e/, 'e').replace("e+", "e"); evalue = str.toExponential(significant_digits-1).replace(/0*e/, 'e').replace(/\.e/, 'e').replace("e+", "e");
@ -163,7 +132,7 @@ function strFormat(str, significant_digits) {
let graphs = (function (){ let graphs = (function (){
let dataset_to_graph_map = {}, let dataset_to_graph_map = {},
blocks, doUpdates=true, top_vars=[], bottom_vars=[], zoomed =false; blocks, liveMode=true, top_vars=[], bottom_vars=[], zoomed =false;
let type = 'linear'; let type = 'linear';
@ -175,6 +144,8 @@ let graphs = (function (){
let container = document.createElement('div'); let container = document.createElement('div');
container.classList.add("graphs-container"); container.classList.add("graphs-container");
let currentMinTime = 0;
let currentMaxTime = 0;
for (let i = 0; i < ngraphs; i++) { for (let i = 0; i < ngraphs; i++) {
let gr = document.createElement('div'); let gr = document.createElement('div');
@ -242,7 +213,7 @@ let graphs = (function (){
} }
//let varlist = top_vars.concat(bottom_vars); //let varlist = top_vars.concat(bottom_vars);
varlist = vars_array[gindex]; varlist = vars_array[gindex];
let el =graph_array[gindex]; let el = graph_array[gindex];
AJAX("http://" + hostPort + "/graph?time=" + minTime/1000 + "," + maxTime/1000 + "&variables=" + varlist + "&id=" + clientID).getJSON().then(function(data){ AJAX("http://" + hostPort + "/graph?time=" + minTime/1000 + "," + maxTime/1000 + "&variables=" + varlist + "&id=" + clientID).getJSON().then(function(data){
//console.log('Graph', block, data) //console.log('Graph', block, data)
@ -255,13 +226,10 @@ let graphs = (function (){
} }
let pdata = []; let pdata = [];
for(let e of data.graph[key]){ for(let e of data.graph[key]){
//if(e[1] == null || e[1] == null){
// continue;
//}
pdata.push({x: e[0]*1000, y: e[1]}); pdata.push({x: e[0]*1000, y: e[1]});
} }
if(pdata.length > 0){ if(pdata.length > 0){
addDataset(gindex, key, [dict[key].label, dict[key].color, pdata]) addDataset(gindex, key, [dict[key].label, dict[key].color, pdata, dict[key].continuous])
/*console.log(timeRange); /*console.log(timeRange);
if(data[data.length-1].x-data[0].x > d && data[data.length-1].x-data[0].x < (30*60+10)*1000){ // Adjust to requested time if(data[data.length-1].x-data[0].x > d && data[data.length-1].x-data[0].x < (30*60+10)*1000){ // Adjust to requested time
d = data[data.length-1].x-data[0].x d = data[data.length-1].x-data[0].x
@ -271,20 +239,91 @@ let graphs = (function (){
} }
} }
chart.setMinMax(minTime,maxTime); chart.setMinMax(minTime,maxTime);
// chart.autoScaleChart(); chart.autoScaleIf();
chart.update(); chart.update();
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // why this? result = AJAX( "http://" + hostPort +
"/updategraph?variables=" + variables() +
"&id=" + clientID).getJSON().then(function(data) {
liveMode = data.live;
console.log('LIVE create', liveMode)
})
//console.log('UPDATE LIVE', result);
}) })
} }
// add dataset to graph with graph_id // add dataset to graph with graph_id
function addDataset(gindex, key, dataset){ function addDataset(gindex, key, dataset){
let g = chart_array[gindex]; let g = chart_array[gindex];
dataset_to_graph_map[key] = [gindex, g.addDataset(dataset)]; dataset_to_graph_map[key] = [gindex, g.addDataset(key, dataset)];
}
function autoScale(chart) {
axis = chart.options.scales.yAxes[0];
tax = chart.options.scales.xAxes[0].ticks;
datasets = chart.data.datasets;
let max = -1e99;
let min = 1e99;
// if there are datasets with values and think lines,
// consider them only. if not, consider all (second pass in the following loop)
let extraMin = min;
let extraMax = max;
for (testwidth = 1; testwidth >= 0; testwidth--) {
for (let i = 0; i < datasets.length; i++){
ds = datasets[i];
if (ds.borderWidth <= testwidth) continue;
let lmax = maxAr(ds.data, tax.min, tax.max);
let lmin = minAr(ds.data, tax.min, tax.max);
if(lmax > max)
max = lmax;
if(lmin < min)
min = lmin;
if (ds.data.length && liveMode) {
lasty = ds.data.slice(-1)[0].y;
console.log('LASTY', lasty);
extraMin = Math.min(extraMin, lasty);
extraMax = Math.max(extraMax, lasty);
}
}
if (min > max) continue; // do a second pass over all curves
break;
}
if (min > max) return;
if (min == max) {
if (min == 0) {
ystep = 1;
} else {
ystep = Math.abs(min * 0.01);
}
min -= ystep;
max += ystep;
} else {
ystep = (max - min) * 0.1;
if (liveMode) {
extraMin = Math.min(min, extraMin - ystep);
extraMax = Math.max(max, extraMax + ystep);
} else {
extraMin = min - ystep * 0.5;
extraMax = max + ystep * 0.5;
}
if (min >= axis.ticks.min && axis.ticks.min >= extraMin &&
max <= axis.ticks.max && axis.ticks.max <= extraMax) {
console.log('NOCHANGE')
return; // do not yet change
}
console.log(min, axis.ticks.min, extraMin)
console.log(max, axis.ticks.max, extraMax)
min = extraMin;
max = extraMax;
}
//console.log('autoScale', min, max, tax.min, tax.max);
axis.min = axis.ticks.min = min;
axis.max = axis.ticks.max = max;
} }
function setMinMax(min, max){ function setMinMax(min, max){
currentMaxTime = max;
currentMinTime = min;
for (let ch of chart_array) { for (let ch of chart_array) {
if (ch) ch.setMinMax(min, max); if (ch) ch.setMinMax(min, max);
} }
@ -326,6 +365,16 @@ let graphs = (function (){
chart_array[i[0]].reloadData(i[1], data); chart_array[i[0]].reloadData(i[1], data);
} }
function variables() {
let vardict = {};
for (let vars of vars_array) {
for (let v of vars) {
vardict[v] = 1;
}
}
return Object.keys(vardict);
}
function reloadData(min, max){ function reloadData(min, max){
min = min/1000; min = min/1000;
@ -334,14 +383,8 @@ let graphs = (function (){
}else{ }else{
max = max/1000; max = max/1000;
} }
let vardict = {};
for (let vars of vars_array) {
for (let v of vars) {
vardict[v] = 1;
}
}
AJAX("http://" + hostPort + "/graph?time=" + min + ","+max+"&variables=" + Object.keys(vardict) + "&id=" + clientID).getJSON().then(function(data){ AJAX("http://" + hostPort + "/graph?time=" + min + ","+max+"&variables=" + variables() + "&id=" + clientID).getJSON().then(function(data){
for(let key in data.graph){ for(let key in data.graph){
let pdata = []; let pdata = [];
for(let e of data.graph[key]){ for(let e of data.graph[key]){
@ -354,10 +397,13 @@ let graphs = (function (){
reloadDataFlag(key, pdata); reloadDataFlag(key, pdata);
} }
} }
for (let ch of chart_array) { // AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // activate updates
if (ch) ch.autoScaleChart(); // should depend on a flag result = AJAX("http://" + hostPort +
} "/updategraph?variables=" + variables() +
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON(); // why this ? "&id=" + clientID).getJSON().then(function(data) {
liveMode = data.live;
console.log('LIVE reload', liveMode)
})
update(); update();
}); });
} }
@ -365,19 +411,21 @@ let graphs = (function (){
function checkReload(chart){ function checkReload(chart){
let xmin = chart.options.scales.xAxes[0].ticks.min, let xmin = chart.options.scales.xAxes[0].ticks.min,
xmax = chart.options.scales.xAxes[0].ticks.max; xmax = chart.options.scales.xAxes[0].ticks.max;
if(xmax < now()-10000){ // was 100000 = 100sec if (xmax < now()-100000) { // was 100000 = 100sec
doUpdates = false; if (liveMode) console.log('UPDATES OFF?')
//doUpdates = false;
}else{ }else{
doUpdates = true; if (!liveMode) console.log('UPDATES ON?')
//doUpdates = true;
} }
if(xmin < minTime || xmax > maxTime || xmax - xmin < 0.5 * (maxTime - minTime)){ if (xmin < minTime || xmax > maxTime || xmax - xmin < 0.5 * (maxTime - minTime)) {
//TODO: the criterium for getting finer resolution data should depend, if better res. is available //TODO: the criterium for getting finer resolution data should depend, if better res. is available
// this information has to come from the server // this information has to come from the server
reloadData(xmin, xmax); reloadData(xmin, xmax);
minTime = xmin; minTime = xmin;
maxTime = xmax; maxTime = xmax;
} else { } else {
autoScale(chart); // TODO: must depend on autoScale flag if (chart.autoScaleFlag) autoScale(chart);
chart.update(); chart.update();
} }
} }
@ -387,7 +435,9 @@ let graphs = (function (){
xmax = chart.options.scales.xAxes[0].ticks.max; xmax = chart.options.scales.xAxes[0].ticks.max;
setMinMax(xmin,xmax); setMinMax(xmin,xmax);
//console.log('zoompan', autoScaleFlag);
for (let ch of chart_array) { for (let ch of chart_array) {
ch.autoScaleIf();
if (ch) ch.redraw(redrawX); if (ch) ch.redraw(redrawX);
} }
update(); update();
@ -399,15 +449,27 @@ let graphs = (function (){
} }
} }
function updateAuto(){
let g_varlist = []; if (liveMode) {
function updateAllDisabled(){ max = now();
// not used anymore? if (currentMaxTime && max > currentMaxTime) {
AJAX("http://" + hostPort + "/graph?time="+timeRange+"&variables=" + g_varlist + "&id=" + clientID).getJSON().then(function(a){ max = currentMaxTime + Math.min(60000, 0.1 * (currentMaxTime - currentMinTime));
AJAX( "http://" + hostPort + "/updategraph?id=" + clientID).getJSON() setMinMax(currentMinTime, max);
}); reloadData(currentMinTime, max);
return;
}
}
for (let ch of chart_array) {
if (ch) {
ch.autoScaleIf();
ch.update();
}
}
} }
/*
let g_varlist = [];
function getVarlist(blocks){ function getVarlist(blocks){
var varlist = []; var varlist = [];
for (var i = 0; i < blocks.length; i++) { for (var i = 0; i < blocks.length; i++) {
@ -417,6 +479,7 @@ let graphs = (function (){
} }
return varlist; return varlist;
} }
*/
let startTime, recvTime, minTime, maxTime; let startTime, recvTime, minTime, maxTime;
@ -425,13 +488,14 @@ let graphs = (function (){
minTime = timeRange[0]*1000; minTime = timeRange[0]*1000;
AJAX("http://" + hostPort + "/gettime?time=-1800,0&id="+ clientID).getJSON().then(function(data){ AJAX("http://" + hostPort + "/gettime?time=-1800,0&id="+ clientID).getJSON().then(function(data){
startTime = data.time[1]*1000; startTime = data.time[1]*1000;
maxTime = startTime; maxTime = startTime + 60000;
console.log('MAXTIME', maxTime - Date.now());
minTime = data.time[0]*1000; minTime = data.time[0]*1000;
recvTime = performance.now(); recvTime = performance.now();
}); });
g_varlist = getVarlist(nblocks) // g_varlist = getVarlist(nblocks)
let f = 0; let f = 0;
insertSlide(f, "graphics", "graphics", container); insertSlide(f, "graphics", "graphics", container);
blocks = nblocks; blocks = nblocks;
@ -514,13 +578,15 @@ let graphs = (function (){
zoompan: zoompan, zoompan: zoompan,
receivedVars: receivedVars, receivedVars: receivedVars,
createSelection: createSelection, createSelection: createSelection,
doUpdates: function(){return doUpdates}, doUpdates: function(){return liveMode},
update: update, update: update,
updateAuto: updateAuto,
now: now, now: now,
zoomed: zoomed, zoomed: zoomed,
checkReload: checkReload, checkReload: checkReload,
getBlocks: getBlocks, getBlocks: getBlocks,
createGraph: createGraph, createGraph: createGraph,
autoScale: autoScale,
} }
})(); })();
@ -567,7 +633,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
y1 = ticks[0]; y1 = ticks[0];
y0 = ticks.slice(-1)[0]; y0 = ticks.slice(-1)[0];
span = y1 - y0; span = y1 - y0;
step = Math.abs(span * 0.1).toExponential(0); step = Math.abs(span * 0.3).toExponential(0);
if (step[0] > '5') { if (step[0] > '5') {
step = '5' + step.substr(1); step = '5' + step.substr(1);
} else if (step[0] > '2') { } else if (step[0] > '2') {
@ -651,6 +717,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
} }
} }
}); });
let autoScaleFlag = true;
//console.log('create legend') //console.log('create legend')
let legend = document.createElement('div'); let legend = document.createElement('div');
@ -724,9 +791,8 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
graphs.zoompan(chart); graphs.zoompan(chart);
});*/ });*/
addControl("Autoscale Y", function(){ let autoScaleRow = addControl("Autoscale Y <strong>on</strong> off", function(){
autoScale(chart); toggleAutoScale();
update();
}); });
addControl("Go to now", function(){ addControl("Go to now", function(){
@ -847,60 +913,91 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
chart.update(); chart.update();
} }
function addDataset(data){ function addDataset(key, data){
let dataset_index = chart.data.datasets.length; let dataset_index = chart.data.datasets.length;
chart.data.datasets.push({data: data[2], label: data[0], origLabel: data[0], chart.data.datasets.push({data: data[2], label: data[0], key: key,
spanGaps: false, lineJoin: 'round', borderWidth: 2, spanGaps: false, lineJoin: 'round', borderWidth: 2, steppedLine: data[3] == 0,
borderColor: data[1],fill: false, pointRadius: 0, tension:0, showLine: true}); borderColor: data[1],fill: false, pointRadius: 0, tension:0, showLine: true});
let dataset = chart.data.datasets[dataset_index]; let dataset = chart.data.datasets[dataset_index];
let legendel = document.createElement('div'); let legendel = document.createElement('div');
let legendelvalue = document.createElement('div'); let legendelvalue = document.createElement('div');
legendelvalue.classList.add('value'); legendelvalue.classList.add('value');
legendels[data[0]] = legendelvalue; legendels[key] = legendelvalue;
legendel.classList.add('legendel') legendel.classList.add('legendel')
let color = document.createElement('div'); let color = document.createElement('div');
color.classList.add('color') color.classList.add('color')
color.style.backgroundColor = dataset.borderColor; color.style.backgroundColor = dataset.borderColor;
legendel.appendChild(color); legendel.appendChild(color);
legendel.innerHTML += dataset.label; let dlabel = document.createElement('div');
legendel.addEventListener('click', function(){ dlabel.innerHTML = dataset.label;
dlabel.addEventListener('click', function(evt){
/*
console.log('LABEL', evt.target)
if(legendmoving) if(legendmoving)
return return
let meta = dataset._meta[Object.keys(dataset._meta)[0]] legendel.firstChild.style.height = '2px';
/* dataset.borderWidth = 2;
if(meta.hidden == null){ labelClicked = true;
meta.hidden = true; //console.log('LABEL', evt.target)
addClass(legendel, 'hidden');
}else{
meta.hidden = null;
delClass(legendel, 'hidden');
}
*/ */
if (dataset.borderWidth == 1) { });
dataset.borderWidth = 2; legendel.appendChild(dlabel);
} else {
dataset.borderWidth = 1;
}
autoScale(chart);
chart.update();
})
legendel.appendChild(legendelvalue); legendel.appendChild(legendelvalue);
legendel.addEventListener('click', function(evt){
if (legendmoving) return;
for (let k in legendels) {
// set all labels to normal font
legendels[k].parentNode.children[1].style.fontWeight = 400;
}
if (evt.target == dlabel) {
// disable all
for (let k in legendels) {
legendels[k].parentNode.firstChild.style.height = '1px';
}
for (ds of chart.data.datasets) {
ds.borderWidth = 1;
}
color.style.height = '2px';
dataset.borderWidth = 2;
dlabel.style.fontWeight = 700; // bold
} else {
if (dataset.borderWidth == 1) {
legendel.firstChild.style.height = '2px';
dataset.borderWidth = 2;
} else {
legendel.firstChild.style.height = '1px';
dataset.borderWidth = 1;
}
}
graphs.autoScale(chart);
chart.update();
});
legend.appendChild(legendel); legend.appendChild(legendel);
return dataset_index; return dataset_index;
} }
function autoScaleChart() { function autoScaleIf() {
autoScale(chart); if (autoScaleFlag) graphs.autoScale(chart);
} }
function pushData(dataset_index, data_point){ function pushData(dataset_index, data_point){
chart.data.datasets[dataset_index].data.push(data_point); data = chart.data.datasets[dataset_index].data;
if(!graphs.zoomed){ //if (chart.data.datasets[dataset_index].key == 'tt:target')
chart.options.scales.xAxes[0].ticks.max = data_point.x; // console.log('BEFORE', data.slice(-3))
}else{ if (data.slice(-1)[0] && data.slice(-1)[0].x >= data_point.x) {
update_max = data_point.x; removed = data.pop();
} }
data.push(data_point);
//if (chart.data.datasets[dataset_index].key == 'tt:target')
// console.log('PUSHED', data.slice(-3))
/*
if (graphs.zoomed) {
update_max = data_point.x;
} else {
chart.options.scales.xAxes[0].ticks.max = data_point.x;
}
*/
} }
function reloadData(index, data){ function reloadData(index, data){
@ -959,6 +1056,17 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
ax.ticks.min = min; ax.ticks.min = min;
} }
function toggleAutoScale () {
autoScaleFlag = !autoScaleFlag;
if (autoScaleFlag) {
graphs.autoScale(chart);
update();
autoScaleRow.innerHTML = "Autoscale <strong>on</strong> off";
} else {
autoScaleRow.innerHTML = "Autoscale on <strong>off</strong>";
}
}
function toggleAxesType(){ function toggleAxesType(){
setAxesType((chart.options.scales.yAxes[0].type=== 'linear') ? 'logarithmic' : 'linear'); setAxesType((chart.options.scales.yAxes[0].type=== 'linear') ? 'logarithmic' : 'linear');
} }
@ -972,6 +1080,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
} }
chart.options.scales.yAxes[0].type = type; chart.options.scales.yAxes[0].type = type;
chart.options.animation.duration = 800; chart.options.animation.duration = 800;
if (autoScaleFlag) graphs.autoScale(chart);
update(); update();
setTimeout(function(){chart.options.animation.duration = 0;},850) setTimeout(function(){chart.options.animation.duration = 0;},850)
} }
@ -996,7 +1105,7 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
let d2 = Math.abs(dp._model.x - x) let d2 = Math.abs(dp._model.x - x)
if(d == 0 || d2 < d){ if(d == 0 || d2 < d){
d = d2; d = d2;
legendels[chart.data.datasets[i].label].innerHTML = legendels[chart.data.datasets[i].key].innerHTML =
strFormat(chart.data.datasets[i].data[dp._index].y, 6); strFormat(chart.data.datasets[i].data[dp._index].y, 6);
test[i]=dp test[i]=dp
} }
@ -1045,7 +1154,8 @@ function Graph(gindex, container, x_label, y_label, tag, scaleType = "linear"){
redraw: redraw, redraw: redraw,
update: update, update: update,
reloadData: reloadData, reloadData: reloadData,
autoScaleChart: autoScaleChart, autoScaleIf: autoScaleIf,
chart: chart,
} }
} }
@ -1096,13 +1206,17 @@ function updateCharts2(graph){
return; return;
} }
for(let key in graph){ for(let key in graph){
for (pt of graph[key]) { if (graph[key][0] != null) {
if (graph[key][1] != null) { // there is at least ONE valid datapoint
// there is at least ONE valid datapoint for (pt of graph[key]) {
graphs.newDataHandler(key, {x: graph[key][0][0]*1000, y: graph[key][0][1]}); graphs.newDataHandler(key, {x: pt[0]*1000, y: pt[1]});
break;
} }
} }
} }
graphs.update(); graphs.updateAuto();
// graphs.update();
} }
function createCharts2(arg) {
console.log('C2', arg)
}

View File

@ -250,6 +250,10 @@ function createInput(s, name, title, info) {
input.setAttribute("name", name); input.setAttribute("name", name);
input.setAttribute("__ctype__", "input"); input.setAttribute("__ctype__", "input");
input.style.width = "100px"; input.style.width = "100px";
input.addEventListener("focus", function(evt) {
let elm = evt.target;
setTimeout(function(){elm.setSelectionRange(0, elm.value.length);},0);
});
input.onkeydown = function (e) { input.onkeydown = function (e) {
if (e.which === 27 || e.key == "Escape") { if (e.which === 27 || e.key == "Escape") {
@ -281,7 +285,8 @@ function createInput(s, name, title, info) {
input.setAttribute("actualValue", oldValue); input.setAttribute("actualValue", oldValue);
} }
var actualValue = input.getAttribute("actualValue"); var actualValue = input.getAttribute("actualValue");
if (value === actualValue || value === oldValue) { if (value == actualValue || value == oldValue ||
parseFloat(value) == parseFloat(actualValue) || parseFloat(value) == parseFloat(oldValue)) {
input.value = actualValue; input.value = actualValue;
// nothing to do. // nothing to do.
row.style.backgroundColor = "white"; row.style.backgroundColor = "white";

View File

@ -166,18 +166,25 @@ All other connections are to be closed (getJSON):
********************************************************************************************************************************* *********************************************************************************************************************************
/updategraph?id=<id> /updategraph?id=<id>[&variables=<variable list>]
if <variables list> is given, the given variables will be updated with the graph-update-message
response: <accept-graph-message> response: <accept-graph-message>
<accept-graph-message> = = { <accept-graph-message> = = {
"type": "accept-graph" "type": "accept-graph",
"live": true/false
} }
the "live" flag is true when the last /graph query was including the actual time
********************************************************************************************************************************* *********************************************************************************************************************************
/graph?time=<start>,<end>&variables=<variable list>&id=<id> /graph?time=<start>,<end>&variables=<variable list>&id=<id>
the given variables are added to the list of variables being updated with the graph-update-message
response: <graph-draw-message> response: <graph-draw-message>
<graph-draw-message> = = { <graph-draw-message> = = {

View File

@ -18,51 +18,67 @@ def get_abs_time(*times):
class ColorMap(object): class ColorMap(object):
''' """"
ColorMap is using official CSS color names, with the exception of Green, as this ColorMap is using official CSS color names, with the exception of Green, as this
is defined differently with X11 colors than in SEA, and used heavily in config files. is defined differently with X11 colors than in SEA, and used heavily in config files.
Here Green is an alias to Lime (#00FF00) and MidGreen is #008000, which is called Green in CSS. Here Green is an alias to Lime (#00FF00) and MidGreen is #008000, which is called Green in CSS.
The function to_code is case insensitive and accepts also names with underscores. The function to_code is case insensitive and accepts also names with underscores.
The order is choosen by M. Zolliker for the SEA client, originally only the first 16 were used. The order is choosen by M. Zolliker for the SEA client, originally only the first 16 were used.
''' """
hex_name = (("#FFFFFF","White"), ("#FF0000","Red"), ("#00FF00","Lime"), ("#0000FF","Blue"), ("#FF00FF","Magenta"), hex_name = (
("#FFFF00","Yellow"), ("#00FFFF","Cyan"), ("#000000","Black"), ("#FFA500","Orange"), ("#006400","DarkGreen"), ("#FFFFFF", "White"), ("#FF0000", "Red"), ("#00FF00", "Lime"), ("#0000FF", "Blue"), ("#FF00FF", "Magenta"),
("#9400D3","DarkViolet"), ("#A52A2A","Brown"), ("#87CEEB","SkyBlue"), ("#808080","Gray"), ("#FF69B4","HotPink"), ("#FFFF00", "Yellow"), ("#00FFFF", "Cyan"), ("#000000", "Black"), ("#FFA500", "Orange"),
("#FFFFE0","LightYellow"), ("#00FF7F","SpringGreen"), ("#000080","Navy"), ("#1E90FF","DodgerBlue"), ("#006400", "DarkGreen"), ("#9400D3", "DarkViolet"), ("#A52A2A", "Brown"), ("#87CEEB", "SkyBlue"),
("#9ACD32","YellowGreen"), ("#008B8B","DarkCyan"), ("#808000","Olive"), ("#DEB887","BurlyWood"), ("#808080", "Gray"), ("#FF69B4", "HotPink"), ("#FFFFE0", "LightYellow"), ("#00FF7F", "SpringGreen"),
("#7B68EE","MediumSlateBlue"), ("#483D8B","DarkSlateBlue"), ("#98FB98","PaleGreen"), ("#FF1493","DeepPink"), ("#000080", "Navy"), ("#1E90FF", "DodgerBlue"), ("#9ACD32", "YellowGreen"), ("#008B8B", "DarkCyan"),
("#FF6347","Tomato"), ("#32CD32","LimeGreen"), ("#DDA0DD","Plum"), ("#7FFF00","Chartreuse"), ("#800080","Purple"), ("#808000", "Olive"), ("#DEB887", "BurlyWood"),
("#00CED1","DarkTurquoise"), ("#8FBC8F","DarkSeaGreen"), ("#4682B4","SteelBlue"), ("#800000","Maroon"), ("#7B68EE", "MediumSlateBlue"), ("#483D8B", "DarkSlateBlue"), ("#98FB98", "PaleGreen"), ("#FF1493", "DeepPink"),
("#3CB371","MediumSeaGreen"), ("#FF4500","OrangeRed"), ("#BA55D3","MediumOrchid"), ("#2F4F4F","DarkSlateGray"), ("#FF6347", "Tomato"), ("#32CD32", "LimeGreen"), ("#DDA0DD", "Plum"), ("#7FFF00", "Chartreuse"),
("#CD853F","Peru"), ("#228B22","ForestGreen"), ("#48D1CC","MediumTurquoise"), ("#DC143C","Crimson"), ("#800080", "Purple"), ("#00CED1", "DarkTurquoise"), ("#8FBC8F", "DarkSeaGreen"), ("#4682B4", "SteelBlue"),
("#D3D3D3","LightGray"), ("#ADFF2F","GreenYellow"), ("#7FFFD4","Aquamarine"), ("#BC8F8F","RosyBrown"), ("#800000", "Maroon"),
("#20B2AA","LightSeaGreen"), ("#C71585","MediumVioletRed"), ("#F0E68C","Khaki"), ("#6495ED","CornflowerBlue"), ("#3CB371", "MediumSeaGreen"), ("#FF4500", "OrangeRed"), ("#BA55D3", "MediumOrchid"),
("#556B2F","DarkOliveGreen"), ("#CD5C5C","IndianRed "), ("#2E8B57","SeaGreen"), ("#F08080","LightCoral"), ("#2F4F4F", "DarkSlateGray"), ("#CD853F", "Peru"), ("#228B22", "ForestGreen"), ("#48D1CC", "MediumTurquoise"),
("#8A2BE2","BlueViolet"), ("#AFEEEE","PaleTurquoise"), ("#4169E1","RoyalBlue"), ("#0000CD","MediumBlue"), ("#DC143C", "Crimson"),
("#B8860B","DarkGoldenRod"), ("#00BFFF","DeepSkyBlue"), ("#FFC0CB","Pink"), ("#4B0082","Indigo "), ("#A0522D","Sienna"), ("#D3D3D3", "LightGray"), ("#ADFF2F", "GreenYellow"), ("#7FFFD4", "Aquamarine"), ("#BC8F8F", "RosyBrown"),
("#FFD700","Gold"), ("#F4A460","SandyBrown"), ("#DAA520","GoldenRod"), ("#DA70D6","Orchid"), ("#E6E6FA","Lavender"), ("#20B2AA", "LightSeaGreen"), ("#C71585", "MediumVioletRed"), ("#F0E68C", "Khaki"),
("#5F9EA0","CadetBlue"), ("#D2691E","Chocolate"), ("#66CDAA","MediumAquaMarine"), ("#6B8E23","OliveDrab"), ("#6495ED", "CornflowerBlue"),
("#A9A9A9","DarkGray"), ("#BDB76B","DarkKhaki"), ("#696969","DimGray"), ("#B0C4DE","LightSteelBlue"), ("#556B2F", "DarkOliveGreen"), ("#CD5C5C", "IndianRed "), ("#2E8B57", "SeaGreen"), ("#F08080", "LightCoral"),
("#191970","MidnightBlue"), ("#FFE4C4","Bisque"), ("#6A5ACD","SlateBlue"), ("#EE82EE","Violet"), ("#8A2BE2", "BlueViolet"), ("#AFEEEE", "PaleTurquoise"), ("#4169E1", "RoyalBlue"), ("#0000CD", "MediumBlue"),
("#8B4513","SaddleBrown"), ("#FF7F50","Coral"), ("#008000","MidGreen"), ("#DB7093","PaleVioletRed"), ("#C0C0C0","Silver"), ("#B8860B", "DarkGoldenRod"), ("#00BFFF", "DeepSkyBlue"), ("#FFC0CB", "Pink"), ("#4B0082", "Indigo "),
("#E0FFFF","LightCyan"), ("#9370DB","MediumPurple"), ("#FF8C00","DarkOrange"), ("#00FA9A","MediumSpringGreen"), ("#A0522D", "Sienna"),
("#E9967A","DarkSalmon"), ("#778899","LightSlateGray"), ("#9932CC","DarkOrchid"), ("#EEE8AA","PaleGoldenRod"), ("#FFD700", "Gold"), ("#F4A460", "SandyBrown"), ("#DAA520", "GoldenRod"), ("#DA70D6", "Orchid"),
("#F8F8FF","GhostWhite"), ("#FFA07A","LightSalmon"), ("#ADD8E6","LightBlue"), ("#D8BFD8","Thistle"), ("#E6E6FA", "Lavender"),
("#FFE4E1","MistyRose"), ("#FFDEAD","NavajoWhite"), ("#40E0D0","Turquoise"), ("#90EE90","LightGreen"), ("#5F9EA0", "CadetBlue"), ("#D2691E", "Chocolate"), ("#66CDAA", "MediumAquaMarine"), ("#6B8E23", "OliveDrab"),
("#B22222","FireBrick"), ("#008080","Teal"), ("#F0FFF0","HoneyDew"), ("#FFFACD","LemonChiffon"), ("#FFF5EE","SeaShell"), ("#A9A9A9", "DarkGray"), ("#BDB76B", "DarkKhaki"), ("#696969", "DimGray"), ("#B0C4DE", "LightSteelBlue"),
("#F5F5DC","Beige"), ("#DCDCDC","Gainsboro"), ("#FA8072","Salmon"), ("#8B008B","DarkMagenta"), ("#FFB6C1","LightPink"), ("#191970", "MidnightBlue"), ("#FFE4C4", "Bisque"), ("#6A5ACD", "SlateBlue"), ("#EE82EE", "Violet"),
("#708090","SlateGray"), ("#87CEFA","LightSkyBlue"), ("#FFEFD5","PapayaWhip"), ("#D2B48C","Tan"), ("#FFFFF0","Ivory"), ("#8B4513", "SaddleBrown"), ("#FF7F50", "Coral"), ("#008000", "MidGreen"), ("#DB7093", "PaleVioletRed"),
("#F0FFFF","Azure"), ("#F5DEB3","Wheat"), ("#00008B","DarkBlue"), ("#FFDAB9","PeachPuff"), ("#8B0000","DarkRed"), ("#C0C0C0", "Silver"),
("#FAF0E6","Linen"), ("#B0E0E6","PowderBlue"), ("#FFE4B5","Moccasin"), ("#F5F5F5","WhiteSmoke"), ("#FFF8DC","Cornsilk"), ("#E0FFFF", "LightCyan"), ("#9370DB", "MediumPurple"), ("#FF8C00", "DarkOrange"),
("#FFFAFA","Snow"), ("#FFF0F5","LavenderBlush"), ("#FFEBCD","BlanchedAlmond"), ("#F0F8FF","AliceBlue"), ("#00FA9A", "MediumSpringGreen"),
("#FAEBD7","AntiqueWhite"), ("#FDF5E6","OldLace"), ("#FAFAD2","LightGoldenRodYellow"), ("#F5FFFA","MintCream"), ("#E9967A", "DarkSalmon"), ("#778899", "LightSlateGray"), ("#9932CC", "DarkOrchid"),
("#FFFAF0","FloralWhite"), ("#7CFC00","LawnGreen"), ("#663399","RebeccaPurple")) ("#EEE8AA", "PaleGoldenRod"),
("#F8F8FF", "GhostWhite"), ("#FFA07A", "LightSalmon"), ("#ADD8E6", "LightBlue"), ("#D8BFD8", "Thistle"),
("#FFE4E1", "MistyRose"), ("#FFDEAD", "NavajoWhite"), ("#40E0D0", "Turquoise"), ("#90EE90", "LightGreen"),
("#B22222", "FireBrick"), ("#008080", "Teal"), ("#F0FFF0", "HoneyDew"), ("#FFFACD", "LemonChiffon"),
("#FFF5EE", "SeaShell"),
("#F5F5DC", "Beige"), ("#DCDCDC", "Gainsboro"), ("#FA8072", "Salmon"), ("#8B008B", "DarkMagenta"),
("#FFB6C1", "LightPink"),
("#708090", "SlateGray"), ("#87CEFA", "LightSkyBlue"), ("#FFEFD5", "PapayaWhip"), ("#D2B48C", "Tan"),
("#FFFFF0", "Ivory"),
("#F0FFFF", "Azure"), ("#F5DEB3", "Wheat"), ("#00008B", "DarkBlue"), ("#FFDAB9", "PeachPuff"),
("#8B0000", "DarkRed"),
("#FAF0E6", "Linen"), ("#B0E0E6", "PowderBlue"), ("#FFE4B5", "Moccasin"), ("#F5F5F5", "WhiteSmoke"),
("#FFF8DC", "Cornsilk"),
("#FFFAFA", "Snow"), ("#FFF0F5", "LavenderBlush"), ("#FFEBCD", "BlanchedAlmond"), ("#F0F8FF", "AliceBlue"),
("#FAEBD7", "AntiqueWhite"), ("#FDF5E6", "OldLace"), ("#FAFAD2", "LightGoldenRodYellow"),
("#F5FFFA", "MintCream"),
("#FFFAF0", "FloralWhite"), ("#7CFC00", "LawnGreen"), ("#663399", "RebeccaPurple"))
codes = {} codes = {}
for i, pair in enumerate(hex_name): for i, pair in enumerate(hex_name):
codes[pair[0]] = i codes[pair[0]] = i
low = pair[1].lower() low = pair[1].lower()
codes[low] = i codes[low] = i
codes[low.replace("gray","grey")] = i codes[low.replace("gray", "grey")] = i
codes["green"] = 2 codes["green"] = 2
codes["fuchsia"] = 4 codes["fuchsia"] = 4
codes["aqua"] = 6 codes["aqua"] = 6
@ -72,7 +88,7 @@ class ColorMap(object):
try: try:
return int(colortext) return int(colortext)
except ValueError: except ValueError:
return ColorMap.codes.get(colortext.lower().replace("_",""),-1) return ColorMap.codes.get(colortext.lower().replace("_", ""),-1)
@staticmethod @staticmethod
def check_hex(code): def check_hex(code):
@ -96,7 +112,6 @@ class ColorMap(object):
return -1 return -1
def get_vars(main, time): def get_vars(main, time):
result = {} result = {}
@ -112,10 +127,13 @@ def get_vars(main, time):
vars.append(vars[0]) vars.append(vars[0])
if len(vars) == 3: if len(vars) == 3:
vars.append("") vars.append("")
name, unit, label, color = vars if len(vars) == 4:
vars.append("") # exact flag
name, unit, label, color, continuous = vars
continuous = int(continuous) if continuous else 0
if not unit in result: if not unit in result:
result[unit] = dict(tag = unit, unit = unit.split("_")[0], curves=Dict()) result[unit] = dict(tag=unit, unit=unit.split("_")[0], curves=Dict())
result[unit]["curves"][name] = dict(name=name, label=label, color=color) result[unit]["curves"][name] = dict(name=name, label=label, color=color, continuous=continuous)
for unit, curvegroup in result.items(): for unit, curvegroup in result.items():
color_set = set() color_set = set()
@ -137,14 +155,19 @@ def get_vars(main, time):
color_set.add(c) color_set.add(c)
curve["original_color"] = col curve["original_color"] = col
curve["color"] = ColorMap.to_hex(c) curve["color"] = ColorMap.to_hex(c)
c = 1 # omit white c = 1 # omit white
for curve in auto_curves: for curve in auto_curves:
while c in color_set: c += 1 # find unused color while c in color_set:
c += 1 # find unused color
curve["color"] = ColorMap.to_hex(c) curve["color"] = ColorMap.to_hex(c)
c += 1 c += 1
return result return result
def get_curves(main, keys, timerange, show_empty=True): def get_curves(main, keys, timerange, cut_begin=True):
curves = main.get_curves(keys, get_abs_time(*timerange), maxpoints=500) curves = main.get_curves(keys, get_abs_time(*timerange), maxpoints=500, cut_begin=cut_begin)
#if 'tt:target' in curves:
# print('---')
# print(curves['tt:target'].fmtm())
# print('TT', curves['tt:target'].for_json()[-5:])
return {k: c.for_json() for k, c in curves.items()} return {k: c.for_json() for k, c in curves.items()}

View File

@ -64,7 +64,7 @@ def get_update(path=None):
@flask.stream_with_context @flask.stream_with_context
def generator(): def generator():
logging.info('UPDATE %s %s', client.id, socket.getfqdn(flask.request.remote_addr.split(':')[-1])) 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, device=instrument.device); msg = dict(type='id', id=client.id, instrument=instrument.title, device=instrument.device);
yield to_json_sse(msg) yield to_json_sse(msg)
try: try:
lastmsg = time.time() lastmsg = time.time()
@ -130,6 +130,7 @@ def reply():
try: try:
id = kwargs.pop('id') id = kwargs.pop('id')
client = instrument.clients[id] client = instrument.clients[id]
print('PATH', path)
msg = getattr(client, "w_" + path[1:])(**kwargs) msg = getattr(client, "w_" + path[1:])(**kwargs)
except Exception as e: except Exception as e:
logging.error('%s', traceback.format_exc()) logging.error('%s', traceback.format_exc())
@ -257,6 +258,7 @@ class Instrument:
self.clients[client.id] = client self.clients[client.id] = client
return client return client
class SeaInstrument(Instrument): class SeaInstrument(Instrument):
# convert SEA layout tag like "-W" to more meaningful name. # convert SEA layout tag like "-W" to more meaningful name.
# the code: 0: modifier, 1: enum name, 2: input element # the code: 0: modifier, 1: enum name, 2: input element
@ -502,17 +504,18 @@ class SeaGraph:
LIVE = 2 LIVE = 2
def __init__(self): def __init__(self):
self.livemode = self.HISTORICAL self.livemode = self.ACTUAL
self.time = [0, 0] self.time = [0, 0]
self.lastvalues = {} self.lastvalues = {}
self.variables = []
def graphpoll(self): def graphpoll(self):
if self.livemode == self.LIVE: if self.livemode == self.LIVE:
self.time[1], = get_abs_time(0) self.time[1], = get_abs_time(0)
else: else:
self.time[1] = self.time[0] # do not update self.time[1] = self.time[0] # do not update
if self.time[1] > self.time[0]: if self.time[1] > self.time[0]:
result = get_curves(main_cache, self.variables, self.time, show_empty=False) result = get_curves(main_cache, self.variables, self.time, cut_begin=False)
self.strip_future(result) self.strip_future(result)
if int(self.time[1] / 60) != int(self.time[0] / 60): if int(self.time[1] / 60) != int(self.time[0] / 60):
# update unchanged values # update unchanged values
@ -533,14 +536,8 @@ class SeaGraph:
self.lastvalues[var] = (endtime, lastx) self.lastvalues[var] = (endtime, lastx)
def strip_future(self, result): def strip_future(self, result):
"""strip future points (happens only on dummy test_day)""" """strip future points (implemented on dummy test_day)"""
# if self.livemode == self.LIVE: pass # do nothing here
for c in result.values():
while len(c):
lastt, lastx = c[-1]
if lastt <= self.time[1]:
break
c.pop()
def w_gettime(self, time): def w_gettime(self, time):
result = get_abs_time(*[float(t) for t in time.split(',')]) result = get_abs_time(*[float(t) for t in time.split(',')])
@ -552,7 +549,8 @@ class SeaGraph:
self.last_t = 0 self.last_t = 0
start, end, now = get_abs_time(*time, 0) start, end, now = get_abs_time(*time, 0)
self.time = [start, end] self.time = [start, end]
self.variables = variables.split(',') oldvars = set(self.variables)
self.variables.extend((v for v in variables.split(',') if v not in oldvars))
self.livemode = self.ACTUAL if end >= now else self.HISTORICAL self.livemode = self.ACTUAL if end >= now else self.HISTORICAL
logging.info('LIVE %g %g %d %d', end, now, end >= now, self.livemode) logging.info('LIVE %g %g %d %d', end, now, end >= now, self.livemode)
# self.scanner = seagraph.NumericScanner(instrument.logger_dir, instrument.test_day) # self.scanner = seagraph.NumericScanner(instrument.logger_dir, instrument.test_day)
@ -561,7 +559,7 @@ class SeaGraph:
self.strip_future(result) self.strip_future(result)
logging.info('VARIABLES: %r %r %r', self.variables, start-now, end-now) logging.info('VARIABLES: %r %r %r', self.variables, start-now, end-now)
for var, curve in list(result.items()): for var, curve in list(result.items()):
logging.info(' %s %r len=%d', var, curve[-1][0] - curve[0][0], len(curve)) logging.info(' %s %r len=%d', var, curve[-1][0] - curve[0][0] if len(curve) else None, len(curve))
self.complete_to_end(result, end) self.complete_to_end(result, end)
self.time[0] = self.time[1] self.time[0] = self.time[1]
# reduction not yet implemented # reduction not yet implemented
@ -575,8 +573,10 @@ class SeaGraph:
logging.info('GotVARS %r', result) logging.info('GotVARS %r', result)
return result return result
def w_updategraph(self): def w_updategraph(self, variables=''):
logging.info("UPD GRAPH %d", self.livemode) if variables:
self.variables = variables.split(',')
logging.info("UPD GRAPH %d %r", self.livemode, self.variables)
if self.livemode == self.HISTORICAL: if self.livemode == self.HISTORICAL:
return dict(type='accept-graph', live=False) return dict(type='accept-graph', live=False)
else: else:
@ -658,7 +658,7 @@ class SeaClient(SeaGraph):
class DummyClient(SeaGraph): class DummyClient(SeaGraph):
async = set(('id','update','redraw','command','reply','graph-update','graph-redraw')) asynch = set(('id','update','redraw','command','reply','graph-update','graph-redraw'))
def __init__(self, host_port): def __init__(self, host_port):
self.linesocket = tcp_lineserver.LineClient(host_port) self.linesocket = tcp_lineserver.LineClient(host_port)
@ -678,7 +678,7 @@ class DummyClient(SeaGraph):
line = self.linesocket.get_line() line = self.linesocket.get_line()
if line != None: if line != None:
msg = json.loads(line) msg = json.loads(line)
if msg.type in self.async: if msg.type in self.asynch:
t = 0 t = 0
# print 'PUSH',msg, replytype # print 'PUSH',msg, replytype
self.queue.append(msg) self.queue.append(msg)
@ -693,6 +693,12 @@ class DummyClient(SeaGraph):
logging.error('REPLY MISMATCH %s %s <> %s', command, replytype, msg.type) logging.error('REPLY MISMATCH %s %s <> %s', command, replytype, msg.type)
return msg return msg
def strip_future(self, result):
for c in result.values():
while len(c):
if c[-1][0] <= self.time[1]:
break
c.pop()
def w_getblock(self, path): def w_getblock(self, path):
return self.cmd_reply(dict(type='getblock', path=path, id=self.id), 'draw') return self.cmd_reply(dict(type='getblock', path=path, id=self.id), 'draw')
@ -718,7 +724,7 @@ class DummyClient(SeaGraph):
messages = [] messages = []
if line: if line:
msg = json.loads(line) msg = json.loads(line)
if msg.type in self.async: if msg.type in self.asynch:
messages.append(msg) messages.append(msg)
else: else:
self.syncreply.append(msg) self.syncreply.append(msg)
@ -761,7 +767,7 @@ class SecopMsg:
self.par = sl[1] self.par = sl[1]
if len(sl) > 2: if len(sl) > 2:
self.value = json.loads(' '.join(sl[2:])) self.value = json.loads(' '.join(sl[2:]))
self.async = self.type in ('update', 'error_update') self.asynch = self.type in ('update', 'error_update')
def __repr__(self): def __repr__(self):
value = repr(self.value) value = repr(self.value)
@ -828,15 +834,15 @@ class SecopClient(SeaGraph):
msg = self.syncreply.pop(0) msg = self.syncreply.pop(0)
break break
line = self.linesocket.get_line() line = self.linesocket.get_line()
if line != None: if line is not None:
msg = SecopMsg(line) msg = SecopMsg(line)
if msg.async: if msg.asynch:
self.consolequeue.append(dict(type='reply',line=line,origin='async')) self.consolequeue.append(dict(type='reply',line=line,origin='async'))
else: else:
self.consolequeue.append(dict(type='reply',line=line,origin='other')) self.consolequeue.append(dict(type='reply',line=line,origin='other'))
if self.out: self.out.write("<"+line+"\n") if self.out: self.out.write("<"+line+"\n")
#print '<', msg.type, msg.par #print '<', msg.type, msg.par
if msg.async and replytype != msg.type + "=" + msg.par: if msg.asynch and replytype != msg.type + "=" + msg.par:
t = 0 t = 0
self.queue.append(msg) self.queue.append(msg)
else: else:
@ -895,31 +901,41 @@ class SecopClient(SeaGraph):
if not command: if not command:
return dict(type='accept-command') return dict(type='accept-command')
cmd = "change " + command cmd = "change " + command
return self.cmd_reply(cmd, 'changed ' + command.split(' ')[0]) self.cmd_reply(cmd, 'changed ' + command.split(' ')[0])
return dict(type='accept-command')
def poll(self): def poll(self):
messages = []
if self.consolequeue: if self.consolequeue:
messages = self.consolequeue messages.extend(self.consolequeue)
self.consolequeue = [] self.consolequeue = []
return messages
if self.queue: if self.queue:
messages = convert_event(self.queue) messages.extend(convert_event(self.queue))
self.queue = [] self.queue = []
return messages while True:
line = self.linesocket.get_line() line = self.linesocket.get_line()
# logging.info('poll %s', line) if not line:
if line: break
if self.out: self.out.write("<"+line+"\n") # logging.info('poll %s', line)
if self.out:
self.out.write("<"+line+"\n")
msg = SecopMsg(line) msg = SecopMsg(line)
if msg.async: # do not flood console with updates if msg.asynch: # do not flood console with updates
self.consolequeue.append(dict(type='reply',line=line,origin='async')) if msg.par == 'tt:target':
print(msg)
self.consolequeue.append(dict(type='reply', line=line, origin='async'))
else: else:
self.consolequeue.append(dict(type='reply',line=line,origin='other')) self.consolequeue.append(dict(type='reply', line=line, origin='other'))
# logging.info('GOT MSG %r %r', msg.async, convert_event(SecopMsg(line))) # logging.info('GOT MSG %r %r', msg.asynch, convert_event(SecopMsg(line)))
if msg.async: if msg.asynch:
return convert_event(SecopMsg(line)) messages.extend(convert_event(SecopMsg(line)))
self.syncreply.append(msg) else:
return [] self.syncreply.append(msg)
# graph messages
msg = self.graphpoll()
if msg:
messages.append(msg)
return messages
def info(self): def info(self):
return ["na"] return ["na"]
@ -939,6 +955,7 @@ class SecopInstrument(Instrument):
def newClient(self): def newClient(self):
cl = SecopClient(self.host_port) cl = SecopClient(self.host_port)
self.device = cl.description['equipment_id'] self.device = cl.description['equipment_id']
print('EQU', self.device)
logging.info('init done %s %s', self.host_port, self.device) logging.info('init done %s %s', self.host_port, self.device)
return self.register(cl) return self.register(cl)
@ -989,8 +1006,8 @@ if __name__ == '__main__':
instrument_config = instrument_list[inst_name] instrument_config = instrument_list[inst_name]
frd = FrappyReader('/home/l_samenv/sea/%s' % inst_name, gevent=gevent) frd = FrappyReader('/Users/zolliker/frappyhist/%s' % inst_name, gevent=gevent)
main_cache = MainCache('/home/l_samenv/histreader/%s_hist' % inst_name, frd, gevent=gevent) main_cache = MainCache('/Users/zolliker/frappyhist/%s_hist' % inst_name, frd, gevent=gevent)
# logging.basicConfig(filename=inst_name+".log", filemode='w', level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s') # logging.basicConfig(filename=inst_name+".log", filemode='w', level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')

View File

@ -5,6 +5,7 @@ import re
import circularlog import circularlog
import logging import logging
class LineHandler(asyncore.dispatcher_with_send): class LineHandler(asyncore.dispatcher_with_send):
def __init__(self, sock): def __init__(self, sock):
@ -38,6 +39,7 @@ class LineHandler(asyncore.dispatcher_with_send):
''' '''
self.send_line("> " + line) self.send_line("> " + line)
class LineServer(asyncore.dispatcher): class LineServer(asyncore.dispatcher):
def __init__(self, host, port, lineHandlerClass): def __init__(self, host, port, lineHandlerClass):
@ -58,9 +60,11 @@ class LineServer(asyncore.dispatcher):
def loop(self): def loop(self):
asyncore.loop() asyncore.loop()
class Disconnected(Exception): class Disconnected(Exception):
pass pass
class LineClient(object): class LineClient(object):
def __init__(self, host_port, announcement=None, filter_ascii=False, ridername="r"): def __init__(self, host_port, announcement=None, filter_ascii=False, ridername="r"):
@ -122,7 +126,8 @@ class LineClient(object):
def close(self): def close(self):
self.socket.close() self.socket.close()
self.connected = False self.connected = False
if __name__ == "__main__": if __name__ == "__main__":
server = LineServer("localhost", 9999, LineHandler) server = LineServer("localhost", 9999, LineHandler)
server.loop() server.loop()