From 386bd3c8882ba990821293dfadc4cad15fba3bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Mon, 6 Nov 2023 19:22:23 +0100 Subject: [PATCH] firmware and firmware build details --- .../control/mesh_firmware_build_detail.html | 78 +++++++++++++ .../control/mesh_firmware_detail.html | 103 ++++++++++++++++++ .../templates/control/mesh_firmwares.html | 12 +- .../control/mesh_firmwares_current.html | 8 +- src/c3nav/control/urls.py | 9 +- src/c3nav/control/views/mesh.py | 75 ++++++++++++- src/c3nav/mesh/models.py | 10 +- 7 files changed, 284 insertions(+), 11 deletions(-) create mode 100644 src/c3nav/control/templates/control/mesh_firmware_build_detail.html create mode 100644 src/c3nav/control/templates/control/mesh_firmware_detail.html diff --git a/src/c3nav/control/templates/control/mesh_firmware_build_detail.html b/src/c3nav/control/templates/control/mesh_firmware_build_detail.html new file mode 100644 index 00000000..9102464d --- /dev/null +++ b/src/c3nav/control/templates/control/mesh_firmware_build_detail.html @@ -0,0 +1,78 @@ +{% extends 'control/base.html' %} +{% load i18n mesh_node %} + +{% block heading %}{% trans 'Mesh' %}{% endblock %} + +{% block subcontent %} +

{% trans 'Firmware Build' %}

+ +
+
+

+ Project name: {{ build.version.project_name }}
+ Version: {{ build.version.version }}
+ IDF Version: {{ build.version.idf_version }}
+ Uploader: {{ build.version.uploader }}
+ Created: {{ build.version.created }}
+

+ + Variant: {{ build.variant }}
+ Chip: {{ build.get_chip_display }}
+
+

Compatible boards:

+
    + {% for board in build.boards %} +
  • {{ board.pretty_name }}
  • + {% endfor %} +
+
+
+

Installed nodes

+ + + + + + {% for node in installed_nodes %} + + + + + {% endfor %} +
{% trans 'Node' %}{% trans 'Hardware' %}
+ {% mesh_node node %} + + {{ node.board.pretty_name }} ({{ node.chip.pretty_name }}) +
+ +

Compatible nodes

+ + + + + + + {% for node in compatible_nodes %} + + + + + + {% endfor %} +
{% trans 'Node' %}{% trans 'Hardware' %}{% trans 'Current Firmware' %}
+ {% mesh_node node %} + + {{ node.board.pretty_name }} ({{ node.chip.pretty_name }}) + + {% if node.firmware_desc.build %} + + {{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }} +
+ Build {{ node.firmware_desc.build.variant }} + {% else %} + {{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }} + {% endif %} +
+
+
+{% endblock %} diff --git a/src/c3nav/control/templates/control/mesh_firmware_detail.html b/src/c3nav/control/templates/control/mesh_firmware_detail.html new file mode 100644 index 00000000..4d9ca2c8 --- /dev/null +++ b/src/c3nav/control/templates/control/mesh_firmware_detail.html @@ -0,0 +1,103 @@ +{% extends 'control/base.html' %} +{% load i18n mesh_node %} + +{% block heading %}{% trans 'Mesh' %}{% endblock %} + +{% block subcontent %} +

{% trans 'Firmware' %}

+ +
+
+

+ Project name: {{ firmware.project_name }}
+ Version: {{ firmware.version }}
+ IDF Version: {{ firmware.idf_version }}
+ Uploader: {{ firmware.uploader }}
+ Created: {{ firmware.created }}
+

+ +

Builds

+ + + + + + + {% for build in builds %} + + + + + + {% endfor %} + +
{% trans 'Build' %}{% trans 'Chip' %}{% trans 'Boards' %}
+ + {{ build.variant }} + + {{ build.get_chip_display }} + {% for board in build.boards %} + {{ board.pretty_name }}
+ {% endfor %} +
+
+
+

Installed nodes

+ + + + + + + {% for node in installed_nodes %} + + + + + + {% endfor %} +
{% trans 'Node' %}{% trans 'Hardware' %}{% trans 'Build' %}
+ {% mesh_node node %} + + {{ node.board.pretty_name }} ({{ node.chip.pretty_name }}) + + {{ node.firmware_desc.build.variant }} +
+ +

Compatible nodes

