diff --git a/docker-compose.yml b/docker-compose.yml index 861fc28..8206e3f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -129,6 +129,9 @@ services: context: ./volumes/proc/ environment: - BROKER_URL=${BROKER_URL} + - PEDESTAL_TOPIC=${PEDESTAL_TOPIC} + - TXA_SITE=${TXA_SITE} + - TXB_SITE=${TXB_SITE} - VIRTUAL_HOST=${PROC_SITE} volumes: - 'sirm_proc:/app' diff --git a/volumes/proc/app.py b/volumes/proc/app.py index c420f73..bfabb7d 100644 --- a/volumes/proc/app.py +++ b/volumes/proc/app.py @@ -9,6 +9,7 @@ from datetime import datetime import random import eventlet import json +from json import JSONEncoder import numpy import base64 import h5py @@ -43,6 +44,7 @@ try: mqtt = Mqtt(app) except: pass + socketio = SocketIO(app) bootstrap = Bootstrap(app) @@ -66,30 +68,39 @@ USHRT_MAX = 65535 DATA_PATH = '/data' RUNNING = False EXPERIMENT = {'name': 'test'} +DEBUG = False + +class NumpyArrayEncoder(JSONEncoder): + def default(self, obj): + if isinstance(obj, numpy.ndarray): + return obj.tolist() + return JSONEncoder.default(self, obj) class HDF5File(): def __init__(self): self.data = {} + self.data_pow = {'powa':[], 'powb':[], 'timestamp':[]} + self.power_ready = True + self.power_time = 0 self.raw = {} self.timestamp = 0 self.enable = False self.metadata = None - def ready(self): - - if len(self.az)<100 or len(self.el)<100 or len(self.saz)<100 or len(self.sel)<100: - return False - return True + def reset(self): + self.data = {} + self.data_pow = {'powa':[], 'powb':[], 'timestamp':[]} + self.power_ready = True + self.power_time = 0 + self.raw = {} + self.timestamp = 0 def add_data(self, var, values): if len(values) > 0: delta = numpy.average(values[1:]-values[:-1]) n = 100 - len(values) - # print(values[-1]+delta, values[0], delta, flush=True) - # missing = numpy.arange(values[-1]+delta, values[0], delta) - print(var, n, numpy.arange(1, n+1)*delta + values[-1], flush=True) if n > 0: missing = numpy.arange(1, n+1)*delta + values[-1] values = values.tolist() @@ -120,10 +131,11 @@ class HDF5File(): dset = grp.create_dataset("azi_speed", data=numpy.array(self.data['saz'])) dset = grp.create_dataset("ele_speed", data=numpy.array(self.data['sel'])) dset = grp.create_dataset("utc", data=self.timestamp) - filelog = filename.replace('.h5', '.txt') - f = open(filelog, 'w') - f.write(json.dumps(self.raw)) - f.close() + if DEBUG: + filelog = filename.replace('.h5', '.txt') + f = open(filelog, 'w') + f.write(json.dumps(self.raw, cls=NumpyArrayEncoder)) + f.close() def write(self, data): @@ -131,6 +143,35 @@ class HDF5File(): self.update(data) self.create_file() + def write_power(self, data): + + if self.power_ready: + filex = "pow@%10.3f.h5" % (self.power_time if self.power_time else self.timestamp) + date_folder = datetime.fromtimestamp(self.timestamp).strftime('%Y-%m-%dT%H-00-00') + filename = os.path.join(DATA_PATH, EXPERIMENT['name'], 'power', date_folder, filex) + if not os.path.exists(os.path.dirname(filename)): + path = os.path.dirname(filename) + os.makedirs(path) + self.fp = h5py.File(filename, 'w') + self.power_ready = False + + if datetime.fromtimestamp(self.timestamp).second == 0: + self.power_time = self.timestamp + grp = self.fp.create_group("Data") + dset = grp.create_dataset("powa", data=numpy.array(self.data_pow['powa'])) + dset = grp.create_dataset("powb", data=numpy.array(self.data_pow['powb'])) + dset = grp.create_dataset("utc", data=numpy.array(self.data_pow['timestamp'])) + self.fp.close() + self.data_pow['powa'] = [] + self.data_pow['powb'] = [] + self.data_pow['timestamp'] = [] + self.power_ready = True + + self.data_pow['powa'].append(data['powa']) + self.data_pow['powb'].append(data['powb']) + self.data_pow['timestamp'].append(self.timestamp) + + HDF = HDF5File() def getSpeedPosition(msg_b64): @@ -268,8 +309,11 @@ def start_proc(): @app.route('/stop') def stop_proc(): - global RUNNING + global RUNNING, DEBUG, HDF + RUNNING = False + DEBUG = False + HDF.reset() return jsonify({'stop': 'ok'}) @@ -283,7 +327,9 @@ def status_proc(): @app.route('/run') def run_proc(): - global RUNNING, EXPERIMENT + global RUNNING, EXPERIMENT, DEBUG + if request.args.get('debug', False): + DEBUG = True path = os.path.join(DATA_PATH, 'TEST') if not os.path.exists(path): os.makedirs(path) @@ -313,14 +359,12 @@ def handle_connect(client, userdata, flags, rc): @mqtt.on_message() def handle_mqtt_message(client, userdata, message): - global RUNNING + global RUNNING, HDF payload = message.payload.decode() az, saz, el, sel, tm = getSpeedPosition(payload) - pwA = get_power(os.environ['TXA_SITE']) - pwB = get_power(os.environ['TXB_SITE']) - if RUNNING: - HDF.write({'az':az, 'el':el, 'saz':saz, 'sel':sel, 'timestamp':tm}) + powa = get_power(os.environ['TXA_SITE']) + powb = get_power(os.environ['TXB_SITE']) times = numpy.arange(tm, tm+1, 0.1, dtype=float) data = dict( @@ -332,13 +376,17 @@ def handle_mqtt_message(client, userdata, message): payload = payload, qos = message.qos, timestamp = times.tolist(), - pwa = [pwa], - pwb = [pwb], + powa = [powa], + powb = [powb], status = 'Running' if RUNNING else 'Not Running' ) socketio.emit('mqtt_message', data=data) + if RUNNING: + HDF.write({'az':az, 'el':el, 'saz':saz, 'sel':sel, 'timestamp':tm, 'powa':powa, 'powb':powb}) + HDF.write_power({'timestamp':tm, 'powa':powa, 'powb':powb}) + @mqtt.on_log() def handle_logging(client, userdata, level, buf): # print(level, buf) diff --git a/volumes/proc/static/favicon.ico b/volumes/proc/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..35d2d351956850343d2c03546311a1d52a7bc8e2 GIT binary patch literal 4286 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 literal 0 Hc$@ new Date(i*1000)); var values = y.map(i => Math.round(i * 100) / 100); var data_update = {x: [tm], y: [values]} - //var windowDateObj = getWindow(x) - //var layout_update = {xaxis: { - // range: [windowDateObj, x[x.length - 1]], - // rangeslider: {range: [plot_start, x[x.length - 1]]} - //}}; - //Plotly.update(plotDiv, {}, layout_update) Plotly.extendTraces(plotDiv, data_update, [0]) -}; + }; + + function streamPlot2(div, x, y1, y2 ){ + var plotDiv = document.getElementById(div); + if (plotDiv.data[0].x.length > 499){ + plotDiv.data[0].x = plotDiv.data[0].x.slice(-500) + plotDiv.data[0].y = plotDiv.data[0].y.slice(-500) + plotDiv.data[1].x = plotDiv.data[1].x.slice(-500) + plotDiv.data[1].y = plotDiv.data[1].y.slice(-500) + } + var tm = x.map(i => new Date(i*1000)); + var values1 = y1.map(i => Math.round(i * 100) / 100); + var values2 = y2.map(i => Math.round(i * 100) / 100); + var data_update = {x: [tm, tm], y: [values1, values2]} + Plotly.extendTraces(plotDiv, data_update, [0, 1]) + }; {% endblock %} @@ -113,61 +115,46 @@ - -
-
-
-

Pedestal Azimuth

-
-
-
-
-
-
-
-
-
-
- +
-

Pedestal Elevation

+

RX log

-
+
- +
-

Pedestal Azimuth Speed

+

Pedestal Position

-
+
- +
-

Pedestal Elevation Speed

+

Pedestal Speed

-
+