firmware and firmware build details

This commit is contained in:
Laura Klünder 2023-11-06 19:22:23 +01:00
parent c872b97fa3
commit 386bd3c888
7 changed files with 284 additions and 11 deletions

View file

@ -0,0 +1,78 @@
{% extends 'control/base.html' %}
{% load i18n mesh_node %}
{% block heading %}{% trans 'Mesh' %}{% endblock %}
{% block subcontent %}
<h4>{% trans 'Firmware Build' %}</h4>
<div class="columns">
<div>
<p>
<strong>Project name:</strong> {{ build.version.project_name }}<br>
<strong>Version:</strong> {{ build.version.version }}<br>
<strong>IDF Version:</strong> {{ build.version.idf_version }}<br>
<strong>Uploader:</strong> {{ build.version.uploader }}<br>
<strong>Created:</strong> {{ build.version.created }}<br>
</p>
<o>
<strong>Variant:</strong> {{ build.variant }}<br>
<strong>Chip:</strong> {{ build.get_chip_display }}<br>
</o>
<h4>Compatible boards:</h4>
<ul>
{% for board in build.boards %}
<li>{{ board.pretty_name }}</li>
{% endfor %}
</ul>
</div>
<div>
<h4>Installed nodes</h4>
<table>
<tr>
<th>{% trans 'Node' %}</th>
<th>{% trans 'Hardware' %}</th>
</tr>
{% for node in installed_nodes %}
<tr>
<td>
{% mesh_node node %}
</td>
<td>
{{ node.board.pretty_name }} ({{ node.chip.pretty_name }})
</td>
</tr>
{% endfor %}
</table>
<h4>Compatible nodes</h4>
<table>
<tr>
<th>{% trans 'Node' %}</th>
<th>{% trans 'Hardware' %}</th>
<th>{% trans 'Current Firmware' %}</th>
</tr>
{% for node in compatible_nodes %}
<tr>
<td>
{% mesh_node node %}
</td>
<td>
{{ node.board.pretty_name }} <small>({{ node.chip.pretty_name }})</small>
</td>
<td>
{% if node.firmware_desc.build %}
<a href="{% url "control.mesh.firmwares.detail" pk=node.firmware_desc.build.version.pk %}">
{{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }}
</a><br>
Build <a href="{% url "control.mesh.firmwares.build.detail" pk=node.firmware_desc.build.pk %}">{{ node.firmware_desc.build.variant }}</a>
{% else %}
{{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,103 @@
{% extends 'control/base.html' %}
{% load i18n mesh_node %}
{% block heading %}{% trans 'Mesh' %}{% endblock %}
{% block subcontent %}
<h4>{% trans 'Firmware' %}</h4>
<div class="columns">
<div>
<p>
<strong>Project name:</strong> {{ firmware.project_name }}<br>
<strong>Version:</strong> {{ firmware.version }}<br>
<strong>IDF Version:</strong> {{ firmware.idf_version }}<br>
<strong>Uploader:</strong> {{ firmware.uploader }}<br>
<strong>Created:</strong> {{ firmware.created }}<br>
</p>
<h4>Builds</h4>
<table>
<tr>
<th>{% trans 'Build' %}</th>
<th>{% trans 'Chip' %}</th>
<th>{% trans 'Boards' %}</th>
</tr>
{% for build in builds %}
<tr>
<td>
<a href="{% url "control.mesh.firmwares.build.detail" pk=build.pk %}">
{{ build.variant }}
</a>
</td>
<td>{{ build.get_chip_display }}</td>
<td>
{% for board in build.boards %}
{{ board.pretty_name }}<br>
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
</div>
<div>
<h4>Installed nodes</h4>
<table>
<tr>
<th>{% trans 'Node' %}</th>
<th>{% trans 'Hardware' %}</th>
<th>{% trans 'Build' %}</th>
</tr>
{% for node in installed_nodes %}
<tr>
<td>
{% mesh_node node %}
</td>
<td>
{{ node.board.pretty_name }} ({{ node.chip.pretty_name }})
</td>
<td>
{{ node.firmware_desc.build.variant }}
</td>
</tr>
{% endfor %}
</table>
<h4>Compatible nodes</h4>
<table>
<tr>
<th>{% trans 'Node' %}</th>
<th>{% trans 'Hardware' %}</th>
<th>{% trans 'Current Firmware' %}</th>
<th>{% trans 'Compatible Builds' %}</th>
</tr>
{% for node in compatible_nodes %}
<tr>
<td>
{% mesh_node node %}
</td>
<td>
{{ node.board.pretty_name }} <small>({{ node.chip.pretty_name }})</small>
</td>
<td>
{% if node.firmware_desc.build %}
<a href="{% url "control.mesh.firmwares.detail" pk=node.firmware_desc.build.version.pk %}">
{{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }}
</a><br>
Build <a href="{% url "control.mesh.firmwares.build.detail" pk=node.firmware_desc.build.pk %}">{{ node.firmware_desc.build.variant }}</a>
{% else %}
{{ node.firmware_desc.project_name }} {{ node.firmware_desc.version }}
{% endif %}
</td>
<td>
{% for build in node.compatible_builds %}
{{ build.variant }}<br>
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}

View file

@ -1,7 +1,7 @@
{% extends 'control/base.html' %}
{% load i18n %}
{% block heading %}{% trans 'Mesh Firmwares' %}{% endblock %}
{% block heading %}{% trans 'Mesh' %}{% endblock %}
{% block subcontent %}
<h4>Firmwares</h4>
@ -23,11 +23,17 @@
<tr>
<td>{{ firmware.created }}</td>
<td>{{ firmware.uploader }}</td>
<td>{{ firmware.project_name }} {{ firmware.version }}</td>
<td>
<a href="{% url "control.mesh.firmwares.detail" pk=firmware.pk %}">
{{ firmware.project_name }} {{ firmware.version }}
</a>
</td>
<td>{{ firmware.idf_version }}</td>
<td>
{% for build in firmware.builds.all %}
{{ build.variant }} ({{ build.get_chip_display }})<br>
<a href="{% url "control.mesh.firmwares.build.detail" pk=build.pk %}">
{{ build.variant }} ({{ build.get_chip_display }})
</a><br>
{% endfor %}
</td>
</tr>

View file

@ -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 %}
<h4>Current Firmwares</h4>
@ -22,7 +22,7 @@
<td>{{ firmware.created }}</td>
<td>
{% if firmware.build %}
<a href="#">{{ firmware.project_name }} {{ firmware.version }}</a>
<a href="{% url "control.mesh.firmwares.detail" pk=firmware.pk %}">{{ firmware.project_name }} {{ firmware.version }}</a>
{% else %}
{{ firmware.project_name }} {{ firmware.version }}<br>
<small>{{ firmware.sha256_hash }}</small>
@ -30,7 +30,9 @@
</td>
<td>
{% if firmware.build %}
<a href="#">{{ firmware.build.variant }} ({{ firmware.chip.pretty_name }})</a>
<a href="{% url "control.mesh.firmwares.build.detail" pk=firmware.build.pk %}">
{{ firmware.build.variant }} ({{ firmware.chip.pretty_name }})
</a>
{% else %}
({{ firmware.chip.pretty_name }})
{% endif %}

View file

@ -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/<int:pk>/', MeshFirmwareDetailView.as_view(), name='control.mesh.firmwares.detail'),
path('mesh/firmwares/builds/<int:pk>/', MeshFirmwareBuildDetailView.as_view(),
name='control.mesh.firmwares.build.detail'),
path('mesh/<str:pk>/', MeshNodeDetailView.as_view(), name='control.mesh.node.detail'),
path('mesh/<str:pk>/edit/', MeshNodeEditView.as_view(), name='control.mesh.node.edit'),
path('mesh/message/sending/<uuid:uuid>/', MeshMessageSendingView.as_view(), name='control.mesh.sending'),

View file

@ -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

View file

@ -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 {