import os from datetime import datetime import json import requests import base64 import struct from struct import pack import time from django.contrib import messages from django.db import models from django.urls import reverse from django.core.validators import MinValueValidator, MaxValueValidator from apps.main.models import Configuration MODE_VALUE = ( ('position', 'Position'), ('speed', 'Speed'), ('table', 'Table') ) class PedestalConfiguration(Configuration): mode = models.CharField( verbose_name='Mode', max_length=10, choices=MODE_VALUE, null=False, blank=False ) axis = models.CharField( verbose_name="Axis", max_length=1000, blank=False, null=False, help_text="Please separate the values with commas when using table mode" ) speed = models.CharField( verbose_name='Speed [°/s]', max_length=1000, blank=True, null=True ) angle = models.CharField( verbose_name="Angle(s) [°]", max_length=1000, blank=True, null=True, help_text="Please separate the values with commas when using table mode" ) min_value = models.FloatField( verbose_name='Min angle [°]', validators=[MinValueValidator(-5), MaxValueValidator(185)], blank=True, null=True ) max_value = models.FloatField( verbose_name='Max angle [°]', validators=[MinValueValidator(-5), MaxValueValidator(185)], blank=True, null=True ) class Meta: db_table = 'pedestal_configurations' def __str__(self): if self.mode=='position': return u'Position: {}º {}'.format(self.angle, self.axis.upper()) if self.mode=='speed': return u'Speed: {}º/s {}'.format(self.speed, self.axis.upper()) if self.mode=='table': axis = [x.strip().upper() for x in self.axis.split(',')] speeds = [float(x.strip()) for x in self.speed.split(',')] table = [float(x.strip()) for x in self.angle.split(',')] return u'Table: Axis {}, Speed {}º/s, Steps {}'.format(axis, speeds, table) @property def label(self): return str(self) def get_absolute_url_plot(self): return reverse('url_plot_pedestal_pulses', args=[str(self.id)]) def request(self, cmd, method='get', **kwargs): req = getattr(requests, method)(self.device.url(cmd), **kwargs) payload = req.json() return payload def status_device(self): try: payload = requests.get(self.device.url()) if payload: self.device.status = 1 elif payload['status']=='disable': self.device.status = 2 else: self.device.status = 1 self.device.save() self.message = 'Pedestal status: {}'.format(payload['status']) return False except Exception as e: if 'No route to host' not in str(e): self.device.status = 4 self.device.save() self.message = 'Pedestal status: {}'.format(str(e)) return False self.device.save() return True def reset_device(self, axi, angle): try: url = self.device.url() + "position?params=" payload_el = {'axis': 'elevation'} payload_az = {'axis': 'azimuth'} if axi == 'elevation': # CORRECT AZ OFFSET azi = angle - float(os.environ.get('AZ_OFFSET', 26.27)) if azi<0: azi += 360 payload_az['position'] = round(azi, 2) payload_el['position'] = 0 elif axi == 'azimuth': payload_el['position'] = angle payload_az['position'] = 0 else: payload_el['position'] = 0 payload_az['position'] = 0 json_data_el = json.dumps(payload_el) json_data_az = json.dumps(payload_az) base64_table_el = base64.standard_b64encode(json_data_el.encode('ascii')) base64_table_az = base64.standard_b64encode(json_data_az.encode('ascii')) time.sleep(0.1) r = requests.get(url + base64_table_el.decode('ascii')) time.sleep(0.1) r = requests.get(url + base64_table_az.decode('ascii')) if r: self.device.status = 3 self.device.save() self.message = 'Pedestal reset' else: return False except Exception as e: self.message = 'Pedestal reset: {}'.format(str(e)) return False return True def stop_device(self): try: command = self.device.url() + "stop" r = requests.get(command) if self.mode == 'table': AX = {'az':'azimuth', 'el':'elevation'} axis = [AX[x.lower().strip()] for x in self.axis.split(',')] list_of_floats = [float(x.strip()) for x in self.angle.split(",")] self.reset_device(axis[0], list_of_floats[0]) if r: self.device.status = 4 self.device.save() self.message = 'Pedestal stopped' else: self.device.status = 4 self.device.save() return False except Exception as e: if 'No route to host' not in str(e): self.device.status = 4 else: self.device.status = 0 #self.message = 'Pedestal stop: {}'.format(str(e)) self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration" self.device.save() return False return True def start_device(self, name_experiment=False): if self.mode == 'table': if len(self.angle.split(',')) > 1: list_speed = [] list_axis = [] for _ in range(len(self.angle.split(','))): list_axis.append(self.axis) list_speed.append(self.speed) if len(self.axis.split(',')) == 1: self.axis = ",".join(map(str, list_axis)) if len(self.speed.split(',')) == 1: self.speed = ",".join(map(str, list_speed)) AX = {'az':'azimuth', 'el':'elevation'} axis = [AX[x.lower().strip()] for x in self.axis.split(',')] if len(axis)==1: axis = axis[0] try: if self.mode == 'position': url = self.device.url() + "position?params=" payload = {'axis': axis, 'position': float(self.angle)} elif self.mode == 'speed': url = self.device.url() + "speed?params=" payload = {'axis': axis, 'speed': float(self.speed)} elif self.mode == 'table': url = self.device.url() + "combinedtable?params=" list_of_floats = [float(x.strip()) for x in self.angle.split(",")] # CORRECT AZ OFFSET for i, ax in enumerate(axis): if ax == 'elevation': azi = list_of_floats[i] - float(os.environ.get('AZ_OFFSET', 26.27)) if azi<0: azi += 360 list_of_floats[i] = round(azi, 2) byte_table = [] for x in list_of_floats: temp = bytearray(struct.pack("f", x)) byte_table.append(temp[3]) byte_table.append(temp[2]) byte_table.append(temp[1]) byte_table.append(temp[0]) coded_table = base64.standard_b64encode(bytes(byte_table)) coded_table_ascii = coded_table.decode('ascii') speed = [float(x.strip()) for x in self.speed.split(',')] if isinstance(axis, str): axis = [axis] payload = { 'arraylength': len(speed), 'axis': axis, 'speed': speed, 'bottom': self.min_value, 'top': self.max_value, 'table': coded_table_ascii } json_data = json.dumps(payload) print(json_data) base64_table = base64.standard_b64encode(json_data.encode('ascii')) url += base64_table.decode('ascii') print(url) r = requests.get(url) if self.mode == 'table': payload['table'] = list_of_floats if name_experiment: name_experiment = name_experiment.split("@") dt = datetime.strptime(name_experiment[1], '%Y-%m-%dT%H-%M-%S') self.clone(experiment=name_experiment[0], experiment_date=dt, type=1) else: self.clone(type=1, experiment = 'empty', experiment_date=datetime.now()) if r: self.device.status = 3 self.device.save() self.message = 'Pedestal configured and started' else: return False except Exception as e: if 'No route to host' not in str(e): self.device.status = 4 else: self.device.status = 0 #self.message = 'Pedestal start: {}'.format(str(e)) self.message = "Pedestal can't start, please check network/device connection or IP address/port configuration" self.device.save() return False return payload def get_absolute_url_import(self): return reverse('url_import_pedestal_conf', args=[str(self.id)])