##// END OF EJS Templates
Fix power monitor
jespinoza -
r394:6790c8880a2c
parent child
Show More
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -1,160 +1,163
1 # docker-compose up -d --build
1 # docker-compose up -d --build
2 version: '3'
2 version: '3'
3
3
4 volumes:
4 volumes:
5 sirm_web:
5 sirm_web:
6 name: sirm_web
6 name: sirm_web
7 driver: local
7 driver: local
8 driver_opts:
8 driver_opts:
9 type: "none"
9 type: "none"
10 o: "bind"
10 o: "bind"
11 device: "${EXPOSE_SIRM}"
11 device: "${EXPOSE_SIRM}"
12 sirm_pgdata:
12 sirm_pgdata:
13 name: sirm_pgdata
13 name: sirm_pgdata
14 driver: local
14 driver: local
15 driver_opts:
15 driver_opts:
16 type: "none"
16 type: "none"
17 o: "bind"
17 o: "bind"
18 device: "${EXPOSE_PGDATA}"
18 device: "${EXPOSE_PGDATA}"
19 sirm_certs:
19 sirm_certs:
20 name: sirm_certs
20 name: sirm_certs
21 driver: local
21 driver: local
22 driver_opts:
22 driver_opts:
23 type: "none"
23 type: "none"
24 o: "bind"
24 o: "bind"
25 device: "${EXPOSE_CERTS}"
25 device: "${EXPOSE_CERTS}"
26 sirm_dhparam:
26 sirm_dhparam:
27 name: sirm_dhparam
27 name: sirm_dhparam
28 driver: local
28 driver: local
29 driver_opts:
29 driver_opts:
30 type: "none"
30 type: "none"
31 o: "bind"
31 o: "bind"
32 device: "${EXPOSE_DHPARAM}"
32 device: "${EXPOSE_DHPARAM}"
33 sirm_proc:
33 sirm_proc:
34 name: sirm_proc
34 name: sirm_proc
35 driver: local
35 driver: local
36 driver_opts:
36 driver_opts:
37 type: "none"
37 type: "none"
38 o: "bind"
38 o: "bind"
39 device: "${EXPOSE_PROC}"
39 device: "${EXPOSE_PROC}"
40 sirm_nas:
40 sirm_nas:
41 name: sirm_nas
41 name: sirm_nas
42 driver: local
42 driver: local
43 driver_opts:
43 driver_opts:
44 type: "none"
44 type: "none"
45 o: "bind"
45 o: "bind"
46 device: "${EXPOSE_NAS}"
46 device: "${EXPOSE_NAS}"
47
47
48 services:
48 services:
49 sirm-nginx-proxy:
49 sirm-nginx-proxy:
50 container_name: sirm-nginx-proxy
50 container_name: sirm-nginx-proxy
51 restart: always
51 restart: always
52 build:
52 build:
53 context: ./images/
53 context: ./images/
54 dockerfile: nginx-proxy/Dockerfile
54 dockerfile: nginx-proxy/Dockerfile
55 args:
55 args:
56 - SIRM_MAX_UPLOAD_SIZE_MB=${SIRM_MAX_UPLOAD_SIZE_MB}
56 - SIRM_MAX_UPLOAD_SIZE_MB=${SIRM_MAX_UPLOAD_SIZE_MB}
57 depends_on:
57 depends_on:
58 - sirm-web
58 - sirm-web
59 networks:
59 networks:
60 - frontend_sirm
60 - frontend_sirm
61 - backend_sirm
61 - backend_sirm
62 ports:
62 ports:
63 - 0.0.0.0:${GENERAL_PORT}:80
63 - 0.0.0.0:${GENERAL_PORT}:80
64 volumes:
64 volumes:
65 - /var/run/docker.sock:/tmp/docker.sock:ro
65 - /var/run/docker.sock:/tmp/docker.sock:ro
66 - sirm_certs:/etc/nginx/certs:ro
66 - sirm_certs:/etc/nginx/certs:ro
67 - sirm_dhparam:/etc/nginx/dhparam
67 - sirm_dhparam:/etc/nginx/dhparam
68 logging:
68 logging:
69 driver: "json-file"
69 driver: "json-file"
70 options:
70 options:
71 max-size: "12m"
71 max-size: "12m"
72
72
73 sirm-web:
73 sirm-web:
74 container_name: 'sirm-web'
74 container_name: 'sirm-web'
75 restart: always
75 restart: always
76 build:
76 build:
77 context: .
77 context: .
78 environment:
78 environment:
79 - LC_ALL=${LC_ALL}
79 - LC_ALL=${LC_ALL}
80 - DB_USER=${DB_USER}
80 - DB_USER=${DB_USER}
81 - DB_NAME=${DB_NAME}
81 - DB_NAME=${DB_NAME}
82 - DB_PASSWORD=${DB_PASSWORD}
82 - DB_PASSWORD=${DB_PASSWORD}
83 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
83 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
84 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
84 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
85 - SIRM_USER=${SIRM_USER}
85 - SIRM_USER=${SIRM_USER}
86 - SIRM_PASSWORD=${SIRM_PASSWORD}
86 - SIRM_PASSWORD=${SIRM_PASSWORD}
87 - SIRM_EMAIL=${SIRM_EMAIL}
87 - SIRM_EMAIL=${SIRM_EMAIL}
88 - VIRTUAL_HOST=${SIRM_SITE}
88 - VIRTUAL_HOST=${SIRM_SITE}
89 volumes:
89 volumes:
90 - 'sirm_web:/workspace/sirm'
90 - 'sirm_web:/workspace/sirm'
91 depends_on:
91 depends_on:
92 - sirm-postgres
92 - sirm-postgres
93 networks:
93 networks:
94 - frontend_sirm
94 - frontend_sirm
95 - backend_sirm
95 - backend_sirm
96 logging:
96 logging:
97 driver: "json-file"
97 driver: "json-file"
98 options:
98 options:
99 max-size: "12m"
99 max-size: "12m"
100
100
101 sirm-postgres:
101 sirm-postgres:
102 container_name: 'sirm-postgres'
102 container_name: 'sirm-postgres'
103 restart: always
103 restart: always
104 build:
104 build:
105 context: ./images/
105 context: ./images/
106 dockerfile: postgres/Dockerfile
106 dockerfile: postgres/Dockerfile
107 args:
107 args:
108 - PGDATA=${PGDATA}
108 - PGDATA=${PGDATA}
109 environment:
109 environment:
110 - LC_ALL=${LC_ALL}
110 - LC_ALL=${LC_ALL}
111 - DB_USER=${DB_USER}
111 - DB_USER=${DB_USER}
112 - DB_NAME=${DB_NAME}
112 - DB_NAME=${DB_NAME}
113 - DB_PASSWORD=${DB_PASSWORD}
113 - DB_PASSWORD=${DB_PASSWORD}
114 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
114 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
115 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
115 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
116 volumes:
116 volumes:
117 - sirm_pgdata:/var/lib/postgresql/data
117 - sirm_pgdata:/var/lib/postgresql/data
118 networks:
118 networks:
119 - backend_sirm
119 - backend_sirm
120 logging:
120 logging:
121 driver: "json-file"
121 driver: "json-file"
122 options:
122 options:
123 max-size: "12m"
123 max-size: "12m"
124
124
125 sirm-proc:
125 sirm-proc:
126 container_name: 'sirm-proc'
126 container_name: 'sirm-proc'
127 restart: always
127 restart: always
128 build:
128 build:
129 context: ./volumes/proc/
129 context: ./volumes/proc/
130 environment:
130 environment:
131 - BROKER_URL=${BROKER_URL}
131 - BROKER_URL=${BROKER_URL}
132 - PEDESTAL_TOPIC=${PEDESTAL_TOPIC}
133 - TXA_SITE=${TXA_SITE}
134 - TXB_SITE=${TXB_SITE}
132 - VIRTUAL_HOST=${PROC_SITE}
135 - VIRTUAL_HOST=${PROC_SITE}
133 volumes:
136 volumes:
134 - 'sirm_proc:/app'
137 - 'sirm_proc:/app'
135 - 'sirm_nas:/data'
138 - 'sirm_nas:/data'
136 networks:
139 networks:
137 - frontend_sirm
140 - frontend_sirm
138 logging:
141 logging:
139 driver: "json-file"
142 driver: "json-file"
140 options:
143 options:
141 max-size: "12m"
144 max-size: "12m"
142
145
143 sirm-cam:
146 sirm-cam:
144 container_name: 'sirm-cam'
147 container_name: 'sirm-cam'
145 image: bkjaya1952/ivms4200-v2.8.2.2_ml-linux
148 image: bkjaya1952/ivms4200-v2.8.2.2_ml-linux
146 restart: always
149 restart: always
147 environment:
150 environment:
148 - VIRTUAL_HOST=${CAM_SITE}
151 - VIRTUAL_HOST=${CAM_SITE}
149 networks:
152 networks:
150 - frontend_sirm
153 - frontend_sirm
151 logging:
154 logging:
152 driver: "json-file"
155 driver: "json-file"
153 options:
156 options:
154 max-size: "12m"
157 max-size: "12m"
155
158
156 networks:
159 networks:
157 frontend_sirm:
160 frontend_sirm:
158 name: frontend_sirm
161 name: frontend_sirm
159 backend_sirm:
162 backend_sirm:
160 name: backend_sirm No newline at end of file
163 name: backend_sirm
@@ -1,348 +1,396
1 """
1 """
2 A small Test application to show how to use Flask-MQTT.
2 A small Test application to show how to use Flask-MQTT.
3
3
4 """
4 """
5 import os
5 import os
6 import time
6 import time
7 import logging
7 import logging
8 from datetime import datetime
8 from datetime import datetime
9 import random
9 import random
10 import eventlet
10 import eventlet
11 import json
11 import json
12 from json import JSONEncoder
12 import numpy
13 import numpy
13 import base64
14 import base64
14 import h5py
15 import h5py
15 try:
16 try:
16 import requests
17 import requests
17 except:
18 except:
18 pass
19 pass
19 from bs4 import BeautifulSoup
20 from bs4 import BeautifulSoup
20 from flask import Flask, render_template, jsonify, request, redirect
21 from flask import Flask, render_template, jsonify, request, redirect
21 from flask_mqtt import Mqtt
22 from flask_mqtt import Mqtt
22 from flask_socketio import SocketIO
23 from flask_socketio import SocketIO
23 from flask_bootstrap import Bootstrap
24 from flask_bootstrap import Bootstrap
24
25
25 eventlet.monkey_patch()
26 eventlet.monkey_patch()
26
27
27 app = Flask(__name__)
28 app = Flask(__name__)
28 app.config['SECRET'] = 'my secret key'
29 app.config['SECRET'] = 'my secret key'
29 app.config['TEMPLATES_AUTO_RELOAD'] = True
30 app.config['TEMPLATES_AUTO_RELOAD'] = True
30 app.config['MQTT_BROKER_URL'] = os.environ['BROKER_URL']
31 app.config['MQTT_BROKER_URL'] = os.environ['BROKER_URL']
31 app.config['MQTT_BROKER_PORT'] = 1883
32 app.config['MQTT_BROKER_PORT'] = 1883
32 app.config['MQTT_CLIENT_ID'] = 'flask_mqtt_sophy'
33 app.config['MQTT_CLIENT_ID'] = 'flask_mqtt_sophy'
33 app.config['MQTT_CLEAN_SESSION'] = True
34 app.config['MQTT_CLEAN_SESSION'] = True
34 app.config['MQTT_USERNAME'] = ''
35 app.config['MQTT_USERNAME'] = ''
35 app.config['MQTT_PASSWORD'] = ''
36 app.config['MQTT_PASSWORD'] = ''
36 app.config['MQTT_KEEPALIVE'] = 5
37 app.config['MQTT_KEEPALIVE'] = 5
37 app.config['MQTT_TLS_ENABLED'] = False
38 app.config['MQTT_TLS_ENABLED'] = False
38 app.config['MQTT_LAST_WILL_TOPIC'] = 'home/lastwill'
39 app.config['MQTT_LAST_WILL_TOPIC'] = 'home/lastwill'
39 app.config['MQTT_LAST_WILL_MESSAGE'] = 'bye'
40 app.config['MQTT_LAST_WILL_MESSAGE'] = 'bye'
40 app.config['MQTT_LAST_WILL_QOS'] = 2
41 app.config['MQTT_LAST_WILL_QOS'] = 2
41
42
42 try:
43 try:
43 mqtt = Mqtt(app)
44 mqtt = Mqtt(app)
44 except:
45 except:
45 pass
46 pass
47
46 socketio = SocketIO(app)
48 socketio = SocketIO(app)
47 bootstrap = Bootstrap(app)
49 bootstrap = Bootstrap(app)
48
50
49 MODE_STOP = 0x00
51 MODE_STOP = 0x00
50 MODE_SPEED = 0x01
52 MODE_SPEED = 0x01
51 MODE_POSITION = 0x02
53 MODE_POSITION = 0x02
52 RX_AZIMUTH = 0x27
54 RX_AZIMUTH = 0x27
53 RX_ELEVATION = 0x47
55 RX_ELEVATION = 0x47
54 TX_AZIMUTH = 0x25
56 TX_AZIMUTH = 0x25
55 TX_ELEVATION = 0x45
57 TX_ELEVATION = 0x45
56 NONE_AXIS = 0x65
58 NONE_AXIS = 0x65
57 RX_FUNCTION = 0x30
59 RX_FUNCTION = 0x30
58 TX_FUNCTION = 0x40
60 TX_FUNCTION = 0x40
59 HEADER = 0x7e
61 HEADER = 0x7e
60 MIN_SPEED = -180.0
62 MIN_SPEED = -180.0
61 MAX_SPEED = 180.0
63 MAX_SPEED = 180.0
62 SHRT_MIN = -32768
64 SHRT_MIN = -32768
63 SHRT_MAX = 32768
65 SHRT_MAX = 32768
64 USHRT_MAX = 65535
66 USHRT_MAX = 65535
65
67
66 DATA_PATH = '/data'
68 DATA_PATH = '/data'
67 RUNNING = False
69 RUNNING = False
68 EXPERIMENT = {'name': 'test'}
70 EXPERIMENT = {'name': 'test'}
71 DEBUG = False
72
73 class NumpyArrayEncoder(JSONEncoder):
74 def default(self, obj):
75 if isinstance(obj, numpy.ndarray):
76 return obj.tolist()
77 return JSONEncoder.default(self, obj)
69
78
70 class HDF5File():
79 class HDF5File():
71
80
72 def __init__(self):
81 def __init__(self):
73 self.data = {}
82 self.data = {}
83 self.data_pow = {'powa':[], 'powb':[], 'timestamp':[]}
84 self.power_ready = True
85 self.power_time = 0
74 self.raw = {}
86 self.raw = {}
75 self.timestamp = 0
87 self.timestamp = 0
76 self.enable = False
88 self.enable = False
77 self.metadata = None
89 self.metadata = None
78
90
79 def ready(self):
91 def reset(self):
80
92 self.data = {}
81 if len(self.az)<100 or len(self.el)<100 or len(self.saz)<100 or len(self.sel)<100:
93 self.data_pow = {'powa':[], 'powb':[], 'timestamp':[]}
82 return False
94 self.power_ready = True
83 return True
95 self.power_time = 0
96 self.raw = {}
97 self.timestamp = 0
84
98
85 def add_data(self, var, values):
99 def add_data(self, var, values):
86
100
87 if len(values) > 0:
101 if len(values) > 0:
88 delta = numpy.average(values[1:]-values[:-1])
102 delta = numpy.average(values[1:]-values[:-1])
89 n = 100 - len(values)
103 n = 100 - len(values)
90 # print(values[-1]+delta, values[0], delta, flush=True)
91 # missing = numpy.arange(values[-1]+delta, values[0], delta)
92 print(var, n, numpy.arange(1, n+1)*delta + values[-1], flush=True)
93 if n > 0:
104 if n > 0:
94 missing = numpy.arange(1, n+1)*delta + values[-1]
105 missing = numpy.arange(1, n+1)*delta + values[-1]
95 values = values.tolist()
106 values = values.tolist()
96 values.extend(missing)
107 values.extend(missing)
97
108
98 self.data[var] = values
109 self.data[var] = values
99
110
100 def update(self, data):
111 def update(self, data):
101
112
102 self.add_data('az', data['az'])
113 self.add_data('az', data['az'])
103 self.add_data('el', data['el'])
114 self.add_data('el', data['el'])
104 self.add_data('saz', data['saz'])
115 self.add_data('saz', data['saz'])
105 self.add_data('sel', data['sel'])
116 self.add_data('sel', data['sel'])
106 self.timestamp = int(data['timestamp'])
117 self.timestamp = int(data['timestamp'])
107
118
108 def create_file(self):
119 def create_file(self):
109
120
110 filex = "pos@%10.3f.h5" % (self.timestamp)
121 filex = "pos@%10.3f.h5" % (self.timestamp)
111 date_folder = datetime.fromtimestamp(self.timestamp).strftime('%Y-%m-%dT%H-00-00')
122 date_folder = datetime.fromtimestamp(self.timestamp).strftime('%Y-%m-%dT%H-00-00')
112 filename = os.path.join(DATA_PATH, EXPERIMENT['name'], 'position', date_folder, filex)
123 filename = os.path.join(DATA_PATH, EXPERIMENT['name'], 'position', date_folder, filex)
113 if not os.path.exists(os.path.dirname(filename)):
124 if not os.path.exists(os.path.dirname(filename)):
114 path = os.path.dirname(filename)
125 path = os.path.dirname(filename)
115 os.makedirs(path)
126 os.makedirs(path)
116 with h5py.File(filename, 'w') as fp:
127 with h5py.File(filename, 'w') as fp:
117 grp = fp.create_group("Data")
128 grp = fp.create_group("Data")
118 dset = grp.create_dataset("azi_pos", data=numpy.array(self.data['az']))
129 dset = grp.create_dataset("azi_pos", data=numpy.array(self.data['az']))
119 dset = grp.create_dataset("ele_pos", data=numpy.array(self.data['el']))
130 dset = grp.create_dataset("ele_pos", data=numpy.array(self.data['el']))
120 dset = grp.create_dataset("azi_speed", data=numpy.array(self.data['saz']))
131 dset = grp.create_dataset("azi_speed", data=numpy.array(self.data['saz']))
121 dset = grp.create_dataset("ele_speed", data=numpy.array(self.data['sel']))
132 dset = grp.create_dataset("ele_speed", data=numpy.array(self.data['sel']))
122 dset = grp.create_dataset("utc", data=self.timestamp)
133 dset = grp.create_dataset("utc", data=self.timestamp)
123 filelog = filename.replace('.h5', '.txt')
134 if DEBUG:
124 f = open(filelog, 'w')
135 filelog = filename.replace('.h5', '.txt')
125 f.write(json.dumps(self.raw))
136 f = open(filelog, 'w')
126 f.close()
137 f.write(json.dumps(self.raw, cls=NumpyArrayEncoder))
138 f.close()
127
139
128 def write(self, data):
140 def write(self, data):
129
141
130 self.raw = data
142 self.raw = data
131 self.update(data)
143 self.update(data)
132 self.create_file()
144 self.create_file()
133
145
146 def write_power(self, data):
147
148 if self.power_ready:
149 filex = "pow@%10.3f.h5" % (self.power_time if self.power_time else self.timestamp)
150 date_folder = datetime.fromtimestamp(self.timestamp).strftime('%Y-%m-%dT%H-00-00')
151 filename = os.path.join(DATA_PATH, EXPERIMENT['name'], 'power', date_folder, filex)
152 if not os.path.exists(os.path.dirname(filename)):
153 path = os.path.dirname(filename)
154 os.makedirs(path)
155 self.fp = h5py.File(filename, 'w')
156 self.power_ready = False
157
158 if datetime.fromtimestamp(self.timestamp).second == 0:
159 self.power_time = self.timestamp
160 grp = self.fp.create_group("Data")
161 dset = grp.create_dataset("powa", data=numpy.array(self.data_pow['powa']))
162 dset = grp.create_dataset("powb", data=numpy.array(self.data_pow['powb']))
163 dset = grp.create_dataset("utc", data=numpy.array(self.data_pow['timestamp']))
164 self.fp.close()
165 self.data_pow['powa'] = []
166 self.data_pow['powb'] = []
167 self.data_pow['timestamp'] = []
168 self.power_ready = True
169
170 self.data_pow['powa'].append(data['powa'])
171 self.data_pow['powb'].append(data['powb'])
172 self.data_pow['timestamp'].append(self.timestamp)
173
174
134 HDF = HDF5File()
175 HDF = HDF5File()
135
176
136 def getSpeedPosition(msg_b64):
177 def getSpeedPosition(msg_b64):
137 AzPosition=[]
178 AzPosition=[]
138 AzSpeed=[]
179 AzSpeed=[]
139 ElPosition=[]
180 ElPosition=[]
140 ElSpeed=[]
181 ElSpeed=[]
141 RawData=[]
182 RawData=[]
142 raw = numpy.frombuffer(base64.decodebytes(msg_b64.encode()),numpy.dtype('B'))
183 raw = numpy.frombuffer(base64.decodebytes(msg_b64.encode()),numpy.dtype('B'))
143 raw_size = len(raw)
184 raw_size = len(raw)
144 Timestamp = (raw[raw_size-4])|(raw[raw_size-3]<<8)|(raw[raw_size-2]<<16)|(raw[raw_size-1]<<24)
185 Timestamp = (raw[raw_size-4])|(raw[raw_size-3]<<8)|(raw[raw_size-2]<<16)|(raw[raw_size-1]<<24)
145 # Timestamp = time.time()
186 # Timestamp = time.time()
146 counter = 0
187 counter = 0
147 while counter < raw_size-4:
188 while counter < raw_size-4:
148 if raw[counter]==HEADER:
189 if raw[counter]==HEADER:
149 if raw[counter+1]==RX_FUNCTION:
190 if raw[counter+1]==RX_FUNCTION:
150 if raw[counter+2]==RX_AZIMUTH or raw[counter+2]==RX_ELEVATION:
191 if raw[counter+2]==RX_AZIMUTH or raw[counter+2]==RX_ELEVATION:
151 iangle = 0.0
192 iangle = 0.0
152 ispeed = 0.0
193 ispeed = 0.0
153 hadstuffing = 0
194 hadstuffing = 0
154
195
155 if (counter+hadstuffing+4<raw_size-4):
196 if (counter+hadstuffing+4<raw_size-4):
156 if raw[counter+hadstuffing+4]==HEADER-1:
197 if raw[counter+hadstuffing+4]==HEADER-1:
157 hadstuffing+=1
198 hadstuffing+=1
158 iangle = int(0x70|raw[counter+hadstuffing+4]&0x0F)
199 iangle = int(0x70|raw[counter+hadstuffing+4]&0x0F)
159 else:
200 else:
160 iangle = int(raw[counter+hadstuffing+4])
201 iangle = int(raw[counter+hadstuffing+4])
161 else:
202 else:
162 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
203 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
163 break
204 break
164
205
165 if (counter+hadstuffing+5<raw_size-4):
206 if (counter+hadstuffing+5<raw_size-4):
166 if raw[counter+hadstuffing+5]==HEADER-1:
207 if raw[counter+hadstuffing+5]==HEADER-1:
167 hadstuffing+=1
208 hadstuffing+=1
168 iangle = iangle + int((0x70|raw[counter+hadstuffing+5]&0x0F)<<8)
209 iangle = iangle + int((0x70|raw[counter+hadstuffing+5]&0x0F)<<8)
169 else:
210 else:
170 iangle = iangle + int(raw[counter+hadstuffing+5]<<8)
211 iangle = iangle + int(raw[counter+hadstuffing+5]<<8)
171 else:
212 else:
172 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
213 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
173 break
214 break
174
215
175 if (counter+hadstuffing+6<raw_size-4):
216 if (counter+hadstuffing+6<raw_size-4):
176 if raw[counter+hadstuffing+6]==HEADER-1:
217 if raw[counter+hadstuffing+6]==HEADER-1:
177 hadstuffing+=1
218 hadstuffing+=1
178 ispeed = int(0x70|raw[counter+hadstuffing+6]&0x0F)
219 ispeed = int(0x70|raw[counter+hadstuffing+6]&0x0F)
179 else:
220 else:
180 ispeed = int(raw[counter+hadstuffing+6])
221 ispeed = int(raw[counter+hadstuffing+6])
181 else:
222 else:
182 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
223 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
183 break
224 break
184
225
185 if (counter+hadstuffing+7<raw_size-4):
226 if (counter+hadstuffing+7<raw_size-4):
186 if raw[counter+hadstuffing+7]==HEADER-1:
227 if raw[counter+hadstuffing+7]==HEADER-1:
187 hadstuffing+=1
228 hadstuffing+=1
188 ispeed = ispeed + int((0x70|raw[counter+hadstuffing+7]&0x0F)<<8)
229 ispeed = ispeed + int((0x70|raw[counter+hadstuffing+7]&0x0F)<<8)
189 else:
230 else:
190 ispeed = ispeed + int(raw[counter+hadstuffing+7]<<8)
231 ispeed = ispeed + int(raw[counter+hadstuffing+7]<<8)
191 else:
232 else:
192 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
233 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
193 break
234 break
194
235
195 if (counter+2<raw_size-4):
236 if (counter+2<raw_size-4):
196 if raw[counter+2]==RX_AZIMUTH:
237 if raw[counter+2]==RX_AZIMUTH:
197 AzPosition.append(iangle*360.0/USHRT_MAX)
238 AzPosition.append(iangle*360.0/USHRT_MAX)
198 AzSpeed.append(((ispeed-SHRT_MIN)*(MAX_SPEED-MIN_SPEED)/(SHRT_MAX-SHRT_MIN))+MIN_SPEED)
239 AzSpeed.append(((ispeed-SHRT_MIN)*(MAX_SPEED-MIN_SPEED)/(SHRT_MAX-SHRT_MIN))+MIN_SPEED)
199 elif raw[counter+2]==RX_ELEVATION:
240 elif raw[counter+2]==RX_ELEVATION:
200 ElPosition.append(iangle*360.0/USHRT_MAX)
241 ElPosition.append(iangle*360.0/USHRT_MAX)
201 ElSpeed.append(((ispeed-SHRT_MIN)*(MAX_SPEED-MIN_SPEED)/(SHRT_MAX-SHRT_MIN))+MIN_SPEED)
242 ElSpeed.append(((ispeed-SHRT_MIN)*(MAX_SPEED-MIN_SPEED)/(SHRT_MAX-SHRT_MIN))+MIN_SPEED)
202 else:
243 else:
203 counter+=1
244 counter+=1
204 continue
245 continue
205 else:
246 else:
206 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
247 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
207 break
248 break
208
249
209 counter = counter+hadstuffing+13
250 counter = counter+hadstuffing+13
210 else:
251 else:
211 counter+=1
252 counter+=1
212 continue
253 continue
213 else:
254 else:
214 counter+=1
255 counter+=1
215 continue
256 continue
216 else:
257 else:
217 counter+=1
258 counter+=1
218 continue
259 continue
219
260
220 az = numpy.array(AzPosition)
261 az = numpy.array(AzPosition)
221 az[numpy.where(az>=359.5)] = 0
262 az[numpy.where(az>=359.5)] = 0
222
263
223 saz = numpy.array(AzSpeed)
264 saz = numpy.array(AzSpeed)
224 saz[numpy.where(saz>=28)] = saz[(saz>=28)]-360
265 saz[numpy.where(saz>=28)] = saz[(saz>=28)]-360
225
266
226 el = numpy.array(ElPosition)
267 el = numpy.array(ElPosition)
227 el[numpy.where((190 <= el) & (el <= 360))] = el[(190 <= el) & (el<= 360)] - 360
268 el[numpy.where((190 <= el) & (el <= 360))] = el[(190 <= el) & (el<= 360)] - 360
228
269
229 sel = numpy.array(ElSpeed)
270 sel = numpy.array(ElSpeed)
230 sel[numpy.where(sel>=28)] = sel[(sel>=28)]-360
271 sel[numpy.where(sel>=28)] = sel[(sel>=28)]-360
231
272
232 return az, saz, el, sel, int(Timestamp)
273 return az, saz, el, sel, int(Timestamp)
233
274
234 def get_power(tx):
275 def get_power(tx):
235
276
236 url = 'http://{}/status.xml'.format(tx)
277 url = 'http://{}/status.xml'.format(tx)
237 try:
278 try:
238 page = requests.get(url, timeout=0.2)
279 page = requests.get(url, timeout=0.2)
239 soup = BeautifulSoup(page.content, 'xml')
280 soup = BeautifulSoup(page.content, 'xml')
240 power = float(soup.find('bucAOutputpower').text)
281 power = float(soup.find('bucAOutputpower').text)
241 except:
282 except:
242 power = 0.0
283 power = 0.0
243 return power
284 return power
244
285
245
286
246 @app.route('/')
287 @app.route('/')
247 def index():
288 def index():
248
289
249 return render_template('index.html')
290 return render_template('index.html')
250
291
251 @app.route('/start', methods=['POST'])
292 @app.route('/start', methods=['POST'])
252 def start_proc():
293 def start_proc():
253
294
254 global EXPERIMENT, RUNNING
295 global EXPERIMENT, RUNNING
255
296
256 EXPERIMENT.update(request.get_json())
297 EXPERIMENT.update(request.get_json())
257 RUNNING = True
298 RUNNING = True
258 print(EXPERIMENT, flush=True)
299 print(EXPERIMENT, flush=True)
259 path = os.path.join(DATA_PATH, EXPERIMENT['name'])
300 path = os.path.join(DATA_PATH, EXPERIMENT['name'])
260 if not os.path.exists(path):
301 if not os.path.exists(path):
261 os.makedirs(path)
302 os.makedirs(path)
262 fo = open(os.path.join(path, 'experiment.conf'), 'w')
303 fo = open(os.path.join(path, 'experiment.conf'), 'w')
263 fo.write(json.dumps(EXPERIMENT, indent=2))
304 fo.write(json.dumps(EXPERIMENT, indent=2))
264 fo.close()
305 fo.close()
265
306
266 return jsonify({'start': 'ok'})
307 return jsonify({'start': 'ok'})
267
308
268 @app.route('/stop')
309 @app.route('/stop')
269 def stop_proc():
310 def stop_proc():
270
311
271 global RUNNING
312 global RUNNING, DEBUG, HDF
313
272 RUNNING = False
314 RUNNING = False
315 DEBUG = False
316 HDF.reset()
273
317
274 return jsonify({'stop': 'ok'})
318 return jsonify({'stop': 'ok'})
275
319
276 @app.route('/status')
320 @app.route('/status')
277 def status_proc():
321 def status_proc():
278
322
279 global RUNNING
323 global RUNNING
280
324
281 return jsonify({'status': RUNNING})
325 return jsonify({'status': RUNNING})
282
326
283 @app.route('/run')
327 @app.route('/run')
284 def run_proc():
328 def run_proc():
285
329
286 global RUNNING, EXPERIMENT
330 global RUNNING, EXPERIMENT, DEBUG
331 if request.args.get('debug', False):
332 DEBUG = True
287 path = os.path.join(DATA_PATH, 'TEST')
333 path = os.path.join(DATA_PATH, 'TEST')
288 if not os.path.exists(path):
334 if not os.path.exists(path):
289 os.makedirs(path)
335 os.makedirs(path)
290 EXPERIMENT['name'] = 'TEST'
336 EXPERIMENT['name'] = 'TEST'
291 RUNNING = True
337 RUNNING = True
292
338
293 return redirect('/')
339 return redirect('/')
294
340
295 @socketio.on('publish')
341 @socketio.on('publish')
296 def handle_publish(json_str):
342 def handle_publish(json_str):
297 data = json.loads(json_str)
343 data = json.loads(json_str)
298 mqtt.publish(data['topic'], data['message'], data['qos'])
344 mqtt.publish(data['topic'], data['message'], data['qos'])
299
345
300 @socketio.on('subscribe')
346 @socketio.on('subscribe')
301 def handle_subscribe(json_str):
347 def handle_subscribe(json_str):
302 data = json.loads(json_str)
348 data = json.loads(json_str)
303 mqtt.subscribe(data['topic'], data['qos'])
349 mqtt.subscribe(data['topic'], data['qos'])
304
350
305 @socketio.on('unsubscribe_all')
351 @socketio.on('unsubscribe_all')
306 def handle_unsubscribe_all():
352 def handle_unsubscribe_all():
307 mqtt.unsubscribe_all()
353 mqtt.unsubscribe_all()
308
354
309 @mqtt.on_connect()
355 @mqtt.on_connect()
310 def handle_connect(client, userdata, flags, rc):
356 def handle_connect(client, userdata, flags, rc):
311 mqtt.subscribe(os.environ.get('PEDESTAL_TOPIC', 'JRO_topic'))
357 mqtt.subscribe(os.environ.get('PEDESTAL_TOPIC', 'JRO_topic'))
312
358
313 @mqtt.on_message()
359 @mqtt.on_message()
314 def handle_mqtt_message(client, userdata, message):
360 def handle_mqtt_message(client, userdata, message):
315
361
316 global RUNNING
362 global RUNNING, HDF
317
363
318 payload = message.payload.decode()
364 payload = message.payload.decode()
319 az, saz, el, sel, tm = getSpeedPosition(payload)
365 az, saz, el, sel, tm = getSpeedPosition(payload)
320 pwA = get_power(os.environ['TXA_SITE'])
366 powa = get_power(os.environ['TXA_SITE'])
321 pwB = get_power(os.environ['TXB_SITE'])
367 powb = get_power(os.environ['TXB_SITE'])
322 if RUNNING:
323 HDF.write({'az':az, 'el':el, 'saz':saz, 'sel':sel, 'timestamp':tm})
324 times = numpy.arange(tm, tm+1, 0.1, dtype=float)
368 times = numpy.arange(tm, tm+1, 0.1, dtype=float)
325
369
326 data = dict(
370 data = dict(
327 az =az[::10].tolist(),
371 az =az[::10].tolist(),
328 el =el[::10].tolist(),
372 el =el[::10].tolist(),
329 saz =saz[::10].tolist(),
373 saz =saz[::10].tolist(),
330 sel =sel[::10].tolist(),
374 sel =sel[::10].tolist(),
331 topic = message.topic,
375 topic = message.topic,
332 payload = payload,
376 payload = payload,
333 qos = message.qos,
377 qos = message.qos,
334 timestamp = times.tolist(),
378 timestamp = times.tolist(),
335 pwa = [pwa],
379 powa = [powa],
336 pwb = [pwb],
380 powb = [powb],
337 status = 'Running' if RUNNING else 'Not Running'
381 status = 'Running' if RUNNING else 'Not Running'
338 )
382 )
339
383
340 socketio.emit('mqtt_message', data=data)
384 socketio.emit('mqtt_message', data=data)
341
385
386 if RUNNING:
387 HDF.write({'az':az, 'el':el, 'saz':saz, 'sel':sel, 'timestamp':tm, 'powa':powa, 'powb':powb})
388 HDF.write_power({'timestamp':tm, 'powa':powa, 'powb':powb})
389
342 @mqtt.on_log()
390 @mqtt.on_log()
343 def handle_logging(client, userdata, level, buf):
391 def handle_logging(client, userdata, level, buf):
344 # print(level, buf)
392 # print(level, buf)
345 pass
393 pass
346
394
347 if __name__ == '__main__':
395 if __name__ == '__main__':
348 socketio.run(app, host='0.0.0.0', port=5000, use_reloader=False, debug=True)
396 socketio.run(app, host='0.0.0.0', port=5000, use_reloader=False, debug=True)
@@ -1,194 +1,181
1 {% extends "bootstrap/base.html" %}
1 {% extends "bootstrap/base.html" %}
2 {% block title %}SOPHY monitor{% endblock %}
2 {% block title %}SOPHY monitor{% endblock %}
3
3
4 {% block styles %}
4 {% block styles %}
5 {{ super() }}
5 {{ super() }}
6 {% endblock %}
6 {% endblock %}
7
7
8 {% block scripts %}
8 {% block scripts %}
9 {{ super() }}
9 {{ super() }}
10 <script type="text/javascript" src="{{ url_for('static', filename='js/plotly-latest.min.js') }}"></script>
10 <script type="text/javascript" src="{{ url_for('static', filename='js/plotly-latest.min.js') }}"></script>
11 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.min.js"></script>
11 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.min.js"></script>
12 <script type="text/javascript" charset="utf-8">
12 <script type="text/javascript" charset="utf-8">
13 $(document).ready(function() {
13 $(document).ready(function() {
14 var socket = io.connect('http://' + document.domain + ':' + location.port);
14 var socket = io.connect('http://' + document.domain + ':' + location.port);
15
15
16 socket.on('connect', function(data) {
16 socket.on('connect', function(data) {
17 console.log('Initialazing plots...');
17 console.log('Initialazing plots...');
18 makePlot("plot-az");
18 makePlot("plot-pos", 2, ["Azimuth", "Elevation"]);
19 makePlot("plot-el");
19 makePlot("plot-speed", 2, ["AZ Speed", "EL Speed"]);
20 makePlot("plot-saz");
20 makePlot("plot-tx", 2, ["Power A", "Power B"]);
21 makePlot("plot-sel");
22 makePlot("plot-tx");
23
24 })
21 })
25
22
26 socket.on('mqtt_message', function(data) {
23 socket.on('mqtt_message', function(data) {
27 console.log(data.topic);
24 console.log(data.topic);
28 var text = '(' + data['topic'] + ' qos: ' + data['qos'] + ') ' + data['payload'];
25 var text = '(' + data['topic'] + ' qos: ' + data['qos'] + ') ' + data['payload'];
29 $('#subscribe_messages').val(text);
26 $('#subscribe_messages').val(text);
30 $('#radar_status').val(data.status);
27 $('#radar_status').val(data.status);
31 streamPlot("plot-az", data.timestamp, data.az );
28 streamPlot2("plot-pos", data.timestamp, data.az, data.el );
32 streamPlot("plot-el", data.timestamp, data.el );
29 streamPlot2("plot-speed", data.timestamp, data.saz, data.sel );
33 streamPlot("plot-saz", data.timestamp, data.saz );
30 streamPlot2("plot-tx", data.timestamp, data.powa, data.powb );
34 streamPlot("plot-sel", data.timestamp, data.sel );
35 })
31 })
36 });
32 });
37
33
38 function makePlot(div){
34 function makePlot(div, n=1, names=["", ""]){
39 var plotDiv = document.getElementById(div);
35 var plotDiv = document.getElementById(div);
40 var traces = [{
36 var traces = [];
41 x: [],
37 for (let i = 0; i < n; i++) {
42 y: []
38 traces.push({x: [], y: [], name: names[i]});
43 }];
39 }
44 var layout = {
40 var layout = {
45 height: 350,
41 height: 350,
46 font: {size: 12},
42 font: {size: 12},
47 margin: { t: 0 },
43 margin: { t: 0 },
48 xaxis: {
44 xaxis: {
49 type: 'date'
45 type: 'date'
50 },
46 },
51 //yaxis: {
52 // range: [0, 110]
53 //}
54 };
47 };
55
48
56 Plotly.plot(plotDiv, traces, layout);
49 Plotly.plot(plotDiv, traces, layout);
57 };
50 };
58
51
59 function streamPlot(div, x, y ){
52 function streamPlot(div, x, y ){
60 var plotDiv = document.getElementById(div);
53 var plotDiv = document.getElementById(div);
61 if (plotDiv.data[0].x.length > 499){
54 if (plotDiv.data[0].x.length > 499){
62 plotDiv.data[0].x = plotDiv.data[0].x.slice(-500)
55 plotDiv.data[0].x = plotDiv.data[0].x.slice(-500)
63 plotDiv.data[0].y = plotDiv.data[0].y.slice(-500)
56 plotDiv.data[0].y = plotDiv.data[0].y.slice(-500)
64 }
57 }
65 var tm = x.map(i => new Date(i*1000));
58 var tm = x.map(i => new Date(i*1000));
66 var values = y.map(i => Math.round(i * 100) / 100);
59 var values = y.map(i => Math.round(i * 100) / 100);
67 var data_update = {x: [tm], y: [values]}
60 var data_update = {x: [tm], y: [values]}
68 //var windowDateObj = getWindow(x)
69 //var layout_update = {xaxis: {
70 // range: [windowDateObj, x[x.length - 1]],
71 // rangeslider: {range: [plot_start, x[x.length - 1]]}
72 //}};
73 //Plotly.update(plotDiv, {}, layout_update)
74 Plotly.extendTraces(plotDiv, data_update, [0])
61 Plotly.extendTraces(plotDiv, data_update, [0])
75 };
62 };
63
64 function streamPlot2(div, x, y1, y2 ){
65 var plotDiv = document.getElementById(div);
66 if (plotDiv.data[0].x.length > 499){
67 plotDiv.data[0].x = plotDiv.data[0].x.slice(-500)
68 plotDiv.data[0].y = plotDiv.data[0].y.slice(-500)
69 plotDiv.data[1].x = plotDiv.data[1].x.slice(-500)
70 plotDiv.data[1].y = plotDiv.data[1].y.slice(-500)
71 }
72 var tm = x.map(i => new Date(i*1000));
73 var values1 = y1.map(i => Math.round(i * 100) / 100);
74 var values2 = y2.map(i => Math.round(i * 100) / 100);
75 var data_update = {x: [tm, tm], y: [values1, values2]}
76 Plotly.extendTraces(plotDiv, data_update, [0, 1])
77 };
76
78
77 </script>
79 </script>
78 {% endblock %}
80 {% endblock %}
79
81
80 {% block content %}
82 {% block content %}
81 <div class="container-fluid">
83 <div class="container-fluid">
82 <div class="row">
84 <div class="row">
83 <div class="col-xs-12">
85 <div class="col-xs-12">
84 <h1>SOPHy monitor</h1>
86 <h1>SOPHy monitor</h1>
85 </div>
87 </div>
86 </div>
88 </div>
87 <div class="row">
89 <div class="row">
88 <!--Messages-->
90 <!--Messages-->
89 <div class="col-xs-6">
91 <div class="col-xs-6">
90 <div class="panel panel-default">
92 <div class="panel panel-default">
91 <div class="panel-heading">
93 <div class="panel-heading">
92 <h3 class="panel-title">Status</h3>
94 <h3 class="panel-title">Status</h3>
93 </div>
95 </div>
94 <div class="panel-body">
96 <div class="panel-body">
95 <div class="col-xs-12">
97 <div class="col-xs-12">
96 <div class="row">
98 <div class="row">
97 <div class="form-horizontal">
99 <div class="form-horizontal">
98 <div class="form-group">
100 <div class="form-group">
99 <div class="col-xs-12">
101 <div class="col-xs-12">
100 <label for="radar_status">Status</label>
102 <label for="radar_status">Status</label>
101 <input id="radar_status" class="form-control" value="Not Running", disabled></input>
103 <input id="radar_status" class="form-control" value="Not Running", disabled></input>
102 </div>
104 </div>
103 </div>
105 </div>
104 <div class="form-group">
106 <div class="form-group">
105 <div class="col-xs-12">
107 <div class="col-xs-12">
106 <label for="subscribe_messages">MQTT Message</label>
108 <label for="subscribe_messages">MQTT Message</label>
107 <textarea id="subscribe_messages" class="form-control" rows=8></textarea>
109 <textarea id="subscribe_messages" class="form-control" rows=8></textarea>
108 </div>
110 </div>
109 </div>
111 </div>
110 </div>
112 </div>
111 </div>`
113 </div>`
112 </div>
114 </div>
113 </div>
115 </div>
114 </div>
116 </div>
115 </div>
117 </div>
116 <!--Azimuth-->
118 <!--RX LOG-->
117 <div class="col-xs-6">
118 <div class="panel panel-default">
119 <div class="panel-heading">
120 <h3 class="panel-title">Pedestal Azimuth</h3>
121 </div>
122 <div class="panel-body">
123 <div class="col-xs-12">
124 <div class="row">
125 <div id="plot-az"></div>
126 </div>
127 </div>
128 </div>
129 </div>
130 </div>
131 <!--Elevation-->
132 <div class="col-xs-6">
119 <div class="col-xs-6">
133 <div class="panel panel-default">
120 <div class="panel panel-default">
134 <div class="panel-heading">
121 <div class="panel-heading">
135 <h3 class="panel-title">Pedestal Elevation</h3>
122 <h3 class="panel-title">RX log</h3>
136 </div>
123 </div>
137 <div class="panel-body">
124 <div class="panel-body">
138 <div class="col-xs-12">
125 <div class="col-xs-12">
139 <div class="row">
126 <div class="row">
140 <div id="plot-el"></div>
127 <div></div>
141 </div>
128 </div>
142 </div>
129 </div>
143 </div>
130 </div>
144 </div>
131 </div>
145 </div>
132 </div>
146 <!--Azimuth Speed-->
133 <!--Position-->
147 <div class="col-xs-6">
134 <div class="col-xs-6">
148 <div class="panel panel-default">
135 <div class="panel panel-default">
149 <div class="panel-heading">
136 <div class="panel-heading">
150 <h3 class="panel-title">Pedestal Azimuth Speed</h3>
137 <h3 class="panel-title">Pedestal Position</h3>
151 </div>
138 </div>
152 <div class="panel-body">
139 <div class="panel-body">
153 <div class="col-xs-12">
140 <div class="col-xs-12">
154 <div class="row">
141 <div class="row">
155 <div id="plot-saz"></div>
142 <div id="plot-pos"></div>
156 </div>
143 </div>
157 </div>
144 </div>
158 </div>
145 </div>
159 </div>
146 </div>
160 </div>
147 </div>
161 <!--Elevation Speed-->
148 <!--Speed-->
162 <div class="col-xs-6">
149 <div class="col-xs-6">
163 <div class="panel panel-default">
150 <div class="panel panel-default">
164 <div class="panel-heading">
151 <div class="panel-heading">
165 <h3 class="panel-title">Pedestal Elevation Speed</h3>
152 <h3 class="panel-title">Pedestal Speed</h3>
166 </div>
153 </div>
167 <div class="panel-body">
154 <div class="panel-body">
168 <div class="col-xs-12">
155 <div class="col-xs-12">
169 <div class="row">
156 <div class="row">
170 <div id="plot-sel"></div>
157 <div id="plot-speed"></div>
171 </div>
158 </div>
172 </div>
159 </div>
173 </div>
160 </div>
174 </div>
161 </div>
175 </div>
162 </div>
176 <!--TX power-->
163 <!--TX power-->
177 <div class="col-xs-6">
164 <div class="col-xs-6">
178 <div class="panel panel-default">
165 <div class="panel panel-default">
179 <div class="panel-heading">
166 <div class="panel-heading">
180 <h3 class="panel-title">SSPA's power</h3>
167 <h3 class="panel-title">SSPA's power</h3>
181 </div>
168 </div>
182 <div class="panel-body">
169 <div class="panel-body">
183 <div class="col-xs-12">
170 <div class="col-xs-12">
184 <div class="row">
171 <div class="row">
185 <div id="plot-tx"></div>
172 <div id="plot-tx"></div>
186 </div>
173 </div>
187 </div>
174 </div>
188 </div>
175 </div>
189 </div>
176 </div>
190 </div>
177 </div>
191 </div>
178 </div>
192 </div>
179 </div>
193 {{debug}}
180 {{debug}}
194 {% endblock %} No newline at end of file
181 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now