+ + + + + + + + {% for node in compatible_nodes %} + + + + + + + {% endfor %} +
{% trans 'Node' %}{% trans 'Hardware' %}{% trans 'Current Firmware' %}{% trans 'Compatible Builds' %}
+ {% mesh_node node %} + + {{ node.board.pretty_name }} ({{ node.chip.pretty_name }}) + + {% if node.firmware_desc.build %} + + {{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }} +
+ Build {{ node.firmware_desc.build.variant }} + {% else %} + {{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }} + {% endif %} +
+ {% for build in node.compatible_builds %} + {{ build.variant }}
+ {% endfor %} +
+
+
+{% endblock %} diff --git a/src/c3nav/control/templates/control/mesh_firmwares.html b/src/c3nav/control/templates/control/mesh_firmwares.html index 731d6f34..6b31fd95 100644 --- a/src/c3nav/control/templates/control/mesh_firmwares.html +++ b/src/c3nav/control/templates/control/mesh_firmwares.html @@ -1,7 +1,7 @@ {% extends 'control/base.html' %} {% load i18n %} -{% block heading %}{% trans 'Mesh Firmwares' %}{% endblock %} +{% block heading %}{% trans 'Mesh' %}{% endblock %} {% block subcontent %}

Firmwares

@@ -23,11 +23,17 @@ {{ firmware.created }} {{ firmware.uploader }} - {{ firmware.project_name }} {{ firmware.version }} + + + {{ firmware.project_name }} {{ firmware.version }} + + {{ firmware.idf_version }} {% for build in firmware.builds.all %} - {{ build.variant }} ({{ build.get_chip_display }})
+ + {{ build.variant }} ({{ build.get_chip_display }}) +
{% endfor %} diff --git a/src/c3nav/control/templates/control/mesh_firmwares_current.html b/src/c3nav/control/templates/control/mesh_firmwares_current.html index db9be23c..7cff67a7 100644 --- a/src/c3nav/control/templates/control/mesh_firmwares_current.html +++ b/src/c3nav/control/templates/control/mesh_firmwares_current.html @@ -1,7 +1,7 @@ {% extends 'control/base.html' %} {% load i18n mesh_node %} -{% block heading %}{% trans 'Mesh Firmwares' %}{% endblock %} +{% block heading %}{% trans 'Mesh' %}{% endblock %} {% block subcontent %}

Current Firmwares

