##// END OF EJS Templates
Add 'reset pedestal' option
eynilupu -
r444:d8e453ba0459
parent child
Show More
@@ -1,200 +1,210
1 from django.core.management.base import BaseCommand
1 from django.core.management.base import BaseCommand
2 from apps.main.models import Experiment
2 from apps.main.models import Experiment
3 from django.shortcuts import get_object_or_404
3 from django.shortcuts import get_object_or_404
4 import os, fnmatch
4 import os, fnmatch
5 import time
5 import time
6 from datetime import datetime
6 from datetime import datetime
7 import h5py
7 import h5py
8 import numpy as np
8 import numpy as np
9
9
10 class Command(BaseCommand):
10 class Command(BaseCommand):
11 """
11 """
12 Check pedestal acquisition each 10 minutes.
12 Check pedestal acquisition each 10 minutes.
13 Example:
13 Example:
14 manage.py restart_pedestal
14 manage.py restart_pedestal
15 """
15 """
16 def handle(self, *args, **options):
16 def handle(self, *args, **options):
17 #start = time.time()
17 #start = time.time()
18 #time.sleep(1)
18 #time.sleep(1)
19 restart_pedestal(self)
19 restart_pedestal(self)
20 #end = time.time()
20 #end = time.time()
21 #self.stdout.write(f'TIME: "{end - start}"')
21 #self.stdout.write(f'TIME: "{end - start}"')
22
22
23 def check_experiment():
23 def check_experiment():
24 if len(Experiment.objects.filter(status=2)) > 0:
24 if len(Experiment.objects.filter(status=2)) > 0:
25 return True
25 return True
26 else:
26 else:
27 return False
27 return False
28
28
29 def pedestal_start(self, id_exp):
29 def pedestal_start(self, id_exp):
30 all_status = Experiment.objects.filter(status=2)
30 all_status = Experiment.objects.filter(status=2)
31 check_id = False
31 check_id = False
32
32
33 if len(all_status) > 0:
33 if len(all_status) > 0:
34 check_id = all_status[0].pk
34 check_id = all_status[0].pk
35
35
36 if check_id and check_id == id_exp:
36 if check_id and check_id == id_exp:
37 exp = get_object_or_404(Experiment, pk=id_exp)
37 exp = get_object_or_404(Experiment, pk=id_exp)
38 name = '{}-R@{}'.format(exp.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S'))
38 name = '{}-R@{}'.format(exp.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S'))
39 exp.pedestal.start_device(name_experiment=name)
39 exp.pedestal.start_device(name_experiment=name)
40 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition was restarted')
40 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition was restarted')
41
41
42 def pedestal_reset(self, id_exp):
43 all_status = Experiment.objects.filter(status=2)
44 check_id = False
45
46 if len(all_status) > 0:
47 check_id = all_status[0].pk
48
49 if check_id and check_id == id_exp:
50 exp = get_object_or_404(Experiment, pk=id_exp)
51 exp.pedestal.reset_device()
52 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition is resetting')
53
42 def pedestal_stop(self, id_exp):
54 def pedestal_stop(self, id_exp):
43 all_status = Experiment.objects.filter(status=2)
55 all_status = Experiment.objects.filter(status=2)
44 check_id = False
56 check_id = False
45
57
46 if len(all_status) > 0:
58 if len(all_status) > 0:
47 check_id = all_status[0].pk
59 check_id = all_status[0].pk
48
60
49 if check_id and check_id == id_exp:
61 if check_id and check_id == id_exp:
50 exp = get_object_or_404(Experiment, pk=id_exp)
62 exp = get_object_or_404(Experiment, pk=id_exp)
51 exp.pedestal.stop_device()
63 exp.pedestal.stop_device()
52 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition "{exp.name}" was stopped')
64 self.stdout.write(f'"{exp.name}" experiment: Pedestal acquisition was stopped')
53
65
54 def hdf5_list_content(get_file):
66 def hdf5_list_content(get_file):
55 table_records = np.array(get_file).tolist()
67 table_records = np.array(get_file).tolist()
56 table_dim = get_file.ndim
68 table_dim = get_file.ndim
57 table_rows = get_file.shape[0]
69 table_rows = get_file.shape[0]
58
70
59 if table_dim == 1 and table_rows >= 1:
71 if table_dim == 1 and table_rows >= 1:
60 #type(table_records[0]) -> float
72 #type(table_records[0]) -> float
61 return table_records
73 return table_records
62 else:
74 else:
63 return False
75 return False
64
76
65 def hdf5_read(file):
77 def hdf5_read(file):
66 dataspeed = {"ele_speed": False, "azi_speed": False}
78 dataspeed = {"ele_speed": False, "azi_speed": False}
67
79
68 for key, value in dataspeed.items():
80 for key, value in dataspeed.items():
69 with h5py.File(file, 'r') as hdf:
81 with h5py.File(file, 'r') as hdf:
70 get = hdf.get('Data'+'/'+key)
82 get = hdf.get('Data'+'/'+key)
71 if get is not None:
83 if get is not None:
72 # 10 values
84 # 10 values
73 dataspeed[key] = hdf5_list_content(get)[-10:]
85 dataspeed[key] = hdf5_list_content(get)[-10:]
74
86
75 return dataspeed
87 return dataspeed
76
88
77 def count_data(last_position):
89 def count_data(last_position):
78 pattern = "pos@*.h5"
90 pattern = "pos@*.h5"
79 count = 0
91 count = 0
80 list_data = []
92 list_data = []
81
93
82 list_position = os.listdir(last_position)
94 list_position = os.listdir(last_position)
83
95
84 for entry in sorted(list_position):
96 for entry in sorted(list_position):
85 if fnmatch.fnmatch(entry, pattern):
97 if fnmatch.fnmatch(entry, pattern):
86 count = count + 1
98 count = count + 1
87 list_data.append(os.path.join(last_position, entry))
99 list_data.append(os.path.join(last_position, entry))
88
100
89 if len(list_data) > 1:
101 if len(list_data) > 1:
90 list_data = list_data[-2]
102 list_data = list_data[-2]
91 else:
103 else:
92 list_data = False
104 list_data = False
93
105
94 return count, list_data
106 return count, list_data
95
107
96 def response_data(datadir, old_path_datetime, old_position, new_position):
108 def response_data(datadir, old_path_datetime, old_position, new_position):
97 path_position = True
109 path_position = True
98 path_datetime = False
110 path_datetime = False
99 read_files = False
111 read_files = False
100
112
101 rootdir = os.path.join(datadir, 'position')
113 rootdir = os.path.join(datadir, 'position')
102 if os.path.isdir(rootdir):
114 if os.path.isdir(rootdir):
103 path_datetime = path_data(os.path.join(datadir, 'position'))
115 path_datetime = path_data(os.path.join(datadir, 'position'))
104
116
105 if path_datetime:
117 if path_datetime:
106 if not old_path_datetime or path_datetime != old_path_datetime:
118 if not old_path_datetime or path_datetime != old_path_datetime:
107 old_position, read_files = count_data(path_datetime)
119 old_position, read_files = count_data(path_datetime)
108 time.sleep(65)
120 time.sleep(65)
109 new_position, read_files = count_data(path_datetime)
121 new_position, read_files = count_data(path_datetime)
110 else:
122 else:
111 time.sleep(65)
123 time.sleep(65)
112 else:
124 else:
113 path_position = False
125 path_position = False
114
126
115 return path_position, path_datetime, old_position, new_position, read_files
127 return path_position, path_datetime, old_position, new_position, read_files
116
128
117 def path_data(rootdir):
129 def path_data(rootdir):
118 list_=[]
130 list_=[]
119 for it in os.scandir(rootdir):
131 for it in os.scandir(rootdir):
120 if it.is_dir():
132 if it.is_dir():
121 try:
133 try:
122 datetime.strptime(it.path.split("/")[-1], "%Y-%m-%dT%H-00-00")
134 datetime.strptime(it.path.split("/")[-1], "%Y-%m-%dT%H-00-00")
123 list_.append(it.path)
135 list_.append(it.path)
124 except ValueError:
136 except ValueError:
125 pass
137 pass
126
138
127 list_ = sorted(list_, reverse=True)
139 list_ = sorted(list_, reverse=True)
128 try:
140 try:
129 return list_[0]
141 return list_[0]
130 except:
142 except:
131 return False
143 return False
132
144
133 def check_count(datadir):
145 def check_count(datadir):
134 old_numbers = 0
146 old_numbers = 0
135 new_numbers = 0
147 new_numbers = 0
136 validation = False
148 validation = False
137 path_datetime = False
149 path_datetime = False
138 speed = {"ele_speed": False, "azi_speed": False}
150 speed = {"ele_speed": False, "azi_speed": False}
139
151
140 path_position, path_datetime, old_numbers, new_numbers, read_files = response_data(datadir, path_datetime, old_numbers, new_numbers)
152 path_position, path_datetime, old_numbers, new_numbers, read_files = response_data(datadir, path_datetime, old_numbers, new_numbers)
141
153
142 for u in range(2):
154 for u in range(2):
143 if new_numbers > old_numbers:
155 if new_numbers > old_numbers:
144 validation = True
156 validation = True
145
157
146 data = hdf5_read(read_files)
158 data = hdf5_read(read_files)
147 for key, value in data.items():
159 for key, value in data.items():
148 try:
160 try:
149 if not max(data[key]) <= 0.1:
161 if not max(data[key]) <= 0.1:
150 speed[key] = True
162 speed[key] = True
151 except:
163 except:
152 pass
164 pass
153 break
165 break
154 else:
166 else:
155 if u < 1:
167 if u < 1:
156 path_position, path_datetime, old_numbers, new_numbers, read_files = response_data(datadir, path_datetime, old_numbers, new_numbers)
168 path_position, path_datetime, old_numbers, new_numbers, read_files = response_data(datadir, path_datetime, old_numbers, new_numbers)
157
169
158 return path_position, path_datetime, validation, speed
170 return path_position, path_datetime, validation, speed
159
171
160 def restart_pedestal(self):
172 def restart_pedestal(self):
161 if check_experiment():
173 if check_experiment():
162
174
163 all_status = Experiment.objects.filter(status=2)
175 all_status = Experiment.objects.filter(status=2)
164 id_exp = all_status[0].pk
176 id_exp = all_status[0].pk
165 datadir_exp = all_status[0].reception_rx.datadir
177 datadir_exp = all_status[0].reception_rx.datadir
166 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA'), '/data')
178 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA'), '/data')
167 datadir_exp = datadir_exp.replace('/rawdata', '')
179 datadir_exp = datadir_exp.replace('/rawdata', '')
168
180
169 path_position, path_datetime, validation, speed = check_count(datadir_exp)
181 path_position, path_datetime, validation, speed = check_count(datadir_exp)
170 if path_position:
182 if path_position:
171 # Execute the process
183 # Execute the process
172 if validation:
184 if validation:
173 self.stdout.write(f'Acquisition pedestal is running')
185 self.stdout.write(f'Acquisition pedestal is running')
174 if speed['ele_speed'] or speed['azi_speed']:
186 if speed['ele_speed'] or speed['azi_speed']:
175 self.stdout.write(f'Pedestal speeds on Azimuth and Elevation are running')
187 self.stdout.write(f'Pedestal speeds on Azimuth and Elevation are running')
176 else:
188 else:
177 for key, value in speed.items():
189 for key, value in speed.items():
178 if not value:
190 if not value:
179 self.stdout.write(f'Speed on {key} is <= 0.1, retry')
191 self.stdout.write(f'Speed on {key} is <= 0.1, retry')
180
192
181 pedestal_stop(self, id_exp)
193 pedestal_stop(self, id_exp)
182 time.sleep(14)
194 time.sleep(14)
183 #pedestal_reset(self, id_exp)
184 #time.sleep(2)
185 pedestal_start(self, id_exp)
195 pedestal_start(self, id_exp)
186
196
187 else:
197 else:
188 if not path_datetime:
198 if not path_datetime:
189 self.stdout.write(f'No such directory with datetime format "%Y-%m-%dT%H-00-00", retry!')
199 self.stdout.write(f'No such directory with datetime format "%Y-%m-%dT%H-00-00", retry!')
190 else:
200 else:
191 self.stdout.write(f'No file increment, retry')
201 self.stdout.write(f'No file increment, retry')
192
202
203 pedestal_reset(self, id_exp)
204 time.sleep(14)
193 pedestal_stop(self, id_exp)
205 pedestal_stop(self, id_exp)
194 time.sleep(14)
206 time.sleep(14)
195 #pedestal_reset(self, id_exp)
196 #time.sleep(2)
197 pedestal_start(self, id_exp)
207 pedestal_start(self, id_exp)
198
208
199 else:
209 else:
200 self.stdout.write(f'No such directory: position, fail!') No newline at end of file
210 self.stdout.write(f'No such directory: position, fail!')
@@ -1,153 +1,157
1 from django.core.management.base import BaseCommand
1 from django.core.management.base import BaseCommand
2 from apps.main.models import Experiment
2 from apps.main.models import Experiment
3 from django.shortcuts import get_object_or_404
3 from django.shortcuts import get_object_or_404
4 import os, fnmatch
4 import os, fnmatch
5 import time
5 import time
6 from datetime import datetime
6 from datetime import datetime
7 import requests
7 import requests
8
8
9 class Command(BaseCommand):
9 class Command(BaseCommand):
10 """
10 """
11 Check data acquisition each 05 minutes.
11 Check data acquisition each 05 minutes.
12 Example:
12 Example:
13 manage.py restart_reception
13 manage.py restart_reception
14 """
14 """
15 def handle(self, *args, **options):
15 def handle(self, *args, **options):
16 #start = time.time()
16 #start = time.time()
17 time.sleep(15)
17 time.sleep(15)
18 restart_acquisition(self)
18 restart_acquisition(self)
19 #end = time.time()
19 #end = time.time()
20 #self.stdout.write(f'TIME: "{end - start}"')
20 #self.stdout.write(f'TIME: "{end - start}"')
21
21
22 def check_experiment():
22 def check_experiment():
23 if len(Experiment.objects.filter(status=2)) > 0:
23 if len(Experiment.objects.filter(status=2)) > 0:
24 return True
24 return True
25 else:
25 else:
26 return False
26 return False
27
27
28 def acquisition_start(self, id_exp):
28 def acquisition_start(self, id_exp):
29 all_status = Experiment.objects.filter(status=2)
29 all_status = Experiment.objects.filter(status=2)
30 check_id = False
30 check_id = False
31
31
32 if len(all_status) > 0:
32 if len(all_status) > 0:
33 check_id = all_status[0].pk
33 check_id = all_status[0].pk
34
34
35 if check_id and check_id == id_exp:
35 if check_id and check_id == id_exp:
36 exp = get_object_or_404(Experiment, pk=id_exp)
36 exp = get_object_or_404(Experiment, pk=id_exp)
37 name = '{}-R@{}'.format(exp.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S'))
37 name = '{}-R@{}'.format(exp.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S'))
38 exp.reception_rx.start_device(name_experiment = name, restart = True)
38 exp.reception_rx.start_device(name_experiment = name, restart = True)
39 self.stdout.write(f'"{exp.name}" experiment: Data acquisition was restarted')
39 self.stdout.write(f'"{exp.name}" experiment: Data acquisition was restarted')
40
40 self.stdout.write(f'Restarting schain...')
41 self.stdout.write(f'Restarting schain...')
42 datadir_exp = exp.reception_rx.datadir
43 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA') + '/', '')
44 datadir_exp = datadir_exp.replace('/rawdata', '')
41
45
42 r = requests.get('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/stop')
46 r = requests.get('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/stop')
43 time.sleep(1)
47 time.sleep(1)
44 r = requests.post('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/start', json={'name': exp.name})
48 r = requests.post('http://'+os.environ.get('SCHAIN_SITE', 'sophy-schain')+'/start', json={'name': datadir_exp})
45
49
46 def acquisition_stop(self, id_exp):
50 def acquisition_stop(self, id_exp):
47 all_status = Experiment.objects.filter(status=2)
51 all_status = Experiment.objects.filter(status=2)
48 check_id = False
52 check_id = False
49
53
50 if len(all_status) > 0:
54 if len(all_status) > 0:
51 check_id = all_status[0].pk
55 check_id = all_status[0].pk
52
56
53 if check_id and check_id == id_exp:
57 if check_id and check_id == id_exp:
54 exp = get_object_or_404(Experiment, pk=id_exp)
58 exp = get_object_or_404(Experiment, pk=id_exp)
55 exp.reception_rx.stop_device()
59 exp.reception_rx.stop_device()
56 self.stdout.write(f'"{exp.name}" experiment: Data acquisition "{exp.name}" was stopped')
60 self.stdout.write(f'"{exp.name}" experiment: Data acquisition "{exp.name}" was stopped')
57
61
58 def count_data(last_channel):
62 def count_data(last_channel):
59 pattern = "rf@*.h5"
63 pattern = "rf@*.h5"
60 count = 0
64 count = 0
61 list_channel = os.listdir(last_channel)
65 list_channel = os.listdir(last_channel)
62
66
63 for entry in sorted(list_channel):
67 for entry in sorted(list_channel):
64 if fnmatch.fnmatch(entry, pattern):
68 if fnmatch.fnmatch(entry, pattern):
65 count = count + 1
69 count = count + 1
66 return count
70 return count
67
71
68 def response_data(datadir, old_channel, old_rawdata, new_rawdata, search):
72 def response_data(datadir, old_channel, old_rawdata, new_rawdata, search):
69 path_channels = {'ch0': True, 'ch1': True}
73 path_channels = {'ch0': True, 'ch1': True}
70 channel = {'ch0': False, 'ch1': False}
74 channel = {'ch0': False, 'ch1': False}
71
75
72 for key, value in path_channels.items():
76 for key, value in path_channels.items():
73 rootdir = os.path.join(datadir, key)
77 rootdir = os.path.join(datadir, key)
74 if os.path.isdir(rootdir):
78 if os.path.isdir(rootdir):
75 channel[key] = path_data(os.path.join(datadir, key))
79 channel[key] = path_data(os.path.join(datadir, key))
76 if key in search:
80 if key in search:
77 if channel[key]:
81 if channel[key]:
78 if not old_channel[key] or channel[key] != old_channel[key]:
82 if not old_channel[key] or channel[key] != old_channel[key]:
79 old_rawdata[key] = count_data(channel[key])
83 old_rawdata[key] = count_data(channel[key])
80 time.sleep(1)
84 time.sleep(1)
81 new_rawdata[key] = count_data(channel[key])
85 new_rawdata[key] = count_data(channel[key])
82 else:
86 else:
83 time.sleep(1)
87 time.sleep(1)
84 else:
88 else:
85 path_channels[key] = False
89 path_channels[key] = False
86
90
87 return path_channels, channel, old_rawdata, new_rawdata
91 return path_channels, channel, old_rawdata, new_rawdata
88
92
89 def path_data(rootdir):
93 def path_data(rootdir):
90 list_=[]
94 list_=[]
91 for it in os.scandir(rootdir):
95 for it in os.scandir(rootdir):
92 if it.is_dir():
96 if it.is_dir():
93 try:
97 try:
94 datetime.strptime(it.path.split("/")[-1], "%Y-%m-%dT%H-00-00")
98 datetime.strptime(it.path.split("/")[-1], "%Y-%m-%dT%H-00-00")
95 list_.append(it.path)
99 list_.append(it.path)
96 except ValueError:
100 except ValueError:
97 pass
101 pass
98
102
99 list_ = sorted(list_, reverse=True)
103 list_ = sorted(list_, reverse=True)
100 try:
104 try:
101 return list_[0]
105 return list_[0]
102 except:
106 except:
103 return False
107 return False
104
108
105 def check_count(datadir):
109 def check_count(datadir):
106 old_numbers = {'ch0': 0, 'ch1': 0}
110 old_numbers = {'ch0': 0, 'ch1': 0}
107 new_numbers = {'ch0': 0, 'ch1': 0}
111 new_numbers = {'ch0': 0, 'ch1': 0}
108 validation = {'ch0': False, 'ch1': False}
112 validation = {'ch0': False, 'ch1': False}
109 channel = {'ch0': False, 'ch1': False}
113 channel = {'ch0': False, 'ch1': False}
110
114
111 path_channels, channel, old_numbers, new_numbers = response_data(datadir, channel, old_numbers, new_numbers, ['ch0', 'ch1'])
115 path_channels, channel, old_numbers, new_numbers = response_data(datadir, channel, old_numbers, new_numbers, ['ch0', 'ch1'])
112
116
113 for key, value in validation.items():
117 for key, value in validation.items():
114 for _ in range(5):
118 for _ in range(5):
115 if new_numbers[key] > old_numbers[key]:
119 if new_numbers[key] > old_numbers[key]:
116 validation[key] = True
120 validation[key] = True
117 break
121 break
118 else:
122 else:
119 path_channels, channel, old_numbers, new_numbers = response_data(datadir, channel, old_numbers, new_numbers, [key])
123 path_channels, channel, old_numbers, new_numbers = response_data(datadir, channel, old_numbers, new_numbers, [key])
120
124
121 return path_channels, channel, validation
125 return path_channels, channel, validation
122
126
123 def restart_acquisition(self):
127 def restart_acquisition(self):
124 if check_experiment():
128 if check_experiment():
125 all_status = Experiment.objects.filter(status=2)
129 all_status = Experiment.objects.filter(status=2)
126 id_exp = all_status[0].pk
130 id_exp = all_status[0].pk
127 datadir_exp = all_status[0].reception_rx.datadir
131 datadir_exp = all_status[0].reception_rx.datadir
128 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA'), '/data')
132 datadir_exp = datadir_exp.replace(os.environ.get('EXPOSE_NAS', '/DATA_RM/DATA'), '/data')
129
133
130 path_channels, channel, validation = check_count(datadir_exp)
134 path_channels, channel, validation = check_count(datadir_exp)
131
135
132 if path_channels['ch0'] and path_channels['ch1']:
136 if path_channels['ch0'] and path_channels['ch1']:
133 # Execute the process
137 # Execute the process
134 if validation['ch0'] and validation['ch1']:
138 if validation['ch0'] and validation['ch1']:
135 self.stdout.write(f'Data acquisition is running')
139 self.stdout.write(f'Data acquisition is running')
136 else:
140 else:
137 if not channel['ch0'] or not channel['ch1']:
141 if not channel['ch0'] or not channel['ch1']:
138 for key, value in channel.items():
142 for key, value in channel.items():
139 if not value:
143 if not value:
140 self.stdout.write(f'No such directory with datetime format "%Y-%m-%dT%H-00-00": channel["{key}"], retry!')
144 self.stdout.write(f'No such directory with datetime format "%Y-%m-%dT%H-00-00": channel["{key}"], retry!')
141 else:
145 else:
142 for key, value in validation.items():
146 for key, value in validation.items():
143 if not value:
147 if not value:
144 self.stdout.write(f'No file increment: channel["{key}"]')
148 self.stdout.write(f'No file increment: channel["{key}"]')
145
149
146 acquisition_stop(self, id_exp)
150 acquisition_stop(self, id_exp)
147 time.sleep(3)
151 time.sleep(3)
148 acquisition_start(self, id_exp)
152 acquisition_start(self, id_exp)
149
153
150 else:
154 else:
151 for key, value in path_channels.items():
155 for key, value in path_channels.items():
152 if not value:
156 if not value:
153 self.stdout.write(f'No such directory: channel["{key}"], fail!') No newline at end of file
157 self.stdout.write(f'No such directory: channel["{key}"], fail!')
@@ -1,653 +1,655
1 import os
1 import os
2 import json
2 import json
3 import requests
3 import requests
4 import time
4 import time
5 from datetime import datetime
5 from datetime import datetime
6 import base64
6 import base64
7
7
8 try:
8 try:
9 from polymorphic.models import PolymorphicModel
9 from polymorphic.models import PolymorphicModel
10 except:
10 except:
11 from polymorphic import PolymorphicModel
11 from polymorphic import PolymorphicModel
12
12
13 from django.template.base import kwarg_re
13 from django.template.base import kwarg_re
14 from django.db import models
14 from django.db import models
15 from django.urls import reverse
15 from django.urls import reverse
16 from django.core.validators import MinValueValidator, MaxValueValidator
16 from django.core.validators import MinValueValidator, MaxValueValidator
17 from django.shortcuts import get_object_or_404
17 from django.shortcuts import get_object_or_404
18 from django.contrib.auth.models import User
18 from django.contrib.auth.models import User
19 from django.db.models.signals import post_save
19 from django.db.models.signals import post_save
20 from django.dispatch import receiver
20 from django.dispatch import receiver
21
21
22 from apps.main.utils import Params
22 from apps.main.utils import Params
23
23
24 DEV_PORTS = {
24 DEV_PORTS = {
25 'pedestal' : 80,
25 'pedestal' : 80,
26 'pedestal_dev' : 80,
26 'pedestal_dev' : 80,
27 'generator' : 80,
27 'generator' : 80,
28 'usrp_rx' : 2000,
28 'usrp_rx' : 2000,
29 'usrp_tx' : 2000,
29 'usrp_tx' : 2000,
30 }
30 }
31
31
32 RADAR_STATES = (
32 RADAR_STATES = (
33 (0, 'No connected'),
33 (0, 'No connected'),
34 (1, 'Connected'),
34 (1, 'Connected'),
35 (2, 'Configured'),
35 (2, 'Configured'),
36 (3, 'Running'),
36 (3, 'Running'),
37 (4, 'Scheduled'),
37 (4, 'Scheduled'),
38 )
38 )
39
39
40 EXPERIMENT_TYPE = (
40 EXPERIMENT_TYPE = (
41 (0, 'RAW_DATA'),
41 (0, 'RAW_DATA'),
42 (1, 'PDATA'),
42 (1, 'PDATA'),
43 )
43 )
44
44
45 DECODE_TYPE = (
45 DECODE_TYPE = (
46 (0, 'None'),
46 (0, 'None'),
47 (1, 'TimeDomain'),
47 (1, 'TimeDomain'),
48 (2, 'FreqDomain'),
48 (2, 'FreqDomain'),
49 (3, 'InvFreqDomain'),
49 (3, 'InvFreqDomain'),
50 )
50 )
51
51
52 DEV_STATES = (
52 DEV_STATES = (
53 (0, 'Unknown'),
53 (0, 'Unknown'),
54 (1, 'Connected'),
54 (1, 'Connected'),
55 (2, 'Configured'),
55 (2, 'Configured'),
56 (3, 'Running'),
56 (3, 'Running'),
57 (4, 'Offline'),
57 (4, 'Offline'),
58 )
58 )
59
59
60 DEV_TYPES = (
60 DEV_TYPES = (
61 ('', 'Select a device type'),
61 ('', 'Select a device type'),
62 ('pedestal', 'Pedestal Controller'),
62 ('pedestal', 'Pedestal Controller'),
63 ('pedestal_dev', 'Pedestal Controller Dev Mode'),
63 ('pedestal_dev', 'Pedestal Controller Dev Mode'),
64 ('generator', 'Pulse Generator'),
64 ('generator', 'Pulse Generator'),
65 ('usrp_rx', 'Universal Software Radio Peripheral Rx'),
65 ('usrp_rx', 'Universal Software Radio Peripheral Rx'),
66 ('usrp_tx', 'Universal Software Radio Peripheral Tx'),
66 ('usrp_tx', 'Universal Software Radio Peripheral Tx'),
67 )
67 )
68
68
69 EXP_STATES = (
69 EXP_STATES = (
70 (0,'Error'), #RED
70 (0,'Error'), #RED
71 (1,'Cancelled'), #YELLOW
71 (1,'Cancelled'), #YELLOW
72 (2,'Running'), #GREEN
72 (2,'Running'), #GREEN
73 (3,'Scheduled'), #BLUE
73 (3,'Scheduled'), #BLUE
74 (4,'Unknown'), #WHITE
74 (4,'Unknown'), #WHITE
75 (5,'Other'), #ORANGE
75 (5,'Other'), #ORANGE
76 )
76 )
77
77
78 CONF_TYPES = (
78 CONF_TYPES = (
79 (0, 'Active'),
79 (0, 'Active'),
80 (1, 'Historical'),
80 (1, 'Historical'),
81 )
81 )
82
82
83 class Profile(models.Model):
83 class Profile(models.Model):
84 user = models.OneToOneField(User, on_delete=models.CASCADE)
84 user = models.OneToOneField(User, on_delete=models.CASCADE)
85 theme = models.CharField(max_length=30, default='spacelab')
85 theme = models.CharField(max_length=30, default='spacelab')
86
86
87
87
88 @receiver(post_save, sender=User)
88 @receiver(post_save, sender=User)
89 def create_user_profile(sender, instance, created, **kwargs):
89 def create_user_profile(sender, instance, created, **kwargs):
90 if created:
90 if created:
91 Profile.objects.create(user=instance)
91 Profile.objects.create(user=instance)
92
92
93 @receiver(post_save, sender=User)
93 @receiver(post_save, sender=User)
94 def save_user_profile(sender, instance, **kwargs):
94 def save_user_profile(sender, instance, **kwargs):
95 instance.profile.save()
95 instance.profile.save()
96
96
97
97
98 class DeviceType(models.Model):
98 class DeviceType(models.Model):
99
99
100 name = models.CharField(max_length = 15, choices = DEV_TYPES, default = 'pedestal')
100 name = models.CharField(max_length = 15, choices = DEV_TYPES, default = 'pedestal')
101 sequence = models.PositiveSmallIntegerField(default=55)
101 sequence = models.PositiveSmallIntegerField(default=55)
102 description = models.TextField(blank=True, null=True)
102 description = models.TextField(blank=True, null=True)
103
103
104 class Meta:
104 class Meta:
105 db_table = 'db_device_types'
105 db_table = 'db_device_types'
106
106
107 def __str__(self):
107 def __str__(self):
108 return u'%s' % self.name.title()
108 return u'%s' % self.name.title()
109
109
110 class Device(models.Model):
110 class Device(models.Model):
111
111
112 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
112 device_type = models.ForeignKey('DeviceType', on_delete=models.CASCADE)
113 ip_address = models.GenericIPAddressField(verbose_name = 'IP address', protocol='IPv4', default='0.0.0.0')
113 ip_address = models.GenericIPAddressField(verbose_name = 'IP address', protocol='IPv4', default='0.0.0.0')
114 port_address = models.PositiveSmallIntegerField(default=2000)
114 port_address = models.PositiveSmallIntegerField(default=2000)
115 description = models.TextField(blank=True, null=True)
115 description = models.TextField(blank=True, null=True)
116 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
116 status = models.PositiveSmallIntegerField(default=4, choices=DEV_STATES)
117 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
117 conf_active = models.PositiveIntegerField(default=0, verbose_name='Current configuration')
118
118
119 class Meta:
119 class Meta:
120 db_table = 'db_devices'
120 db_table = 'db_devices'
121
121
122 def __str__(self):
122 def __str__(self):
123 ret = self.device_type
123 ret = self.device_type
124 return str(ret)
124 return str(ret)
125
125
126 @property
126 @property
127 def name(self):
127 def name(self):
128 return str(self)
128 return str(self)
129
129
130 def get_status(self):
130 def get_status(self):
131 return self.status
131 return self.status
132
132
133 @property
133 @property
134 def status_color(self):
134 def status_color(self):
135 color = 'muted'
135 color = 'muted'
136 if self.status == 0:
136 if self.status == 0:
137 color = "danger"
137 color = "danger"
138 elif self.status == 1:
138 elif self.status == 1:
139 color = "primary"
139 color = "primary"
140 elif self.status == 2:
140 elif self.status == 2:
141 color = "info"
141 color = "info"
142 elif self.status == 3:
142 elif self.status == 3:
143 color = "success"
143 color = "success"
144
144
145 return color
145 return color
146
146
147 def url(self, path=None):
147 def url(self, path=None):
148
148
149 if path:
149 if path:
150 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
150 return 'http://{}:{}/{}/'.format(self.ip_address, self.port_address, path)
151 else:
151 else:
152 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
152 return 'http://{}:{}/'.format(self.ip_address, self.port_address)
153
153
154 def get_absolute_url(self):
154 def get_absolute_url(self):
155 return reverse('url_device', args=[str(self.id)])
155 return reverse('url_device', args=[str(self.id)])
156
156
157 def get_absolute_url_edit(self):
157 def get_absolute_url_edit(self):
158 return reverse('url_edit_device', args=[str(self.id)])
158 return reverse('url_edit_device', args=[str(self.id)])
159
159
160 def get_absolute_url_delete(self):
160 def get_absolute_url_delete(self):
161 return reverse('url_delete_device', args=[str(self.id)])
161 return reverse('url_delete_device', args=[str(self.id)])
162
162
163 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
163 def change_ip(self, ip_address, mask, gateway, dns, **kwargs):
164
164
165 if self.device_type.name=='pedestal':
165 if self.device_type.name=='pedestal':
166 headers = {'content-type': "application/json",
166 headers = {'content-type': "application/json",
167 'cache-control': "no-cache"}
167 'cache-control': "no-cache"}
168
168
169 ip = [int(x) for x in ip_address.split('.')]
169 ip = [int(x) for x in ip_address.split('.')]
170 dns = [int(x) for x in dns.split('.')]
170 dns = [int(x) for x in dns.split('.')]
171 gateway = [int(x) for x in gateway.split('.')]
171 gateway = [int(x) for x in gateway.split('.')]
172 subnet = [int(x) for x in mask.split('.')]
172 subnet = [int(x) for x in mask.split('.')]
173
173
174 payload = {
174 payload = {
175 "ip": ip,
175 "ip": ip,
176 "dns": dns,
176 "dns": dns,
177 "gateway": gateway,
177 "gateway": gateway,
178 "subnet": subnet
178 "subnet": subnet
179 }
179 }
180
180
181 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
181 req = requests.post(self.url('changeip'), data=json.dumps(payload), headers=headers)
182 try:
182 try:
183 answer = req.json()
183 answer = req.json()
184 if answer['changeip']=='ok':
184 if answer['changeip']=='ok':
185 self.message = '25|IP succesfully changed'
185 self.message = '25|IP succesfully changed'
186 self.ip_address = ip_address
186 self.ip_address = ip_address
187 self.save()
187 self.save()
188 else:
188 else:
189 self.message = '30|An error ocuur when changing IP'
189 self.message = '30|An error ocuur when changing IP'
190 except Exception as e:
190 except Exception as e:
191 self.message = '40|{}'.format(str(e))
191 self.message = '40|{}'.format(str(e))
192 else:
192 else:
193 self.message = 'Not implemented'
193 self.message = 'Not implemented'
194 return False
194 return False
195
195
196 return True
196 return True
197
197
198
198
199 class Experiment(PolymorphicModel):
199 class Experiment(PolymorphicModel):
200
200
201 name = models.CharField(max_length=40, default='', unique=True)
201 name = models.CharField(max_length=40, default='', unique=True)
202 pedestal = models.ForeignKey('pedestal.PedestalConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "pedestal_conf")
202 pedestal = models.ForeignKey('pedestal.PedestalConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "pedestal_conf")
203 generator = models.ForeignKey('Device', null=False, blank=False, on_delete=models.PROTECT, default=2, editable=False, limit_choices_to={'device_type__name': 'generator'}, related_name = "generator_conf")
203 generator = models.ForeignKey('Device', null=False, blank=False, on_delete=models.PROTECT, default=2, editable=False, limit_choices_to={'device_type__name': 'generator'}, related_name = "generator_conf")
204 reception_rx = models.ForeignKey('usrp_rx.USRPRXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "usrp_rx_CONF")
204 reception_rx = models.ForeignKey('usrp_rx.USRPRXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "usrp_rx_CONF")
205 transmission_tx = models.ForeignKey('usrp_tx.USRPTXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "usrp_tx")
205 transmission_tx = models.ForeignKey('usrp_tx.USRPTXConfiguration', null=False, blank=False, on_delete=models.PROTECT, default=None, limit_choices_to={'type': 0}, related_name = "usrp_tx")
206 task = models.CharField(max_length=36, default='', blank=True, null=True)
206 task = models.CharField(max_length=36, default='', blank=True, null=True)
207 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
207 status = models.PositiveSmallIntegerField(default=4, choices=EXP_STATES)
208 author = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
208 author = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
209 hash = models.CharField(default='', max_length=64, null=True, blank=True)
209 hash = models.CharField(default='', max_length=64, null=True, blank=True)
210 latitude = models.FloatField(null=False, blank=False, default=0, editable=False)
210 latitude = models.FloatField(null=False, blank=False, default=0, editable=False)
211 longitude = models.FloatField(null=False, blank=False, default=0, editable=False)
211 longitude = models.FloatField(null=False, blank=False, default=0, editable=False)
212 altitude = models.FloatField(null=False, blank=False, default=0, editable=False)
212 altitude = models.FloatField(null=False, blank=False, default=0, editable=False)
213 heading = models.FloatField(null=True, blank=True)
213 heading = models.FloatField(null=True, blank=True)
214 mode_stop = models.CharField(max_length=3, null=False, blank=False, default='web', editable=False)
214 mode_stop = models.CharField(max_length=3, null=False, blank=False, default='web', editable=False)
215
215
216 class Meta:
216 class Meta:
217 db_table = 'db_experiments'
217 db_table = 'db_experiments'
218 ordering = ('name',)
218 ordering = ('name',)
219
219
220 def __str__(self):
220 def __str__(self):
221 return u'%s' % (self.name)
221 return u'%s' % (self.name)
222
222
223 def jsonify(self):
223 def jsonify(self):
224
224
225 data = {}
225 data = {}
226
226
227 ignored = []
227 ignored = []
228
228
229 for field in self._meta.fields:
229 for field in self._meta.fields:
230 if field.name in ignored:
230 if field.name in ignored:
231 continue
231 continue
232 data[field.name] = field.value_from_object(self)
232 data[field.name] = field.value_from_object(self)
233
233
234 data['configurations'] = ['{}'.format(conf.pk) for
234 data['configurations'] = ['{}'.format(conf.pk) for
235 conf in Configuration.objects.filter(experiment=self, type=0)]
235 conf in Configuration.objects.filter(experiment=self, type=0)]
236
236
237 return data
237 return data
238
238
239 def clone(self, **kwargs):
239 def clone(self, **kwargs):
240
240
241 confs = Configuration.objects.filter(experiment=self, type=0)
241 confs = Configuration.objects.filter(experiment=self, type=0)
242 self.pk = None
242 self.pk = None
243 self.name = '{}_{:%y%m%d}'.format(self.name, datetime.now())
243 self.name = '{}_{:%y%m%d}'.format(self.name, datetime.now())
244 for attr, value in kwargs.items():
244 for attr, value in kwargs.items():
245 setattr(self, attr, value)
245 setattr(self, attr, value)
246
246
247 self.save()
247 self.save()
248
248
249 for conf in confs:
249 for conf in confs:
250 conf.clone(experiment=self)
250 conf.clone(experiment=self)
251
251
252 return self
252 return self
253
253
254
254
255 def generator_start(self):
255 def generator_start(self):
256 try:
256 try:
257 experiment = get_object_or_404(Experiment, pk=self.id)
257 experiment = get_object_or_404(Experiment, pk=self.id)
258 generator_url = experiment.generator.url()
258 generator_url = experiment.generator.url()
259
259
260 period = self.transmission_tx.ipp*2/0.3
260 period = self.transmission_tx.ipp*2/0.3
261 if self.transmission_tx.enable_2:
261 if self.transmission_tx.enable_2:
262 payload = {"Delay": 1 + self.transmission_tx.delay, "periode1": period, "width1": self.transmission_tx.pulse_1 + 6, "repeatability1": self.transmission_tx.repetitions_1, "periode2": period, "width2": self.transmission_tx.pulse_2 + 6, "repeatability2": self.transmission_tx.repetitions_2, "enable": 1}
262 payload = {"Delay": 1 + self.transmission_tx.delay, "periode1": period, "width1": self.transmission_tx.pulse_1 + 6, "repeatability1": self.transmission_tx.repetitions_1, "periode2": period, "width2": self.transmission_tx.pulse_2 + 6, "repeatability2": self.transmission_tx.repetitions_2, "enable": 1}
263 else:
263 else:
264 payload = {"Delay": 1 + self.transmission_tx.delay, "periode1": period, "width1": self.transmission_tx.pulse_1 + 6, "repeatability1": 1, "periode2": period, "width2": self.transmission_tx.pulse_1 + 6, "repeatability2": 1, "enable": 1}
264 payload = {"Delay": 1 + self.transmission_tx.delay, "periode1": period, "width1": self.transmission_tx.pulse_1 + 6, "repeatability1": 1, "periode2": period, "width2": self.transmission_tx.pulse_1 + 6, "repeatability2": 1, "enable": 1}
265
265
266 json_trmode = json.dumps(payload)
266 json_trmode = json.dumps(payload)
267
267
268 base64_trmode = base64.standard_b64encode(json_trmode.encode('ascii'))
268 base64_trmode = base64.standard_b64encode(json_trmode.encode('ascii'))
269
269
270 trmode_url = generator_url + "trmode?params="
270 trmode_url = generator_url + "trmode?params="
271 complete_url_trmode = trmode_url + base64_trmode.decode('ascii')
271 complete_url_trmode = trmode_url + base64_trmode.decode('ascii')
272
272
273 requests.get(complete_url_trmode)
273 requests.get(complete_url_trmode)
274 except:
274 except:
275 return False
275 return False
276 return True
276 return True
277
277
278 def generator_stop(self):
278 def generator_stop(self):
279 try:
279 try:
280 experiment = get_object_or_404(Experiment, pk=self.id)
280 experiment = get_object_or_404(Experiment, pk=self.id)
281 generator_url = experiment.generator.url()
281 generator_url = experiment.generator.url()
282
282
283 payload = {"enable": 0}
283 payload = {"enable": 0}
284
284
285 json_trmode_selector = json.dumps(payload)
285 json_trmode_selector = json.dumps(payload)
286 base64_trmode_selector = base64.standard_b64encode(json_trmode_selector.encode('ascii'))
286 base64_trmode_selector = base64.standard_b64encode(json_trmode_selector.encode('ascii'))
287
287
288 trmode_url = generator_url + "trmode?params="
288 trmode_url = generator_url + "trmode?params="
289 url_trmode_selector = trmode_url + base64_trmode_selector.decode('ascii')
289 url_trmode_selector = trmode_url + base64_trmode_selector.decode('ascii')
290 requests.get(url_trmode_selector)
290 requests.get(url_trmode_selector)
291 except:
291 except:
292 return False
292 return False
293 return True
293 return True
294
294
295 def start(self):
295 def start(self):
296 '''
296 '''
297 Configure and start experiments's devices
297 Configure and start experiments's devices
298 '''
298 '''
299 all_status = Experiment.objects.filter(status=2)
299 all_status = Experiment.objects.filter(status=2)
300
300
301 if self.status != 2:
301 if self.status != 2:
302 if len(all_status) == 0:
302 if len(all_status) == 0:
303 data = {
303 data = {
304 'name': '{}@{}'.format(self.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S')),
304 'name': '{}@{}'.format(self.name, datetime.now().strftime('%Y-%m-%dT%H-%M-%S')),
305 'latitude': self.latitude,
305 'latitude': self.latitude,
306 'longitude': self.longitude,
306 'longitude': self.longitude,
307 'altitude': self.altitude,
307 'altitude': self.altitude,
308 'heading': self.heading
308 'heading': self.heading
309 }
309 }
310
310
311 try:
311 try:
312 data['pedestal'] = self.pedestal.start_device(name_experiment=data['name'])
312 data['pedestal'] = self.pedestal.start_device(name_experiment=data['name'])
313 time.sleep(1.0)
313 time.sleep(1.0)
314 self.generator_start()
314 self.generator_start()
315 time.sleep(1.0)
315 time.sleep(1.0)
316 data['usrp_tx'] = self.transmission_tx.start_device(name_experiment=data['name'])
316 data['usrp_tx'] = self.transmission_tx.start_device(name_experiment=data['name'])
317 time.sleep(1.0)
317 time.sleep(1.0)
318 data['usrp_rx'] = self.reception_rx.start_device(name_experiment=data['name'])
318 data['usrp_rx'] = self.reception_rx.start_device(name_experiment=data['name'])
319 time.sleep(0.1)
319 time.sleep(0.1)
320 proc_url = 'http://'+os.environ['PROC_SITE']+'/start'
320 proc_url = 'http://'+os.environ['PROC_SITE']+'/start'
321 requests.post(proc_url, json=data)
321 requests.post(proc_url, json=data)
322
322
323 except:
323 except:
324 return 0
324 return 0
325 return 2
325 return 2
326 else:
326 else:
327 return 5
327 return 5
328 else:
328 else:
329 return 2
329 return 2
330
330
331
331
332 def stop(self):
332 def stop(self):
333 '''
333 '''
334 Stop experiments's devices
334 Stop experiments's devices
335 PEDESTAL, GENERATOR & USRP's
335 PEDESTAL, GENERATOR & USRP's
336 '''
336 '''
337
337
338 try:
338 try:
339 self.transmission_tx.stop_device()
339 self.transmission_tx.stop_device()
340 time.sleep(1.0)
340 time.sleep(1.0)
341 self.generator_stop()
341 self.generator_stop()
342 time.sleep(0.1)
342 time.sleep(0.1)
343 self.reception_rx.stop_device()
343 self.reception_rx.stop_device()
344 time.sleep(0.1)
344 time.sleep(0.1)
345 self.pedestal.reset_device()
346 time.sleep(14)
345 self.pedestal.stop_device()
347 self.pedestal.stop_device()
346 time.sleep(0.1)
348 time.sleep(0.1)
347 proc_url = 'http://'+os.environ['PROC_SITE']+'/stop'
349 proc_url = 'http://'+os.environ['PROC_SITE']+'/stop'
348 requests.get(proc_url)
350 requests.get(proc_url)
349 except:
351 except:
350 return 0
352 return 0
351 return 4
353 return 4
352
354
353 def get_status(self):
355 def get_status(self):
354
356
355 if self.status == 3:
357 if self.status == 3:
356 return
358 return
357
359
358 confs = Configuration.objects.filter(experiment=self, type=0)
360 confs = Configuration.objects.filter(experiment=self, type=0)
359
361
360 for conf in confs:
362 for conf in confs:
361 conf.status_device()
363 conf.status_device()
362
364
363 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
365 total = confs.aggregate(models.Sum('device__status'))['device__status__sum']
364
366
365 if total==2*confs.count():
367 if total==2*confs.count():
366 status = 1
368 status = 1
367 elif total == 3*confs.count():
369 elif total == 3*confs.count():
368 status = 2
370 status = 2
369 else:
371 else:
370 status = 0
372 status = 0
371
373
372 self.status = status
374 self.status = status
373 self.save()
375 self.save()
374
376
375 def status_color(self):
377 def status_color(self):
376 color = 'muted'
378 color = 'muted'
377 if self.status == 0:
379 if self.status == 0:
378 color = "danger"
380 color = "danger"
379 elif self.status == 1:
381 elif self.status == 1:
380 color = "warning"
382 color = "warning"
381 elif self.status == 2:
383 elif self.status == 2:
382 color = "success"
384 color = "success"
383 elif self.status == 3:
385 elif self.status == 3:
384 color = "info"
386 color = "info"
385
387
386 return color
388 return color
387
389
388 def parms_to_dict(self):
390 def parms_to_dict(self):
389
391
390 params = Params({})
392 params = Params({})
391 params.add(self.jsonify(), 'experiments')
393 params.add(self.jsonify(), 'experiments')
392
394
393 configurations = Configuration.objects.filter(experiment=self, type=0)
395 configurations = Configuration.objects.filter(experiment=self, type=0)
394
396
395 for conf in configurations:
397 for conf in configurations:
396 params.add(conf.jsonify(), 'configurations')
398 params.add(conf.jsonify(), 'configurations')
397
399
398 return params.data
400 return params.data
399
401
400 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
402 def dict_to_parms(self, parms, CONF_MODELS, id_exp=None):
401
403
402 configurations = Configuration.objects.filter(experiment=self)
404 configurations = Configuration.objects.filter(experiment=self)
403
405
404 if id_exp is not None:
406 if id_exp is not None:
405 exp_parms = parms['experiments']['byId'][id_exp]
407 exp_parms = parms['experiments']['byId'][id_exp]
406 else:
408 else:
407 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
409 exp_parms = parms['experiments']['byId'][parms['experiments']['allIds'][0]]
408
410
409 if configurations:
411 if configurations:
410 for configuration in configurations:
412 for configuration in configurations:
411 configuration.delete()
413 configuration.delete()
412
414
413 for id_conf in exp_parms['configurations']:
415 for id_conf in exp_parms['configurations']:
414 conf_parms = parms['configurations']['byId'][id_conf]
416 conf_parms = parms['configurations']['byId'][id_conf]
415 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
417 device = Device.objects.filter(device_type__name=conf_parms['device_type'])[0]
416 model = CONF_MODELS[conf_parms['device_type']]
418 model = CONF_MODELS[conf_parms['device_type']]
417 conf = model(
419 conf = model(
418 experiment = self,
420 experiment = self,
419 device = device,
421 device = device,
420 )
422 )
421 conf.dict_to_parms(parms, id=id_conf)
423 conf.dict_to_parms(parms, id=id_conf)
422
424
423
425
424 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
426 self.name = '{}-{}'.format(exp_parms['name'], datetime.now().strftime('%y%m%d'))
425 self.save()
427 self.save()
426
428
427 return self
429 return self
428
430
429 def get_absolute_url(self):
431 def get_absolute_url(self):
430 return reverse('url_experiment', args=[str(self.id)])
432 return reverse('url_experiment', args=[str(self.id)])
431
433
432 def get_absolute_url_edit(self):
434 def get_absolute_url_edit(self):
433 return reverse('url_edit_experiment', args=[str(self.id)])
435 return reverse('url_edit_experiment', args=[str(self.id)])
434
436
435 def get_absolute_url_delete(self):
437 def get_absolute_url_delete(self):
436 return reverse('url_delete_experiment', args=[str(self.id)])
438 return reverse('url_delete_experiment', args=[str(self.id)])
437
439
438 def get_absolute_url_import(self):
440 def get_absolute_url_import(self):
439 return reverse('url_import_experiment', args=[str(self.id)])
441 return reverse('url_import_experiment', args=[str(self.id)])
440
442
441 def get_absolute_url_export(self):
443 def get_absolute_url_export(self):
442 return reverse('url_export_experiment', args=[str(self.id)])
444 return reverse('url_export_experiment', args=[str(self.id)])
443
445
444 def get_absolute_url_start(self):
446 def get_absolute_url_start(self):
445 return reverse('url_start_experiment', args=[str(self.id)])
447 return reverse('url_start_experiment', args=[str(self.id)])
446
448
447 def get_absolute_url_stop(self):
449 def get_absolute_url_stop(self):
448 return reverse('url_stop_experiment', args=[str(self.id)])
450 return reverse('url_stop_experiment', args=[str(self.id)])
449
451
450
452
451 class Configuration(PolymorphicModel):
453 class Configuration(PolymorphicModel):
452
454
453 id = models.AutoField(primary_key=True)
455 id = models.AutoField(primary_key=True)
454 experiment = models.CharField(default='empty', editable=False, max_length=64, null=True, blank=True)
456 experiment = models.CharField(default='empty', editable=False, max_length=64, null=True, blank=True)
455 experiment_date = models.DateTimeField(default=datetime.now, editable=False)
457 experiment_date = models.DateTimeField(default=datetime.now, editable=False)
456 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
458 device = models.ForeignKey('Device', verbose_name='Device', null=True, on_delete=models.CASCADE)
457 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
459 type = models.PositiveSmallIntegerField(default=0, choices=CONF_TYPES)
458 created_date = models.DateTimeField(auto_now_add=True)
460 created_date = models.DateTimeField(auto_now_add=True)
459 programmed_date = models.DateTimeField(auto_now=True)
461 programmed_date = models.DateTimeField(auto_now=True)
460 parameters = models.TextField(default='{}')
462 parameters = models.TextField(default='{}')
461 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
463 author = models.ForeignKey(User, null=True, blank=True,on_delete=models.CASCADE)
462 hash = models.CharField(default='', max_length=64, null=True, blank=True)
464 hash = models.CharField(default='', max_length=64, null=True, blank=True)
463 message = ""
465 message = ""
464
466
465 class Meta:
467 class Meta:
466 db_table = 'db_configurations'
468 db_table = 'db_configurations'
467 ordering = ('device__device_type__name',)
469 ordering = ('device__device_type__name',)
468
470
469 def __str__(self):
471 def __str__(self):
470
472
471 ret = u'{} '.format(self.device.device_type.name.upper())
473 ret = u'{} '.format(self.device.device_type.name.upper())
472
474
473 if 'mix' in [f.name for f in self._meta.get_fields()]:
475 if 'mix' in [f.name for f in self._meta.get_fields()]:
474 if self.mix:
476 if self.mix:
475 ret = '{} MIX '.format(self.device.device_type.name.upper())
477 ret = '{} MIX '.format(self.device.device_type.name.upper())
476
478
477 if 'label' in [f.name for f in self._meta.get_fields()]:
479 if 'label' in [f.name for f in self._meta.get_fields()]:
478 ret += '{}'.format(self.label)
480 ret += '{}'.format(self.label)
479
481
480 return ret
482 return ret
481
483
482 @property
484 @property
483 def name(self):
485 def name(self):
484
486
485 return str(self)
487 return str(self)
486
488
487 @property
489 @property
488 def label(self):
490 def label(self):
489
491
490 return str(self)
492 return str(self)
491
493
492 def jsonify(self):
494 def jsonify(self):
493
495
494 data = {}
496 data = {}
495
497
496 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
498 ignored = ('type', 'polymorphic_ctype', 'configuration_ptr',
497 'created_date', 'programmed_date', 'device',
499 'created_date', 'programmed_date', 'device',
498 'experiment', 'author')
500 'experiment', 'author')
499
501
500 for field in self._meta.fields:
502 for field in self._meta.fields:
501 if field.name in ignored:
503 if field.name in ignored:
502 continue
504 continue
503 data[field.name] = field.value_from_object(self)
505 data[field.name] = field.value_from_object(self)
504
506
505 data['device_type'] = self.device.device_type.name
507 data['device_type'] = self.device.device_type.name
506 return data
508 return data
507
509
508 def clone(self, **kwargs):
510 def clone(self, **kwargs):
509 before_id = self.id
511 before_id = self.id
510
512
511 self.pk = None
513 self.pk = None
512 self.id = None
514 self.id = None
513 for attr, value in kwargs.items():
515 for attr, value in kwargs.items():
514 setattr(self, attr, value)
516 setattr(self, attr, value)
515 self.save()
517 self.save()
516
518
517 self.id = before_id
519 self.id = before_id
518 return self
520 return self
519
521
520 def parms_to_dict(self):
522 def parms_to_dict(self):
521
523
522 params = Params({})
524 params = Params({})
523 params.add(self.jsonify(), 'configurations')
525 params.add(self.jsonify(), 'configurations')
524 return params.data
526 return params.data
525
527
526 def parms_to_text(self):
528 def parms_to_text(self):
527
529
528 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
530 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
529
531
530
532
531 def parms_to_binary(self):
533 def parms_to_binary(self):
532
534
533 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
535 raise NotImplementedError("This method should be implemented in %s Configuration model" %str(self.device.device_type.name).upper())
534
536
535
537
536 def dict_to_parms(self, parameters, id=None):
538 def dict_to_parms(self, parameters, id=None):
537
539
538 params = Params(parameters)
540 params = Params(parameters)
539
541
540 if id:
542 if id:
541 data = params.get_conf(id_conf=id)
543 data = params.get_conf(id_conf=id)
542 else:
544 else:
543 data = params.get_conf(dtype=self.device.device_type.name)
545 data = params.get_conf(dtype=self.device.device_type.name)
544
546
545 for key, value in data.items():
547 for key, value in data.items():
546 if key not in ('id', 'device_type'):
548 if key not in ('id', 'device_type'):
547 setattr(self, key, value)
549 setattr(self, key, value)
548
550
549 self.save()
551 self.save()
550
552
551
553
552 def export_to_file(self, format="json"):
554 def export_to_file(self, format="json"):
553
555
554 content_type = ''
556 content_type = ''
555
557
556 if format == 'racp':
558 if format == 'racp':
557 content_type = 'text/plain'
559 content_type = 'text/plain'
558 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
560 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, 'racp')
559 content = self.parms_to_text(file_format = 'racp')
561 content = self.parms_to_text(file_format = 'racp')
560
562
561 if format == 'text':
563 if format == 'text':
562 content_type = 'text/plain'
564 content_type = 'text/plain'
563 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
565 filename = '%s_%s.%s' %(self.device.device_type.name, self.name, self.device.device_type.name)
564 content = self.parms_to_text()
566 content = self.parms_to_text()
565
567
566 if format == 'binary':
568 if format == 'binary':
567 content_type = 'application/octet-stream'
569 content_type = 'application/octet-stream'
568 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
570 filename = '%s_%s.bin' %(self.device.device_type.name, self.name)
569 content = self.parms_to_binary()
571 content = self.parms_to_binary()
570
572
571 if not content_type:
573 if not content_type:
572 content_type = 'application/json'
574 content_type = 'application/json'
573 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
575 filename = '%s_%s.json' %(self.device.device_type.name, self.name)
574 content = json.dumps(self.parms_to_dict(), indent=2)
576 content = json.dumps(self.parms_to_dict(), indent=2)
575
577
576
578
577 fields = {'content_type':content_type,
579 fields = {'content_type':content_type,
578 'filename':filename,
580 'filename':filename,
579 'content':content
581 'content':content
580 }
582 }
581
583
582 return fields
584 return fields
583
585
584 def import_from_file(self, fp):
586 def import_from_file(self, fp):
585
587
586 parms = {}
588 parms = {}
587
589
588 path, ext = os.path.splitext(fp.name)
590 path, ext = os.path.splitext(fp.name)
589
591
590 if ext == '.json':
592 if ext == '.json':
591 parms = json.load(fp)
593 parms = json.load(fp)
592
594
593 return parms
595 return parms
594
596
595 def status_device(self):
597 def status_device(self):
596
598
597 self.message = 'Function not supported'
599 self.message = 'Function not supported'
598 return False
600 return False
599
601
600
602
601 def stop_device(self):
603 def stop_device(self):
602
604
603 self.message = 'Function not supported'
605 self.message = 'Function not supported'
604 return False
606 return False
605
607
606
608
607 def start_device(self):
609 def start_device(self):
608
610
609 self.message = 'Function not supported'
611 self.message = 'Function not supported'
610 return False
612 return False
611
613
612
614
613 def write_device(self):
615 def write_device(self):
614
616
615 self.message = 'Function not supported'
617 self.message = 'Function not supported'
616 return False
618 return False
617
619
618
620
619 def read_device(self):
621 def read_device(self):
620
622
621 self.message = 'Function not supported'
623 self.message = 'Function not supported'
622 return False
624 return False
623
625
624
626
625 def get_absolute_url(self):
627 def get_absolute_url(self):
626 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
628 return reverse('url_%s_conf' % self.device.device_type.name, args=[str(self.id)])
627
629
628 def get_absolute_url_edit(self):
630 def get_absolute_url_edit(self):
629 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
631 return reverse('url_edit_%s_conf' % self.device.device_type.name, args=[str(self.id)])
630
632
631 def get_absolute_url_delete(self):
633 def get_absolute_url_delete(self):
632 return reverse('url_delete_dev_conf', args=[str(self.id)])
634 return reverse('url_delete_dev_conf', args=[str(self.id)])
633
635
634 def get_absolute_url_import(self):
636 def get_absolute_url_import(self):
635 return reverse('url_import_dev_conf', args=[str(self.id)])
637 return reverse('url_import_dev_conf', args=[str(self.id)])
636
638
637 def get_absolute_url_export(self):
639 def get_absolute_url_export(self):
638 return reverse('url_export_dev_conf', args=[str(self.id)])
640 return reverse('url_export_dev_conf', args=[str(self.id)])
639
641
640 def get_absolute_url_write(self):
642 def get_absolute_url_write(self):
641 return reverse('url_write_dev_conf', args=[str(self.id)])
643 return reverse('url_write_dev_conf', args=[str(self.id)])
642
644
643 def get_absolute_url_read(self):
645 def get_absolute_url_read(self):
644 return reverse('url_read_dev_conf', args=[str(self.id)])
646 return reverse('url_read_dev_conf', args=[str(self.id)])
645
647
646 def get_absolute_url_start(self):
648 def get_absolute_url_start(self):
647 return reverse('url_start_dev_conf', args=[str(self.id)])
649 return reverse('url_start_dev_conf', args=[str(self.id)])
648
650
649 def get_absolute_url_stop(self):
651 def get_absolute_url_stop(self):
650 return reverse('url_stop_dev_conf', args=[str(self.id)])
652 return reverse('url_stop_dev_conf', args=[str(self.id)])
651
653
652 def get_absolute_url_status(self):
654 def get_absolute_url_status(self):
653 return reverse('url_status_dev_conf', args=[str(self.id)])
655 return reverse('url_status_dev_conf', args=[str(self.id)])
@@ -1,296 +1,317
1 import os
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):
122
123 try:
124 r = requests.get(self.device.url() + 'reset')
125
126 if r:
127 #self.device.status = 3
128 #self.device.save()
129 self.message = 'Pedestal restarted'
130 else:
131 return False
132
133 except Exception as e:
134 self.message = "Pedestal can't restarted: {}".format(str(e))
135 return False
136
137 return True
138
139 def initial_device(self, axi, angle):
122
140
123 try:
141 try:
124 url = self.device.url() + "position?params="
142 url = self.device.url() + "position?params="
125
143
126 payload_el = {'axis': 'elevation'}
144 payload_el = {'axis': 'elevation'}
127 payload_az = {'axis': 'azimuth'}
145 payload_az = {'axis': 'azimuth'}
128
146
129 if axi == 'elevation':
147 if axi == 'elevation':
130 # CORRECT AZ OFFSET
148 # CORRECT AZ OFFSET
131 azi = angle - float(os.environ.get('AZ_OFFSET', 26.27))
149 azi = angle - float(os.environ.get('AZ_OFFSET', 26.27))
132 if azi<0: azi += 360
150 if azi<0: azi += 360
133 payload_az['position'] = round(azi, 2)
151 payload_az['position'] = round(azi, 2)
134 payload_el['position'] = 0
152 payload_el['position'] = 0
135 elif axi == 'azimuth':
153 elif axi == 'azimuth':
136 payload_el['position'] = angle
154 payload_el['position'] = angle
137 payload_az['position'] = 0
155 payload_az['position'] = 0
138 else:
156 else:
139 payload_el['position'] = 0
157 payload_el['position'] = 0
140 payload_az['position'] = 0
158 payload_az['position'] = 0
141
159
142 json_data_el = json.dumps(payload_el)
160 json_data_el = json.dumps(payload_el)
143 json_data_az = json.dumps(payload_az)
161 json_data_az = json.dumps(payload_az)
144
162
145 base64_table_el = base64.standard_b64encode(json_data_el.encode('ascii'))
163 base64_table_el = base64.standard_b64encode(json_data_el.encode('ascii'))
146 base64_table_az = base64.standard_b64encode(json_data_az.encode('ascii'))
164 base64_table_az = base64.standard_b64encode(json_data_az.encode('ascii'))
147
165
148 time.sleep(0.1)
166 time.sleep(0.1)
149 r = requests.get(url + base64_table_el.decode('ascii'))
167 r = requests.get(url + base64_table_el.decode('ascii'))
150 time.sleep(0.1)
168 time.sleep(0.1)
151 r = requests.get(url + base64_table_az.decode('ascii'))
169 r = requests.get(url + base64_table_az.decode('ascii'))
152
170
153 if r:
171 if r:
154 self.device.status = 3
172 self.device.status = 3
155 self.device.save()
173 self.device.save()
156 self.message = 'Pedestal reset'
174 self.message = 'Pedestal - initial position'
157 else:
175 else:
158 return False
176 return False
159
177
160 except Exception as e:
178 except Exception as e:
161 self.message = 'Pedestal reset: {}'.format(str(e))
179 self.message = 'Pedestal - initial position: {}'.format(str(e))
162 return False
180 return False
163
181
164 return True
182 return True
165
183
166 def stop_device(self):
184 def stop_device(self):
167
185
168 try:
186 try:
169 command = self.device.url() + "stop"
187 command = self.device.url() + "stop"
170 r = requests.get(command)
188 r = requests.get(command)
171
189
172 if self.mode == 'table':
190 if self.mode == 'table':
173 AX = {'az':'azimuth', 'el':'elevation'}
191 AX = {'az':'azimuth', 'el':'elevation'}
174 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
192 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
175 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
193 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
176 self.reset_device(axis[0], list_of_floats[0])
194 self.initial_device(axis[0], list_of_floats[0])
177
195
178 if r:
196 if r:
179 self.device.status = 4
197 self.device.status = 4
180 self.device.save()
198 self.device.save()
181 self.message = 'Pedestal stopped'
199 self.message = 'Pedestal stopped'
182 else:
200 else:
183 self.device.status = 4
201 self.device.status = 4
184 self.device.save()
202 self.device.save()
185 return False
203 return False
186 except Exception as e:
204 except Exception as e:
187 if 'No route to host' not in str(e):
205 if 'No route to host' not in str(e):
188 self.device.status = 4
206 self.device.status = 4
189 else:
207 else:
190 self.device.status = 0
208 self.device.status = 0
191 #self.message = 'Pedestal stop: {}'.format(str(e))
209 #self.message = 'Pedestal stop: {}'.format(str(e))
192 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
210 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
193 self.device.save()
211 self.device.save()
194 return False
212 return False
195
213
196 return True
214 return True
197
215
198 def start_device(self, name_experiment=False):
216 def start_device(self, name_experiment=False):
199
217
200 if self.mode == 'table':
218 if self.mode == 'table':
201 if len(self.angle.split(',')) > 1:
219 if len(self.angle.split(',')) > 1:
202 list_speed = []
220 list_speed = []
203 list_axis = []
221 list_axis = []
204 for _ in range(len(self.angle.split(','))):
222 for _ in range(len(self.angle.split(','))):
205 list_axis.append(self.axis)
223 list_axis.append(self.axis)
206 list_speed.append(self.speed)
224 list_speed.append(self.speed)
207
225
208 if len(self.axis.split(',')) == 1:
226 if len(self.axis.split(',')) == 1:
209 self.axis = ",".join(map(str, list_axis))
227 self.axis = ",".join(map(str, list_axis))
210 if len(self.speed.split(',')) == 1:
228 if len(self.speed.split(',')) == 1:
211 self.speed = ",".join(map(str, list_speed))
229 self.speed = ",".join(map(str, list_speed))
212
230
213 AX = {'az':'azimuth', 'el':'elevation'}
231 AX = {'az':'azimuth', 'el':'elevation'}
214 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
232 axis = [AX[x.lower().strip()] for x in self.axis.split(',')]
215 if len(axis)==1:
233 if len(axis)==1:
216 axis = axis[0]
234 axis = axis[0]
217
235
218 try:
236 try:
219 if self.mode == 'position':
237 if self.mode == 'position':
220 url = self.device.url() + "position?params="
238 url = self.device.url() + "position?params="
221 payload = {'axis': axis, 'position': float(self.angle)}
239 payload = {'axis': axis, 'position': float(self.angle)}
222 elif self.mode == 'speed':
240 elif self.mode == 'speed':
223 url = self.device.url() + "speed?params="
241 url = self.device.url() + "speed?params="
224 payload = {'axis': axis, 'speed': float(self.speed)}
242 payload = {'axis': axis, 'speed': float(self.speed)}
225 elif self.mode == 'table':
243 elif self.mode == 'table':
226 url = self.device.url() + "combinedtable?params="
244 url = self.device.url() + "combinedtable?params="
227 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
245 list_of_floats = [float(x.strip()) for x in self.angle.split(",")]
228
246
229 # CORRECT AZ OFFSET
247 # CORRECT AZ OFFSET
230 for i, ax in enumerate(axis):
248 for i, ax in enumerate(axis):
231 if ax == 'elevation':
249 if ax == 'elevation':
232 azi = list_of_floats[i] - float(os.environ.get('AZ_OFFSET', 26.27))
250 azi = list_of_floats[i] - float(os.environ.get('AZ_OFFSET', 26.27))
233 if azi<0: azi += 360
251 if azi<0: azi += 360
234 list_of_floats[i] = round(azi, 2)
252 list_of_floats[i] = round(azi, 2)
235
253
236 byte_table = []
254 byte_table = []
237 for x in list_of_floats:
255 for x in list_of_floats:
238 temp = bytearray(struct.pack("f", x))
256 temp = bytearray(struct.pack("f", x))
239 byte_table.append(temp[3])
257 byte_table.append(temp[3])
240 byte_table.append(temp[2])
258 byte_table.append(temp[2])
241 byte_table.append(temp[1])
259 byte_table.append(temp[1])
242 byte_table.append(temp[0])
260 byte_table.append(temp[0])
243
261
244 coded_table = base64.standard_b64encode(bytes(byte_table))
262 coded_table = base64.standard_b64encode(bytes(byte_table))
245 coded_table_ascii = coded_table.decode('ascii')
263 coded_table_ascii = coded_table.decode('ascii')
246 speed = [float(x.strip()) for x in self.speed.split(',')]
264 speed = [float(x.strip()) for x in self.speed.split(',')]
247
265
248 if isinstance(axis, str):
266 if isinstance(axis, str):
249 axis = [axis]
267 axis = [axis]
250
268
251 payload = {
269 payload = {
252 'arraylength': len(speed),
270 'arraylength': len(speed),
253 'axis': axis,
271 'axis': axis,
254 'speed': speed,
272 'speed': speed,
255 'bottom': self.min_value,
273 'bottom': self.min_value,
256 'top': self.max_value,
274 'top': self.max_value,
257 'table': coded_table_ascii
275 'table': coded_table_ascii
258 }
276 }
259
277
260 json_data = json.dumps(payload)
278 json_data = json.dumps(payload)
261 print(json_data)
279 print(json_data)
262 base64_table = base64.standard_b64encode(json_data.encode('ascii'))
280 base64_table = base64.standard_b64encode(json_data.encode('ascii'))
263 url += base64_table.decode('ascii')
281 url += base64_table.decode('ascii')
264 print(url)
282 print(url)
265 r = requests.get(url)
283 r = requests.get(url)
266
284
267 if self.mode == 'table':
285 if self.mode == 'table':
268 payload['table'] = list_of_floats
286 payload['table'] = list_of_floats
269
287
270 if name_experiment:
288 if name_experiment:
271 name_experiment = name_experiment.split("@")
289 name_experiment = name_experiment.split("@")
272 dt = datetime.strptime(name_experiment[1], '%Y-%m-%dT%H-%M-%S')
290 dt = datetime.strptime(name_experiment[1], '%Y-%m-%dT%H-%M-%S')
273 self.clone(experiment=name_experiment[0], experiment_date=dt, type=1)
291 self.clone(experiment=name_experiment[0], experiment_date=dt, type=1)
274 else:
292 else:
275 self.clone(type=1, experiment = 'empty', experiment_date=datetime.now())
293 self.clone(type=1, experiment = 'empty', experiment_date=datetime.now())
276
294
277 if r:
295 if r:
278 self.device.status = 3
296 self.device.status = 3
279 self.device.save()
297 self.device.save()
280 self.message = 'Pedestal configured and started'
298 self.message = 'Pedestal configured and started'
281 else:
299 else:
282 return False
300 return False
283 except Exception as e:
301 except Exception as e:
284 if 'No route to host' not in str(e):
302 if 'No route to host' not in str(e):
285 self.device.status = 4
303 self.device.status = 4
286 else:
304 else:
287 self.device.status = 0
305 self.device.status = 0
288 #self.message = 'Pedestal start: {}'.format(str(e))
306 #self.message = 'Pedestal start: {}'.format(str(e))
289 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
307 self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration"
290 self.device.save()
308 self.device.save()
291 return False
309 return False
292
310
293 return payload
311 return payload
294
312
295 def get_absolute_url_import(self):
313 def get_absolute_url_import(self):
296 return reverse('url_import_pedestal_conf', args=[str(self.id)]) No newline at end of file
314 return reverse('url_import_pedestal_conf', args=[str(self.id)])
315
316 def get_absolute_url_reset(self):
317 return reverse('url_reset_pedestal_conf', args=[str(self.id)]) No newline at end of file
@@ -1,30 +1,34
1 {% extends "dev_conf.html" %}
1 {% extends "dev_conf.html" %}
2 {% load static %}
2 {% load static %}
3 {% load bootstrap4 %}
3 {% load bootstrap4 %}
4 {% load main_tags %}
4 {% load main_tags %}
5
5
6 {% block extra-menu-actions %}
7 <li><a href="{{ dev_conf.get_absolute_url_reset }}"><span class="fas fa-spinner" aria-hidden="true"></span> Reset </a></li>
8 {% endblock %}
9
6 {% block content-detail %}
10 {% block content-detail %}
7
11
8 <h2>Pedestal</h2>
12 <h2>Pedestal</h2>
9 <table class="table table-bordered">
13 <table class="table table-bordered">
10 <tr>
14 <tr>
11 <th>Status</th>
15 <th>Status</th>
12 <td class="text-{{dev_conf.device.status_color}}"><strong>{{dev_conf.device.get_status_display}}</strong></td>
16 <td class="text-{{dev_conf.device.status_color}}"><strong>{{dev_conf.device.get_status_display}}</strong></td>
13 </tr>
17 </tr>
14
18
15 {% for key in dev_conf_keys %}
19 {% for key in dev_conf_keys %}
16 <tr>
20 <tr>
17 <th>{% get_verbose_field_name dev_conf key %}</th>
21 <th>{% get_verbose_field_name dev_conf key %}</th>
18 <td>{{dev_conf|attr:key}}</td>
22 <td>{{dev_conf|attr:key}}</td>
19 </tr>
23 </tr>
20 {% endfor %}
24 {% endfor %}
21 </table>
25 </table>
22 {% endblock %}
26 {% endblock %}
23
27
24 {% block extra-js%}
28 {% block extra-js%}
25 <script type="text/javascript">
29 <script type="text/javascript">
26 $("#bt_toggle").click(function() {
30 $("#bt_toggle").click(function() {
27 $(".panel-collapse").collapse('toggle')
31 $(".panel-collapse").collapse('toggle')
28 });
32 });
29 </script>
33 </script>
30 {% endblock %} No newline at end of file
34 {% endblock %}
@@ -1,11 +1,12
1 from django.urls import path
1 from django.urls import path
2
2
3 from . import views
3 from . import views
4
4
5 urlpatterns = (
5 urlpatterns = (
6 path('<int:conf_id>/', views.conf, name='url_pedestal_conf'),
6 path('<int:conf_id>/', views.conf, name='url_pedestal_conf'),
7 path('<int:conf_id>/import/', views.import_file, name='url_import_pedestal_conf'),
7 path('<int:conf_id>/import/', views.import_file, name='url_import_pedestal_conf'),
8 path('<int:conf_id>/edit/', views.conf_edit, name='url_edit_pedestal_conf'),
8 path('<int:conf_id>/edit/', views.conf_edit, name='url_edit_pedestal_conf'),
9 path('<int:conf_id>/reset/', views.conf_reset, name='url_reset_pedestal_conf'),
9 #url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_pedestal_conf'),
10 #url(r'^(?P<id_conf>-?\d+)/write/$', 'apps.main.views.dev_conf_write', name='url_write_pedestal_conf'),
10 #url(r'^(?P<id_conf>-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_pedestal_conf'),
11 #url(r'^(?P<id_conf>-?\d+)/read/$', 'apps.main.views.dev_conf_read', name='url_read_pedestal_conf'),
11 )
12 )
@@ -1,120 +1,132
1
1
2 import json
2 import json
3
3
4 from django.contrib import messages
4 from django.contrib import messages
5 from django.utils.safestring import mark_safe
5 from django.utils.safestring import mark_safe
6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
6 from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
7 from django.contrib.auth.decorators import login_required
7 from django.contrib.auth.decorators import login_required
8
8
9 from apps.main.models import Experiment, Device
9 from apps.main.models import Experiment, Device
10 from apps.main.views import sidebar
10 from apps.main.views import sidebar
11
11
12 from .models import PedestalConfiguration
12 from .models import PedestalConfiguration
13 from .forms import PedestalConfigurationForm, PedestalImportForm
13 from .forms import PedestalConfigurationForm, PedestalImportForm
14
14
15
15
16 def conf(request, conf_id):
16 def conf(request, conf_id):
17
17
18 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
18 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
19
19
20 kwargs = {}
20 kwargs = {}
21 kwargs['dev_conf'] = conf
21 kwargs['dev_conf'] = conf
22
22
23 if conf.mode == 'position':
23 if conf.mode == 'position':
24 kwargs['dev_conf_keys'] = ['mode', 'axis', 'angle']
24 kwargs['dev_conf_keys'] = ['mode', 'axis', 'angle']
25 elif conf.mode == 'speed':
25 elif conf.mode == 'speed':
26 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed']
26 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed']
27 else:
27 else:
28 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed', 'angle', 'min_value', 'max_value']
28 kwargs['dev_conf_keys'] = ['mode', 'axis', 'speed', 'angle', 'min_value', 'max_value']
29
29
30
30
31 kwargs['title'] = 'Configuration'
31 kwargs['title'] = 'Configuration'
32 kwargs['suptitle'] = 'Detail'
32 kwargs['suptitle'] = 'Detail'
33
33
34 kwargs['button'] = 'Edit Configuration'
34 kwargs['button'] = 'Edit Configuration'
35
35
36 conf.status_device()
36 conf.status_device()
37
37
38 ###### SIDEBAR ######
38 ###### SIDEBAR ######
39 kwargs.update(sidebar(conf=conf))
39 kwargs.update(sidebar(conf=conf))
40
40
41 return render(request, 'pedestal_conf.html', kwargs)
41 return render(request, 'pedestal_conf.html', kwargs)
42
42
43 @login_required
43 @login_required
44 def conf_edit(request, conf_id):
44 def conf_edit(request, conf_id):
45
45
46 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
46 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
47
47
48
48
49 if request.method=='GET':
49 if request.method=='GET':
50
50
51 form = PedestalConfigurationForm(instance=conf)
51 form = PedestalConfigurationForm(instance=conf)
52 if conf.mode == 'position':
52 if conf.mode == 'position':
53 form.fields['speed'].disabled = True
53 form.fields['speed'].disabled = True
54 form.fields['max_value'].disabled = True
54 form.fields['max_value'].disabled = True
55 form.fields['min_value'].disabled = True
55 form.fields['min_value'].disabled = True
56 elif conf.mode == 'speed':
56 elif conf.mode == 'speed':
57 form.fields['angle'].disabled = True
57 form.fields['angle'].disabled = True
58 form.fields['max_value'].disabled = True
58 form.fields['max_value'].disabled = True
59 form.fields['min_value'].disabled = True
59 form.fields['min_value'].disabled = True
60
60
61 elif request.method=='POST':
61 elif request.method=='POST':
62
62
63 line_data = {}
63 line_data = {}
64 conf_data = {}
64 conf_data = {}
65 clock_data = {}
65 clock_data = {}
66 extras = []
66 extras = []
67
67
68 #classified post fields
68 #classified post fields
69
69
70 form = PedestalConfigurationForm(request.POST, instance=conf)
70 form = PedestalConfigurationForm(request.POST, instance=conf)
71
71
72 if form.is_valid():
72 if form.is_valid():
73 form.save()
73 form.save()
74
74
75 messages.success(request, 'Pedestal configuration successfully updated')
75 messages.success(request, 'Pedestal configuration successfully updated')
76
76
77 return redirect(conf.get_absolute_url())
77 return redirect(conf.get_absolute_url())
78
78
79 kwargs = {}
79 kwargs = {}
80 kwargs['dev_conf'] = conf
80 kwargs['dev_conf'] = conf
81 kwargs['form'] = form
81 kwargs['form'] = form
82 kwargs['edit'] = True
82 kwargs['edit'] = True
83
83
84 kwargs['title'] = 'Pedestal Configuration'
84 kwargs['title'] = 'Pedestal Configuration'
85 kwargs['suptitle'] = 'Edit'
85 kwargs['suptitle'] = 'Edit'
86 kwargs['button'] = 'Update'
86 kwargs['button'] = 'Update'
87
87
88 return render(request, 'pedestal_conf_edit.html', kwargs)
88 return render(request, 'pedestal_conf_edit.html', kwargs)
89
89
90 def import_file(request, conf_id):
90 def import_file(request, conf_id):
91
91
92 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
92 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
93 if request.method=='POST':
93 if request.method=='POST':
94 form = PedestalImportForm(request.POST, request.FILES)
94 form = PedestalImportForm(request.POST, request.FILES)
95 if form.is_valid():
95 if form.is_valid():
96 try:
96 try:
97 data = conf.import_from_file(request.FILES['file_name'])
97 data = conf.import_from_file(request.FILES['file_name'])
98 conf.dict_to_parms(data)
98 conf.dict_to_parms(data)
99 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
99 messages.success(request, 'Configuration "%s" loaded succesfully' % request.FILES['file_name'])
100 return redirect(conf.get_absolute_url_edit())
100 return redirect(conf.get_absolute_url_edit())
101
101
102 except Exception as e:
102 except Exception as e:
103 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
103 messages.error(request, 'Error parsing file: "%s" - %s' % (request.FILES['file_name'], repr(e)))
104 else:
104 else:
105 messages.warning(request, 'Your current configuration will be replaced')
105 messages.warning(request, 'Your current configuration will be replaced')
106 form = PedestalImportForm()
106 form = PedestalImportForm()
107
107
108 kwargs = {}
108 kwargs = {}
109 kwargs['form'] = form
109 kwargs['form'] = form
110 kwargs['title'] = 'Pedestal Configuration'
110 kwargs['title'] = 'Pedestal Configuration'
111 kwargs['suptitle'] = 'Import file'
111 kwargs['suptitle'] = 'Import file'
112 kwargs['button'] = 'Upload'
112 kwargs['button'] = 'Upload'
113 kwargs['previous'] = conf.get_absolute_url()
113 kwargs['previous'] = conf.get_absolute_url()
114
114
115 return render(request, 'pedestal_import.html', kwargs)
115 return render(request, 'pedestal_import.html', kwargs)
116
116
117 @login_required
118 def conf_reset(request, conf_id):
119
120 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
121
122 if conf.reset_device():
123 messages.success(request, conf.message)
124 else:
125 messages.error(request, conf.message)
126
127 return redirect(conf.get_absolute_url())
128
117 def conf_raw(request, conf_id):
129 def conf_raw(request, conf_id):
118 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
130 conf = get_object_or_404(PedestalConfiguration, pk=conf_id)
119 raw = conf.write_device(raw=True)
131 raw = conf.write_device(raw=True)
120 return HttpResponse(raw, content_type='application/json') No newline at end of file
132 return HttpResponse(raw, content_type='application/json')
General Comments 0
You need to be logged in to leave comments. Login now