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