from django.http import HttpResponse from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required import datetime from common.models import Log, WeatherWatch, SiteWatch, ScientificProgram, Config, PyrosUser, PlcDeviceStatus, Telescope, TelescopeCommand from django.core import serializers import utils.Logger as l from django.forms import modelformset_factory from dashboard.forms import ConfigForm, UserForm from dashboard.decorator import level_required from django.views.generic.edit import UpdateView from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from django.urls import reverse_lazy, reverse from django.http import Http404 import json from random import randint from devices.Telescope import TelescopeController from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault from devices.CameraVISRemoteControlDefault import CameraVISRemoteControlDefault from devices.CameraNIRRemoteControlDefault import CameraNIRRemoteControlDefault from devices import PLC from django.core.mail import send_mail import time import utils.celme as celme from collections import OrderedDict SUN_ELEV_DAY_THRESHOLD = -10 MAX_LOGS_LINES = 100 log = l.setupLogger("dashboard", "dashboard") def index(request): if request.user.is_authenticated: return render(request, 'dashboard/index.html', {'USER_LEVEL': request.user.user_level.priority, 'base_template' : "base.html"}) # return the initial view (the dashboard's one) return render(request, 'dashboard/index.html', {'USER_LEVEL': 0, 'base_template' : "base_unlogged.html"}) # return the initial view (the dashboard's one) def retrieve_env(request): try: weather_status = WeatherWatch.objects.latest('updated') plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds() timeout_affichage = datetime.datetime.now() - datetime.timedelta(seconds=timeout) sunelev = get_sunelev() t = datetime.datetime.now() + datetime.timedelta(hours=-7) isDay = False if sunelev >= SUN_ELEV_DAY_THRESHOLD: isDay = True return render(request, 'dashboard/observation_status_env.html', locals()) except WeatherWatch.DoesNotExist: raise Http404("No WeatherWatch matches the given query.") ''' Function that call celme code to determine sun elevation, maybe it should be moved somewhere else ? ''' def get_sunelev(): date = celme.dates.Date("now") site = celme.Site("MPC 244.5367 0.85792 +0.51292") # coords of san pedro martir site skyobj= {'planet':'Sun'} outputs = ['name','ra','dec','elev'] target = celme.Target() target.define(skyobj) output0s = ['ra','dec'] results = target.ephem(date,site,output0s) ra = results['RA'] dec = results['DEC'] skyobj= {'RA':ra , 'DEC':dec } target.define(skyobj) results = target.ephem(date,site,outputs) elev = round(results['ELEV'],2) return elev def retrieve_env_navbar(request): ''' Function which get the last status of the plc in th db, the config info, the sunelev, put it in a json and send it to the client. This function is called every REFRESH_ICONS_FREQUENCE_MILLISECONDS in base.html ''' if request.is_ajax(): try: weather_status = WeatherWatch.objects.latest('updated') plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_mode = plc_device_status.plc_mode is_safe = plc_device_status.is_safe weather = serializers.serialize('json', [weather_status]) weather = json.loads(weather) ack = Config.objects.get(id=1).ack plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds() weather[0]['max_sunelev'] = SUN_ELEV_DAY_THRESHOLD #weather[0]['sunelev'] = 10 weather[0]['sunelev'] = get_sunelev() weather[0]["plc_mode"] = plc_mode weather[0]["is_safe"] = is_safe weather[0]["ACK"] = ack weather[0]["plc_timeout"] = timeout weather[0]["max_plc_timeout"] = plc_timeout weather[0]["pyros_mode"] = Config.objects.get(id=1).pyros_state weather[0]["sitewatch_global_status"] = SiteWatch.objects.latest('updated').global_status return HttpResponse(json.dumps(weather), content_type="application/json") except WeatherWatch.DoesNotExist: raise Http404("No WeatherWatch matches the given query.") def retrieve_main_icon(request): if request.is_ajax(): try: weather_status = WeatherWatch.objects.latest('updated') plc_mode = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created').plc_mode weather = serializers.serialize('json', [weather_status]) weather = json.loads(weather) weather[0]["plc_mode"] = plc_mode weather[0]["sitewatch_global_status"] = SiteWatch.objects.latest('updated').global_status return HttpResponse(json.dumps(weather), content_type="application/json") except WeatherWatch.DoesNotExist: raise Http404("No WeatherWatch matches the given query.") @login_required @level_required(6) def users(request): instance = PyrosUser.objects.order_by("-id") return render(request, 'dashboard/users_management.html', {'instance': instance}) # return the initial view (the users management's one) @login_required @level_required(2) def routines(request): url_ = reverse('admin:common_request_changelist') return redirect(url_) def weather(request): if request.user.is_authenticated: return render(request, 'dashboard/reload_weather.html', {'base_template' : "base.html"}) # return the needed html file return render(request, 'dashboard/reload_weather.html', {'base_template' : "base_unlogged.html"}) def weather_current(request): # PM 20180718 #if request.is_ajax(): try: weather_status = WeatherWatch.objects.latest('updated') plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_mode = plc_device_status.plc_mode is_safe = plc_device_status.is_safe weather = serializers.serialize('json', [weather_status]) weather = json.loads(weather) ack = Config.objects.get(id=1).ack plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds() weather[0]['max_sunelev'] = SUN_ELEV_DAY_THRESHOLD weather[0]['sunelev'] = get_sunelev() weather[0]["plc_mode"] = plc_mode weather[0]["is_safe"] = is_safe weather[0]["ACK"] = ack weather[0]["plc_timeout"] = timeout weather[0]["max_plc_timeout"] = plc_timeout weather[0]["pyros_mode"] = Config.objects.get(id=1).pyros_state return HttpResponse(json.dumps(weather), content_type="application/json") except WeatherWatch.DoesNotExist: raise Http404("No WeatherWatch matches the given query.") def weather_config(request): # PM 20180926 prototype whithout database try: #import os from src.monitoring.plc_checker import PlcChecker #cur_dir = os.path.abspath(".") colibri_json = open("../simulators/plc/colibri-new-fixed-2.json") colibri_struct = json.load(colibri_json) plc_status = colibri_struct["statuses"][1]["entities"][0] plc_checker = PlcChecker(plc_status) plc_checker.scan_captors() return render(request, 'dashboard/config_weather.html', {'weather_config' : plc_checker.captors_conf}) except Config.DoesNotExist: return render(request, 'dashboard/config_weather.html', {'weather_info' : None}) def weather_current_old(request): try: if (len(Config.objects.all()) == 1): monitoring = int(int(Config.objects.get(id=1).row_data_save_frequency) / 5) else: monitoring = 60 if (len(WeatherWatch.objects.all()) > 0): weather_info = WeatherWatch.objects.order_by("-id")[:monitoring] # Use 300 seconds by default with an iteration every 5 seconds # Get the number of data available else: weather_info = None return render(request, 'dashboard/current_weather.html', {'weather_info' : site_current, 'iteration' : monitoring}) except Config.DoesNotExist: return render(request, 'dashboard/current_weather.html', {'weather_info' : None, 'iteration' : 60}) def site(request): if request.user.is_authenticated: return render(request, 'dashboard/reload_site.html', {'base_template' : "base.html"}) # return the needed html file return render(request, 'dashboard/reload_site.html', {'base_template' : "base_unlogged.html"}) # return the needed html file def site_current(request): try: if (len(Config.objects.all()) == 1): monitoring = int(int(Config.objects.get(id=1).row_data_save_frequency) / 5) else: monitoring = 60 if (len(SiteWatch.objects.all()) > 0): site_info = SiteWatch.objects.order_by("-id")[:monitoring] else: site_info = None return render(request, 'dashboard/current_site.html', {'site_info' : site_info, 'iteration' : monitoring, 'global_mode' : Config.objects.get(id=1).global_mode}) except Config.DoesNotExist: return render(request, 'dashboard/current_site.html', {'site_info' : None, 'iteration' : 60}) @login_required @level_required(2) def proposal(request): if (len(ScientificProgram.objects.all()) > 0): # checking if the observatory table is empty proposal_info = ScientificProgram.objects.order_by("-id")[:100] # Sorting Weather table nb_info_proposal = len(proposal_info) # Get the number of data available else: # if empty set everything to 0 / None (variables are checked in src/templates/scheduler/current_weather.html) proposal_info = None nb_info_proposal = 0 return render(request, 'dashboard/proposal.html', {'proposal_info' : proposal_info, 'nb_info_proposal' : nb_info_proposal}) @login_required @level_required(5) def configUpdate(request): instance = get_object_or_404(Config, id=1) form = ConfigForm(request.POST or None, instance=instance) if form.is_valid(): form.save() return redirect('../user_manager/profile') return render(request, 'dashboard/configuration.html', {'form': form}) @login_required def devices(request): url_ = reverse('admin:common_device_changelist') return redirect(url_) @login_required def system(request): return render(request, 'dashboard/system.html') @login_required def system_retrieve_logs(request): ''' Called by the dashboard system page with ajax request every seconds, to get the logs and print them ''' if request.is_ajax(): alert_logs = Log.objects.filter(agent='Alert manager').order_by("-created")[:MAX_LOGS_LINES] scheduler_logs = Log.objects.filter(agent='Scheduler').order_by("-created")[:MAX_LOGS_LINES] majordome_logs = Log.objects.filter(agent='Majordome').order_by("-created")[:MAX_LOGS_LINES] obs_logs = Log.objects.filter(agent='Observation manager').order_by("-created")[:MAX_LOGS_LINES] analyzer_logs = Log.objects.filter(agent='Analyzer').order_by("-created")[:MAX_LOGS_LINES] monitoring_logs = Log.objects.filter(agent='Monitoring').order_by("-created")[:MAX_LOGS_LINES] return render(request, 'dashboard/system_logs.html', locals()) def schedule(request): url_ = reverse('admin:common_schedule_changelist') return redirect(url_) @login_required @level_required(6) def quotas(request): url_ = reverse('admin:common_pyrosuser_changelist') return redirect(url_) @login_required @level_required(3) def change_globalMode(request): try : config = get_object_or_404(Config, id=1) plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') if config.global_mode == False and plc_device_status.is_safe == False: return redirect('states') config.global_mode = not config.global_mode config.save() return redirect('states') except Config.DoesNotExist: return redirect('states') @login_required @level_required(4) def change_bypass(request): try : config = get_object_or_404(Config, id=1) plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') if plc_device_status.is_safe == True: return redirect('states') config.bypass = not config.bypass config.save() return redirect('states') except Config.DoesNotExist: return redirect('states') @login_required @level_required(3) def change_lock(request): try : config = get_object_or_404(Config, id=1) plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') if config.lock == False and plc_device_status.is_safe == False: return redirect('states') config.lock = not config.lock if (config.lock == True): config.ntc = not config.ntc config.save() return redirect('states') except Config.DoesNotExist: return redirect('states') @login_required @level_required(6) def change_activate(request, pk): try : user = get_object_or_404(PyrosUser, pk=pk) user.is_active = not user.is_active text_mail = "" text_object = "" if (user.first_time == False and user.is_active == True): user.first_time = True text_mail = "Hi,\n\nCongratulations, your registration has been approuved by the PI. Welcome to the Colibri Control Center.\n\nCordialy,\n\nColibri Control Center" text_object = "[COLIBRI CC] Welcome" elif (user.is_active == True): text_mail = "Hi,\n\nYour account on the Colibri Control Center have been re-activated.\n\nCordialy,\n\nColibri Control Center" text_object = "[COLIBRI CC] Re-activation" else : text_mail = "Hi,\n\nYour account on the Colibri Control Center have benn desactivated. Please contact the PI for futher information.\n\nCordialy,\n\nColibri Control Center" text_object = "[COLIBRI CC] Desactivation" user.save() send_mail(text_object, text_mail, '', [user.email], fail_silently=False,) return redirect('user-detail', pk=pk) except PyrosUser.DoesNotExist: return redirect('user-detail', pk=pk) @login_required @level_required(3) def send_command_to_cameraVIS_1(request): data = "" with open('../simulators/config/grammar.json') as f: data = json.load(f, object_pairs_hook=OrderedDict) json_str = json.dumps(data) return render(request, "dashboard/send_command_cameraVIS_1.html", locals()) @login_required @level_required(3) def submit_command_to_cameraVIS_1(request): ''' function called when a command it submitted for the cameraVIS_1 in the remote control page (called in the corresponding control_command file) ''' if request.method == 'POST': commands = [request.POST.get("first_command"), request.POST.get("first_param")] try: #TODO faire un truc plus joli pour gérer les params queqlue soit leur nombre input_0 = request.POST.get("input_number_0") input_1 = request.POST.get("input_number_1") input_2 = request.POST.get("input_number_2") input_3 = request.POST.get("input_number_3") if input_0: commands.append(input_0) if input_1: commands.append(input_1) if input_2: commands.append(input_2) if input_3: commands.append(input_3) except Exception: pass response = CameraVISRemoteControlDefault(commands, expert_mode=False, chosen_camera="ddrago_r").exec_command() #TODO passer en JS pour send les réponses en AJAX return redirect('send_command_to_cameraVIS_1') @login_required @level_required(3) def submit_command_to_cameraVIS_1_expert(request): ''' function called when a command it submitted in expert mode for the cameraVIS_1 in the remote control page (called in the corresponding control_command file) ''' if request.method == 'POST': param = request.POST.get("commande_expert") if param: response = CameraVISRemoteControlDefault(param, expert_mode=True, chosen_camera="ddrago_r").exec_command() #os.system("echo \"status :" + response + "\" >> /home/portos/IRAP/pyros/src/status") return HttpResponse(json.dumps({'message': "Command send OK", 'response': response})) return HttpResponse(json.dumps({'message': "Missing command data"})) return redirect('submit_command_to_telescope') @login_required @level_required(3) def send_command_to_cameraNIR(request): data = "" with open('../simulators/config/grammar.json') as f: data = json.load(f, object_pairs_hook=OrderedDict) json_str = json.dumps(data) return render(request, "dashboard/send_command_cameraNIR.html", locals()) @login_required @level_required(3) def submit_command_to_cameraNIR(request): ''' function called when a command it submitted for the cameraNIR in the remote control page (called in the corresponding control_command file) ''' if request.method == 'POST': commands = [request.POST.get("first_command"), request.POST.get("first_param")] try: #TODO faire un truc plus joli pour gérer les params queqlue soit leur nombre input_0 = request.POST.get("input_number_0") input_1 = request.POST.get("input_number_1") input_2 = request.POST.get("input_number_2") input_3 = request.POST.get("input_number_3") if input_0: commands.append(input_0) if input_1: commands.append(input_1) if input_2: commands.append(input_2) if input_3: commands.append(input_3) except Exception: pass response = CameraNIRRemoteControlDefault(commands, expert_mode=False).exec_command() #TODO passer en JS pour send les réponses en AJAX return redirect('send_command_to_cameraNIR') @login_required @level_required(3) def submit_command_to_cameraNIR_expert(request): ''' function called when a command it submitted in expert mode for the cameraNIR in the remote control page (called in the corresponding control_command file) ''' if request.method == 'POST': param = request.POST.get("commande_expert") if param: response = CameraNIRRemoteControlDefault(param, expert_mode=True).exec_command() return HttpResponse(json.dumps({'message': "Command send OK", 'response': response})) return HttpResponse(json.dumps({'message': "Missing command data"})) return redirect('submit_command_to_cameraNIR') @login_required @level_required(3) def send_command_to_cameraVIS_2(request): data = "" with open('../simulators/config/grammar.json') as f: data = json.load(f, object_pairs_hook=OrderedDict) json_str = json.dumps(data) return render(request, "dashboard/send_command_cameraVIS_2.html", locals()) @login_required @level_required(3) def submit_command_to_cameraVIS_2(request): ''' function called when a command it submitted for the cameraVIS_2 in the remote control page (called in the corresponding control_command file) ''' if request.method == 'POST': commands = [request.POST.get("first_command"), request.POST.get("first_param")] try: #TODO faire un truc plus joli pour gérer les params queqlue soit leur nombre input_0 = request.POST.get("input_number_0") input_1 = request.POST.get("input_number_1") input_2 = request.POST.get("input_number_2") input_3 = request.POST.get("input_number_3") if input_0: commands.append(input_0) if input_1: commands.append(input_1) if input_2: commands.append(input_2) if input_3: commands.append(input_3) except Exception: pass response = CameraVISRemoteControlDefault(commands, expert_mode=False, chosen_camera="ddrago_b").exec_command() #TODO passer en JS pour send les réponses en AJAX return redirect('send_command_to_cameraVIS_2') @login_required @level_required(3) def submit_command_to_cameraVIS_2_expert(request): ''' function called when a command it submitted in expert mode for the cameraVIS_2 in the remote control page (called in the corresponding control_command file) ''' if request.method == 'POST': param = request.POST.get("commande_expert") if param: response = CameraVISRemoteControlDefault(param, expert_mode=True, chosen_camera="ddrago_b").exec_command() return HttpResponse(json.dumps({'message': "Command send OK", 'response': response})) return HttpResponse(json.dumps({'message': "Missing command data"})) return redirect('submit_command_to_cameraVIS_2') @login_required @level_required(3) def send_command_to_telescope(request): data = "" with open('../simulators/config/grammar.json') as f: data = json.load(f, object_pairs_hook=OrderedDict) json_str = json.dumps(data) return render(request, "dashboard/send_command_telescope.html", locals()) @login_required @level_required(3) def submit_command_to_telescope(request): ''' function called when a command it submitted for the Telescope in the remote control page (called in control_command.js) ''' if request.method == 'POST': commands = [request.POST.get("first_command"), request.POST.get("first_param")] try: #TODO faire un truc plus joli pour gérer les params quelque soit leur nombre la c'est du rapide super moche et max 4 input input_0 = request.POST.get("input_number_0") input_1 = request.POST.get("input_number_1") input_2 = request.POST.get("input_number_2") input_3 = request.POST.get("input_number_3") if input_0: commands.append(input_0) if input_1: commands.append(input_1) if input_2: commands.append(input_2) if input_3: commands.append(input_3) except Exception: pass request = ' '.join(commands) NEW_MODE = True if NEW_MODE: TelescopeCommand.objects.create(request=request) else: response = TelescopeRemoteControlDefault(commands, False).exec_command() #TODO passer en JS pour send les réponses en AJAX return redirect('send_command_to_telescope') @login_required @level_required(3) def submit_command_to_telescope_expert(request): ''' function called when a command it submitted in expert mode for the Telescope in the remote control page (called in control_command.js) ''' if request.method == 'POST': param = request.POST.get("commande_expert") if param: request = TelescopeCommand.objects.create(request=param) time.sleep(1) response = TelescopeCommand.objects.get(pk=request.id).answer return HttpResponse(json.dumps({'message': "Command send OK", 'response': response})) return HttpResponse(json.dumps({'message': "Missing command data"})) return redirect('submit_command_to_telescope') @login_required @level_required(3) def submit_command_to_plc(request): if request.method == 'POST': param = request.POST.get("commande_expert") if param: plc_controller = PLC.PLCController() response = "Unrecognized command" if param.startswith("GET STATUS ") or param =="GET STATUS": #pas beau a revoir (classe dédiée ?) response = plc_controller.getStatus(param) elif param.startswith("SWITCH LIGHTS"): response = plc_controller.switch_lights(param) elif param.endswith(" SHUTTERS"): response = plc_controller.manage_shutters(param) return HttpResponse(json.dumps({'message': "Command send OK", 'response': response})) return HttpResponse(json.dumps({'message': "Missing command data"})) return redirect('submit_command_to_plc') @login_required @level_required(3) def send_command_to_plc(request): return render(request, 'dashboard/send_command_to_plc.html') @login_required @level_required(2) def user_detail_view(request,pk): try: user_id=PyrosUser.objects.get(pk=pk) current_user = request.user except PyrosUser.DoesNotExist: raise Http404("User does not exist") return render(request, 'dashboard/user_detail.html', context={'user' : user_id, 'current_user' : current_user, 'USER_LEVEL': request.user.user_level.priority}) @login_required @level_required(6) def user_detail_edit(request,pk): edit = get_object_or_404(PyrosUser, pk=pk) form = UserForm(request.POST or None, instance=edit) if form.is_valid(): form.save() return redirect('user-detail', pk=pk) return render(request, 'dashboard/user_detail_edit.html', {'form': form}) @login_required @level_required(3) def operator_state(request): instance = get_object_or_404(Config, id=1) plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') return render(request, 'dashboard/operator_state.html', {'config' : instance, 'is_safe' : plc_device_status.is_safe}) @login_required @level_required(3) def simulator(request): try : config = get_object_or_404(Config, id=1) plc_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') return(render(request, 'dashboard/simulator.html', locals())) except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_switch_ack(request): try : config = get_object_or_404(Config, id=1) config.ack = not config.ack config.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') # if safe => switch to unsafe # if unsafe => switch to safe @login_required @level_required(7) def simulator_switch_safe(request): try : plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_device_status.is_safe = not plc_device_status.is_safe plc_device_status.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_give_auto(request): try : plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_device_status.plc_mode = "AUTO" plc_device_status.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_give_manu(request): try : plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_device_status.plc_mode = "MANU" plc_device_status.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_give_ko(request): try : plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created') plc_device_status.plc_mode = "OFF" plc_device_status.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_switch_bypass(request): try : config = get_object_or_404(Config, id=1) config.bypass = not config.bypass config.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_switch_lock(request): try : config = get_object_or_404(Config, id=1) config.lock = not config.lock config.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_switch_globalMode(request): try : config = get_object_or_404(Config, id=1) config.global_mode = not config.global_mode config.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_majordome_restart(request): try : config = get_object_or_404(Config, id=1) config.majordome_state = "OCS-RESTART" config.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator') @login_required @level_required(7) def simulator_majordome_shutdown(request): try : config = get_object_or_404(Config, id=1) config.majordome_state = "OCS-SHUTDOWN" config.save() return redirect('simulator') except Config.DoesNotExist: return redirect('simulator')