more ota status stuff in python and more way to communicate status in c
This commit is contained in:
parent
6eaf087f71
commit
434e1edcc0
6 changed files with 87 additions and 10 deletions
|
@ -18,7 +18,7 @@ from c3nav.mesh import messages
|
|||
from c3nav.mesh.messages import (MESH_BROADCAST_ADDRESS, MESH_NONE_ADDRESS, MESH_ROOT_ADDRESS, OTA_CHUNK_SIZE,
|
||||
MeshMessage, MeshMessageType)
|
||||
from c3nav.mesh.models import MeshNode, MeshUplink, NodeMessage, OTAUpdate, OTAUpdateRecipient, OTARecipientStatus
|
||||
from c3nav.mesh.utils import MESH_ALL_UPLINKS_GROUP, UPLINK_PING, get_mesh_uplink_group
|
||||
from c3nav.mesh.utils import MESH_ALL_UPLINKS_GROUP, UPLINK_PING, get_mesh_uplink_group, MESH_ALL_OTA_GROUP
|
||||
from c3nav.routing.rangelocator import RangeLocator
|
||||
|
||||
|
||||
|
@ -597,9 +597,16 @@ class MeshUIConsumer(AsyncJsonWebsocketConsumer):
|
|||
if content.get("subscribe", None) == "ranging":
|
||||
await self.channel_layer.group_add("mesh_msg_received", self.channel_name)
|
||||
self.msg_received_filter = {"msg_type": MeshMessageType.LOCATE_RANGE_RESULTS.name}
|
||||
await self.dump_newest_messages(MeshMessageType.LOCATE_RANGE_RESULTS)
|
||||
if content.get("subscribe", None) == "ota":
|
||||
await self.channel_layer.group_add("mesh_msg_received", self.channel_name)
|
||||
self.msg_received_filter = {"msg_type": MeshMessageType.OTA_STATUS.name}
|
||||
update_id = content.get("update_id", 0)
|
||||
self.msg_received_filter = {"msg_type": MeshMessageType.OTA_STATUS.name,
|
||||
"update_id": update_id}
|
||||
await self.channel_layer.group_add(MESH_ALL_OTA_GROUP, self.channel_name)
|
||||
await self.dump_newest_messages(MeshMessageType.OTA_STATUS)
|
||||
for recipient in await self._qs_as_list(OTAUpdateRecipient.objects.filter(update_id=update_id)):
|
||||
await self.send_json(recipient.get_status_json())
|
||||
if "send_msg" in content:
|
||||
msg_to_send = self.scope["session"].pop("mesh_msg_%s" % content["send_msg"], None)
|
||||
if not msg_to_send:
|
||||
|
@ -619,6 +626,22 @@ class MeshUIConsumer(AsyncJsonWebsocketConsumer):
|
|||
**msg_to_send["msg_data"],
|
||||
}).send(sender=self.channel_name)
|
||||
|
||||
async def dump_newest_messages(self, msg_type: MeshMessageType, include_ota=False):
|
||||
for msg in await self._get_last_messages(msg_type):
|
||||
await self.mesh_msg_received({
|
||||
"type": "mesh.msg_received",
|
||||
"msg": msg.data
|
||||
})
|
||||
|
||||
@database_sync_to_async
|
||||
def _get_last_messages(self, msg_type):
|
||||
results = (node.last_messages[msg_type] for node in MeshNode.objects.prefetch_last_messages(msg_type))
|
||||
return [msg for msg in results if msg]
|
||||
|
||||
@database_sync_to_async
|
||||
def _qs_as_list(self, qs):
|
||||
return list(qs)
|
||||
|
||||
async def mesh_log_entry(self, data):
|
||||
await self.send_json(data)
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class MeshMessageType(EnumSchemaByNameMixin, IntEnum):
|
|||
OTA_REQUEST_FRAGMENTS = 0x25
|
||||
OTA_SETTING = 0x26
|
||||
OTA_APPLY = 0x27
|
||||
OTA_ABORT = 0x29
|
||||
OTA_ABORT = 0x28
|
||||
|
||||
LOCATE_REQUEST_RANGE = 0x30
|
||||
LOCATE_RANGE_RESULTS = 0x31
|
||||
|
@ -269,6 +269,25 @@ class ConfigUplinkMessage(MeshMessage, msg_type=MeshMessageType.CONFIG_UPLINK):
|
|||
port: int = field(metadata={"format": SimpleFormat('H')})
|
||||
|
||||
|
||||
|
||||
@unique
|
||||
class OTADeviceStatus(EnumSchemaByNameMixin, IntEnum):
|
||||
""" ota status, the ones >= 0x10 denote a permanent failure """
|
||||
NONE = 0x00
|
||||
|
||||
STARTED = 0x01
|
||||
APPLIED = 0x02
|
||||
|
||||
START_FAILED = 0x10
|
||||
WRITE_FAILED = 0x12
|
||||
APPLY_FAILED = 0x13
|
||||
ROLLED_BACK = 0x14
|
||||
|
||||
@property
|
||||
def pretty_name(self):
|
||||
return self.name.replace('_', ' ').lower()
|
||||
|
||||
|
||||
@dataclass
|
||||
class OTAStatusMessage(MeshMessage, msg_type=MeshMessageType.OTA_STATUS):
|
||||
""" report OTA status """
|
||||
|
@ -277,6 +296,7 @@ class OTAStatusMessage(MeshMessage, msg_type=MeshMessageType.OTA_STATUS):
|
|||
highest_chunk: int = field(metadata={"format": SimpleFormat('H')})
|
||||
auto_apply: bool = field(metadata={"format": BoolFormat()})
|
||||
auto_reboot: bool = field(metadata={"format": BoolFormat()})
|
||||
status: OTADeviceStatus = field(metadata={"format": EnumFormat('B')})
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
|
@ -7,6 +7,8 @@ from functools import cached_property
|
|||
from operator import attrgetter
|
||||
from typing import Any, Mapping, Optional, Self
|
||||
|
||||
import channels
|
||||
from asgiref.sync import async_to_sync
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import NotSupportedError, models
|
||||
|
@ -21,7 +23,7 @@ from c3nav.mesh.dataformats import BoardType, ChipType, FirmwareImage
|
|||
from c3nav.mesh.messages import ConfigFirmwareMessage, ConfigHardwareMessage
|
||||
from c3nav.mesh.messages import MeshMessage as MeshMessage
|
||||
from c3nav.mesh.messages import MeshMessageType
|
||||
from c3nav.mesh.utils import UPLINK_TIMEOUT
|
||||
from c3nav.mesh.utils import UPLINK_TIMEOUT, MESH_ALL_OTA_GROUP
|
||||
from c3nav.routing.rangelocator import RangeLocator
|
||||
|
||||
FirmwareLookup = namedtuple('FirmwareLookup', ('sha256_hash', 'chip', 'project_name', 'version', 'idf_version'))
|
||||
|
@ -512,3 +514,18 @@ class OTAUpdateRecipient(models.Model):
|
|||
UniqueConstraint(fields=["node"], condition=Q(status=OTARecipientStatus.RUNNING),
|
||||
name='only_one_active_ota'),
|
||||
)
|
||||
|
||||
async def send_status(self):
|
||||
"""
|
||||
use this for OTA stuffs
|
||||
"""
|
||||
channels.layers.get_channel_layer().group_send(MESH_ALL_OTA_GROUP, self.get_status_json())
|
||||
|
||||
def get_status_json(self):
|
||||
return {
|
||||
"type": "mesh.ota_recipient_status",
|
||||
"node": self.node_id,
|
||||
"update": self.update_id,
|
||||
"status": self.status,
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
{% endif %}
|
||||
{% if nodes_xyz %}
|
||||
const nodes_xyz = JSON.parse(document.getElementById('nodes-xyz').textContent);
|
||||
const nodes_distances = {}
|
||||
const nodes_distances = {};
|
||||
{% endif %}
|
||||
{% if update %}
|
||||
const update_id = {{ update.pk }};
|
||||
{% endif %}
|
||||
|
||||
function connect() {
|
||||
|
@ -26,7 +29,7 @@ function connect() {
|
|||
{% elif ranging_form %}
|
||||
ws.send(JSON.stringify({"subscribe": "ranging"}));
|
||||
{% elif update %}
|
||||
ws.send(JSON.stringify({"subscribe": "ota-{{ update.pk }}"}));
|
||||
ws.send(JSON.stringify({"subscribe": "ota", "update_id": update_id}));
|
||||
{% else %}
|
||||
ws.send(JSON.stringify({"subscribe": "log"}));
|
||||
{% endif %}
|
||||
|
@ -100,6 +103,13 @@ function connect() {
|
|||
{% endif %}
|
||||
break;
|
||||
|
||||
case 'mesh.ota_recipient_status':
|
||||
{% if update %}
|
||||
var row = document.querySelector(`[id="ota-recipient-${data.update}-${data.node}"]`);
|
||||
if (!row) break;
|
||||
row.querySelector('.status').innerText = data.status;
|
||||
{% endif %}
|
||||
|
||||
case 'mesh.msg_received':
|
||||
{% if ranging_form %}
|
||||
var cell, key, src_node, peer_node;
|
||||
|
@ -158,10 +168,12 @@ function connect() {
|
|||
}
|
||||
{% endif %}
|
||||
{% if update %}
|
||||
var row = document.querySelector(`#ota-recipients-${data.msg.update_id} [id="recipient-${data.msg.src}"]`);
|
||||
var row = document.querySelector(`[id="ota-recipient-${data.msg.update_id}-${data.msg.src}"]`);
|
||||
if (!row) break;
|
||||
row.querySelector('.received_bytes').innerText = data.msg.received_bytes;
|
||||
row.querySelector('progress').value = data.msg.received_bytes;
|
||||
row.querySelector('.auto-apply span').innerText = data.msg.auto_apply ? 'yes' : 'no';
|
||||
row.querySelector('.auto-reboot span').innerText = data.msg.auto_reboot ? 'yes' : 'no';
|
||||
{% endif %}
|
||||
{% if send_uuid and msg_type == "MESH_ROUTE_REQUEST" %}
|
||||
if (data.msg.route) {
|
||||
|
|
|
@ -18,16 +18,20 @@
|
|||
<strong>Created:</strong> {{ update.created }}
|
||||
</div>
|
||||
<div>
|
||||
<table id="ota-recipients-{{ update.pk }}">
|
||||
<table>
|
||||
<tr>
|
||||
<th>{% trans 'Node' %}</th>
|
||||
<th>{% trans 'Status' %}</th>
|
||||
<th>{% trans 'Progress' %}</th>
|
||||
</tr>
|
||||
{% for recipient in update.recipients.all %}
|
||||
<tr id="recipient-{{ recipient.node_id }}">
|
||||
<tr id="ota-recipient-{{ update.pk }}-{{ recipient.node_id }}">
|
||||
<td>{% mesh_node recipient.node %}</td>
|
||||
<td>{{ recipient.get_status_display }}</td>
|
||||
<td>
|
||||
<span class="status"></span><br>
|
||||
<span class="auto-apply"><strong>auto apply:</strong> <span></span><br></span>
|
||||
<span class="auto-reboot"><strong>auto reboot:</strong> <span></span><br></span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="received_bytes">??</span> of {{ update.build.binary.size }} bytes
|
||||
<br>
|
||||
|
|
|
@ -6,6 +6,7 @@ def get_mesh_uplink_group(address):
|
|||
|
||||
|
||||
MESH_ALL_UPLINKS_GROUP = "mesh_uplink_all"
|
||||
MESH_ALL_OTA_GROUP = "mesh_ota_all"
|
||||
UPLINK_PING = 5
|
||||
UPLINK_TIMEOUT = UPLINK_PING+5
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue