mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Store channel frequency & width as independent values
This commit is contained in:
@ -651,10 +651,10 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
|
||||
model = Interface
|
||||
fields = [
|
||||
'id', 'url', 'display', 'device', 'name', 'label', 'type', 'enabled', 'parent', 'lag', 'mtu', 'mac_address',
|
||||
'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_width', 'untagged_vlan',
|
||||
'tagged_vlans', 'mark_connected', 'cable', 'link_peer', 'link_peer_type', 'connected_endpoint',
|
||||
'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields', 'created',
|
||||
'last_updated', 'count_ipaddresses', '_occupied',
|
||||
'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
||||
'rf_channel_width', 'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'link_peer',
|
||||
'link_peer_type', 'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags',
|
||||
'custom_fields', 'created', 'last_updated', 'count_ipaddresses', '_occupied',
|
||||
]
|
||||
|
||||
def validate(self, data):
|
||||
|
@ -936,7 +936,7 @@ class PowerOutletBulkEditForm(
|
||||
class InterfaceBulkEditForm(
|
||||
form_from_model(Interface, [
|
||||
'label', 'type', 'parent', 'lag', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description',
|
||||
'mode', 'rf_role', 'rf_channel', 'rf_channel_width',
|
||||
'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width',
|
||||
]),
|
||||
BootstrapMixin,
|
||||
AddRemoveTagsForm,
|
||||
@ -988,7 +988,7 @@ class InterfaceBulkEditForm(
|
||||
class Meta:
|
||||
nullable_fields = [
|
||||
'label', 'parent', 'lag', 'mac_address', 'wwn', 'mtu', 'description', 'mode', 'rf_channel',
|
||||
'rf_channel_width', 'untagged_vlan', 'tagged_vlans',
|
||||
'rf_channel_frequency', 'rf_channel_width', 'untagged_vlan', 'tagged_vlans',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -595,7 +595,8 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
|
||||
model = Interface
|
||||
fields = (
|
||||
'device', 'name', 'label', 'parent', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address', 'wwn',
|
||||
'mtu', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_width',
|
||||
'mtu', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
||||
'rf_channel_width',
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -1014,9 +1014,13 @@ class InterfaceFilterForm(DeviceComponentFilterForm):
|
||||
widget=StaticSelectMultiple(),
|
||||
label='Wireless channel'
|
||||
)
|
||||
rf_channel_frequency = forms.IntegerField(
|
||||
required=False,
|
||||
label='Channel frequency (MHz)'
|
||||
)
|
||||
rf_channel_width = forms.IntegerField(
|
||||
required=False,
|
||||
label='Channel width (kHz)'
|
||||
label='Channel width (MHz)'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
@ -1108,8 +1108,8 @@ class InterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm):
|
||||
model = Interface
|
||||
fields = [
|
||||
'device', 'name', 'label', 'type', 'enabled', 'parent', 'lag', 'mac_address', 'wwn', 'mtu', 'mgmt_only',
|
||||
'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_width', 'wireless_lans',
|
||||
'untagged_vlan', 'tagged_vlans', 'tags',
|
||||
'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
||||
'rf_channel_width', 'wireless_lans', 'untagged_vlan', 'tagged_vlans', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'device': forms.HiddenInput(),
|
||||
@ -1123,6 +1123,8 @@ class InterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm):
|
||||
}
|
||||
help_texts = {
|
||||
'mode': INTERFACE_MODE_HELP_TEXT,
|
||||
'rf_channel_frequency': "Populated by selected channel (if set)",
|
||||
'rf_channel_width': "Populated by selected channel (if set)",
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -480,9 +480,13 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
||||
widget=StaticSelect(),
|
||||
label='Wireless channel'
|
||||
)
|
||||
rf_channel_width = forms.IntegerField(
|
||||
rf_channel_frequency = forms.DecimalField(
|
||||
required=False,
|
||||
label='Channel width'
|
||||
label='Channel frequency (MHz)'
|
||||
)
|
||||
rf_channel_width = forms.DecimalField(
|
||||
required=False,
|
||||
label='Channel width (MHz)'
|
||||
)
|
||||
untagged_vlan = DynamicModelChoiceField(
|
||||
queryset=VLAN.objects.all(),
|
||||
@ -494,8 +498,8 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
||||
)
|
||||
field_order = (
|
||||
'device', 'name_pattern', 'label_pattern', 'type', 'enabled', 'parent', 'lag', 'mtu', 'mac_address',
|
||||
'description', 'mgmt_only', 'mark_connected', 'rf_role', 'rf_channel', 'rf_channel_width', 'mode',
|
||||
'untagged_vlan', 'tagged_vlans', 'tags'
|
||||
'description', 'mgmt_only', 'mark_connected', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
||||
'rf_channel_width', 'mode', 'untagged_vlan', 'tagged_vlans', 'tags'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -20,10 +20,15 @@ class Migration(migrations.Migration):
|
||||
name='rf_channel',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='rf_channel_frequency',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='rf_channel_width',
|
||||
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||
field=models.DecimalField(blank=True, decimal_places=3, max_digits=7, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
|
@ -19,6 +19,7 @@ from utilities.ordering import naturalize_interface
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from utilities.query_functions import CollateAsChar
|
||||
from wireless.choices import *
|
||||
from wireless.utils import get_channel_attr
|
||||
|
||||
|
||||
__all__ = (
|
||||
@ -537,10 +538,19 @@ class Interface(ComponentModel, BaseInterface, LinkTermination, PathEndpoint):
|
||||
blank=True,
|
||||
verbose_name='Wireless channel'
|
||||
)
|
||||
rf_channel_width = models.PositiveSmallIntegerField(
|
||||
rf_channel_frequency = models.DecimalField(
|
||||
max_digits=7,
|
||||
decimal_places=2,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Channel width (kHz)'
|
||||
verbose_name='Channel frequency (MHz)'
|
||||
)
|
||||
rf_channel_width = models.DecimalField(
|
||||
max_digits=7,
|
||||
decimal_places=3,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Channel width (MHz)'
|
||||
)
|
||||
wireless_link = models.ForeignKey(
|
||||
to='wireless.WirelessLink',
|
||||
@ -641,13 +651,33 @@ class Interface(ComponentModel, BaseInterface, LinkTermination, PathEndpoint):
|
||||
if self.pk and self.lag_id == self.pk:
|
||||
raise ValidationError({'lag': "A LAG interface cannot be its own parent."})
|
||||
|
||||
# RF channel attributes may be set only for wireless interfaces
|
||||
# RF role & channel may only be set for wireless interfaces
|
||||
if self.rf_role and not self.is_wireless:
|
||||
raise ValidationError({'rf_role': "Wireless role may be set only on wireless interfaces."})
|
||||
if self.rf_channel and not self.is_wireless:
|
||||
raise ValidationError({'rf_channel': "Channel may be set only on wireless interfaces."})
|
||||
if self.rf_channel_width and not self.is_wireless:
|
||||
|
||||
# Validate channel frequency against interface type and selected channel (if any)
|
||||
if self.rf_channel_frequency:
|
||||
if not self.is_wireless:
|
||||
raise ValidationError({
|
||||
'rf_channel_frequency': "Channel frequency may be set only on wireless interfaces.",
|
||||
})
|
||||
if self.rf_channel and self.rf_channel_frequency != get_channel_attr(self.rf_channel, 'frequency'):
|
||||
raise ValidationError({
|
||||
'rf_channel_frequency': "Cannot specify custom frequency with channel selected.",
|
||||
})
|
||||
elif self.rf_channel:
|
||||
self.rf_channel_frequency = get_channel_attr(self.rf_channel, 'frequency')
|
||||
|
||||
# Validate channel width against interface type and selected channel (if any)
|
||||
if self.rf_channel_width:
|
||||
if not self.is_wireless:
|
||||
raise ValidationError({'rf_channel_width': "Channel width may be set only on wireless interfaces."})
|
||||
if self.rf_channel and self.rf_channel_width != get_channel_attr(self.rf_channel, 'width'):
|
||||
raise ValidationError({'rf_channel_width': "Cannot specify custom width with channel selected."})
|
||||
elif self.rf_channel:
|
||||
self.rf_channel_width = get_channel_attr(self.rf_channel, 'width')
|
||||
|
||||
# Validate untagged VLAN
|
||||
if self.untagged_vlan and self.untagged_vlan.site not in [self.device.site, None]:
|
||||
|
@ -496,8 +496,9 @@ class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable
|
||||
model = Interface
|
||||
fields = (
|
||||
'pk', 'name', 'device', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address', 'wwn',
|
||||
'rf_role', 'rf_channel', 'rf_channel_width', 'description', 'mark_connected', 'cable', 'cable_color',
|
||||
'wireless_link', 'link_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan', 'tagged_vlans',
|
||||
'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'description', 'mark_connected',
|
||||
'cable', 'cable_color', 'wireless_link', 'link_peer', 'connection', 'tags', 'ip_addresses', 'untagged_vlan',
|
||||
'tagged_vlans',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description')
|
||||
|
||||
|
@ -276,9 +276,25 @@
|
||||
<th scope="row">Channel</th>
|
||||
<td>{{ object.get_rf_channel_display|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Channel Frequency</th>
|
||||
<td>
|
||||
{% if object.rf_channel_frequency %}
|
||||
{{ object.rf_channel_frequency|simplify_decimal }} MHz
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Channel Width</th>
|
||||
<td>{{ object.rf_channel_width|placeholder }}</td>
|
||||
<td>
|
||||
{% if object.rf_channel_width %}
|
||||
{{ object.rf_channel_width|simplify_decimal }} MHz
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -36,6 +36,7 @@
|
||||
</div>
|
||||
{% render_field form.rf_role %}
|
||||
{% render_field form.rf_channel %}
|
||||
{% render_field form.rf_channel_frequency %}
|
||||
{% render_field form.rf_channel_width %}
|
||||
{% render_field form.wireless_lans %}
|
||||
</div>
|
||||
|
@ -31,4 +31,24 @@
|
||||
{{ interface.get_rf_channel_display|placeholder }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Channel Frequency</th>
|
||||
<td>
|
||||
{% if interface.rf_channel_frequency %}
|
||||
{{ interface.rf_channel_frequency|simplify_decimal }} MHz
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Channel Width</th>
|
||||
<td>
|
||||
{% if interface.rf_channel_width %}
|
||||
{{ interface.rf_channel_width|simplify_decimal }} MHz
|
||||
{% else %}
|
||||
<span class="text-muted">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import datetime
|
||||
import decimal
|
||||
import json
|
||||
import re
|
||||
from typing import Dict, Any
|
||||
@ -146,6 +147,19 @@ def humanize_megabytes(mb):
|
||||
return f'{mb} MB'
|
||||
|
||||
|
||||
@register.filter()
|
||||
def simplify_decimal(value):
|
||||
"""
|
||||
Return the simplest expression of a decimal value. Examples:
|
||||
1.00 => '1'
|
||||
1.20 => '1.2'
|
||||
1.23 => '1.23'
|
||||
"""
|
||||
if type(value) is not decimal.Decimal:
|
||||
return value
|
||||
return str(value).rstrip('0.')
|
||||
|
||||
|
||||
@register.filter()
|
||||
def tzoffset(value):
|
||||
"""
|
||||
|
@ -12,81 +12,79 @@ class WirelessRoleChoices(ChoiceSet):
|
||||
|
||||
|
||||
class WirelessChannelChoices(ChoiceSet):
|
||||
CHANNEL_AUTO = 'auto'
|
||||
|
||||
# 2.4 GHz
|
||||
CHANNEL_24G_1 = '2.4g-1'
|
||||
CHANNEL_24G_2 = '2.4g-2'
|
||||
CHANNEL_24G_3 = '2.4g-3'
|
||||
CHANNEL_24G_4 = '2.4g-4'
|
||||
CHANNEL_24G_5 = '2.4g-5'
|
||||
CHANNEL_24G_6 = '2.4g-6'
|
||||
CHANNEL_24G_7 = '2.4g-7'
|
||||
CHANNEL_24G_8 = '2.4g-8'
|
||||
CHANNEL_24G_9 = '2.4g-9'
|
||||
CHANNEL_24G_10 = '2.4g-10'
|
||||
CHANNEL_24G_11 = '2.4g-11'
|
||||
CHANNEL_24G_12 = '2.4g-12'
|
||||
CHANNEL_24G_13 = '2.4g-13'
|
||||
CHANNEL_24G_1 = '2.4g-1-2412-22'
|
||||
CHANNEL_24G_2 = '2.4g-2-2417-22'
|
||||
CHANNEL_24G_3 = '2.4g-3-2422-22'
|
||||
CHANNEL_24G_4 = '2.4g-4-2427-22'
|
||||
CHANNEL_24G_5 = '2.4g-5-2432-22'
|
||||
CHANNEL_24G_6 = '2.4g-6-2437-22'
|
||||
CHANNEL_24G_7 = '2.4g-7-2442-22'
|
||||
CHANNEL_24G_8 = '2.4g-8-2447-22'
|
||||
CHANNEL_24G_9 = '2.4g-9-2452-22'
|
||||
CHANNEL_24G_10 = '2.4g-10-2457-22'
|
||||
CHANNEL_24G_11 = '2.4g-11-2462-22'
|
||||
CHANNEL_24G_12 = '2.4g-12-2467-22'
|
||||
CHANNEL_24G_13 = '2.4g-13-2472-22'
|
||||
|
||||
# 5 GHz
|
||||
CHANNEL_5G_32 = '5g-32'
|
||||
CHANNEL_5G_34 = '5g-34'
|
||||
CHANNEL_5G_36 = '5g-36'
|
||||
CHANNEL_5G_38 = '5g-38'
|
||||
CHANNEL_5G_40 = '5g-40'
|
||||
CHANNEL_5G_42 = '5g-42'
|
||||
CHANNEL_5G_44 = '5g-44'
|
||||
CHANNEL_5G_46 = '5g-46'
|
||||
CHANNEL_5G_48 = '5g-48'
|
||||
CHANNEL_5G_50 = '5g-50'
|
||||
CHANNEL_5G_52 = '5g-52'
|
||||
CHANNEL_5G_54 = '5g-54'
|
||||
CHANNEL_5G_56 = '5g-56'
|
||||
CHANNEL_5G_58 = '5g-58'
|
||||
CHANNEL_5G_60 = '5g-60'
|
||||
CHANNEL_5G_62 = '5g-62'
|
||||
CHANNEL_5G_64 = '5g-64'
|
||||
CHANNEL_5G_100 = '5g-100'
|
||||
CHANNEL_5G_102 = '5g-102'
|
||||
CHANNEL_5G_104 = '5g-104'
|
||||
CHANNEL_5G_106 = '5g-106'
|
||||
CHANNEL_5G_108 = '5g-108'
|
||||
CHANNEL_5G_110 = '5g-110'
|
||||
CHANNEL_5G_112 = '5g-112'
|
||||
CHANNEL_5G_114 = '5g-114'
|
||||
CHANNEL_5G_116 = '5g-116'
|
||||
CHANNEL_5G_118 = '5g-118'
|
||||
CHANNEL_5G_120 = '5g-120'
|
||||
CHANNEL_5G_122 = '5g-122'
|
||||
CHANNEL_5G_124 = '5g-124'
|
||||
CHANNEL_5G_126 = '5g-126'
|
||||
CHANNEL_5G_128 = '5g-128'
|
||||
CHANNEL_5G_132 = '5g-132'
|
||||
CHANNEL_5G_134 = '5g-134'
|
||||
CHANNEL_5G_136 = '5g-136'
|
||||
CHANNEL_5G_138 = '5g-138'
|
||||
CHANNEL_5G_140 = '5g-140'
|
||||
CHANNEL_5G_142 = '5g-142'
|
||||
CHANNEL_5G_144 = '5g-144'
|
||||
CHANNEL_5G_149 = '5g-149'
|
||||
CHANNEL_5G_151 = '5g-151'
|
||||
CHANNEL_5G_153 = '5g-153'
|
||||
CHANNEL_5G_155 = '5g-155'
|
||||
CHANNEL_5G_157 = '5g-157'
|
||||
CHANNEL_5G_159 = '5g-159'
|
||||
CHANNEL_5G_161 = '5g-161'
|
||||
CHANNEL_5G_163 = '5g-163'
|
||||
CHANNEL_5G_165 = '5g-165'
|
||||
CHANNEL_5G_167 = '5g-167'
|
||||
CHANNEL_5G_169 = '5g-169'
|
||||
CHANNEL_5G_171 = '5g-171'
|
||||
CHANNEL_5G_173 = '5g-173'
|
||||
CHANNEL_5G_175 = '5g-175'
|
||||
CHANNEL_5G_177 = '5g-177'
|
||||
CHANNEL_5G_32 = '5g-32-5160-20'
|
||||
CHANNEL_5G_34 = '5g-34-5170-40'
|
||||
CHANNEL_5G_36 = '5g-36-5180-20'
|
||||
CHANNEL_5G_38 = '5g-38-5190-40'
|
||||
CHANNEL_5G_40 = '5g-40-5200-20'
|
||||
CHANNEL_5G_42 = '5g-42-5210-80'
|
||||
CHANNEL_5G_44 = '5g-44-5220-20'
|
||||
CHANNEL_5G_46 = '5g-46-5230-40'
|
||||
CHANNEL_5G_48 = '5g-48-5240-20'
|
||||
CHANNEL_5G_50 = '5g-50-5250-160'
|
||||
CHANNEL_5G_52 = '5g-52-5260-20'
|
||||
CHANNEL_5G_54 = '5g-54-5270-40'
|
||||
CHANNEL_5G_56 = '5g-56-5280-20'
|
||||
CHANNEL_5G_58 = '5g-58-5290-80'
|
||||
CHANNEL_5G_60 = '5g-60-5300-20'
|
||||
CHANNEL_5G_62 = '5g-62-5310-40'
|
||||
CHANNEL_5G_64 = '5g-64-5320-20'
|
||||
CHANNEL_5G_100 = '5g-100-5500-20'
|
||||
CHANNEL_5G_102 = '5g-102-5510-40'
|
||||
CHANNEL_5G_104 = '5g-104-5520-20'
|
||||
CHANNEL_5G_106 = '5g-106-5530-80'
|
||||
CHANNEL_5G_108 = '5g-108-5540-20'
|
||||
CHANNEL_5G_110 = '5g-110-5550-40'
|
||||
CHANNEL_5G_112 = '5g-112-5560-20'
|
||||
CHANNEL_5G_114 = '5g-114-5570-160'
|
||||
CHANNEL_5G_116 = '5g-116-5580-20'
|
||||
CHANNEL_5G_118 = '5g-118-5590-40'
|
||||
CHANNEL_5G_120 = '5g-120-5600-20'
|
||||
CHANNEL_5G_122 = '5g-122-5610-80'
|
||||
CHANNEL_5G_124 = '5g-124-5620-20'
|
||||
CHANNEL_5G_126 = '5g-126-5630-40'
|
||||
CHANNEL_5G_128 = '5g-128-5640-20'
|
||||
CHANNEL_5G_132 = '5g-132-5660-20'
|
||||
CHANNEL_5G_134 = '5g-134-5670-40'
|
||||
CHANNEL_5G_136 = '5g-136-5680-20'
|
||||
CHANNEL_5G_138 = '5g-138-5690-80'
|
||||
CHANNEL_5G_140 = '5g-140-5700-20'
|
||||
CHANNEL_5G_142 = '5g-142-5710-40'
|
||||
CHANNEL_5G_144 = '5g-144-5720-20'
|
||||
CHANNEL_5G_149 = '5g-149-5745-20'
|
||||
CHANNEL_5G_151 = '5g-151-5755-40'
|
||||
CHANNEL_5G_153 = '5g-153-5765-20'
|
||||
CHANNEL_5G_155 = '5g-155-5775-80'
|
||||
CHANNEL_5G_157 = '5g-157-5785-20'
|
||||
CHANNEL_5G_159 = '5g-159-5795-40'
|
||||
CHANNEL_5G_161 = '5g-161-5805-20'
|
||||
CHANNEL_5G_163 = '5g-163-5815-160'
|
||||
CHANNEL_5G_165 = '5g-165-5825-20'
|
||||
CHANNEL_5G_167 = '5g-167-5835-40'
|
||||
CHANNEL_5G_169 = '5g-169-5845-20'
|
||||
CHANNEL_5G_171 = '5g-171-5855-80'
|
||||
CHANNEL_5G_173 = '5g-173-5865-20'
|
||||
CHANNEL_5G_175 = '5g-175-5875-40'
|
||||
CHANNEL_5G_177 = '5g-177-5885-20'
|
||||
|
||||
CHOICES = (
|
||||
(CHANNEL_AUTO, 'Auto'),
|
||||
(
|
||||
'2.4 GHz (802.11b/g/n/ax)',
|
||||
(
|
||||
|
@ -56,7 +56,10 @@ class WirelessLANForm(BootstrapMixin, CustomFieldModelForm):
|
||||
class WirelessLinkForm(BootstrapMixin, CustomFieldModelForm):
|
||||
device_a = DynamicModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label='Device A'
|
||||
label='Device A',
|
||||
initial_params={
|
||||
'interfaces': '$interface_a'
|
||||
}
|
||||
)
|
||||
interface_a = DynamicModelChoiceField(
|
||||
queryset=Interface.objects.all(),
|
||||
@ -69,7 +72,10 @@ class WirelessLinkForm(BootstrapMixin, CustomFieldModelForm):
|
||||
)
|
||||
device_b = DynamicModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label='Device B'
|
||||
label='Device B',
|
||||
initial_params={
|
||||
'interfaces': '$interface_b'
|
||||
}
|
||||
)
|
||||
interface_b = DynamicModelChoiceField(
|
||||
queryset=Interface.objects.all(),
|
||||
|
27
netbox/wireless/utils.py
Normal file
27
netbox/wireless/utils.py
Normal file
@ -0,0 +1,27 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from .choices import WirelessChannelChoices
|
||||
|
||||
__all__ = (
|
||||
'get_channel_attr',
|
||||
)
|
||||
|
||||
|
||||
def get_channel_attr(channel, attr):
|
||||
"""
|
||||
Return the specified attribute of a given WirelessChannelChoices value.
|
||||
"""
|
||||
if channel not in WirelessChannelChoices.values():
|
||||
raise ValueError(f"Invalid channel value: {channel}")
|
||||
|
||||
channel_values = channel.split('-')
|
||||
attrs = {
|
||||
'band': channel_values[0],
|
||||
'id': int(channel_values[1]),
|
||||
'frequency': Decimal(channel_values[2]),
|
||||
'width': Decimal(channel_values[3]),
|
||||
}
|
||||
if attr not in attrs:
|
||||
raise ValueError(f"Invalid channel attribute: {attr}")
|
||||
|
||||
return attrs[attr]
|
Reference in New Issue
Block a user