mesh debugging and control

This commit is contained in:
Laura Klünder 2023-10-02 22:02:25 +02:00
parent 4c40597cd3
commit df6efbc8d5
11 changed files with 201 additions and 12 deletions

View file

@ -4,7 +4,7 @@ from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from c3nav.mesh import messages
from c3nav.mesh.models import MeshNode, NodeMessage
from c3nav.mesh.models import MeshNode, NodeMessage, Firmware
class MeshConsumer(AsyncWebsocketConsumer):
@ -69,6 +69,16 @@ class MeshConsumer(AsyncWebsocketConsumer):
await self.log_received_message(msg)
if isinstance(msg, messages.ConfigFirmwareMessage):
await self._handle_config_firmware_msg(msg)
return
@database_sync_to_async
def _handle_config_firmware_msg(self, msg):
self.firmware, created = Firmware.objects.get_or_create(**msg.to_model_data())
self.node.firmware = self.firmware
self.node.save()
@database_sync_to_async
def get_node(self, address):
return MeshNode.objects.get_or_create(address=address)
@ -100,3 +110,8 @@ class MeshConsumer(AsyncWebsocketConsumer):
@database_sync_to_async
def remove_route_to_nodes(self, route_address, node_addresses):
MeshNode.objects.filter(address__in=node_addresses, route_id=route_address).update(route_id=None)
@database_sync_to_async
def set_node_firmware(self, firmware):
self.node.firmware = firmware
self.node.save()

View file

@ -112,6 +112,8 @@ class ConfigDumpMessage(Message, msg_id=MessageType.CONFIG_DUMP):
@dataclass
class ConfigFirmwareMessage(Message, msg_id=MessageType.CONFIG_FIRMWARE):
chip: int = field(metadata={'format': SimpleFormat('H')})
revision: int = field(metadata={'format': SimpleFormat('2B')})
magic_word: int = field(metadata={'format': SimpleFormat('I')}, repr=False)
secure_version: int = field(metadata={'format': SimpleFormat('I')})
reserv1: list[int] = field(metadata={'format': SimpleFormat('2I')}, repr=False)
@ -123,6 +125,15 @@ class ConfigFirmwareMessage(Message, msg_id=MessageType.CONFIG_FIRMWARE):
app_elf_sha256: str = field(metadata={'format': HexFormat(32)})
reserv2: list[int] = field(metadata={'format': SimpleFormat('20I')}, repr=False)
def to_model_data(self):
return {
'chip': self.chip,
'project_name': self.project_name,
'version': self.version,
'idf_version': self.idf_version,
'sha256_hash': self.app_elf_sha256,
}
@dataclass
class ConfigPositionMessage(Message, msg_id=MessageType.CONFIG_POSITION):

View file

@ -0,0 +1,27 @@
# Generated by Django 4.2.1 on 2023-10-02 19:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mesh', '0001_initial'),
]
operations = [
migrations.AlterUniqueTogether(
name='firmware',
unique_together={('chip', 'project_name', 'version', 'idf_version', 'sha256_hash')},
),
migrations.AddField(
model_name='meshnode',
name='firmware',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='installed_on', to='mesh.firmware', verbose_name='firmware'),
),
migrations.RemoveField(
model_name='firmware',
name='compile_time',
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.1 on 2023-10-02 19:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mesh', '0002_alter_firmware_unique_together_meshnode_firmware_and_more'),
]
operations = [
migrations.AddField(
model_name='meshnode',
name='name',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='name'),
),
]

View file

@ -11,13 +11,18 @@ class ChipID(models.IntegerChoices):
class MeshNode(models.Model):
address = models.CharField(_('mac address'), max_length=17, primary_key=True)
name = models.CharField(_('name'), max_length=32, null=True, blank=True)
first_seen = models.DateTimeField(_('first seen'), auto_now_add=True)
parent_node = models.ForeignKey('MeshNode', models.PROTECT, null=True,
related_name='child_nodes', verbose_name=_('parent node'))
route = models.ForeignKey('MeshNode', models.PROTECT, null=True,
related_name='routed_nodes', verbose_name=_('route'))
firmware = models.ForeignKey('Firmware', models.PROTECT, null=True,
related_name='installed_on', verbose_name=_('firmware'))
def __str__(self):
if self.name:
return '%s (%s)' % (self.address, self.name)
return self.address
@ -38,11 +43,10 @@ class Firmware(models.Model):
project_name = models.CharField(_('project name'), max_length=32)
version = models.CharField(_('firmware version'), max_length=32)
idf_version = models.CharField(_('IDF version'), max_length=32)
compile_time = models.DateTimeField(_('compile time'))
sha256_hash = models.CharField(_('SHA256 hash'), unique=True, max_length=64)
binary = models.FileField(_('firmware file'), null=True)
class Meta:
unique_together = [
('chip', 'project_name', 'version', 'idf_version', 'compile_time', 'sha256_hash'),
('chip', 'project_name', 'version', 'idf_version', 'sha256_hash'),
]