Added Scanner identification and MQTT handling

This commit is contained in:
2022-04-13 15:43:20 +02:00
parent 4da41fe1cd
commit 4b7234fa68
18 changed files with 595 additions and 76 deletions

View File

@@ -1,3 +1,4 @@
from django.contrib import admin
from .models import Scanner
# Register your models here.
admin.site.register(Scanner)

View File

@@ -0,0 +1,54 @@
from channels.generic.websocket import AsyncWebsocketConsumer
import json
import logging
from homelog import settings
LOGGER = logging.getLogger(__name__)
class BookerFeConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.scanner_id = self.scope['url_route']['kwargs']['scanner_id']
self.scanner_group_name = self.scanner_id
self.group_name = self.scanner_group_name
#self.group_name = settings.MQTT_CHANNEL_NAME
# join to group
await self.channel_layer.group_add(self.scanner_group_name, self.channel_name)
topic = f"barcodescanner/{self.scanner_id}/scan"
LOGGER.debug(f"send mqtt_subscribe topic {topic} to channel group {self.scanner_group_name} (my channel is {self.channel_name})")
await self.channel_layer.send(settings.MQTT_CHANNEL_NAME, {
"type": "mqtt.subscribe",
"topic": topic,
"group": self.scanner_group_name
})
await self.accept()
async def disconnect(self):
# leave group
await self.channel_layer.group_discard(self.group_name, self.channel_name)
LOGGER.debug(f"disconnect from channel group {self.group_name}")
async def receive(self, text_data):
print('>>>', text_data)
msg = '{"message":"pong!"}' if text_data == '{"message":"ping"}' else text_data
print('<<<', msg)
await self.channel_layer.group_send(
self.scanner_group_name,
{
'type': 'distribute',
'text': msg
}
)
async def distribute(self, event):
valother = event['text']
LOGGER.debug(f"distribute text={valother}")
await self.send(text_data=valother)
async def mqtt_message(self, event):
message = event['message']
topic = message['topic']
payload = message['payload']
LOGGER.debug(f"Received message with payload={payload}, topic={topic}")
await self.send(text_data=json.dumps({'message': payload, 'topic': topic}))

View File

@@ -1,3 +1,18 @@
from django.db import models
from django.conf import settings
from homelog.system_user import get_deleted_user
# Create your models here.
class Scanner(models.Model):
named_id = models.CharField(max_length=40, unique=True)
description = models.CharField(max_length=200)
lwt_topic = models.CharField(max_length=200)
last_online_ts = models.DateTimeField('last datetime this scanner has been online')
assigned_channel_name = models.CharField(max_length=200)
assigned_group_name = models.CharField(max_length=200)
created_ts = models.DateTimeField('datetime created', auto_now_add=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_deleted_user),
related_name='created_scanners')
changed_ts = models.DateTimeField('datetime updated', auto_now=True)
changed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_deleted_user),
related_name='changed_scanners')

View File

@@ -1,48 +0,0 @@
from channels.generic.websocket import AsyncWebsocketConsumer
import json
'''
class ScannerCollector(WebsocketConsumer):
def connect(self):
self.accept()
def disconnect(self, close_code):
pass
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
self.send(text_data=json.dumps({
'message': message
}))
'''
class ScannerCollector(AsyncWebsocketConsumer):
async def connect(self):
self.group_name = 'scanner'
# join to group
await self.channel_layer.group_add(self.group_name, self.channel_name)
await self.accept()
async def disconnect(self):
# leave group
await self.channel_layer.group_discard(self.group_name, self.channel_name)
async def receive(self, text_data):
print('>>>', text_data)
msg = '{"message":"pong!"}' if text_data == '{"message":"ping"}' else text_data
print('<<<', msg)
await self.channel_layer.group_send(
self.group_name,
{
'type': 'distribute',
'text': msg
}
)
async def distribute(self, event):
valother = event['text']
await self.send(text_data=valother)

View File

@@ -0,0 +1,77 @@
import datetime
import logging
import re
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from booker.models import Scanner
from asgiref.sync import sync_to_async
from channels.db import database_sync_to_async
from django.contrib.auth import get_user_model
from homelog.system_user import get_system_user
from homelog import settings
from django.core.exceptions import ObjectDoesNotExist
LOGGER = logging.getLogger(__name__)
class ScannerAnnounceConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.group_name = 'scanner-announce'
# join to group
await self.channel_layer.group_add(self.group_name, self.channel_name)
LOGGER.debug(f"send mqtt_subscribe to channel layer {settings.MQTT_CHANNEL_NAME} to answer on channel {self.group_name} (my channel is {self.channel_name})")
await self.channel_layer.send(settings.MQTT_CHANNEL_NAME, {
"type": "mqtt.subscribe",
"topic": "barcodescanner/+/status",
"group": self.group_name
})
LOGGER.debug("ScannerAnnounceConsumer initialized")
await self.accept()
async def receive(self, mqtt_message):
pass
async def disconnect(self, code):
await self.channel_layer.send(settings.MQTT_CHANNEL_NAME, {
"type": "mqtt.unsubscribe",
"topic": "barcodescanner/#/status",
"group": self.group_name
})
LOGGER.debug(f"Disconnect from scanner-announce, unsubscribing topic; code={code}")
await self.channel_layer.group_discard(self.group_name, self.channel_name)
async def distribute(self, event):
valother = event['text']
await self.send(text_data=valother)
@database_sync_to_async
def get_or_create_scanner(self, named_id, topic):
scanner, created = Scanner.objects.get_or_create(named_id=named_id, defaults={
'lwt_topic': topic,
'last_online_ts': datetime.datetime.now(),
'created_by': get_system_user(),
'changed_by': get_system_user()
})
if created:
LOGGER.debug(f"Created new scanner entry for {named_id}")
else:
LOGGER.debug(f"Updated scanner entry for {named_id}")
return scanner
async def mqtt_message(self, event):
message = event['message']
topic = message['topic']
qos = message['qos']
payload = message['payload']
print('Received a message at topic: ', topic)
print('with payload ', payload)
print('and QOS ', qos)
named_id = 'invalid'
m = re.match(r'barcodescanner\/(barcodescan-[0-9,a-f]{6})\/status', topic)
if m:
named_id = m[1]
await self.send(text_data=json.dumps({'message': payload, 'scanner': named_id, 'topic': topic}))
LOGGER.debug(f"Got MQTT message from {topic} with payload {payload}")
if payload == 'Online' or payload == 'online':
scanner = await self.get_or_create_scanner(named_id=named_id, topic=topic)

View File

@@ -4,21 +4,55 @@
{% block title %}Scanner Index{% endblock %}
{% block content %}
What chat room would you like to enter?<br>
<input id="room-name-input" type="text" size="100"><br>
<input id="room-name-submit" type="button" value="Enter">
<div class="container">
<div class="row">
<h1>Booker</h1>
<p>Choose a scanner you want to use to book assets and container into/outof containers.</p>
</div>
<div class="row">
<div class="cols-12">
<textarea id="chat-log" cols="100" rows="7"></textarea><br>
<script>
document.querySelector('#room-name-input').focus();
document.querySelector('#room-name-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#room-name-submit').click();
}
};
What scanner would you like to use? (Refresh page if your new scanner is not shown)<br>
{% for scanner in object_list %}
<a href="/booker/{{ scanner.named_id }}/">{{ scanner.named_id }}: {{ scanner.description }}</a><br />
{% endfor %}
<input id="scanner-name-input" type="text" size="100"><br>
<input id="scanner-name-submit" type="button" value="Enter">
document.querySelector('#room-name-submit').onclick = function(e) {
var roomName = document.querySelector('#room-name-input').value;
window.location.pathname = '/booker/' + roomName + '/';
};
</script>
<script>
document.querySelector('#scanner-name-input').focus();
document.querySelector('#scanner-name-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#scanner-name-submit').click();
}
};
document.querySelector('#scanner-name-submit').onclick = function(e) {
var scannerName = document.querySelector('#scanner-name-input').value;
window.location.pathname = '/booker/' + scannerName + '/';
};
</script>
<script>
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/scanner-announce/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.scanner + ': ' + data.message + '\n');
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
document.querySelector('#chat-log').value += ('ERROR: Chat socket closed unexpectedly!\n');
};
</script>
</div>
</div>
</div>
{% endblock %}

View File

@@ -7,15 +7,15 @@
<textarea id="chat-log" cols="100" rows="20"></textarea><br>
<input id="chat-message-input" type="text" size="100"><br>
<input id="chat-message-submit" type="button" value="Send">
{{ scanner_id|json_script:"room-name" }}
{{ scanner_id|json_script:"scanner_id" }}
<script>
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const scannerId = JSON.parse(document.getElementById('scanner_id').textContent);
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/scannerdata/'
+ roomName
+ '/ws/scanner/'
+ scannerId
+ '/'
);

View File

@@ -4,6 +4,6 @@ from . import views
app_name = 'booker'
urlpatterns = [
path('', views.index, name='index'),
path('', views.IndexView.as_view(), name='index'),
path('<str:scanner_id>/', views.scanner, name='scanner')
]

View File

@@ -1,10 +1,14 @@
from django.shortcuts import render
from django.views.generic import ListView
from .models import Scanner
def index(request):
return render(request, 'booker/index.html')
class IndexView(ListView):
model = Scanner
template_name = 'booker/index.html'
def scanner(request, scanner_id):
return render(request, 'booker/scanner.html', {
'scanner_id': scanner_id
})
})