75 Commits

Author SHA1 Message Date
a6ec455563 select_experiment: move links to instruments to top 2025-05-23 13:50:21 +02:00
be404b625b main js: fix clientTags 2025-05-23 13:05:17 +02:00
191f0aed80 logfile name depending on port 2025-05-23 13:04:37 +02:00
b24384f387 improve further select_experiments: add time range in link 2025-05-21 15:37:19 +02:00
e136b66732 no extra headline for central server 2025-05-21 13:14:26 +02:00
822e3ab6a2 big fix: treat history_only=None properly 2025-05-21 13:08:06 +02:00
b1ffe99a5d remove grey background on select_experiments 2025-05-21 12:11:16 +02:00
7d4607e947 work on select_experiment
- on currently running exp. make two links, to instrument
  or history only
- create dummy secop client when hideRightPart is used in order
  to avoid waiting impossible connection
2025-05-21 11:35:25 +02:00
55dd7a3777 fix bug not changing host 2025-05-20 16:59:25 +02:00
fd37ee0dfc cosmetics on home 2025-05-20 16:55:10 +02:00
90e8aa5df0 select_experiment: use links to instruments 2025-05-20 16:51:01 +02:00
6df42b9541 continue with graphics when secop connection fails 2025-05-20 16:51:01 +02:00
2984c051e9 use single instrument name instead of 'n_a' 2025-05-20 16:04:38 +02:00
46fca20f09 add links to servers on intruments 2025-05-20 15:10:19 +02:00
2ed1e3c292 instrument=main: for multiple instruments (on linse-c) 2025-05-20 15:10:19 +02:00
6390d37ab4 add usual locations of sehistory and frappy to sys.path 2025-05-20 10:30:00 +02:00
925bdfc472 improve command handling 2025-05-13 11:11:19 +02:00
3b438d68b2 fix bug in select_experiment page 2025-05-13 11:11:19 +02:00
a94cc98c42 remove obsolete stuff + small adjustments 2025-05-13 11:11:19 +02:00
2cd78ae1e9 rename files with spaces in doc 2025-05-13 11:11:19 +02:00
a4fda418b2 fix chart config parameters
- add SEA dil pressures
- read config each time when it is used
2025-05-13 11:11:19 +02:00
179db4c0a3 remove some console.log for debug 2025-05-13 11:10:35 +02:00
5c70017238 fix simple command (e.g. stop) 2025-05-13 11:10:27 +02:00
268ebc7e93 lazyPermission: allow to configure starting with writePermission=true 2025-05-13 11:10:14 +02:00
f66b071813 Merge commit '62da014d4041e' 2025-05-13 11:09:38 +02:00
d6a69ba05e Prepare radio-button-group 2025-05-13 11:09:04 +02:00
f883c913ed Merge branch 'master' of gitlab.psi.ch:samenv/seweb 2025-05-02 11:04:07 +02:00
a229626bdf change value of input element only when opening the edit
updates do not need to update them
(not yet done for enum and checkbox)
2025-05-02 11:02:22 +02:00
0a75a0aa37 Merge branch 'daniel' - 2025-05-02 2025-05-02 11:01:47 +02:00
d2ce97b2ab Fixed some layout issues fpr modules and parameters 2025-05-02 11:01:31 +02:00
06bdbbb02e change value of input element only when opening the edit
updates do not need to update them
(not yet done for enum and checkbox)
2025-05-02 10:56:53 +02:00
d6479a7ece pushbutton changed to link in left column 2025-05-02 10:55:53 +02:00
a8e14eb797 okay-button for input 2025-05-02 10:52:32 +02:00
b704440f36 make write permission check case insensitive 2025-05-02 10:45:48 +02:00
10387261c0 back to (modified) old icon theme 2025-05-02 10:45:15 +02:00
9f2bfd668a Changed some icons 2025-05-02 10:45:09 +02:00
70b40646ef modules-Block: prepared different input options, grid-element: panel-background added -> icon always visible 2025-05-02 10:44:46 +02:00
43624b4222 send instrument='n_a' if not available
instead of null

+ remove another debugging print statement
2025-05-02 10:43:34 +02:00
e51942c97f make sure instrument and device are availabel separately
- added comment to the alert to be modified
  ("You changed a field without pressing the return key.")
2025-05-02 10:43:34 +02:00
ae7ed7bdd8 get a faster response from a change
in the previous implementation, the row-waiting-for-answer
class was removed only on the next poll. this should happen
more quickly.

