add more mesh control panels and navigation

This commit is contained in:
Laura Klünder 2023-10-04 23:05:36 +02:00
parent 6c747803b7
commit 7e759fefd5
6 changed files with 80 additions and 19 deletions

View file

@ -0,0 +1,15 @@
{% extends 'control/base.html' %}
{% load i18n %}
{% block heading %}
{{ title }}
{% endblock %}
{% block subcontent %}
<form method="POST" style="max-width:400px;">
{% csrf_token %}
{{ form }}
<button type="submit">{% trans 'Save' %}</button>
</form>
{% endblock %}

View file

@ -6,14 +6,30 @@
{% block subcontent %} {% block subcontent %}
<div class="columns"> <div class="columns">
<div> <div>
<h4>General</h4>
<p>
<strong>Address:</strong> {{ node.address }}<br>
<strong>Name:</strong> {% if node.name %}{{ node.name }}{% else %}<em>{% trans '(no name)' %}</em>{% endif %}
</p>
<p>
<a class="button" href="{% url "control.mesh_node.edit" pk=node.pk %}">
{% trans 'Edit' %}
</a>
<a class="button" href="{% url "control.mesh_messages" %}?src_nodes={{ node.address }}">
{% trans 'View messages' %}
</a>
</p>
<h4>Firmware</h4> <h4>Firmware</h4>
<strong>Chip:</strong> {{ node.last_messages.CONFIG_FIRMWARE.parsed.get_chip_display }} rev{{ node.last_messages.CONFIG_FIRMWARE.parsed.revision|join:"." }} <p>
<br> <strong>Chip:</strong> {{ node.last_messages.CONFIG_FIRMWARE.parsed.get_chip_display }} rev{{ node.last_messages.CONFIG_FIRMWARE.parsed.revision|join:"." }}
<strong>Firmware:</strong> {{ node.last_messages.CONFIG_FIRMWARE.parsed.project_name }} {{ node.last_messages.CONFIG_FIRMWARE.parsed.version }} (IDF {{ node.last_messages.CONFIG_FIRMWARE.parsed.idf_version }}) <br>
<br> <strong>Firmware:</strong> {{ node.last_messages.CONFIG_FIRMWARE.parsed.project_name }} {{ node.last_messages.CONFIG_FIRMWARE.parsed.version }} (IDF {{ node.last_messages.CONFIG_FIRMWARE.parsed.idf_version }})
<strong>Compile Date:</strong> {{ node.last_messages.CONFIG_FIRMWARE.parsed.compile_date }} {{ node.last_messages.CONFIG_FIRMWARE.parsed.compile_time }} <br>
<br> <strong>Compile Date:</strong> {{ node.last_messages.CONFIG_FIRMWARE.parsed.compile_date }} {{ node.last_messages.CONFIG_FIRMWARE.parsed.compile_time }}
<strong>SHA256:</strong> <small>{{ node.last_messages.CONFIG_FIRMWARE.parsed.app_elf_sha256 }}</small> <br>
<strong>SHA256:</strong> <small>{{ node.last_messages.CONFIG_FIRMWARE.parsed.app_elf_sha256 }}</small>
</p>
</div> </div>
<div> <div>
<h4>Uplink</h4> <h4>Uplink</h4>
@ -32,7 +48,6 @@
</a> </a>
</p> </p>
<h4>Position</h4> <h4>Position</h4>
<p> <p>
<strong>X=</strong>{{ node.last_messages.CONFIG_POSITION.parsed.x_pos }}, <strong>Y=</strong>{{ node.last_messages.CONFIG_POSITION.parsed.y_pos }}, <strong>Z=</strong>{{ node.last_messages.CONFIG_POSITION.parsed.z_pos }} <strong>X=</strong>{{ node.last_messages.CONFIG_POSITION.parsed.x_pos }}, <strong>Y=</strong>{{ node.last_messages.CONFIG_POSITION.parsed.y_pos }}, <strong>Z=</strong>{{ node.last_messages.CONFIG_POSITION.parsed.z_pos }}

View file

@ -1,6 +1,7 @@
from django.urls import path from django.urls import path
from c3nav.control.views.mesh import MeshNodeListView, MeshMessageListView, MeshNodeDetailView, MeshMessageSendView from c3nav.control.views.mesh import MeshNodeListView, MeshMessageListView, MeshNodeDetailView, MeshMessageSendView, \
MeshNodeEditView
from c3nav.control.views.mapupdates import map_updates from c3nav.control.views.mapupdates import map_updates
from c3nav.control.views.announcements import announcement_list, announcement_detail from c3nav.control.views.announcements import announcement_list, announcement_detail
from c3nav.control.views.access import grant_access, grant_access_qr from c3nav.control.views.access import grant_access, grant_access_qr
@ -18,6 +19,7 @@ urlpatterns = [
path('mesh/', MeshNodeListView.as_view(), name='control.mesh_nodes'), path('mesh/', MeshNodeListView.as_view(), name='control.mesh_nodes'),
path('mesh/messages/', MeshMessageListView.as_view(), name='control.mesh_messages'), path('mesh/messages/', MeshMessageListView.as_view(), name='control.mesh_messages'),
path('mesh/<str:pk>/', MeshNodeDetailView.as_view(), name='control.mesh_node.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/<str:recipient>/message/<str:msg_type>/', MeshMessageSendView.as_view(), name='control.mesh_message.send'), path('mesh/<str:recipient>/message/<str:msg_type>/', MeshMessageSendView.as_view(), name='control.mesh_message.send'),
path('', ControlPanelIndexView.as_view(), name='control.index'), path('', ControlPanelIndexView.as_view(), name='control.index'),
] ]

View file

@ -1,13 +1,14 @@
from django.contrib import messages from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.db.models import Max from django.db.models import Max
from django.http import Http404 from django.http import Http404
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import ListView, DetailView, FormView from django.views.generic import ListView, DetailView, FormView, UpdateView
from c3nav.control.forms import MeshMessageFilterForm from c3nav.control.forms import MeshMessageFilterForm
from c3nav.control.views.base import ControlPanelMixin from c3nav.control.views.base import ControlPanelMixin
from c3nav.mesh.forms import MeshMessageForm from c3nav.mesh.forms import MeshMessageForm, MeshNodeForm
from c3nav.mesh.messages import MeshMessageType from c3nav.mesh.messages import MeshMessageType
from c3nav.mesh.models import MeshNode, NodeMessage from c3nav.mesh.models import MeshNode, NodeMessage
@ -32,6 +33,22 @@ class MeshNodeDetailView(ControlPanelMixin, DetailView):
return super().get_queryset().annotate(last_msg=Max('received_messages__datetime')).prefetch_last_messages() return super().get_queryset().annotate(last_msg=Max('received_messages__datetime')).prefetch_last_messages()
class MeshNodeEditView(ControlPanelMixin, SuccessMessageMixin, UpdateView):
model = MeshNode
form_class = MeshNodeForm
template_name = "control/form.html"
success_message = _('Name updated successfully')
def get_context_data(self, **kwargs):
return {
**super().get_context_data(),
'title': _('Editing mesh node: %s') % self.get_object(),
}
def get_success_url(self):
return reverse('control.mesh_node.detail', kwargs={'pk': self.get_object().pk})
class MeshMessageListView(ControlPanelMixin, ListView): class MeshMessageListView(ControlPanelMixin, ListView):
model = NodeMessage model = NodeMessage
template_name = "control/mesh_messages.html" template_name = "control/mesh_messages.html"

View file

@ -166,3 +166,9 @@ class ConfigPositionMessageForm(MeshMessageForm):
x_pos = forms.IntegerField(min_value=0, max_value=2**16-1, label=_('X')) x_pos = forms.IntegerField(min_value=0, max_value=2**16-1, label=_('X'))
y_pos = forms.IntegerField(min_value=0, max_value=2 ** 16 - 1, label=_('Y')) y_pos = forms.IntegerField(min_value=0, max_value=2 ** 16 - 1, label=_('Y'))
z_pos = forms.IntegerField(min_value=0, max_value=2 ** 16 - 1, label=_('Z')) z_pos = forms.IntegerField(min_value=0, max_value=2 ** 16 - 1, label=_('Z'))
class MeshNodeForm(forms.ModelForm):
class Meta:
model = MeshNode
fields = ["name"]

View file

@ -90,11 +90,17 @@ class MeshMessage:
def fromjson(cls, data) -> M: def fromjson(cls, data) -> M:
kwargs = data.copy() kwargs = data.copy()
klass = cls.msg_types[kwargs.pop('msg_id')] klass = cls.msg_types[kwargs.pop('msg_id')]
kwargs = klass.upgrade_json(kwargs)
names = set(field.name for field in fields(klass))
for field_ in fields(klass): for field_ in fields(klass):
if is_dataclass(field_.type): if is_dataclass(field_.type):
kwargs[field_.name] = field_.type.fromjson(kwargs[field_.name]) kwargs[field_.name] = field_.type.fromjson(kwargs[field_.name])
return klass(**kwargs) return klass(**kwargs)
@classmethod
def upgrade_json(cls, data):
return data
def send(self): def send(self):
async_to_sync(channels.layers.get_channel_layer().group_send)(get_mesh_comm_group(self.dst), { async_to_sync(channels.layers.get_channel_layer().group_send)(get_mesh_comm_group(self.dst), {
"type": "mesh.send", "type": "mesh.send",
@ -256,14 +262,14 @@ class ConfigFirmwareMessage(MeshMessage, msg_id=MeshMessageType.CONFIG_FIRMWARE)
app_elf_sha256: str = field(metadata={"format": HexFormat(32)}) app_elf_sha256: str = field(metadata={"format": HexFormat(32)})
reserv2: list[int] = field(metadata={"format": SimpleFormat('20I')}, repr=False) reserv2: list[int] = field(metadata={"format": SimpleFormat('20I')}, repr=False)
def to_model_data(self): @classmethod
return { def upgrade_json(cls, data):
'chip': self.chip, data = data.copy() # todo: deepcopy?
'project_name': self.project_name, print(data)
'version': self.version, if 'revision' in data:
'idf_version': self.idf_version, data['revision_major'], data['revision_minor'] = data.pop('revision')
'sha256_hash': self.app_elf_sha256, print(data)
} return data
def get_chip_display(self): def get_chip_display(self):
return ChipType(self.chip).name.replace('_', '-') return ChipType(self.chip).name.replace('_', '-')