Skip to content
Snippets Groups Projects
Commit 85bcab95 authored by shinedday's avatar shinedday
Browse files

Use asgi for canvas

parent 26340ea4
No related branches found
No related tags found
No related merge requests found
"""
ASGI config for iotamak_ihm project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
"""
# mysite/asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'iotamak_ihm.settings')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "iotamak_ihm.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
import ping.routing
application = get_asgi_application()
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket":
AuthMiddlewareStack(
URLRouter(
ping.routing.websocket_urlpatterns
)
)
,
})
......@@ -32,13 +32,14 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads/')
# Application definition
INSTALLED_APPS = [
'ping.apps.PingConfig',
'ping',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'channels',
]
MIDDLEWARE = [
......@@ -70,6 +71,15 @@ TEMPLATES = [
]
WSGI_APPLICATION = 'iotamak_ihm.wsgi.application'
ASGI_APPLICATION = 'iotamak_ihm.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
# Database
......
from channels.generic.websocket import AsyncWebsocketConsumer
import json
class GraphConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = 'event'
self.room_group_name = self.room_name+"_graph"
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
print(self.room_group_name)
await self.accept()
async def disconnect(self, code):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
print("DISCONNECED CODE: ",code)
async def receive(self, text_data=None, bytes_data=None):
data = json.loads(text_data)
message = data['message']
await self.channel_layer.group_send(
self.room_group_name,{
"type": 'send_message_to_frontend',
"message": message
}
)
async def send_message_to_frontend(self,event):
# Receive message from room group
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
class CanvasConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = 'event'
self.room_group_name = self.room_name+"_canvas"
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
print(self.room_group_name)
await self.accept()
async def disconnect(self, code):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
print("DISCONNECED CODE: ",code)
async def receive(self, text_data=None, bytes_data=None):
data = json.loads(text_data)
message = data['message']
await self.channel_layer.group_send(
self.room_group_name,{
"type": 'send_message_to_frontend',
"message": message
}
)
async def send_message_to_frontend(self,event):
# Receive message from room group
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
\ No newline at end of file
# chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path("ws/canvas/", consumers.CanvasConsumer.as_asgi()),
re_path("ws/graph/", consumers.GraphConsumer.as_asgi()),
]
\ No newline at end of file
......@@ -5,65 +5,15 @@
<meta charset="utf-8">
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'ping/index.css' %}">
<script
src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"
integrity="sha512-QSkVNOCYLtj73J4hbmVoOV6KVZuMluZlioC+trLpewV8qMjsWqlIQvkn1KGX2StWvPMdWGBqim1xlC8krl1EKQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<title>Play - IOTAMAK</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
function canvasApp() {
var cycle = 1;
theCanvas = document.getElementById('canvasOne');
context = theCanvas.getContext('2d');
function erraseCanvas() {
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
}
function drawScreen(metrics) {
erraseCanvas();
var count = metrics.length;
for (let id_agent = 0; id_agent < count; id_agent++) {
if ( metrics[id_agent][2] == 0){
context.fillStyle = "#000000";
}
else {
context.fillStyle = "#e00000";
}
context.beginPath();
context.arc(metrics[id_agent][0], metrics[id_agent][1], 1, 0, Math.PI * 2, true);
context.closePath();
context.fill();
}
}
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();
}
</script>
</head>
<body>
......@@ -113,12 +63,86 @@
<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>
<canvas id="canvasOne" width="{{ canvas.0 }}" height="{{ canvas.1 }}" style="border:1px solid #000000;">
Your browser does not support the HTML 5 Canvas.
</canvas>
<script type="text/javascript">
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/canvas/'
);
theCanvas = document.getElementById('canvasOne');
context = theCanvas.getContext('2d');
function erraseCanvas() {
context.clearRect(0, 0, theCanvas.width, theCanvas.height);
}
chatSocket.onmessage = function (e) {
const metrics = JSON.parse(e.data).message;
erraseCanvas();
var count = metrics.length;
for (let id_agent = 0; id_agent < count; id_agent++) {
context.fillStyle = metrics[id_agent][2];
context.beginPath();
context.arc(metrics[id_agent][0], metrics[id_agent][1], 1, 0, Math.PI * 2, true);
context.closePath();
context.fill();
};
};
chatSocket.onclose = function (e) {
console.error('Chat socket closed unexpectedly');
};
</script>
{% endif %}
<canvas id="myChart" width="500" height="500" style="border:1px solid #000000;"></canvas>
<script>
var chart_data = {
labels: ["0", "1", "2", "3"],
type: 'line',
data: {
datasets: [{
data: [0,0,0,0]
}]
}
};
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, chart_data);
const graphSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/graph/'
);
graphSocket.onmessage = function (e) {
const metrics = JSON.parse(e.data).message;
console.log(metrics);
new_graph_data = chart_data.data.datasets[0].data;
new_graph_data.shift();
new_graph_data.push(metrics[0]);
console.log(new_graph_data);
chart_data.data.datasets[0].data = new_graph_data;
console.log(new_graph_data);
myChart.update();
};
</script>
</body>
</html>
\ No newline at end of file
......@@ -15,7 +15,7 @@ from django.urls import reverse
from iotAmak.tool.ssh_client import Cmd
from paho.mqtt.client import Client as MQTTClient
from .tool import delete_folder, get_ssh_client
from .tool import delete_folder, get_ssh_client, canvas_event_triger, graph_event_triger
from ..models import Experiment, CurrentExperiment, Metrics
client = MQTTClient(client_id="django-ihm")
......@@ -37,9 +37,23 @@ def agent_metric(client, userdata, message) -> None:
results = literal_eval(message.payload.decode("utf-8"))
exp = CurrentExperiment.objects.all()[0]
metric = Metrics(cycle=exp.cycle, metrics=results)
metric.save()
metrics = Metrics(cycle=exp.cycle, metrics=results)
metrics.save()
# if canvas
cycle_metrics = [
[metric.get("x"), metric.get("y"), metric.get("color")]
for metric in results if metric != {}]
canvas_event_triger(cycle_metrics)
# if graph
data = 0
for metric in results:
if metric == {}:
pass
elif metric.get("color") != "#000000":
data += 1
graph_event_triger([data, exp.cycle])
def cycle_done(client, userdata, message) -> None:
cur_exp = CurrentExperiment.objects.all()[0]
......@@ -73,7 +87,7 @@ def experiment_load(request):
def experiment_start(request):
broker_ip = "192.168.124.209"
broker_ip = "192.168.193.209"
ssh = get_ssh_client()
experiment_path = str(settings.MEDIA_ROOT) + "current_experiment/" + Experiment.objects.get(status="Selected").name
......
import os
import shutil
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from iotAmak.tool.remote_client import RemoteClient
from iotAmak.tool.ssh_client import SSHClient
......@@ -27,4 +29,25 @@ def get_remote_client():
return res
def get_ssh_client():
return SSHClient(get_remote_client())
\ No newline at end of file
return SSHClient(get_remote_client())
def canvas_event_triger(metrics):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'event_canvas',
{
'type': 'send_message_to_frontend',
'message': metrics
}
)
def graph_event_triger(metrics):
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
'event_graph',
{
'type': 'send_message_to_frontend',
'message': metrics
}
)
Django >= 4.0.4
channels >= 3.0.4
channels-redis >= 3.4.0
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment