add possibility to set LED_CONFIG message

This commit is contained in:
Laura Klünder 2023-10-04 17:03:53 +02:00
parent c5ac3ceb76
commit e0961c16c1
5 changed files with 137 additions and 36 deletions

View file

@ -17,19 +17,41 @@
</div>
<div>
<h4>Uplink</h4>
<p>
<strong>Enabled:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.enabled }},
<strong>SSID:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.ssid }},
<strong>Channel:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.channel }}<br>
<strong>Host:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.host }},
<strong>Port:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.port }},
<strong>UDP:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.udp }},
<strong>SSL:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.ssl }}
<strong>SSL:</strong> {{ node.last_messages.CONFIG_UPLINK.parsed.ssl }}<br>
</p>
<p>
<a class="button" href="{% url "control.mesh_message.send" recipient=node.address msg_type="CONFIG_UPLINK" %}">
{% trans 'Change' %}
</a>
</p>
<h4>Position</h4>
<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 }}
</p>
<p>
<a class="button" href="{% url "control.mesh_message.send" recipient=node.address msg_type="CONFIG_POSITION" %}">
{% trans 'Change' %}
</a>
</p>
<h4>LED config</h4>
<p>
{{ node.last_messages.CONFIG_LED.parsed.led_config }}
</p>
<p>
<a class="button" href="{% url "control.mesh_message.send" recipient=node.address msg_type="CONFIG_LED" %}">
{% trans 'Change' %}
</a>
</p>
</div>
</div>
{% endblock %}

View file

@ -109,7 +109,7 @@ class MeshConsumer(WebsocketConsumer):
def add_dst_nodes(self, addresses):
for address in addresses:
# create group name for this address
group = self.comm_address_group(address)
group = get_mesh_comm_group(address)
# if we aren't handling this address yet, join the group
if address not in self.dst_nodes:
@ -140,7 +140,7 @@ class MeshConsumer(WebsocketConsumer):
def remove_dst_nodes(self, addresses):
for address in tuple(addresses):
# create group name for this address
group = self.comm_address_group(address)
group = get_mesh_comm_group(address)
# leave the group
if address in self.dst_nodes:

View file

@ -138,14 +138,3 @@ class LedConfigFormat:
else:
raise ValueError
return value, data[4:]
def from_json(self, value):
if value is None:
return None
type_ = value.pop('type')
if type_ == 'serial':
return SerialLedConfig(**value)
elif type_ == 'multipin':
return MultipinLedConfig(**value)
raise ValueError

View file

@ -1,7 +1,11 @@
from dataclasses import fields as dataclass_fields
from django import forms
from django.core.exceptions import ValidationError
from django.http import Http404
from django.utils.translation import gettext_lazy as _
from c3nav.mesh.dataformats import LedConfig
from c3nav.mesh.messages import MeshMessageType, MeshMessage, ROOT_ADDRESS
from c3nav.mesh.models import MeshNode
@ -54,6 +58,29 @@ class MeshMessageForm(forms.Form):
def get_recipient_display(self):
return self.recipient_choices[self.recipient]
def get_cleaned_msg_data(self):
msg_data = self.cleaned_data.copy()
msg_data.pop('recipients', None)
return msg_data
def send(self):
if not self.is_valid():
raise Exception('nope')
msg_data = {
'msg_id': self.msg_type,
'src': ROOT_ADDRESS,
**self.get_cleaned_msg_data(),
}
recipients = [self.recipient] if self.recipient else self.cleaned_data['recipients']
for recipient in recipients:
print('sending to ', recipient)
MeshMessage.fromjson({
'dst': recipient,
**msg_data,
}).send()
class ConfigUplinkMessageForm(MeshMessageForm):
msg_type = MeshMessageType.CONFIG_UPLINK
@ -67,20 +94,76 @@ class ConfigUplinkMessageForm(MeshMessageForm):
host = forms.CharField(required=False, label=_('host'), max_length=63)
port = forms.IntegerField(min_value=1, max_value=65535, label=_('port'))
def send(self):
if not self.is_valid():
raise Exception('nope')
msg_data = {
'msg_id': self.msg_type,
'src': ROOT_ADDRESS,
**self.cleaned_data,
class ConfigLedMessageForm(MeshMessageForm):
msg_type = MeshMessageType.CONFIG_LED
led_type = forms.ChoiceField(choices=(
('', _('no LED')),
(1, _('serial LED')),
(2, _('multipin LED'))
))
gpio = forms.IntegerField(min_value=0, max_value=48, required=False,
label=_('gpio pin'), help_text=_('serial only'))
rmt = forms.IntegerField(min_value=0, max_value=7, required=False,
label=_('rmt'), help_text=_('serial only'))
gpio_r = forms.IntegerField(min_value=0, max_value=48, required=False,
label=_('gpio red'), help_text=_('multipin only'))
gpio_g = forms.IntegerField(min_value=0, max_value=48, required=False,
label=_('gpio green'), help_text=_('multipin only'))
gpio_b = forms.IntegerField(min_value=0, max_value=48, required=False,
label=_('gpio blue'), help_text=_('multipin only'))
def clean(self):
cleaned_data = super().clean()
led_type = int(cleaned_data["led_type"])
if led_type:
required_fields = set(field.name for field in dataclass_fields(LedConfig.ledconfig_types[led_type]))
else:
required_fields = set()
errors = {}
led_config = {
"led_type": led_type
}
recipients = [self.recipient] if self.recipient else self.cleaned_data['recipients']
for recipient in recipients:
print('sending to ', recipient)
MeshMessage.fromjson({
'dst': recipient,
**msg_data,
}).send()
for key, value in cleaned_data.items():
if key == "recipients":
continue
if value and key not in required_fields:
errors[key] = _("this field is not allowed for this LED type")
for key in required_fields:
value = cleaned_data.pop(key, "")
if value == "":
errors[key] = _("this field is required for this LED type")
led_config[key] = value
cleaned_data["led_config"] = led_config
if errors:
raise ValidationError(errors)
return cleaned_data
def get_cleaned_msg_data(self):
msg_data = super().get_cleaned_msg_data().copy()
msg_data = {
"led_config": msg_data["led_config"],
}
return msg_data
def __init__(self, *args, initial=None, **kwargs):
if initial:
initial.update(initial.pop('led_config'))
super().__init__(*args, initial=initial, **kwargs)
class ConfigPositionMessageForm(MeshMessageForm):
msg_type = MeshMessageType.CONFIG_POSITION
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'))
z_pos = forms.IntegerField(min_value=0, max_value=2 ** 16 - 1, label=_('Z'))

View file

@ -1351,3 +1351,10 @@ button + button {
.material-icons {
text-transform: none !important;
}
.helptext {
display: block;
margin-top: -1.5rem;
font-style: italic;
margin-bottom: 1.5rem;
}