diff --git a/ping/templates/ping/play.html b/ping/templates/ping/play.html index b0f0affb4ce4f7b7561a36758229fe5db42bbbae..48d9d96cd2276bb1d4560fa5151bde2f8fac12db 100644 --- a/ping/templates/ping/play.html +++ b/ping/templates/ping/play.html @@ -16,9 +16,8 @@ } function canvasApp() { - var metrics = {{ metrics }}; - var cycle = 0; + var cycle = 1; theCanvas = document.getElementById('canvasOne'); context = theCanvas.getContext('2d'); @@ -27,25 +26,37 @@ context.clearRect(0, 0, theCanvas.width, theCanvas.height); } - function drawScreen() { + function drawScreen(metrics) { erraseCanvas(); - var count = metrics[cycle].length; + var count = metrics.length; for (let id_agent = 0; id_agent < count; id_agent++) { - context.fillStyle = "#000000"; + if ( metrics[id_agent][2] == 0){ + context.fillStyle = "#000000"; + } + else { + context.fillStyle = "#e00000"; + } context.beginPath(); - context.arc(metrics[cycle][id_agent][0], metrics[cycle][id_agent][1], 1, 0, Math.PI * 2, true); + context.arc(metrics[id_agent][0], metrics[id_agent][1], 1, 0, Math.PI * 2, true); context.closePath(); context.fill(); } } - function gameLoop() { - if (cycle < metrics.length) { - window.setTimeout(gameLoop, 20); - drawScreen(); - cycle = cycle + 1; + async function gameLoop() { + let data = await fetch("./metric/".concat("", cycle.toString().concat("", "/"))) + .then((response) => response.json()) + .then(data => {return data.data;}) + while (data.length == 0){ + await new Promise(r => setTimeout(r, 1000)); + data = await fetch("./metric/".concat("", cycle.toString().concat("", "/"))) + .then((response) => response.json()) + .then(data => {return data.data;}) } + drawScreen(data) + cycle = cycle + 1 + window.setTimeout(gameLoop, 20); } gameLoop(); @@ -99,9 +110,14 @@ <button type='submit'> Kill Amas, Env, Scheduler</button> </form> - <canvas id="canvasOne" width="500" height="500" style="border:1px solid #000000;"> - Your browser does not support the HTML 5 Canvas. - </canvas> + <form action='./export_csv/' method='GET'> + <button type='submit'> Export all metrics</button> + </form> + {% if canvas %} + <canvas id="canvasOne" width="{{ canvas.0 }}" height="{{ canvas.1 }}" style="border:1px solid #000000;"> + Your browser does not support the HTML 5 Canvas. + </canvas> + {% endif %} </body> diff --git a/ping/urls.py b/ping/urls.py index 1dcf382abcc5c040fcf507333e3456de2eea3c34..039a484029dd3fdbe0b8382b54a7a293dcc8a9e2 100644 --- a/ping/urls.py +++ b/ping/urls.py @@ -24,4 +24,6 @@ urlpatterns = [ path('play/global/start', views.experiment_start, name='start_exp'), path('play/global/load', views.experiment_load, name='load_exp'), path('play/global/kill', views.experiment_kill, name='kill_exp'), + path('play/metric/<int:metrics_id>/', views.experiment_metric, name='metrics'), + path('play/export_csv/', views.export_csv, name='csv'), ] \ No newline at end of file diff --git a/ping/views/experiment.py b/ping/views/experiment.py index c0ed1ba151d8dd9052911fd8e0c921a50932e97e..4ac42b75e09582bf5e0f27b75892b617eb2dff53 100644 --- a/ping/views/experiment.py +++ b/ping/views/experiment.py @@ -47,7 +47,7 @@ def check(request, experiment_id): delete_folder(str(settings.MEDIA_ROOT) + "/tmp") return HttpResponseRedirect(reverse('ping:experiment')) - required_files = ["amas.py", "agent.py", "env.py", "scheduler.py"] + required_files = ["amas.py", "agent.py", "env.py", "scheduler.py", "config.json"] for required_file in required_files: if not os.path.exists(folder_path + "/" + required_file): exp.status = "Wrong format : " + required_file + " file is expected" diff --git a/ping/views/network.py b/ping/views/network.py index f9e147a6e4380e2a8a0d634ec3f36ed37d24ea7f..7c669d5ab0532fd05b1f22ad0c8e3ed1c74d712d 100644 --- a/ping/views/network.py +++ b/ping/views/network.py @@ -13,7 +13,7 @@ from ..models import Client, Agent def update(request): ssh = get_ssh_client() - version = "0.0.2" + version = "0.0.3" commands = [ Cmd( cmd="cd Desktop/mqtt_goyon/iotamak-core" diff --git a/ping/views/play.py b/ping/views/play.py index c2518131039ea9cc5b1f806dcaa2015e7dd70c33..773eb88ae3071231d2a333989a34e1699f22eb25 100644 --- a/ping/views/play.py +++ b/ping/views/play.py @@ -1,12 +1,15 @@ +import csv import os import sys import zipfile +import json + from ast import literal_eval from subprocess import Popen from time import sleep from django.conf import settings -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.template import loader from django.urls import reverse from iotAmak.tool.ssh_client import Cmd @@ -17,6 +20,7 @@ from ..models import Experiment, CurrentExperiment, Metrics client = MQTTClient(client_id="django-ihm") + def subscribe(mqttclient, topic, fun): mqttclient.subscribe(topic) mqttclient.message_callback_add(topic, fun) @@ -36,6 +40,7 @@ def agent_metric(client, userdata, message) -> None: metric = Metrics(cycle=exp.cycle, metrics=results) metric.save() + def cycle_done(client, userdata, message) -> None: cur_exp = CurrentExperiment.objects.all()[0] cur_exp.cycle += 1 @@ -47,8 +52,8 @@ def update_nbr_agent(client, userdata, message) -> None: exp.nbr_agent += 1 exp.save() -def experiment_load(request): +def experiment_load(request): delete_folder(str(settings.MEDIA_ROOT) + "current_experiment") exp = Experiment.objects.get(status="Selected") @@ -66,9 +71,9 @@ def experiment_load(request): return HttpResponseRedirect(reverse('ping:play')) -def experiment_start(request): - broker_ip = "192.168.157.209" +def experiment_start(request): + broker_ip = "192.168.236.209" ssh = get_ssh_client() experiment_path = str(settings.MEDIA_ROOT) + "current_experiment/" + Experiment.objects.get(status="Selected").name @@ -82,13 +87,13 @@ def experiment_start(request): subscribe(client, "amas/all_metric", agent_metric) # start subprocess scheduler - p1 = Popen([sys.executable, experiment_path+'/scheduler.py', broker_ip]) + p1 = Popen([sys.executable, experiment_path + '/scheduler.py', broker_ip]) sleep(1) # start subprocess amas send_client = [c.to_send() for c in ssh.clients] - p2 = Popen([sys.executable, experiment_path+'/amas.py', broker_ip, str(send_client)]) + p2 = Popen([sys.executable, experiment_path + '/amas.py', broker_ip, str(send_client)]) # start subprocess env - p3 = Popen([sys.executable, experiment_path+'/env.py', broker_ip]) + p3 = Popen([sys.executable, experiment_path + '/env.py', broker_ip]) exp = CurrentExperiment.objects.all()[0] exp.amas_pid = p2.pid @@ -98,9 +103,24 @@ def experiment_start(request): return HttpResponseRedirect(reverse('ping:play')) + def main_play(request): + context = {} + canvas = [] + if len(CurrentExperiment.objects.all()) > 0: cycle = CurrentExperiment.objects.all()[0].cycle + exp = CurrentExperiment.objects.all()[0] + with open( + str(settings.MEDIA_ROOT) + "current_experiment/" + exp.name + "/config.json", + mode='r', + encoding='utf-8' + ) as f: + data = json.load(f) + + if "canvas" in data: + canvas = [data.get("canvas").get("height"), data.get("canvas").get("width")] + else: cycle = 0 metrics = [] @@ -112,8 +132,10 @@ def main_play(request): metrics.append(cycle_metrics) + context["metrics"] = metrics + context["canvas"] = canvas + template = loader.get_template('ping/play.html') - context = {"metrics": metrics} return HttpResponse(template.render(context, request)) @@ -131,6 +153,7 @@ def scheduler_start(request): client.publish("ihm/unpause") return HttpResponseRedirect(reverse('ping:play')) + def experiment_share(request): # get selected experiment exp = Experiment.objects.get(status="Selected") @@ -152,18 +175,47 @@ def experiment_share(request): return HttpResponseRedirect(reverse('ping:play')) + def experiment_stop(request): client.publish("ihm/exit") client.publish("ihm/step") return HttpResponseRedirect(reverse('ping:play')) + def experiment_kill(request): exp = CurrentExperiment.objects.all()[0] - if exp.amas_pid != 0 : - os.system("kill "+str(exp.amas_pid)) - if exp.env_pid != 0 : - os.system("kill "+str(exp.env_pid)) - if exp.scheduler_pid != 0 : - os.system("kill "+str(exp.scheduler_pid)) + if exp.amas_pid != 0: + os.system("kill " + str(exp.amas_pid)) + if exp.env_pid != 0: + os.system("kill " + str(exp.env_pid)) + if exp.scheduler_pid != 0: + os.system("kill " + str(exp.scheduler_pid)) return HttpResponseRedirect(reverse('ping:play')) + + +def experiment_metric(request, metrics_id): + raw_metrics = Metrics.objects.filter(cycle=metrics_id) + if len(raw_metrics) == 0: + return JsonResponse({'data': []}) + else: + cycle_metrics = [ + [metric.get("x"), metric.get("y"), metric.get("color")] + for metric in raw_metrics[0].metrics if metric != {}] + return JsonResponse({'data': cycle_metrics}) + +def export_csv(request): + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="users.csv"' + + writer = csv.writer(response) + writer.writerow(['cycle'] + ["Agent_"+key for key in Metrics.objects.order_by('?').first().metrics[0].keys()]) + + for m in Metrics.objects.all(): + cycle = m.cycle + metrics = m.metrics + for metric in metrics: + if metric != {}: + writer.writerow([cycle] + [value for value in metric.values()]) + + return response \ No newline at end of file