@@ -22,7 +22,7 @@ {{ firmware.created }} {% if firmware.build %} - {{ firmware.project_name }} {{ firmware.version }} + {{ firmware.project_name }} {{ firmware.version }} {% else %} {{ firmware.project_name }} {{ firmware.version }}
{{ firmware.sha256_hash }} @@ -30,7 +30,9 @@ {% if firmware.build %} - {{ firmware.build.variant }} ({{ firmware.chip.pretty_name }}) + + {{ firmware.build.variant }} ({{ firmware.chip.pretty_name }}) + {% else %} ({{ firmware.chip.pretty_name }}) {% endif %} diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py index 9e82a48c..ad0d0925 100644 --- a/src/c3nav/control/urls.py +++ b/src/c3nav/control/urls.py @@ -4,9 +4,9 @@ from c3nav.control.views.access import grant_access, grant_access_qr from c3nav.control.views.announcements import announcement_detail, announcement_list from c3nav.control.views.base import ControlPanelIndexView from c3nav.control.views.mapupdates import map_updates -from c3nav.control.views.mesh import (MeshFirmwaresCurrentListView, MeshFirmwaresListView, MeshLogView, - MeshMessageListView, MeshMessageSendingView, MeshMessageSendView, - MeshNodeDetailView, MeshNodeEditView, MeshNodeListView) +from c3nav.control.views.mesh import (MeshFirmwareBuildDetailView, MeshFirmwareDetailView, MeshFirmwaresCurrentListView, + MeshFirmwaresListView, MeshLogView, MeshMessageListView, MeshMessageSendingView, + MeshMessageSendView, MeshNodeDetailView, MeshNodeEditView, MeshNodeListView) from c3nav.control.views.users import UserListView, user_detail urlpatterns = [ @@ -22,6 +22,9 @@ urlpatterns = [ path('mesh/messages/', MeshMessageListView.as_view(), name='control.mesh.messages'), path('mesh/firmwares/', MeshFirmwaresListView.as_view(), name='control.mesh.firmwares'), path('mesh/firmwares/current/', MeshFirmwaresCurrentListView.as_view(), name='control.mesh.firmwares.current'), + path('mesh/firmwares//', MeshFirmwareDetailView.as_view(), name='control.mesh.firmwares.detail'), + path('mesh/firmwares/builds//', MeshFirmwareBuildDetailView.as_view(), + name='control.mesh.firmwares.build.detail'), path('mesh//', MeshNodeDetailView.as_view(), name='control.mesh.node.detail'), path('mesh//edit/', MeshNodeEditView.as_view(), name='control.mesh.node.edit'), path('mesh/message/sending//', MeshMessageSendingView.as_view(), name='control.mesh.sending'), diff --git a/src/c3nav/control/views/mesh.py b/src/c3nav/control/views/mesh.py index 44f16605..df940432 100644 --- a/src/c3nav/control/views/mesh.py +++ b/src/c3nav/control/views/mesh.py @@ -14,7 +14,7 @@ from c3nav.control.forms import MeshMessageFilterForm from c3nav.control.views.base import ControlPanelMixin from c3nav.mesh.forms import MeshMessageForm, MeshNodeForm from c3nav.mesh.messages import MeshMessage, MeshMessageType -from c3nav.mesh.models import FirmwareVersion, MeshNode, NodeMessage +from c3nav.mesh.models import FirmwareBuild, FirmwareVersion, MeshNode, NodeMessage from c3nav.mesh.utils import get_node_names, group_msg_type_choices @@ -215,3 +215,76 @@ class MeshFirmwaresCurrentListView(ControlPanelMixin, TemplateView): **super().get_context_data(), "firmwares": firmwares, } + + +class MeshFirmwareDetailView(ControlPanelMixin, DetailView): + model = FirmwareVersion + template_name = "control/mesh_firmware_detail.html" + context_object_name = "firmware" + + def get_queryset(self): + return super().get_queryset().prefetch_related('builds', 'builds__firmwarebuildboard_set') + + def get_context_data(self, **kwargs): + ctx = super().get_context_data() + + nodes = list(MeshNode.objects.all().prefetch_firmwares().prefetch_last_messages( + MeshMessageType.CONFIG_BOARD, + )) + builds = self.get_object().builds.all() + + build_lookups = set(build.get_firmware_description().get_lookup() for build in builds) + + installed_nodes = [] + compatible_nodes = [] + for node in nodes: + if node.firmware_desc.get_lookup() in build_lookups: + installed_nodes.append(node) + else: + node.compatible_builds = [] + for build in builds: + if node.board in build.boards: + node.compatible_builds.append(build) + if node.compatible_builds: + compatible_nodes.append(node) + + ctx.update({ + 'builds': builds, + 'installed_nodes': installed_nodes, + 'compatible_nodes': compatible_nodes, + }) + return ctx + + +class MeshFirmwareBuildDetailView(ControlPanelMixin, DetailView): + model = FirmwareBuild + template_name = "control/mesh_firmware_build_detail.html" + context_object_name = "build" + + def get_queryset(self): + return super().get_queryset().prefetch_related('firmwarebuildboard_set') + + def get_context_data(self, **kwargs): + ctx = super().get_context_data() + + nodes = list(MeshNode.objects.all().prefetch_firmwares().prefetch_last_messages( + MeshMessageType.CONFIG_BOARD, + )) + + build_lookup = self.get_object().get_firmware_description().get_lookup() + build_boards = self.get_object().boards + + installed_nodes = [] + compatible_nodes = [] + for node in nodes: + if node.firmware_desc.get_lookup() == build_lookup: + installed_nodes.append(node) + else: + if node.board in build_boards: + compatible_nodes.append(node) + + ctx.update({ + 'installed_nodes': installed_nodes, + 'compatible_nodes': compatible_nodes, + }) + return ctx diff --git a/src/c3nav/mesh/models.py b/src/c3nav/mesh/models.py index 1ce84bd5..ac731a9b 100644 --- a/src/c3nav/mesh/models.py +++ b/src/c3nav/mesh/models.py @@ -192,6 +192,14 @@ class MeshNode(models.Model): sha256_hash=firmware_msg.app_desc.app_elf_sha256, ) + @cached_property + def chip(self) -> ChipType: + return self.last_messages[MeshMessageType.CONFIG_HARDWARE].parsed.chip + + @cached_property + def board(self) -> ChipType: + return self.last_messages[MeshMessageType.CONFIG_BOARD].parsed.board_config.board + class MeshUplink(models.Model): """ @@ -278,7 +286,7 @@ class FirmwareBuild(models.Model): @property def boards(self): - return [board.board for board in self.firmwarebuildboard_set.all()] + return {BoardType[board.board] for board in self.firmwarebuildboard_set.all()} def serialize(self): return {