+ remove some print statements
2025-05-02 10:43:34 +02:00
202095d539 change row-waiting-for-answer color to a light yellow
orangered is too aggressive
2025-05-02 10:42:40 +02:00
cf0a979cc9 add nv.speed to generic.ini 2025-05-02 10:42:40 +02:00
8d38dc31f2 Changed some icons, modules block: different input elements (not tested), write permission promt 2025-05-02 10:42:40 +02:00
9bacb41be8 Global write permission | lock button
+ lock icon added: click -> toggle global write permission
2025-05-02 10:42:40 +02:00
8119f221bd input element display:block instead of float -> displayed in the same row 2025-05-02 10:42:40 +02:00
b9a1e7db99 Changed updateValue... 2025-05-02 10:42:40 +02:00
2fda3164e6 use type=rdonly for modules without target, but with a value 2025-05-02 10:42:40 +02:00
0a6ff13ee6 treat different types for module block 2025-05-02 10:42:40 +02:00
9780ab7097 Changed some icons... 2025-05-02 10:42:08 +02:00
9b7261261f fix do command 2025-05-02 10:42:08 +02:00
f6aff481e2 Fixed some display problems for module and parameter block 2025-05-02 10:42:08 +02:00
e6e69c8f5c Edit button for module block 2025-05-02 10:42:08 +02:00
df582a2f23 console not shown at start, infobox for touch device 2025-05-02 10:41:55 +02:00
8f7406c31b fixes for select_instrument 2025-05-02 10:41:55 +02:00
09bf402bbb implement SECoP commands on the server side 2025-05-02 10:41:55 +02:00
6e20ed0f8f Some bugfixes for input elements 2025-05-02 10:39:18 +02:00
960e95c447 Diverse Anpassungen besonders bei SEAWebClientGroup 2025-05-02 10:39:18 +02:00
27f60e1187 report status and target in update_main
+ add SECoP commands [WIP]
+ fix case 4 (error icon) in updateStatus (SEAWebClientCommunication.js)
2025-05-02 10:39:18 +02:00
5c1c94bffc Änderungen für den Modul- und denParameterblock 2025-05-02 10:39:18 +02:00
5d10b6d48d console, modules 2025-05-02 10:39:18 +02:00
d1ea9225dc status-icon with statuscode, use entire row as link to parameters 2025-05-02 10:39:18 +02:00
639949f24b change status update slightly
- formatted is like "BUSY, moving"
- value as with other tuples
- statuscode 0..4
2025-04-15 17:52:22 +02:00
555aca9ed0 add statuscode to update for status
- value in a status update now contains the text only
2025-04-15 17:37:29 +02:00
38b2dbcf93 added component info (from SECoP description)
+ add target update for modules block
2025-04-15 17:37:29 +02:00
33c9896bb1 Another icon 2025-04-15 17:37:29 +02:00
da17309e78 some more icons 2025-04-15 17:37:29 +02:00
9b3f89ddaa Some missing icons 2025-04-15 17:37:29 +02:00
3d37b10d61 Some new icons with logic (not completed yet) 2025-04-15 17:37:29 +02:00
8d668f7de6 Some esponsivity bugfixes 2025-04-15 17:37:29 +02:00
85fdaa445f server: remove unnecessary nesting in SecopInteractor.get_components 2025-04-15 17:37:29 +02:00
e132b43263 fix missing initialization of node_map in SecopInteractor 2025-04-15 17:37:28 +02:00
56f85d9a39 small fixes
- variable homeButton was removed in SEAWebClientMain.js
- add webserver.log to .gitignore
2025-04-15 17:37:28 +02:00
bc9c1361e5 followup change: fix dummy webserver
the dummy server was no longer working after server rework
2025-04-15 17:37:28 +02:00
11a475149a Restored some HTML-Debugging-tools 2025-04-15 17:37:28 +02:00
9f5ae58b9b rework of the server side
main change: the same server may be used for several instruments

- client classes are 'Interactors' dealing with the parameters etc.
- methods from history are added to the clients
+ improvements on the js client side
2025-03-19 08:37:58 +01:00
4 changed files with 105 additions and 49 deletions

View File

@ -78,14 +78,15 @@ new Settings()
.treat("lazyPermission", "wr", to_bool, true);
let args = '';
if (window.instrument) {
window.clientTags = "&instrument=" + window.instrument;
args += "&instrument=" + window.instrument;
} else {
let args = '';
if (window.stream) { args += "&stream=" + window.stream; }
if (window.device) { args += "&device=" + window.device; }
window.clientTags = args;
}
if (window.hideRightPart) { args += "&history_only=1"; }
window.clientTags = args;
// console.log('TAGS', window.clientTags);

View File

@ -1,8 +1,10 @@
#!/usr/bin/env python
import sys
from os.path import expanduser
# look for sehistory and frappy at usual locations in home directory
sys.path.extend([expanduser('~'), expanduser('~/frappy')])
import argparse
import socket
from webserver import server
from base import Client
from influxgraph import InfluxGraph
@ -38,6 +40,5 @@ def parseArgv(argv):
args = parseArgv(sys.argv[1:])
instrument = socket.gethostname().split('.')[0] if args.instrument == 'HOST' else args.instrument
instrument = None if args.instrument=='main' else args.instrument
server.run(int(args.port), SEHistory(), InfluxGraph, Client, single_instrument=instrument, secop=SecopInteractor)

View File

@ -54,9 +54,12 @@ class SecopInteractor(SecopClient):
self.module_updates = set()
self.param_updates = set()
self.updates = {}
self.connect()
node_map.update({k: self for k in self.modules})
self.register_callback(None, updateItem=self.updateItem)
try:
self.connect()
node_map.update({k: self for k in self.modules})
self.register_callback(None, updateItem=self.updateItem)
except Exception as e:
print(repr(e))
def add_main_components(self, components):
for name, desc in self.modules.items():

View File

@ -14,6 +14,11 @@ import flask
import circularlog
instruments = {ins: 8642 for ins in
['amor', 'boa', 'camea', 'dmc', 'eiger', 'focus', 'hrpt', 'sans', 'tasp', 'zebra']
}
def guess_mimetype(filename):
if filename.endswith('.js'):
mimetype = 'text/javascript'
@ -86,9 +91,13 @@ class Server:
tags['device'] = devices[0] if len(devices) == 1 else devices
return streams, tags, ','.join(device_names)
def register_client(self, instrument=None, stream=None, device=None):
def register_client(self, instrument=None, stream=None, device=None, history_only=None):
streams, tags, device_name = self.lookup_streams(instrument, stream, device)
client = self.client_cls(self, streams, instrument or '', device_name)
if (history_only or '0') != '0':
# create dummy client
client = self.client_cls(self, [], '', '')
else:
client = self.client_cls(self, streams, instrument or '', device_name)
history = self.history_cls(self, instrument, device_name, tags)
# history.db.debug = True
# all relevant methods of the history instance are saved in client.handlers
@ -106,7 +115,7 @@ class Server:
app.debug = True
logging.basicConfig(filename='webserver.log', filemode='w', level=logging.INFO,
logging.basicConfig(filename=f'logfile{port}.log', filemode='w', level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s')
# srv = gevent.wsgi.WSGIServer(('', port), app, keyfile='key.key', certfile='key.crt')
@ -137,7 +146,7 @@ pollinterval = 0.2
@app.route('/update')
def get_update(_=None):
# Client Adress: socket.getfqdn(flask.request.remote_addr)
kwargs = {k: flask.request.values.get(k) for k in ('instrument', 'stream', 'device')}
kwargs = {k: flask.request.values.get(k) for k in ('instrument', 'stream', 'device', 'history_only')}
client = server.register_client(**kwargs)
client.remote_info = circularlog.strtm() + " " + socket.getfqdn(flask.request.remote_addr.split(':')[-1])
@ -147,7 +156,8 @@ def get_update(_=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=kwargs.get('instrument') or 'n_a',
msg = dict(type='id', id=client.id,
instrument=kwargs.get('instrument') or server.single_instrument or 'n_a',
device=client.device_name)
yield to_json_sse(msg)
try:
@ -303,28 +313,31 @@ def default():
return general_file('SEAWebClient.html')
@app.route('/select_instrument')
def select_instrument():
out = ['''<html><body><table>
<style>
th {
text-align: left;
}
</style>
<tr><th>instrument</th><th colspan=99>devices</th></tr>''']
result = {}
for stream, tags in server.db.get_streams().items():
ins = tags.get('instrument', '0')
result.setdefault(ins, []).append((stream, tags.get('device')))
bare_streams = result.pop('0', [])
for ins, streams in result.items():
out.append(f'<tr><td><a href="/?ins={ins}">{ins}</a></td>')
out.extend(f'<td>{d or s}</td>' for s, d in streams)
out.append('</tr>')
for stream, device in bare_streams:
out.append(f'<tr><td><a href="/?srv={stream}">{stream}</a></td><td>{device}</td><tr>')
out.extend(['</table></body></html>', ''])
return '\n'.join(out)
#@app.route('/select_instrument')
#def select_instrument():
# out = ['''<html><body><table>
#<style>
#th {
# text-align: left;
#}
#</style>
#<tr><th>instrument</th><th colspan=99>devices</th></tr>''']
# result = {}
# for stream, tags in server.db.get_streams().items():
# ins = tags.get('instrument', '0')
# result.setdefault(ins, []).append((stream, tags.get('device')))
# bare_streams = result.pop('0', [])
# for ins, streams in result.items():
# out.append(f'<tr><td><a href="/?ins={ins}">{ins}</a></td>')
# out.extend(f'<td>{d or s}</td>' for s, d in streams)
# out.append('</tr>')
# for stream, device in bare_streams:
# out.append(f'<tr><td><a href="/?srv={stream}">{stream}</a></td><td>{device}</td><tr>')
# out.append('</table>')
# out.append('<h3>servers on the instruments:</h3>')
# out.extend([f"<a href='http://{i.lower()}.psi.ch:8642/'>{i}</a>&nbsp;\n" for i in instlist])
# out.extend(['</body></html>', ''])
# return '\n'.join(out)
@app.route('/select_experiment')
@ -335,7 +348,6 @@ content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale
<style>
th {
text-align: left;
background-color: #cccccc;
}
a {
text-decoration: none;
@ -343,11 +355,27 @@ a {
</style></head>
<body><table>
''']
showtitle = 0
ONEMONTH = 30 * 24 * 3600
def title(text):
out.append(f'<tr><td colspan=2><b>{text}</b></td></tr>')
out.append('<br><i>direct link to instruments:</i><br>')
out.extend([f'<a href="http://{ins}.psi.ch:{port}/">{ins.upper()}</a>&nbsp;\n'
for ins, port in instruments.items()])
if server.db.has_local:
out.append('<h3><a href="http://linse-c.psi.ch:8888/">linse-c (central)</a></h3>')
class prev: # just a namesapce
title = None
legend = None
def change_title(text):
if text == prev.title:
return False
if prev.legend:
out.append(f'<tr>{prev.legend}</tr>')
prev.legend = None
prev.title = text
out.append(f'<tr><td colspan=3><br><i>{text}:</i></td></tr>')
return True
# TODO: sort this by (instrument / device) and list dates
# period format: Ymd..Ymd, Ymd (single date), Ymd..now, HM..now
@ -369,27 +397,50 @@ a {
chunk_list.sort(reverse=True)
for end, beg, key, devices in chunk_list:
today, begdate, enddate = (time.strftime("%Y-%m-%d", time.localtime(t)) for t in (now, beg, end))
port = None
if key[0] == 'instrument':
ins = key[1]
port = instruments.get(ins)
left = ins.upper()
else:
left = key[1] # shown in left column
args = ['='.join(key)]
remote = None if port is None else f'http://{ins}.psi.ch:{port}'
history_only = bool(remote)
if end > now:
if begdate == today:
daterange = f'since {time.strftime("%H:%M", time.localtime(beg))}'
else:
daterange = f'since {begdate}'
if showtitle == 0:
title('currently running')
showtitle = 1
change_title('currently running')
else:
args.append(f'time={beg},{end}')
history_only = True
remote = None
daterange = begdate if begdate == enddate else f'{begdate}...{enddate}'
if end < now - ONEMONTH:
if showtitle == 1:
title('older than 30 days')
showtitle = 2
if end > now - ONEMONTH:
change_title('recently running (history graphics only)')
else:
change_title('older than 30 days')
if history_only:
args.append('hr=1')
out.append(f'<tr><th><a href="/?{"&".join(args)}">{key[1]} / {" ".join(devices)}</a></th>')
def link(label):
return f'<a href="/?{"&".join(args)}">{label}</a>'
label = " ".join(devices)
if remote:
prev.legend = '<td></td><td></td><td colspan=2>linse-c*: <i>history graphics only</i></td>'
out.append(f'<tr><td><a href="{remote}">{ins.upper()}</a></td>'
f'<td>{label}</td><td>{link("linse-c*")}</td>')
else:
out.append(f'<tr><td>{link(left)}</td><td colspan=2>{label}</td>')
out.append(f'<td>{daterange}</td></tr>')
if timerange:
out.append(f'<h3><a href="/select_experiment?time=all">earlier dates</a></h3><br>')
out.extend(['</table></body></html>', ''])
out.append('</table>')
out.extend(['</body></html>', ''])
except Exception as e:
logging.error('%s', traceback.format_exc())
circularlog.log()