##// END OF EJS Templates
1)Update schain contenainer - 2)Add acq template - 3)Add AZ OFFSET pedestal parameter - 4)Add scheduler (sudo crontab) - 5)Add sirm-job container
eynilupu -
r438:4bd0c7e20a9b
parent child
Show More
@@ -0,0 +1,77
1 #!/usr/bin/env python
2
3 import os, sys
4 import signal
5 import time
6 import json
7 import paho.mqtt.client as paho
8 from watchdog.events import FileSystemEventHandler
9 from watchdog.observers.polling import PollingObserver
10 import platform
11
12 MQTTHOST = os.getenv('BROKER_URL', '192.168.1.130')
13 PROCSITE = os.getenv('PROC_SITE', 'sophy-proc')
14 MQTTPORT = int(os.getenv('MQTTPORT', 1883))
15 MQTTUSERNAME = os.getenv('MQTTUSERNAME', None)
16 MQTTPASSWORD = os.getenv('MQTTPASSWORD', None)
17 MQTTWATCHDIR = '/data'
18 MQTTQOS = int(os.getenv('MQTTQOS', 0))
19 MQTTRETAIN = int(os.getenv('MQTTRETAIN', 0))
20
21 MQTTFIXEDTOPIC = os.getenv('MQTTFIXEDTOPIC', 'sophy/acq')
22
23 WATCHDEBUG = os.getenv('WATCHDEBUG', 1)
24
25 # Publish with retain (True or False)
26 if MQTTRETAIN == 1:
27 MQTTRETAIN=True
28 else:
29 MQTTRETAIN=False
30
31 OS = platform.system()
32
33 clientid = 'sophy-acq-%s' % os.getpid()
34 mqtt = paho.Client(clientid, clean_session=True)
35
36 if MQTTUSERNAME is not None or MQTTPASSWORD is not None:
37 mqtt.username_pw_set(MQTTUSERNAME, MQTTPASSWORD)
38
39 def on_publish(mosq, userdata, mid):
40 pass
41
42 def on_disconnect(mosq, userdata, rc):
43 print ("disconnected")
44 time.sleep(1)
45
46 def on_message(client, userdata, msg):
47 payload = msg.payload.decode()
48 print(f"Received `{payload}` from `{msg.topic}` topic", flush=True)
49
50 def signal_handler(signal, frame):
51 """ Bail out at the top level """
52
53 mqtt.loop_stop()
54 mqtt.disconnect()
55
56 sys.exit(0)
57
58 def main():
59 print('Sophy acquisition monitor will publish messages to {}'.format(MQTTFIXEDTOPIC), flush=True)
60 mqtt.on_disconnect = on_disconnect
61 mqtt.on_publish = on_publish
62 mqtt.connect(MQTTHOST, MQTTPORT)
63 mqtt.subscribe('sophy/control')
64 mqtt.on_message = on_message
65
66 mqtt.loop_start()
67
68 signal.signal(signal.SIGINT, signal_handler)
69
70 test = json.dumps({'file': '', 'size': ''})
71
72 while 1:
73 mqtt.publish(MQTTFIXEDTOPIC, test, qos=MQTTQOS, retain=MQTTRETAIN)
74 time.sleep(1)
75
76 if __name__ == '__main__':
77 main() No newline at end of file
@@ -0,0 +1,63
1 {% extends "bootstrap/base.html" %}
2 {% block title %}SOPHY monitor{% endblock %}
3
4 {% block styles %}
5 {{ super() }}
6 {% endblock %}
7
8 {% block scripts %}
9 {{ super() }}
10 <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" charset="utf-8">
12 $(document).ready(function() {
13 var socket = io.connect('http://' + document.domain + ':' + location.port);
14
15 socket.on('connect', function(data) {
16 console.log('Connecting... OK');
17 })
18 socket.on('mqtt_message', function(data) {
19 console.log(data.topic);
20 if (data['topic'].includes('acq')) {
21 var payload = JSON.parse(data.payload);
22 console.log(payload);
23 }
24 })
25 });
26
27 </script>
28 {% endblock %}
29
30 {% block content %}
31 <div class="container-fluid">
32 <div class="row">
33 <div class="col-xs-12">
34 <h1>SOPHy monitor</h1>
35 </div>
36 </div>
37 <div class="row">
38 <!--Messages-->
39 <div class="col-xs-12">
40 <div class="panel panel-default">
41 <div class="panel-heading">
42 <h3 class="panel-title">MQTT</h3>
43 </div>
44 <div class="panel-body">
45 <div class="col-xs-12">
46 <div class="row">
47 <div class="form-horizontal">
48 <div class="form-group">
49 <div class="col-xs-12">
50 <label for="mqtt_acq">Log Message</label>
51 <textarea id="mqtt_acq" class="form-control" rows=10></textarea>
52 </div>
53 </div>
54 </div>
55 </div>`
56 </div>
57 </div>
58 </div>
59 </div>
60 </div>
61 </div>
62 {{debug}}
63 {% endblock %} No newline at end of file
@@ -0,0 +1,40
1 from django.core.management.base import BaseCommand
2 from apps.main.models import Experiment
3 from django.shortcuts import get_object_or_404
4 import os
5 import time
6 import requests
7
8 class Command(BaseCommand):
9 """
10 Create a superuser if none exist
11 Example:
12 manage.py reset_exp --pk=1
13 """
14
15 def handle(self, *args, **options):
16 if check_experiment():
17 #value = 36
18 #experiment = get_object_or_404(Experiment, pk=value)
19 ##time.sleep(15)
20 #experiment.stop()
21 #self.stdout.write(f'Experiment "{value}" was stoped')
22 #time.sleep(15)
23 #experiment.start()
24 #self.stdout.write(f'Experiment "{value}" is running')
25 value = 36
26 self.stdout.write(f'Experiment "{value}" is running')
27 else:
28 pass
29
30 def check_experiment():
31 try:
32 url = 'http://{}/status'.format(os.environ.get('PROC_SITE', 'sophy-proc'))
33 response = requests.get(url, timeout=0.4)
34 if response.status_code == 200:
35 data = response.json()
36 return data['status']
37 else:
38 return False
39 except:
40 return False No newline at end of file
@@ -0,0 +1,41
1 #!/usr/local/bin/python
2
3 import os
4 import sys
5 from datetime import datetime, timedelta
6 from time import sleep
7 import django
8
9 sys.path.append('/workspace/sirm')
10 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "radarsys.settings")
11 django.setup()
12
13 from apps.main.models import Experiment
14
15 exp = Experiment.objects.get(pk=36)
16
17 N = 0
18 ok = True
19
20 while True:
21 if N >=3:
22 ok = False
23 print('Stopping Experiment {}'.format(exp.name))
24 exp.stop()
25 sleep(30)
26 print('Starting Experiment {}'.format(exp.name))
27 exp.start()
28 dt = datetime.utcnow()
29 sleep(30)
30 path = os.path.join(exp.reception_rx.datadir, 'ch0', dt.strftime('%Y-%m-%dT%H-00-00'))
31 path = path.replace('DATA_RM/DATA', 'data')
32 if not os.path.exists(path):
33 N += 1
34 continue
35 else:
36 break
37
38 if ok:
39 print('Experiment started ok in {} try at {}!!!'.format(N+1, dt-timedelta(hours=5)))
40 else:
41 print('Error starting Experiment') No newline at end of file
@@ -1,35 +1,38
1 1 #General settings
2 2 LC_ALL=C.UTF-8
3 3 SIRM_SITE=<SIRM SITE>
4 4 PROC_SITE=<PROC SITE>
5 5 CAM_SITE=<CAM SITE>
6 6 SCHAIN_SITE=<SCHAIN SITE>
7 7 GENERAL_PORT=<GENERAL PORT>
8 8 BROKER_URL=<BROKER SITE>
9 9 SOPHY_TOPIC=<SOPHY TOPIC>
10 10 TXA_SITE=<IP TXA>
11 11 TXB_SITE=<IP TXB>
12 12 SIRM_MAX_UPLOAD_SIZE_MB=20
13 13
14 #PEDESTAL - AZ OFFSET
15 AZ_OFFSET=26.27
16
14 17 #Postgres settings
15 18 POSTGRES_PORT_5432_TCP_ADDR=sirm-postgres
16 19 POSTGRES_PORT_5432_TCP_PORT=5432
17 20 DB_NAME=radarsys
18 21 DB_USER=docker
19 22 DB_PASSWORD=docker
20 23 PGDATA=/var/lib/postgresql/data
21 24
22 25 #Volumes - path
23 26 EXPOSE_SIRM=./volumes/sirm
24 27 EXPOSE_PROC=./volumes/proc
25 28 EXPOSE_SCHAIN=./volumes/schain
26 29 EXPOSE_CAM=/path/to/cam
27 30 EXPOSE_NAS=/path/to/nas_data
28 31 EXPOSE_PGDATA=/path/to/pg_data
29 32 EXPOSE_CERTS=/path/to/certs
30 33 EXPOSE_DHPARAM=/path/to/dhparam
31 34
32 35 #Superuser settings
33 36 SIRM_USER=admin
34 37 SIRM_PASSWORD=soporte
35 38 SIRM_EMAIL=admin@igp.gob.pe No newline at end of file
@@ -1,10 +1,13
1 1 volumes/pg_data
2 2 volumes/dhparam
3 3 volumes/certs
4 4 volumes/sirm/static_files/*
5 5 volumes/cam
6 6 volumes/sirm/.gitkeep
7 volumes/sirm/log.log
8 volumes/schain/schain
7 9 migrations
8 10 *.pyc
9 11 *initial.py
10 .DS_Store No newline at end of file
12 .DS_Store
13 .env No newline at end of file
@@ -1,243 +1,269
1 1 # docker-compose up -d --build
2 2 version: '3'
3 3
4 4 volumes:
5 5 sirm_web:
6 6 name: sirm_web
7 7 driver: local
8 8 driver_opts:
9 9 type: "none"
10 10 o: "bind"
11 11 device: "${EXPOSE_SIRM}"
12 12 sirm_pgdata:
13 13 name: sirm_pgdata
14 14 driver: local
15 15 driver_opts:
16 16 type: "none"
17 17 o: "bind"
18 18 device: "${EXPOSE_PGDATA}"
19 19 sirm_certs:
20 20 name: sirm_certs
21 21 driver: local
22 22 driver_opts:
23 23 type: "none"
24 24 o: "bind"
25 25 device: "${EXPOSE_CERTS}"
26 26 sirm_dhparam:
27 27 name: sirm_dhparam
28 28 driver: local
29 29 driver_opts:
30 30 type: "none"
31 31 o: "bind"
32 32 device: "${EXPOSE_DHPARAM}"
33 33 sirm_proc:
34 34 name: sirm_proc
35 35 driver: local
36 36 driver_opts:
37 37 type: "none"
38 38 o: "bind"
39 39 device: "${EXPOSE_PROC}"
40 40 sirm_nas:
41 41 name: sirm_nas
42 42 driver: local
43 43 driver_opts:
44 44 type: "none"
45 45 o: "bind"
46 46 device: "${EXPOSE_NAS}"
47 47 sirm_cam:
48 48 name: sirm_cam
49 49 driver: local
50 50 driver_opts:
51 51 type: "none"
52 52 o: "bind"
53 53 device: "${EXPOSE_CAM}"
54 54 sirm_schain:
55 55 name: sirm_schain
56 56 driver: local
57 57 driver_opts:
58 58 type: "none"
59 59 o: "bind"
60 60 device: "${EXPOSE_SCHAIN}"
61 61
62 62 services:
63 63 sirm-nginx-proxy:
64 64 container_name: sirm-nginx-proxy
65 65 restart: always
66 66 build:
67 67 context: ./images/
68 68 dockerfile: nginx-proxy/Dockerfile
69 69 args:
70 70 - SIRM_MAX_UPLOAD_SIZE_MB=${SIRM_MAX_UPLOAD_SIZE_MB}
71 71 depends_on:
72 72 - sirm-web
73 73 networks:
74 74 - frontend_sirm
75 75 - backend_sirm
76 76 ports:
77 77 - 0.0.0.0:${GENERAL_PORT}:80
78 78 volumes:
79 79 - /var/run/docker.sock:/tmp/docker.sock:ro
80 80 - sirm_certs:/etc/nginx/certs:ro
81 81 - sirm_dhparam:/etc/nginx/dhparam
82 82 logging:
83 83 driver: "json-file"
84 84 options:
85 85 max-size: "12m"
86 86
87 87 sirm-web:
88 88 container_name: 'sirm-web'
89 89 restart: always
90 90 build:
91 91 context: .
92 92 environment:
93 93 - LC_ALL=${LC_ALL}
94 94 - DB_USER=${DB_USER}
95 95 - DB_NAME=${DB_NAME}
96 96 - DB_PASSWORD=${DB_PASSWORD}
97 97 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
98 98 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
99 99 - EXPOSE_NAS=${EXPOSE_NAS}
100 100 - PROC_SITE=${PROC_SITE}
101 101 - SIRM_USER=${SIRM_USER}
102 102 - SIRM_PASSWORD=${SIRM_PASSWORD}
103 103 - SIRM_EMAIL=${SIRM_EMAIL}
104 - AZ_OFFSET=${AZ_OFFSET}
104 105 - VIRTUAL_HOST=${SIRM_SITE}
105 106 volumes:
106 107 - 'sirm_web:/workspace/sirm'
108 - 'sirm_nas:/data'
107 109 depends_on:
108 110 - sirm-postgres
109 111 networks:
110 112 - frontend_sirm
111 113 - backend_sirm
114 labels:
115 ofelia.enabled: "true"
116 ofelia.job-exec.datecron.schedule: "@every 5s"
117 ofelia.job-exec.datecron.command: "python manage.py reset_exp"
118 logging:
119 driver: "json-file"
120 options:
121 max-size: "12m"
122
123 sirm-job:
124 container_name: 'sirm-job'
125 image: mcuadros/ofelia:latest
126 depends_on:
127 - sirm-web
128 networks:
129 - frontend_sirm
130 - backend_sirm
131 command: daemon --docker
132 volumes:
133 - /var/run/docker.sock:/var/run/docker.sock:ro
134 labels:
135 ofelia.job-local.my-test-job.schedule: "@every 5s"
136 ofelia.job-local.my-test-job.command: "date"
112 137 logging:
113 138 driver: "json-file"
114 139 options:
115 140 max-size: "12m"
116 141
117 142 sirm-postgres:
118 143 container_name: 'sirm-postgres'
119 144 restart: always
120 145 build:
121 146 context: ./images/
122 147 dockerfile: postgres/Dockerfile
123 148 args:
124 149 - PGDATA=${PGDATA}
125 150 environment:
126 151 - LC_ALL=${LC_ALL}
127 152 - DB_USER=${DB_USER}
128 153 - DB_NAME=${DB_NAME}
129 154 - DB_PASSWORD=${DB_PASSWORD}
130 155 - POSTGRES_PORT_5432_TCP_ADDR=${POSTGRES_PORT_5432_TCP_ADDR}
131 156 - POSTGRES_PORT_5432_TCP_PORT=${POSTGRES_PORT_5432_TCP_PORT}
132 157 volumes:
133 158 - sirm_pgdata:/var/lib/postgresql/data
134 159 networks:
135 160 - backend_sirm
136 161 logging:
137 162 driver: "json-file"
138 163 options:
139 164 max-size: "12m"
140 165
141 166 sirm-proc:
142 167 container_name: 'sirm-proc'
143 168 restart: always
144 169 build:
145 170 context: ./volumes/proc/
146 171 environment:
147 172 - BROKER_URL=${BROKER_URL}
148 173 - SOPHY_TOPIC=${SOPHY_TOPIC}
149 174 - TXA_SITE=${TXA_SITE}
150 175 - TXB_SITE=${TXB_SITE}
176 - SCHAIN_SITE=${SCHAIN_SITE}
151 177 - VIRTUAL_HOST=${PROC_SITE}
152 178 volumes:
153 179 - 'sirm_proc:/app'
154 180 - 'sirm_nas:/data'
155 181 networks:
156 182 - frontend_sirm
157 183 logging:
158 184 driver: "json-file"
159 185 options:
160 186 max-size: "12m"
161 187
162 188 sirm-monitor:
163 189 container_name: 'sirm-monitor'
164 190 restart: always
165 191 image: 'sirm_sirm-proc'
166 192 command: ["python", "monitor.py"]
167 193 environment:
168 194 - BROKER_URL=${BROKER_URL}
169 195 - TXA_SITE=${TXA_SITE}
170 196 - TXB_SITE=${TXB_SITE}
171 197 volumes:
172 198 - 'sirm_proc:/app'
173 199 - 'sirm_nas:/data'
174 200 networks:
175 201 - frontend_sirm
176 202 depends_on:
177 203 - sirm-proc
178 204 logging:
179 205 driver: "json-file"
180 206 options:
181 207 max-size: "12m"
182 208
183 209 sirm-acq:
184 210 container_name: 'sirm-acq'
185 211 restart: always
186 212 image: 'sirm_sirm-proc'
187 213 command: ["python", "acq.py"]
188 214 environment:
189 215 - BROKER_URL=${BROKER_URL}
190 216 - TXA_SITE=${TXA_SITE}
191 217 - TXB_SITE=${TXB_SITE}
192 218 - PROC_SITE=${PROC_SITE}
193 219 volumes:
194 220 - 'sirm_proc:/app'
195 221 - 'sirm_nas:/data'
196 222 networks:
197 223 - frontend_sirm
198 224 depends_on:
199 225 - sirm-proc
200 226 logging:
201 227 driver: "json-file"
202 228 options:
203 229 max-size: "12m"
204 230
205 231 sirm-cam:
206 232 container_name: 'sirm-cam'
207 233 image: bkjaya1952/ivms4200-v2.8.2.2_ml-linux
208 234 restart: always
209 235 environment:
210 236 - VIRTUAL_HOST=${CAM_SITE}
211 237 volumes:
212 238 - 'sirm_cam:/root/.wine/drive_c/iVMS-4200'
213 239 networks:
214 240 - frontend_sirm
215 241 logging:
216 242 driver: "json-file"
217 243 options:
218 244 max-size: "12m"
219 245
220 246 sirm-schain:
221 247 container_name: 'sirm-schain'
222 248 restart: always
223 249 build:
224 250 context: ./volumes/schain/
225 251 environment:
226 252 - BROKER_URL=${BROKER_URL}
227 253 - BACKEND=Agg
228 254 - VIRTUAL_HOST=${SCHAIN_SITE}
229 255 volumes:
230 256 - 'sirm_nas:/data'
231 257 - 'sirm_schain:/app'
232 258 networks:
233 259 - frontend_sirm
234 260 logging:
235 261 driver: "json-file"
236 262 options:
237 263 max-size: "12m"
238 264
239 265 networks:
240 266 frontend_sirm:
241 267 name: frontend_sirm
242 268 backend_sirm:
243 269 name: backend_sirm
@@ -1,378 +1,389
1 1 """
2 2 A small Test application to show how to use Flask-MQTT.
3 3
4 4 """
5 5 import os
6 6 import time
7 7 import logging
8 8 from datetime import datetime
9 9 import random
10 10 import eventlet
11 11 import json
12 12 from json import JSONEncoder
13 13 import numpy
14 14 import base64
15 15 import h5py
16 16 try:
17 17 import requests
18 18 except:
19 19 pass
20 20 from bs4 import BeautifulSoup
21 21 from flask import Flask, render_template, jsonify, request, redirect
22 22 from flask_mqtt import Mqtt
23 23 from flask_socketio import SocketIO
24 24 from flask_bootstrap import Bootstrap
25 25
26 26 eventlet.monkey_patch()
27 27
28 28 app = Flask(__name__)
29 29 app.config['SECRET'] = 'my secret key'
30 30 app.config['TEMPLATES_AUTO_RELOAD'] = True
31 31 app.config['MQTT_BROKER_URL'] = os.environ['BROKER_URL']
32 32 app.config['MQTT_BROKER_PORT'] = 1883
33 33 app.config['MQTT_CLIENT_ID'] = 'flask_mqtt_{}'.format(int(random.random()*100))
34 34 app.config['MQTT_CLEAN_SESSION'] = True
35 35 app.config['MQTT_USERNAME'] = ''
36 36 app.config['MQTT_PASSWORD'] = ''
37 37 app.config['MQTT_KEEPALIVE'] = 5
38 38 app.config['MQTT_TLS_ENABLED'] = False
39 39 app.config['MQTT_LAST_WILL_TOPIC'] = 'sophy/error'
40 40 app.config['MQTT_LAST_WILL_MESSAGE'] = 'Bye from flask'
41 41 app.config['MQTT_LAST_WILL_QOS'] = 1
42 42
43 43 mqtt = Mqtt(app)
44 44
45 45 socketio = SocketIO(app)
46 46 bootstrap = Bootstrap(app)
47 47
48 48 MODE_STOP = 0x00
49 49 MODE_SPEED = 0x01
50 50 MODE_POSITION = 0x02
51 51 RX_AZIMUTH = 0x27
52 52 RX_ELEVATION = 0x47
53 53 TX_AZIMUTH = 0x25
54 54 TX_ELEVATION = 0x45
55 55 NONE_AXIS = 0x65
56 56 RX_FUNCTION = 0x30
57 57 TX_FUNCTION = 0x40
58 58 HEADER = 0x7e
59 59 MIN_SPEED = -180.0
60 60 MAX_SPEED = 180.0
61 61 SHRT_MIN = -32768
62 62 SHRT_MAX = 32768
63 63 USHRT_MAX = 65535
64 64
65 65 DATA_PATH = '/data'
66 66 RUNNING = False
67 67 EXPERIMENT = {'name': 'test'}
68 68 DEBUG = False
69 69
70 70 class NumpyArrayEncoder(JSONEncoder):
71 71 def default(self, obj):
72 72 if isinstance(obj, numpy.ndarray):
73 73 return obj.tolist()
74 74 return JSONEncoder.default(self, obj)
75 75
76 76 class HDF5File():
77 77
78 78 def __init__(self):
79 79 self.first = True
80 80 self.data_pos = {'az':[], 'el':[], 'saz':[], 'sel':[], 'timestamp':[]}
81 81 self.pos_ready = True
82 82 self.pos_time = 0
83 83 self.raw = {}
84 84 self.timestamp = 0
85 85 self.metadata = None
86 86
87 87 def reset(self):
88 88 self.first = True
89 89 self.data_pos = {'az':[], 'el':[], 'saz':[], 'sel':[], 'timestamp':[]}
90 90 self.pos_time = 0
91 91 self.raw = {}
92 92 self.timestamp = 0
93 93
94 94 def update(self, data):
95 95
96 96 for var in ('az', 'el', 'saz', 'sel'):
97 97 tmp = numpy.array(data[var][:99])[::4].tolist()
98 98 while len(tmp)<25:
99 99 tmp.append(numpy.nan)
100 100 self.data_pos[var].extend(tmp)
101 101
102 102 self.data_pos['timestamp'].extend(numpy.linspace(int(data['timestamp'])-1, int(data['timestamp'])-0.04, 25).tolist())
103 103 self.timestamp = int(data['timestamp'])
104 104
105 105 def write(self, data):
106 106
107 107 if self.first:
108 108 self.pos_time = int(data['timestamp'])
109 self.timestamp = int(data['timestamp'])
109 110 self.first = False
110 111
111 112 self.raw = data
113 if True:
114 date_folder = datetime.fromtimestamp(self.timestamp).strftime('%Y-%m-%dT%H-00-00')
115 filelog = os.path.join(DATA_PATH, EXPERIMENT['name'], 'position', date_folder, "pos@%10.3f.txt" % (self.timestamp))
116 if not os.path.exists(os.path.dirname(filelog)):
117 path = os.path.dirname(filelog)
118 os.makedirs(path)
119 f = open(filelog, 'w')
120 f.write(json.dumps(self.raw, cls=NumpyArrayEncoder))
121 f.close()
122
123 if int(data['timestamp'])<= self.timestamp:
124 print('Bad time')
125 return
126
112 127 self.update(data)
113 128
114 129 if self.pos_ready:
115 130 filex = "pos@%10.3f.h5" % (self.pos_time)
116 131 date_folder = datetime.fromtimestamp(self.pos_time).strftime('%Y-%m-%dT%H-00-00')
117 132 filename = os.path.join(DATA_PATH, EXPERIMENT['name'], 'position', date_folder, filex)
118 133 if not os.path.exists(os.path.dirname(filename)):
119 134 path = os.path.dirname(filename)
120 135 os.makedirs(path)
121 136 self.fpos = h5py.File(filename, 'w')
122 137 self.pos_ready = False
123 138
124 139 if datetime.fromtimestamp(self.timestamp).second == 0:
125 140 self.pos_time = self.timestamp
126 141 grp = self.fpos.create_group("Data")
127 142 dset = grp.create_dataset("azi_pos", data=numpy.array(self.data_pos['az']))
128 143 dset = grp.create_dataset("ele_pos", data=numpy.array(self.data_pos['el']))
129 144 dset = grp.create_dataset("azi_speed", data=numpy.array(self.data_pos['saz']))
130 145 dset = grp.create_dataset("ele_speed", data=numpy.array(self.data_pos['sel']))
131 146 dset = grp.create_dataset("utc", data=numpy.array(self.data_pos['timestamp']))
132 147 self.fpos.close()
133 148 self.data_pos['az'] = []
134 149 self.data_pos['el'] = []
135 150 self.data_pos['saz'] = []
136 151 self.data_pos['sel'] = []
137 152 self.data_pos['timestamp'] = []
138 153 self.pos_ready = True
139 154
140 if DEBUG:
141 date_folder = datetime.fromtimestamp(self.timestamp).strftime('%Y-%m-%dT%H-00-00')
142 filelog = os.path.join(DATA_PATH, EXPERIMENT['name'], 'position', date_folder, "pos@%10.3f.txt" % (self.timestamp))
143 f = open(filelog, 'w')
144 f.write(json.dumps(self.raw, cls=NumpyArrayEncoder))
145 f.close()
155
146 156
147 157
148 158 HDF = HDF5File()
149 159
150 160 def getSpeedPosition(msg_b64):
151 161 AzPosition=[]
152 162 AzSpeed=[]
153 163 ElPosition=[]
154 164 ElSpeed=[]
155 165 raw = numpy.frombuffer(base64.decodebytes(msg_b64.encode()),numpy.dtype('B'))
156 166 raw_size = len(raw)
157 167 Timestamp = (raw[raw_size-4])|(raw[raw_size-3]<<8)|(raw[raw_size-2]<<16)|(raw[raw_size-1]<<24)
158 168 # Timestamp = time.time()
159 169 counter = 0
160 170 while counter < raw_size-4:
161 171 if raw[counter]==HEADER:
162 172 if raw[counter+1]==RX_FUNCTION:
163 173 if raw[counter+2]==RX_AZIMUTH or raw[counter+2]==RX_ELEVATION:
164 174 iangle = 0.0
165 175 ispeed = 0.0
166 176 hadstuffing = 0
167 177
168 178 if (counter+hadstuffing+4<raw_size-4):
169 179 if raw[counter+hadstuffing+4]==HEADER-1:
170 180 hadstuffing+=1
171 181 iangle = int(0x70|raw[counter+hadstuffing+4]&0x0F)
172 182 else:
173 183 iangle = int(raw[counter+hadstuffing+4])
174 184 else:
175 185 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
176 186 break
177 187
178 188 if (counter+hadstuffing+5<raw_size-4):
179 189 if raw[counter+hadstuffing+5]==HEADER-1:
180 190 hadstuffing+=1
181 191 iangle = iangle + int((0x70|raw[counter+hadstuffing+5]&0x0F)<<8)
182 192 else:
183 193 iangle = iangle + int(raw[counter+hadstuffing+5]<<8)
184 194 else:
185 195 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
186 196 break
187 197
188 198 if (counter+hadstuffing+6<raw_size-4):
189 199 if raw[counter+hadstuffing+6]==HEADER-1:
190 200 hadstuffing+=1
191 201 ispeed = int(0x70|raw[counter+hadstuffing+6]&0x0F)
192 202 else:
193 203 ispeed = int(raw[counter+hadstuffing+6])
194 204 else:
195 205 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
196 206 break
197 207
198 208 if (counter+hadstuffing+7<raw_size-4):
199 209 if raw[counter+hadstuffing+7]==HEADER-1:
200 210 hadstuffing+=1
201 211 ispeed = ispeed + int((0x70|raw[counter+hadstuffing+7]&0x0F)<<8)
202 212 else:
203 213 ispeed = ispeed + int(raw[counter+hadstuffing+7]<<8)
204 214 else:
205 215 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
206 216 break
207 217
208 218 if (counter+2<raw_size-4):
209 219 if raw[counter+2]==RX_AZIMUTH:
210 220 AzPosition.append(iangle*360.0/USHRT_MAX)
211 221 AzSpeed.append(((ispeed-SHRT_MIN)*(MAX_SPEED-MIN_SPEED)/(SHRT_MAX-SHRT_MIN))+MIN_SPEED)
212 222 elif raw[counter+2]==RX_ELEVATION:
213 223 ElPosition.append(iangle*360.0/USHRT_MAX)
214 224 ElSpeed.append(((ispeed-SHRT_MIN)*(MAX_SPEED-MIN_SPEED)/(SHRT_MAX-SHRT_MIN))+MIN_SPEED)
215 225 else:
216 226 counter+=1
217 227 continue
218 228 else:
219 229 logging.debug("Warning: Index out of bounds. The packet is incomplete or corrupted.")
220 230 break
221 231
222 232 counter = counter+hadstuffing+13
223 233 else:
224 234 counter+=1
225 235 continue
226 236 else:
227 237 counter+=1
228 238 continue
229 239 else:
230 240 counter+=1
231 241 continue
232 242
233 243 az = numpy.array(AzPosition)
234 244 az[numpy.where(az>=359.8)] = 0
235 245 az = numpy.round(az, 2)
236 246
237 247 saz = numpy.array(AzSpeed)
238 248 saz[numpy.where(saz>=28)] = saz[(saz>=28)]-360
239 249 saz = numpy.round(saz, 2)
240 250
241 251 el = numpy.array(ElPosition)
242 252 el[numpy.where((190 <= el) & (el <= 360))] = el[(190 <= el) & (el<= 360)] - 360
243 253 el = numpy.round(el, 2)
244 254
245 255 sel = numpy.array(ElSpeed)
246 256 sel[numpy.where(sel>=28)] = sel[(sel>=28)]-360
247 257 sel = numpy.round(sel, 2)
248 258
249 259 return az, saz, el, sel, int(Timestamp)
250 260
251 261
252 262 @app.route('/')
253 263 def index():
254 264 global RUNNING, EXPERIMENT
255 265 running = 'Running' if RUNNING else 'Not Running'
256 266 name = '-' if EXPERIMENT['name']=='test' else EXPERIMENT['name']
257 267 return render_template('index.html', status=running, experiment_name=name)
258 268
259 269 @app.route('/start', methods=['POST'])
260 270 def start_proc():
261 271
262 272 global EXPERIMENT, RUNNING
263 273
264 274 EXPERIMENT.update(request.get_json())
265 275 RUNNING = True
266 276 path = os.path.join(DATA_PATH, EXPERIMENT['name'])
267 277 if not os.path.exists(path):
268 278 os.makedirs(path)
269 279 fo = open(os.path.join(path, 'experiment.conf'), 'w')
270 280 fo.write(json.dumps(EXPERIMENT, indent=2))
271 281 fo.close()
272 282
273 283 mqtt.publish('sophy/control', json.dumps(EXPERIMENT))
274 284 socketio.emit('mqtt_message', data={'topic':'monitor', 'status': 'Running', 'name': EXPERIMENT['name']})
285 r = requests.post('http://sirm-schain/start', data=EXPERIMENT)
286 print('Starting schain: {}'.format(r))
275 287
276 288 return jsonify({'start': 'ok'})
277 289
278 290 @app.route('/stop')
279 291 def stop_proc():
280 292
281 293 global RUNNING, DEBUG, HDF, EXPERIMENT
282 294
283 295 RUNNING = False
284 296 DEBUG = False
285 297 HDF.reset()
286 298 socketio.emit('mqtt_message', data={'topic':'monitor', 'status': 'Not Running'})
287 299 mqtt.publish('sophy/control', json.dumps({'stop': 'ok'}))
300 r = requests.get('http://sirm-schain/stop')
301 print('Stopping schain: {}'.format(r))
288 302
289 303 return jsonify({'stop': 'ok'})
290 304
291 305 @app.route('/status')
292 306 def status_proc():
293 307
294 308 global RUNNING
295 309
296 310 return jsonify({'status': RUNNING})
297 311
298 312 @app.route('/run')
299 313 def run_proc():
300 314
301 315 global RUNNING, EXPERIMENT, DEBUG
302 316 if request.args.get('debug', False):
303 317 DEBUG = True
304 318 name = request.args.get('name', 'TEST')
305 319 path = os.path.join(DATA_PATH, name)
306 320 if not os.path.exists(path):
307 321 os.makedirs(path)
308 322 EXPERIMENT['name'] = name
309 323 RUNNING = True
310 324
311 325 mqtt.publish('sophy/control', json.dumps(EXPERIMENT))
312 326 socketio.emit('mqtt_message', data={'topic':'monitor', 'status': 'Running'})
313 327
314 328 return redirect('/')
315 329
316 330 @app.route('/mqtt')
317 331 def mqtt_log():
318
319 332 return render_template('mqtt.html')
320 333
321 334 @app.route('/acq')
322 335 def acq_log():
323
324 336 return render_template('acq.html')
325 337
326 338 @socketio.on('publish')
327 339 def handle_publish(json_str):
328 340 data = json.loads(json_str)
329 341 mqtt.publish(data['topic'], data['message'], data['qos'])
330 342
331 343 @socketio.on('subscribe')
332 344 def handle_subscribe(json_str):
333 345 data = json.loads(json_str)
334 346 mqtt.subscribe(data['topic'], data['qos'])
335 347
336 348 @socketio.on('unsubscribe_all')
337 349 def handle_unsubscribe_all():
338 350 mqtt.unsubscribe_all()
339 351
340 352 @mqtt.on_connect()
341 353 def handle_connect(client, userdata, flags, rc):
342 354 mqtt.subscribe(os.environ.get('SOPHY_TOPIC', 'sophy/#'))
343 355
344 356 @mqtt.on_message()
345 357 def handle_mqtt_message(client, userdata, message):
346 358
347 359 global RUNNING, HDF
348 360
349 361 payload = message.payload.decode()
350 362 data = {}
351 363
352 364 if 'pedestal' in message.topic:
353 365
354 366 az, saz, el, sel, tm = getSpeedPosition(payload)
355 367 times = numpy.linspace(tm, tm+0.9, 10)
356 368 data['az'] = az[:100][::10].tolist()
357 369 data['el'] = el[:100][::10].tolist()
358 370 data['saz'] = saz[:100][::10].tolist()
359 371 data['sel'] = sel[:100][::10].tolist()
360 372 data['timestamp'] = times.tolist()
361 373
362 374 if RUNNING:
363 375 HDF.write({'az':az.tolist(), 'el':el.tolist(), 'saz':saz.tolist(), 'sel':sel.tolist(), 'timestamp':tm})
364 376
365 377 data['payload'] = payload
366 378 data['topic'] = message.topic
367 379 data['qos'] = message.qos
368 380
369 381 socketio.emit('mqtt_message', data=data)
370 382
371 383 @mqtt.on_log()
372 384 def handle_logging(client, userdata, level, buf):
373 385 # print(level, buf)
374 386 pass
375 387
376 388 if __name__ == '__main__':
377 socketio.run(app, host='0.0.0.0', port=5000, use_reloader=False, debug=True)
378
389 socketio.run(app, host='0.0.0.0', port=5000, use_reloader=False, debug=True) No newline at end of file
@@ -1,225 +1,225
1 1 {% extends "bootstrap/base.html" %}
2 2 {% block title %}SOPHY monitor{% endblock %}
3 3
4 4 {% block styles %}
5 5 {{ super() }}
6 6 {% endblock %}
7 7
8 8 {% block scripts %}
9 9 {{ super() }}
10 10 <script type="text/javascript" src="{{ url_for('static', filename='js/plotly-latest.min.js') }}"></script>
11 11 <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.min.js"></script>
12 12 <script type="text/javascript" charset="utf-8">
13 13 $(document).ready(function() {
14 14 var socket = io.connect('http://' + document.domain + ':' + location.port);
15 15 var rx_log_array = [];
16 16 socket.on('connect', function(data) {
17 17 console.log('Initialazing plots...');
18 18 makePlot("plot-pos", 2, ["Azimuth", "Elevation"]);
19 19 makePlot("plot-speed", 2, ["AZ Speed", "EL Speed"]);
20 20 makePlot("plot-tx", 2, ["Power A", "Power B"]);
21 21 })
22 22
23 23 socket.on('mqtt_message', function(data) {
24 24 console.log(data['topic']);
25 25 if (data['topic'].includes('monitor')){
26 26 if (rx_log_array.length > 7){
27 27 rx_log_array.shift();
28 28 }
29 29 rx_log_array.push(data['payload']);
30 30 $('#rx_log').val(rx_log_array.join('\r\n'));
31 31 if ('status' in data) {
32 32 $('#radar_status').val(data.status);
33 33 if (data.status == 'Running') {
34 34 $('#radar_status').css('color', 'green');
35 35 }else {
36 36 $('#radar_status').css('color', 'red');
37 37 }
38 38 }
39 39 if ('name' in data){
40 40 $('#experiment').val(data.name);
41 41 }
42 42 } else if (data['topic'].includes('pedestal')) {
43 43 streamPlot2("plot-pos", data.timestamp, data.az, data.el );
44 44 streamPlot2("plot-speed", data.timestamp, data.saz, data.sel );
45 45 //streamPlot2("plot-tx", data.timestamp, data.powa, data.powb );
46 46 //$('#status_txa').val(data.status_powa);
47 47 //if (data.status_powa == 'OK') {
48 48 // $('#status_txa').css('color', 'green');
49 49 // }else {
50 50 // $('#status_txa').css('color', 'red');
51 51 // }
52 52 //$('#status_txb').val(data.status_powb);
53 53 //if (data.status_powb == 'OK') {
54 54 // $('#status_txb').css('color', 'green');
55 55 // }else {
56 56 // $('#status_txb').css('color', 'red');
57 57 // }
58 58 } else if (data['topic'].includes('tx')) {
59 59 var payload = JSON.parse(data.payload);
60 60 streamPlot2("plot-tx", payload.timestamp, payload.powa, payload.powb );
61 61 $('#status_txa').val(payload.status_powa);
62 62 if (payload.status_powa == 'OK') {
63 63 $('#status_txa').css('color', 'green');
64 64 }else {
65 65 $('#status_txa').css('color', 'red');
66 66 }
67 67 $('#status_txb').val(payload.status_powb);
68 68 if (payload.status_powb == 'OK') {
69 69 $('#status_txb').css('color', 'green');
70 70 }else {
71 71 $('#status_txb').css('color', 'red');
72 72 }
73 73 }
74 74 })
75 75 });
76 76
77 77 function makePlot(div, n=1, names=["", ""]){
78 78 var plotDiv = document.getElementById(div);
79 79 var traces = [];
80 80 for (let i = 0; i < n; i++) {
81 81 traces.push({x: [], y: [], name: names[i]});
82 82 }
83 var yrange = [0, 40];
83 var yrange = [0, 50];
84 84 if (div == "plot-pos"){yrange = [0, 360];}
85 85 if (div == "plot-speed"){yrange = [-15, 15];}
86 86 var layout = {
87 87 height: 350,
88 88 font: {size: 12},
89 89 margin: { t: 0 },
90 90 xaxis: {
91 91 type: 'date'
92 92 },
93 93 yaxis: {
94 94 range: yrange,
95 95 },
96 96 };
97 97
98 98 Plotly.plot(plotDiv, traces, layout);
99 99 };
100 100
101 101 function streamPlot(div, x, y ){
102 102 var plotDiv = document.getElementById(div);
103 103 if (plotDiv.data[0].x.length > 599){
104 104 plotDiv.data[0].x = plotDiv.data[0].x.slice(-600)
105 105 plotDiv.data[0].y = plotDiv.data[0].y.slice(-600)
106 106 }
107 107 var tm = x.map(i => new Date(i*1000));
108 108 var values = y.map(i => Math.round(i * 100) / 100);
109 109 var data_update = {x: [tm], y: [values]}
110 110 Plotly.extendTraces(plotDiv, data_update, [0])
111 111 };
112 112
113 113 function streamPlot2(div, x, y1, y2 ){
114 114 var plotDiv = document.getElementById(div);
115 115 if (plotDiv.data[0].x.length > 499){
116 116 plotDiv.data[0].x = plotDiv.data[0].x.slice(-600)
117 117 plotDiv.data[0].y = plotDiv.data[0].y.slice(-600)
118 118 plotDiv.data[1].x = plotDiv.data[1].x.slice(-600)
119 119 plotDiv.data[1].y = plotDiv.data[1].y.slice(-600)
120 120 }
121 121 var tm = x.map(i => new Date(i*1000));
122 122 var values1 = y1.map(i => Math.round(i * 100) / 100);
123 123 var values2 = y2.map(i => Math.round(i * 100) / 100);
124 124 var data_update = {x: [tm, tm], y: [values1, values2]}
125 125 Plotly.extendTraces(plotDiv, data_update, [0, 1])
126 126 };
127 127
128 128 </script>
129 129 {% endblock %}
130 130
131 131 {% block content %}
132 132 <div class="container-fluid">
133 133 <div class="row">
134 134 <div class="col-xs-12">
135 135 <h1>SOPHy monitor</h1>
136 136 </div>
137 137 </div>
138 138 <div class="row">
139 139 <!--Messages-->
140 140 <div class="col-xs-6">
141 141 <div class="panel panel-default">
142 142 <div class="panel-heading">
143 143 <h3 class="panel-title">Status</h3>
144 144 </div>
145 145 <div class="panel-body">
146 146 <div class="col-xs-12">
147 147 <div class="form-row">
148 148 <div class="form-group col-xs-6">
149 149 <label for="radar_status">Status</label>
150 150 <input id="radar_status" class="form-control" value="{{status}}" disabled></input>
151 151 </div>
152 152 <div class="form-group col-xs-6">
153 153 <label for="experiment">Experiment</label>
154 154 <input id="experiment" class="form-control" value="{{experiment_name}}" disabled></input>
155 155 </div>
156 156 </div>
157 157 <div class="form-row">
158 158 <div class="form-group col-xs-6">
159 159 <label for="status_txa">TX A</label>
160 160 <input id="status_txa" class="form-control" value="{{txa}}" disabled></input>
161 161 </div>
162 162 <div class="form-group col-xs-6">
163 163 <label for="status_txb">TX B</label>
164 164 <input id="status_txb" class="form-control" value="{{txb}}" disabled></input>
165 165 </div>
166 166 </div>
167 167 <div class="form-row">
168 168 <div class="form-group col-xs-12">
169 169 <label for="rx_log">RX Log</label>
170 170 <textarea id="rx_log" class="form-control" rows=7></textarea>
171 171 </div>
172 172 </div>
173 173 </div>
174 174 </div>
175 175 </div>
176 176 </div>
177 177 <!--Position-->
178 178 <div class="col-xs-6">
179 179 <div class="panel panel-default">
180 180 <div class="panel-heading">
181 181 <h3 class="panel-title">Pedestal Position</h3>
182 182 </div>
183 183 <div class="panel-body">
184 184 <div class="col-xs-12">
185 185 <div class="row">
186 186 <div id="plot-pos"></div>
187 187 </div>
188 188 </div>
189 189 </div>
190 190 </div>
191 191 </div>
192 192 <!--Speed-->
193 193 <div class="col-xs-6">
194 194 <div class="panel panel-default">
195 195 <div class="panel-heading">
196 196 <h3 class="panel-title">Pedestal Speed</h3>
197 197 </div>
198 198 <div class="panel-body">
199 199 <div class="col-xs-12">
200 200 <div class="row">
201 201 <div id="plot-speed"></div>
202 202 </div>
203 203 </div>
204 204 </div>
205 205 </div>
206 206 </div>
207 207 <!--TX power-->
208 208 <div class="col-xs-6">
209 209 <div class="panel panel-default">
210 210 <div class="panel-heading">
211 211 <h3 class="panel-title">SSPA's power</h3>
212 212 </div>
213 213 <div class="panel-body">
214 214 <div class="col-xs-12">
215 215 <div class="row">
216 216 <div id="plot-tx"></div>
217 217 </div>
218 218 </div>
219 219 </div>
220 220 </div>
221 221 </div>
222 222 </div>
223 223 </div>
224 224 {{debug}}
225 225 {% endblock %}
@@ -1,106 +1,110
1 1 import os
2 2 import sys
3 3 import time
4 4 import json
5 5 import base64
6 6 import logging
7 7 from datetime import datetime
8 8 import zmq
9 9 from watchdog.observers import Observer
10 10 from watchdog.events import FileSystemEventHandler
11 11
12 12
13 13 EXP = sys.argv[1]
14 14 main_path = '/DATA_RM/DATA/{}/plots'.format(EXP)
15 15
16 print(main_path)
16 if not os.path.exists(main_path):
17 os.makedirs(main_path)
17 18
18 19 CODES = {
19 20 'V': 'Velocity',
20 21 'P': 'Power',
22 'Z': 'Reflectivity',
23 'W': 'Spectral Width'
21 24
22 25 }
23 26
24 27 DATA = {
25 28 'time': 0,
26 29 'metadata': {
27 30 'localtime': True,
28 31 'type': 'image',
29 32 'interval': 150,
30 'tag' : 'Jicamarca'
33 'tag' : 'Huancayo'
31 34 },
32 35 'data': '',
33 36 'plot': '',
34 37 }
35 38
36 39
37 40 class FileHandler(FileSystemEventHandler):
38 41
39 42 last = {
40 43 'V': 0,
41 44 'P': 0,
42
45 'Z': 0,
46 'W': 0,
43 47 }
44 48
45 49 def on_modified(self, event):
46 50 data = DATA.copy()
47 51 path = event.src_path
48 52 filename = path.split('/')[-1]
49 53
50 54 try:
51 55 if not filename.count('_')==2:
52 56 return
53 57
54 58 dt = datetime.strptime(filename.split('.png')[0][2:], '%Y%m%d_%H%M%S')
55 59 tm = (dt-datetime(1970,1,1)).total_seconds() + 5*60*60
56 60 except:
57 61 return
58 62
59 63 code = filename[0]
60 64 if code not in CODES:
61 65 return
62 66
63 67 data['code'] = 400
64 68 stats = os.stat(path)
65 69 time.sleep(1)
66 70
67 71 if (tm-self.last[code]) >= 10:
68 72 data['time'] = tm
69 73 data['plot'] = CODES[code]
70 74 print('sending {} {}'.format( data['plot'], path))
71 75
72 76 data['data'] = base64.b64encode(bytearray(open(path, 'rb').read())).decode()
73 77
74 78 self.socket.send_string(json.dumps(data))
75 79
76 80 poller = zmq.Poller()
77 81 poller.register(self.socket, zmq.POLLIN)
78 82 if poller.poll(10*10000): # 10s timeout in milliseconds
79 83 print(self.socket.recv())
80 84 else:
81 85 print('Server Down...')
82 86 self.last[code] = tm
83 87 else:
84 88 print('Skipping {}'.format(path))
85 89
86 90
87 91 if __name__ == "__main__":
88 92
89 93 event = FileHandler()
90 94 event.context = zmq.Context()
91 95 print ("Connecting to server...")
92 96 event.socket = event.context.socket(zmq.REQ)
93 97 #event.socket.connect ("tcp://10.10.20.128:4444")
94 event.socket.connect ("tcp://10.10.110.243:4444")
98 event.socket.connect ("tcp://190.187.237.239:4444")
95 99
96 100 observer = Observer()
97 101 observer.schedule(event, main_path, recursive=True)
98 102 observer.start()
99 103
100 104 try:
101 105 while True:
102 106 time.sleep(1)
103 107 except KeyboardInterrupt:
104 108 observer.stop()
105 109
106 110 observer.join() No newline at end of file
@@ -1,151 +1,307
1 #!/opt/conda/bin/python
1 # SOPHY PROC script
2 2 import os, sys, json, argparse
3 3 import datetime
4 4 import time
5 5
6
7 PATH = '/data'
6 PATH = '/DATA_RM/DATA'
7 #PATH = '/data'
8 # PATH = '/Users/jespinoza/workspace/data/'
8 9
9 10 PARAM = {
10 'P': {'name': 'dataPP_POWER', 'zmin': 35, 'zmax': 60, 'colormap': 'viridis', 'label': 'Power', 'cb_label': 'dB'},
11 'V': {'name': 'dataPP_DOP', 'zmin': -20, 'zmax': 20, 'colormap': 'seismic', 'label': 'Velocity', 'cb_label': 'm/s'}
12 }
11 'P': {'name': 'dataPP_POWER', 'zmin': 30, 'zmax': 60, 'colormap': 'jet', 'label': 'Power', 'wrname': 'Pow','cb_label': 'dB', 'ch':0},
12 'V': {'name': 'dataPP_DOP', 'zmin': -20, 'zmax': 20, 'colormap': 'seismic', 'label': 'Velocity', 'wrname': 'Vel', 'cb_label': 'm/s', 'ch':0},
13 'RH': {'name': 'RhoHV_R', 'zmin': 0, 'zmax': 1, 'colormap': 'jet', 'label': 'Coef.Correlacion', 'wrname':'R', 'cb_label': '*', 'ch':0},
14 'FD': {'name': 'PhiD_P', 'zmin': -180,'zmax': 180,'colormap': 'RdBu_r', 'label': 'Fase Diferencial', 'wrname':'P' , 'cb_label': 'ΒΊ', 'ch':0},
15 'ZD': {'name': 'Zdb_D', 'zmin': -20, 'zmax': 80, 'colormap': 'viridis','label': 'Reflect.Diferencial','wrname':'D' , 'cb_label': 'dBz','ch':0},
16 'Z': {'name': 'Zdb', 'zmin': -40, 'zmax': 80, 'colormap': 'viridis','label': 'Reflectividad', 'wrname':'Z', 'cb_label': 'dBz','ch':1},
17 'W': {'name': 'Sigmav_W', 'zmin': -20, 'zmax': 60, 'colormap': 'viridis','label': 'Spectral Width', 'wrname':'S', 'cb_label': 'hz', 'ch':1}
18 }
19
20 def max_index(r, sample_rate, ipp):
21
22 return int(sample_rate*ipp*1e6 * r / 60) + int(sample_rate*ipp*1e6 * 1.2 / 60)
13 23
14 24 def main(args):
15 25
16 26 experiment = args.experiment
17 fp = open(os.path.join(PATH, experiment, 'experiment.conf'))
27 fp = open(os.path.join(PATH, experiment, 'experiment.conf'))
18 28 conf = json.loads(fp.read())
19 29
20 30 ipp_km = conf['usrp_tx']['ipp']
21 31 ipp = ipp_km * 2 /300000
22 samp_rate = conf['usrp_rx']['sample_rate']
32 sample_rate = conf['usrp_rx']['sample_rate']
23 33 axis = ['0' if x=='elevation' else '1' for x in conf['pedestal']['axis']] # AZIMUTH 1 ELEVACION 0
24 34 speed_axis = conf['pedestal']['speed']
25 steeps = conf['pedestal']['table']
35 steps = conf['pedestal']['table']
26 36 time_offset = args.time_offset
27 37 parameters = args.parameters
28 38 start_date = experiment.split('@')[1].split('T')[0].replace('-', '/')
29 39 end_date = start_date
30 start_time = experiment.split('@')[1].split('T')[1].replace('-', ':')
40 if args.start_time:
41 start_time = args.start_time
42 else:
43 start_time = experiment.split('@')[1].split('T')[1].replace('-', ':')
44 #start_time = '13:00:00'
31 45 end_time = '23:59:59'
32 max_index = int(samp_rate*ipp*1e6 * args.range / 60) + int(samp_rate*ipp*1e6 * 1.2 / 60)
33 46 N = int(1/(speed_axis[0]*ipp)) # 1 GRADO DE RESOLUCION
34 47 path = os.path.join(PATH, experiment, 'rawdata')
35 48 path_ped = os.path.join(PATH, experiment, 'position')
36 49 path_plots = os.path.join(PATH, experiment, 'plots')
37 50 path_save = os.path.join(PATH, experiment, 'param')
51 RMIX = 5
38 52
39 dBmin = 35
40 dBmax = 60
41 Vmin = -20
42 Vmax = 20
43
44 53 from schainpy.controller import Project
45
54
46 55 project = Project()
47 56 project.setup(id='1', name='Sophy', description='sophy proc')
48
57 print(start_time)
49 58 reader = project.addReadUnit(datatype='DigitalRFReader',
50 59 path=path,
51 60 startDate=start_date,
52 61 endDate=end_date,
53 startTime=start_time,
62 start_time=start_time,
54 63 endTime=end_time,
55 delay=0,
56 online=0,
64 delay=30,
65 online=args.online,
57 66 walk=1,
58 67 ippKm = ipp_km,
59 68 getByBlock = 1,
60 69 nProfileBlocks = N,
61 70 )
62 71
63 voltage = project.addProcUnit(datatype='VoltageProc', inputId=reader.getId())
64 op = voltage.addOperation(name='setH0')
65 op.addParameter(name='h0', value='-1.2')
72 if not conf['usrp_tx']['enable_2']: # One Pulse
73 voltage = project.addProcUnit(datatype='VoltageProc', inputId=reader.getId())
66 74
67 if args.range > 0:
68 op = voltage.addOperation(name='selectHeights')
69 op.addParameter(name='minIndex', value='0', format='int')
70 op.addParameter(name='maxIndex', value=max_index, format='int')
75 if conf['usrp_tx']['code_type_1']:
76 code = [c.split() for c in conf['usrp']['code_1']]
77 op = voltage.addOperation(name='Decoder', optype='other')
78 op.addParameter(name='code', value=code)
79 op.addParameter(name='nCode', value=len(code), format='int')
80 op.addParameter(name='nBaud', value=len(code[0]), format='int')
71 81
72 op = voltage.addOperation(name='PulsePair_vRF', optype='other')
73 op.addParameter(name='n', value=int(N), format='int')
82 op = voltage.addOperation(name='setH0')
83 op.addParameter(name='h0', value='-1.2')
74 84
75 proc = project.addProcUnit(datatype='ParametersProc', inputId=voltage.getId())
76
77 op = proc.addOperation(name='PedestalInformation')
78 op.addParameter(name='path', value=path_ped, format='str')
79 op.addParameter(name='interval', value='0.04', format='float')
80 op.addParameter(name='time_offset', value=time_offset)
81 op.addParameter(name='az_offset', value=0, format='int')
82
83 for param in parameters:
84
85 op = proc.addOperation(name='Block360_vRF4')
86 op.addParameter(name='axis', value=','.join(axis))
87 op.addParameter(name='attr_data', value=PARAM[param]['name'])
88 op.addParameter(name='runNextOp', value=True)
89
90 if axis[0] == '1':
91 path_fig = '/PPI-{}km'.format(args.range)
92 op= proc.addOperation(name='Weather_vRF_Plot')
93 if args.save: op.addParameter(name='save', value=path_plots+path_fig, format='str')
85 if args.range > 0:
86 op = voltage.addOperation(name='selectHeights')
87 op.addParameter(name='minIndex', value='0', format='int')
88 op.addParameter(name='maxIndex', value=max_index(RMIX, sample_rate, ipp), format='int')
89
90 op = voltage.addOperation(name='PulsePair_vRF', optype='other')
91 op.addParameter(name='n', value=int(N), format='int')
92
93 proc = project.addProcUnit(datatype='ParametersProc', inputId=voltage.getId())
94
95 opObj10 = proc.addOperation(name="WeatherRadar")
96 opObj10.addParameter(name='variableList',value='Reflectividad,VelocidadRadial,AnchoEspectral')
97
98 # {"latitude": -12.0404828587, "longitude": -75.2147483647, "altitude": 3379.2147483647}
99
100 op = proc.addOperation(name='PedestalInformation')
101 op.addParameter(name='path', value=path_ped, format='str')
102 op.addParameter(name='interval', value='0.04')
103 op.addParameter(name='time_offset', value=time_offset)
104 op.addParameter(name='az_offset', value=-26.2)
105
106 for param in parameters:
107 op = proc.addOperation(name='Block360_vRF4')
108 #op.addParameter(name='axis', value=','.join(axis))
109 op.addParameter(name='attr_data', value=PARAM[param]['name'])
110 op.addParameter(name='runNextOp', value=True)
111
112 op= proc.addOperation(name='WeatherParamsPlot')
113 if args.save: op.addParameter(name='save', value=path_plots, format='str')
94 114 op.addParameter(name='save_period', value=-1)
95 115 op.addParameter(name='show', value=args.show)
96 116 op.addParameter(name='channels', value='1,')
97 117 op.addParameter(name='zmin', value=PARAM[param]['zmin'])
98 118 op.addParameter(name='zmax', value=PARAM[param]['zmax'])
99 119 op.addParameter(name='attr_data', value=PARAM[param]['name'], format='str')
100 120 op.addParameter(name='labels', value=[PARAM[param]['label']])
101 121 op.addParameter(name='save_code', value=param)
102 122 op.addParameter(name='cb_label', value=PARAM[param]['cb_label'])
103 123 op.addParameter(name='colormap', value=PARAM[param]['colormap'])
104 if axis[0] == '0':
105 path_fig = '/RHI{}km'.format(args.range)
106 op= proc.addOperation(name='WeatherRHI_vRF4_Plot')
107 if args.save: op.addParameter(name='save', value=path_plots+path_fig, format='str')
124
125 desc = {
126 'Data': {
127 PARAM[param]['name']: PARAM[param]['label'],
128 'utctime': 'time'
129 },
130 'Metadata': {
131 'heightList': 'range',
132 'data_azi': 'azimuth',
133 'data_ele': 'elevation',
134 }
135 }
136
137 if args.save:
138 opObj10 = proc.addOperation(name='HDFWriter')
139 opObj10.addParameter(name='path',value=path_save+'-{}'.format(param), format='str')
140 opObj10.addParameter(name='Reset',value=True)
141 opObj10.addParameter(name='setType',value='weather')
142 opObj10.addParameter(name='description',value='desc')
143 opObj10.addParameter(name='blocksPerFile',value='1',format='int')
144 opObj10.addParameter(name='metadataList',value='heightList,data_azi,data_ele')
145 opObj10.addParameter(name='dataList',value='{},utctime'.format(PARAM[param]['name']))
146
147 else: #Two pulses
148
149 voltage1 = project.addProcUnit(datatype='VoltageProc', inputId=reader.getId())
150
151 op = voltage1.addOperation(name='ProfileSelector')
152 op.addParameter(name='profileRangeList', value='0,{}'.format(conf['usrp_tx']['repetitions_1']-1))
153
154 if conf['usrp_tx']['code_type_1'] != 'None':
155 code = [c.split() for c in conf['usrp_tx']['code_1']]
156 op = voltage1.addOperation(name='Decoder', optype='other')
157 op.addParameter(name='code', value=code)
158 op.addParameter(name='nCode', value=len(code), format='int')
159 op.addParameter(name='nBaud', value=len(code[0]), format='int')
160
161 op = voltage1.addOperation(name='setH0')
162 op.addParameter(name='h0', value='-1.2')
163
164 if args.range > 0:
165 op = voltage1.addOperation(name='selectHeights')
166 op.addParameter(name='minIndex', value='0', format='int')
167 op.addParameter(name='maxIndex', value=max_index(RMIX, sample_rate, ipp), format='int')
168
169 op = voltage1.addOperation(name='PulsePair_vRF', optype='other')
170 op.addParameter(name='n', value=int(N), format='int')
171
172 proc1 = project.addProcUnit(datatype='ParametersProc', inputId=voltage1.getId())
173 proc1.addParameter(name='runNextUnit', value=True)
174
175 opObj10 = proc1.addOperation(name="WeatherRadar")
176 opObj10.addParameter(name='variableList',value='Reflectividad,VelocidadRadial,AnchoEspectral')
177
178 # {"latitude": -12.0404828587, "longitude": -75.2147483647, "altitude": 3379.2147483647}
179
180 op = proc1.addOperation(name='PedestalInformation')
181 op.addParameter(name='path', value=path_ped, format='str')
182 op.addParameter(name='interval', value='0.04')
183 op.addParameter(name='time_offset', value=time_offset)
184 op.addParameter(name='az_offset', value=-26.2)
185
186 for param in parameters:
187 op = proc1.addOperation(name='Block360_vRF4')
188 op.addParameter(name='attr_data', value=PARAM[param]['name'])
189 op.addParameter(name='runNextOp', value=True)
190
191 voltage2 = project.addProcUnit(datatype='VoltageProc', inputId=reader.getId())
192
193 op = voltage2.addOperation(name='ProfileSelector')
194 op.addParameter(name='profileRangeList', value='{},{}'.format(conf['usrp_tx']['repetitions_1'], conf['usrp_tx']['repetitions_1']+conf['usrp_tx']['repetitions_2']-1))
195
196
197 if conf['usrp_tx']['code_type_2']:
198 codes = [ c.strip() for c in conf['usrp_tx']['code_2'].split(',')]
199 code = []
200 for c in codes:
201 code.append([int(x) for x in c])
202 op = voltage2.addOperation(name='Decoder', optype='other')
203 op.addParameter(name='code', value=code)
204 op.addParameter(name='nCode', value=len(code), format='int')
205 op.addParameter(name='nBaud', value=len(code[0]), format='int')
206
207 op = voltage2.addOperation(name='CohInt', optype='other') #Minimo integrar 2 perfiles por ser codigo complementario
208 op.addParameter(name='n', value=len(code), format='int')
209 ncode = len(code)
210 else:
211 ncode = 1
212
213 op = voltage2.addOperation(name='setH0')
214 op.addParameter(name='h0', value='-1.2')
215
216 if args.range > 0:
217 op = voltage2.addOperation(name='selectHeights')
218 op.addParameter(name='minIndex', value=max_index(RMIX, sample_rate, ipp), format='int')
219 op.addParameter(name='maxIndex', value=max_index(args.range, sample_rate, ipp), format='int')
220
221 op = voltage2.addOperation(name='PulsePair_vRF', optype='other')
222 op.addParameter(name='n', value=int(N)/ncode, format='int')
223
224 proc2 = project.addProcUnit(datatype='ParametersProc', inputId=voltage2.getId())
225
226 opObj10 = proc2.addOperation(name="WeatherRadar")
227 opObj10.addParameter(name='variableList',value='Reflectividad,AnchoEspectral')
228
229 # {"latitude": -12.0404828587, "longitude": -75.2147483647, "altitude": 3379.2147483647}
230
231 op = proc2.addOperation(name='PedestalInformation')
232 op.addParameter(name='path', value=path_ped, format='str')
233 op.addParameter(name='interval', value='0.04')
234 op.addParameter(name='time_offset', value=time_offset)
235 op.addParameter(name='az_offset', value=-26.2)
236
237 for param in parameters:
238 op = proc2.addOperation(name='Block360_vRF4')
239 #op.addParameter(name='axis', value=','.join(axis))
240 op.addParameter(name='attr_data', value=PARAM[param]['name'])
241 op.addParameter(name='runNextOp', value=True)
242
243 merge = project.addProcUnit(datatype='MergeProc', inputId=[proc1.getId(), proc2.getId()])
244 merge.addParameter(name='attr_data', value=PARAM[param]['name'])
245 merge.addParameter(name='mode', value='7') #RM
246
247 op= merge.addOperation(name='WeatherParamsPlot')
248 if args.save: op.addParameter(name='save', value=path_plots, format='str')
108 249 op.addParameter(name='save_period', value=-1)
109 250 op.addParameter(name='show', value=args.show)
110 op.addParameter(name='channels', value='(1,)')
251 op.addParameter(name='channels', value='1,')
111 252 op.addParameter(name='zmin', value=PARAM[param]['zmin'])
112 253 op.addParameter(name='zmax', value=PARAM[param]['zmax'])
113 254 op.addParameter(name='attr_data', value=PARAM[param]['name'], format='str')
114 255 op.addParameter(name='labels', value=[PARAM[param]['label']])
115 256 op.addParameter(name='save_code', value=param)
116 257 op.addParameter(name='cb_label', value=PARAM[param]['cb_label'])
117 258 op.addParameter(name='colormap', value=PARAM[param]['colormap'])
118
119 if args.save:
120 opObj10 = proc.addOperation(name='HDFWriter')
121 opObj10.addParameter(name='path',value=path_save, format='str')
122 opObj10.addParameter(name='Reset',value=True)
123 opObj10.addParameter(name='blocksPerFile',value='1',format='int')
124 opObj10.addParameter(name='metadataList',value='heightList,data_azi,data_ele')
125 opObj10.addParameter(name='dataList',value='dataPP_POWER,utctime')
259
260 desc = {
261 'Data': {
262 PARAM[param]['name']: PARAM[param]['label'],
263 'utctime': 'time'
264 },
265 'Metadata': {
266 'heightList': 'range',
267 'data_azi': 'azimuth',
268 'data_ele': 'elevation',
269 }
270 }
271
272 if args.save:
273 opObj10 = merge.addOperation(name='HDFWriter')
274 opObj10.addParameter(name='path',value=path_save, format='str')
275 opObj10.addParameter(name='Reset',value=True)
276 opObj10.addParameter(name='setType',value='weather')
277 opObj10.addParameter(name='description',value='desc')
278 opObj10.addParameter(name='blocksPerFile',value='1',format='int')
279 opObj10.addParameter(name='metadataList',value='heightList,data_azi,data_ele')
280 opObj10.addParameter(name='dataList',value='{},utctime'.format(PARAM[param]['name']))
126 281
127 282 project.start()
128 283
129 284 if __name__ == '__main__':
130 285
131 286 parser = argparse.ArgumentParser(description='Script to process SOPHy data.')
132 287 parser.add_argument('experiment',
133 288 help='Experiment name')
134 289 parser.add_argument('--parameters', nargs='*', default=['P'],
135 290 help='Variables to process: P, Z, V')
136 291 parser.add_argument('--time_offset', default=0,
137 292 help='Fix time offset')
138 293 parser.add_argument('--range', default=0, type=float,
139 294 help='Max range to plot')
140 295 parser.add_argument('--save', action='store_true',
141 296 help='Create output files')
142 297 parser.add_argument('--show', action='store_true',
143 298 help='Show matplotlib plot.')
144 299 parser.add_argument('--online', action='store_true',
145 300 help='Set online mode.')
146 parser.add_argument('--rti', action='store_true',
147 help='Set RTI plot.')
301 parser.add_argument('--start_time', default='',
302 help='Set start time.')
148 303
149 args = parser.parse_args()
150 304
151 main(args)
305 args = parser.parse_args()
306 print(args)
307 main(args) No newline at end of file
@@ -1,285 +1,296
1 import ast
1 import os
2 2 from datetime import datetime
3 3 import json
4 4 import requests
5 5 import base64
6 6 import struct
7 7 from struct import pack
8 8 import time
9 9 from django.contrib import messages
10 10 from django.db import models
11 11 from django.urls import reverse
12 12 from django.core.validators import MinValueValidator, MaxValueValidator
13 13
14 14 from apps.main.models import Configuration
15 15
16 16 MODE_VALUE = (
17 17 ('position', 'Position'),
18 18 ('speed', 'Speed'),
19 19 ('table', 'Table')
20 20 )
21 21
22 22 class PedestalConfiguration(Configuration):
23 23
24 24 mode = models.CharField(
25 25 verbose_name='Mode',
26 26 max_length=10,
27 27 choices=MODE_VALUE,
28 28 null=False,
29 29 blank=False
30 30 )
31 31
32 32 axis = models.CharField(
33 33 verbose_name="Axis",
34 34 max_length=1000,
35 35 blank=False,
36 36 null=False,
37 37 help_text="Please separate the values with commas when using table mode"
38 38 )
39 39
40 40 speed = models.CharField(
41 41 verbose_name='Speed [Β°/s]',
42 42 max_length=1000,
43 43 blank=True,
44 44 null=True
45 45 )
46 46
47 47 angle = models.CharField(
48 48 verbose_name="Angle(s) [Β°]",
49 49 max_length=1000,
50 50 blank=True,
51 51 null=True,
52 52 help_text="Please separate the values with commas when using table mode"
53 53 )
54 54
55 55 min_value = models.FloatField(
56 56 verbose_name='Min angle [Β°]',
57 57 validators=[MinValueValidator(-5), MaxValueValidator(185)],
58 58 blank=True,
59 59 null=True
60 60 )
61 61
62 62 max_value = models.FloatField(
63 63 verbose_name='Max angle [Β°]',
64 64 validators=[MinValueValidator(-5), MaxValueValidator(185)],
65 65 blank=True,
66 66 null=True
67 67 )
68 68
69 69 class Meta:
70 70 db_table = 'pedestal_configurations'
71 71
72 72 def __str__(self):
73 73 if self.mode=='position':
74 74 return u'Position: {}ΒΊ {}'.format(self.angle, self.axis.upper())
75 75 if self.mode=='speed':
76 76 return u'Speed: {}ΒΊ/s {}'.format(self.speed, self.axis.upper())
77 77 if self.mode=='table':
78 78 axis = [x.strip().upper() for x in self.axis.split(',')]
79 79 speeds = [float(x.strip()) for x in self.speed.split(',')]
80 80 table = [float(x.strip()) for x in self.angle.split(',')]
81 81 return u'Table: Axis {}, Speed {}ΒΊ/s, Steps {}'.format(axis, speeds, table)
82 82
83 83 @property
84 84 def label(self):
85 85 return str(self)
86 86
87 87 def get_absolute_url_plot(self):
88 88 return reverse('url_plot_pedestal_pulses', args=[str(self.id)])
89 89
90 90 def request(self, cmd, method='get', **kwargs):
91 91
92 92 req = getattr(requests, method)(self.device.url(cmd), **kwargs)
93 93 payload = req.json()
94 94
95 95 return payload
96 96
97 97 def status_device(self):
98 98
99 99 try:
100 100 payload = requests.get(self.device.url())
101 101
102 102 if payload:
103 103 self.device.status = 1
104 104 elif payload['status']=='disable':
105 105 self.device.status = 2
106 106 else:
107 107 self.device.status = 1
108 108 self.device.save()
109 109 self.message = 'Pedestal status: {}'.format(payload['status'])
110 110 return False
111 111 except Exception as e:
112 112 if 'No route to host' not in str(e):
113 113 self.device.status = 4
114 114 self.device.save()
115 115 self.message = 'Pedestal status: {}'.format(str(e))
116 116 return False
117 117
118 118 self.device.save()
119 119 return True
120 120
121 121 def reset_device(self, axi, angle):
122 122
123 123 try:
124 124 url = self.device.url() + "position?params="
125 125
126 126 payload_el = {'axis': 'elevation'}
127 127 payload_az = {'axis': 'azimuth'}
128 128
129 129 if axi == 'elevation':
130 payload_az['position'] = angle
130 # CORRECT AZ OFFSET
131 azi = angle - float(os.environ.get('AZ_OFFSET', 26.27))
132 if azi<0: azi += 360
133 payload_az['position'] = round(azi, 2)
131 134 payload_el['position'] = 0
132 135 elif axi == 'azimuth':
133 136 payload_el['position'] = angle
134 137 payload_az['position'] = 0
135 138 else:
136 139 payload_el['position'] = 0
137 140 payload_az['position'] = 0
138 141
139 142 json_data_el = json.dumps(payload_el)
140 143 json_data_az = json.dumps(payload_az)
141 144
142 145 base64_table_el = base64.standard_b64encode(json_data_el.encode('ascii'))
143 146 base64_table_az = base64.standard_b64encode(json_data_az.encode('ascii'))
144 147
145 148 time.sleep(0.1)
146 149 r = requests.get(url + base64_table_el.decode('ascii'))
147 150 time.sleep(0.1)
148 151 r = requests.get(url + base64_table_az.decode('ascii'))
149 152
150 153 if r:
151 154 self.device.status = 3
152 155 self.device.save()
153 156 self.message = 'Pedestal reset'
154 157 else:
155 158 return False
156 159
157 160 except Exception as e:
158 161 self.message = 'Pedestal reset: {}'.format(str(e))
159 162 return False
160 163
161 164 return True
162 165
163 166 def stop_device(self):
164 167
165 168 try:
166 169 command = self.device.url() + "stop"
167 170 r = requests.get(command)
168 171
169 172 if self.mode == 'table':
170 173 AX = {'az':'azimuth', 'el':'elevation'}
171 174 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
172 175 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
173 176 self.reset_device(axis[0], list_of_floats[0])
174 177
175 178 if r:
176 179 self.device.status = 4
177 180 self.device.save()
178 181 self.message = 'Pedestal stopped'
179 182 else:
180 183 self.device.status = 4
181 184 self.device.save()
182 185 return False
183 186 except Exception as e:
184 187 if 'No route to host' not in str(e):
185 188 self.device.status = 4
186 189 else:
187 190 self.device.status = 0
188 191 #self.message = 'Pedestal stop: {}'.format(str(e))
189 192 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
190 193 self.device.save()
191 194 return False
192 195
193 196 return True
194 197
195 198 def start_device(self, name_experiment=False):
196 199
197 200 if self.mode == 'table':
198 201 if len(self.angle.split(',')) > 1:
199 202 list_speed = []
200 203 list_axis = []
201 204 for _ in range(len(self.angle.split(','))):
202 205 list_axis.append(self.axis)
203 206 list_speed.append(self.speed)
204 207
205 208 if len(self.axis.split(',')) == 1:
206 209 self.axis = ",".join(map(str, list_axis))
207 210 if len(self.speed.split(',')) == 1:
208 211 self.speed = ",".join(map(str, list_speed))
209 212
210 213 AX = {'az':'azimuth', 'el':'elevation'}
211 214 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
212 215 if len(axis)==1:
213 216 axis = axis[0]
214 217
215 218 try:
216 219 if self.mode == 'position':
217 220 url = self.device.url() + "position?params="
218 221 payload = {'axis': axis, 'position': float(self.angle)}
219 222 elif self.mode == 'speed':
220 223 url = self.device.url() + "speed?params="
221 224 payload = {'axis': axis, 'speed': float(self.speed)}
222 225 elif self.mode == 'table':
223 226 url = self.device.url() + "combinedtable?params="
224 227 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
228
229 # CORRECT AZ OFFSET
230 for i, ax in enumerate(axis):
231 if ax == 'elevation':
232 azi = list_of_floats[i] - float(os.environ.get('AZ_OFFSET', 26.27))
233 if azi<0: azi += 360
234 list_of_floats[i] = round(azi, 2)
235
225 236 byte_table = []
226 237 for x in list_of_floats:
227 238 temp = bytearray(struct.pack("f", x))
228 239 byte_table.append(temp[3])
229 240 byte_table.append(temp[2])
230 241 byte_table.append(temp[1])
231 242 byte_table.append(temp[0])
232 243
233 244 coded_table = base64.standard_b64encode(bytes(byte_table))
234 245 coded_table_ascii = coded_table.decode('ascii')
235 246 speed = [float(x.strip()) for x in self.speed.split(',')]
236 247
237 248 if isinstance(axis, str):
238 249 axis = [axis]
239 250
240 251 payload = {
241 252 'arraylength': len(speed),
242 253 'axis': axis,
243 254 'speed': speed,
244 255 'bottom': self.min_value,
245 256 'top': self.max_value,
246 257 'table': coded_table_ascii
247 258 }
248 259
249 260 json_data = json.dumps(payload)
250 261 print(json_data)
251 262 base64_table = base64.standard_b64encode(json_data.encode('ascii'))
252 263 url += base64_table.decode('ascii')
253 264 print(url)
254 265 r = requests.get(url)
255 266
256 267 if self.mode == 'table':
257 268 payload['table'] = list_of_floats
258 269
259 270 if name_experiment:
260 271 name_experiment = name_experiment.split("@")
261 272 dt = datetime.strptime(name_experiment[1], '%Y-%m-%dT%H-%M-%S')
262 273 self.clone(experiment=name_experiment[0], experiment_date=dt, type=1)
263 274 else:
264 275 self.clone(type=1, experiment = 'empty', experiment_date=datetime.now())
265 276
266 277 if r:
267 278 self.device.status = 3
268 279 self.device.save()
269 280 self.message = 'Pedestal configured and started'
270 281 else:
271 282 return False
272 283 except Exception as e:
273 284 if 'No route to host' not in str(e):
274 285 self.device.status = 4
275 286 else:
276 287 self.device.status = 0
277 288 #self.message = 'Pedestal start: {}'.format(str(e))
278 289 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
279 290 self.device.save()
280 291 return False
281 292
282 293 return payload
283 294
284 295 def get_absolute_url_import(self):
285 return reverse('url_import_pedestal_conf', args=[str(self.id)])
296 return reverse('url_import_pedestal_conf', args=[str(self.id)]) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now