Make WiFi channels configurable (fixes #50).

This commit is contained in:
Patrick Fairbank
2017-10-24 20:49:42 -07:00
parent 42935908b2
commit 11d4f4a8c1
9 changed files with 97 additions and 23 deletions

View File

@@ -15,6 +15,9 @@ CREATE TABLE event_settings (
apaddress VARCHAR(255),
apusername VARCHAR(255),
appassword VARCHAR(255),
apteamchannel int,
apadminchannel int,
apadminwpakey VARCHAR(255),
switchaddress VARCHAR(255),
switchpassword VARCHAR(255),
bandwidthmonitoringenabled bool,

View File

@@ -27,19 +27,23 @@ const (
)
type AccessPoint struct {
address string
port int
username string
password string
address string
port int
username string
password string
teamChannel int
adminChannel int
adminWpaKey string
}
func NewAccessPoint(address, username, password string) *AccessPoint {
return &AccessPoint{address: address, port: accessPointSshPort, username: username, password: password}
func NewAccessPoint(address, username, password string, teamChannel, adminChannel int, adminWpaKey string) *AccessPoint {
return &AccessPoint{address: address, port: accessPointSshPort, username: username, password: password,
teamChannel: teamChannel, adminChannel: adminChannel, adminWpaKey: adminWpaKey}
}
// Sets up wireless networks for the given set of teams.
func (ap *AccessPoint) ConfigureTeamWifi(red1, red2, red3, blue1, blue2, blue3 *model.Team) error {
config, err := generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3)
config, err := ap.generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3)
if err != nil {
return err
}
@@ -47,6 +51,15 @@ func (ap *AccessPoint) ConfigureTeamWifi(red1, red2, red3, blue1, blue2, blue3 *
return ap.runCommand(command)
}
func (ap *AccessPoint) ConfigureAdminWifi() error {
config, err := ap.generateAccessPointConfig(nil, nil, nil, nil, nil, nil)
if err != nil {
return err
}
command := fmt.Sprintf("cat <<ENDCONFIG > /etc/config/wireless && wifi radio1\n%sENDCONFIG\n", config)
return ap.runCommand(command)
}
// Logs into the access point via SSH and runs the given shell command.
func (ap *AccessPoint) runCommand(command string) error {
// Open an SSH connection to the AP.
@@ -69,7 +82,7 @@ func (ap *AccessPoint) runCommand(command string) error {
return session.Run(command)
}
func generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3 *model.Team) (string, error) {
func (ap *AccessPoint) generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3 *model.Team) (string, error) {
// Determine what new SSIDs are needed.
networks := make(map[int]*model.Team)
var err error
@@ -97,8 +110,14 @@ func generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3 *model.Team
if err != nil {
return "", err
}
data := struct {
Networks map[int]*model.Team
TeamChannel int
AdminChannel int
AdminWpaKey string
}{networks, ap.teamChannel, ap.adminChannel, ap.adminWpaKey}
var configFile bytes.Buffer
err = template.Execute(&configFile, networks)
err = template.Execute(&configFile, data)
if err != nil {
return "", err
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/Team254/cheesy-arena/model"
"github.com/stretchr/testify/assert"
"regexp"
"strconv"
"testing"
)
@@ -17,26 +18,31 @@ func TestConfigureAccessPoint(t *testing.T) {
ssidRe := regexp.MustCompile("option ssid '([-\\w ]+)'")
wpaKeyRe := regexp.MustCompile("option key '([-\\w ]+)'")
vlanRe := regexp.MustCompile("option network 'vlan(\\d+)'")
channelRe := regexp.MustCompile("option channel '(\\d+)'")
ap := AccessPoint{teamChannel: 1234, adminChannel: 4321, adminWpaKey: "blorpy"}
// Should not configure any team SSIDs if there are no teams.
config, _ := generateAccessPointConfig(nil, nil, nil, nil, nil, nil)
config, _ := ap.generateAccessPointConfig(nil, nil, nil, nil, nil, nil)
assert.NotContains(t, config, "option device 'radio0'")
ssids := ssidRe.FindAllStringSubmatch(config, -1)
wpaKeys := wpaKeyRe.FindAllStringSubmatch(config, -1)
vlans := vlanRe.FindAllStringSubmatch(config, -1)
channels := channelRe.FindAllStringSubmatch(config, -1)
assert.Equal(t, "Cheesy Arena", ssids[0][1])
assert.Equal(t, "1234Five", wpaKeys[0][1])
assert.Equal(t, ap.adminWpaKey, wpaKeys[0][1])
assert.Equal(t, "100", vlans[0][1])
assert.Equal(t, strconv.Itoa(ap.adminChannel), channels[0][1])
assert.Equal(t, strconv.Itoa(ap.teamChannel), channels[1][1])
// Should configure two SSID for two teams.
config, _ = generateAccessPointConfig(&model.Team{Id: 254, WpaKey: "aaaaaaaa"}, nil, nil, nil, nil,
config, _ = ap.generateAccessPointConfig(&model.Team{Id: 254, WpaKey: "aaaaaaaa"}, nil, nil, nil, nil,
&model.Team{Id: 1114, WpaKey: "bbbbbbbb"})
assert.Equal(t, 2, len(radioRe.FindAllString(config, -1)))
ssids = ssidRe.FindAllStringSubmatch(config, -1)
wpaKeys = wpaKeyRe.FindAllStringSubmatch(config, -1)
vlans = vlanRe.FindAllStringSubmatch(config, -1)
assert.Equal(t, "Cheesy Arena", ssids[0][1])
assert.Equal(t, "1234Five", wpaKeys[0][1])
assert.Equal(t, ap.adminWpaKey, wpaKeys[0][1])
assert.Equal(t, "100", vlans[0][1])
assert.Equal(t, "254", ssids[1][1])
assert.Equal(t, "aaaaaaaa", wpaKeys[1][1])
@@ -46,7 +52,7 @@ func TestConfigureAccessPoint(t *testing.T) {
assert.Equal(t, "60", vlans[2][1])
// Should configure all SSIDs for six teams.
config, _ = generateAccessPointConfig(&model.Team{Id: 1, WpaKey: "11111111"},
config, _ = ap.generateAccessPointConfig(&model.Team{Id: 1, WpaKey: "11111111"},
&model.Team{Id: 2, WpaKey: "22222222"}, &model.Team{Id: 3, WpaKey: "33333333"},
&model.Team{Id: 4, WpaKey: "44444444"}, &model.Team{Id: 5, WpaKey: "55555555"},
&model.Team{Id: 6, WpaKey: "66666666"})
@@ -55,7 +61,7 @@ func TestConfigureAccessPoint(t *testing.T) {
wpaKeys = wpaKeyRe.FindAllStringSubmatch(config, -1)
vlans = vlanRe.FindAllStringSubmatch(config, -1)
assert.Equal(t, "Cheesy Arena", ssids[0][1])
assert.Equal(t, "1234Five", wpaKeys[0][1])
assert.Equal(t, ap.adminWpaKey, wpaKeys[0][1])
assert.Equal(t, "100", vlans[0][1])
assert.Equal(t, "1", ssids[1][1])
assert.Equal(t, "11111111", wpaKeys[1][1])
@@ -77,7 +83,7 @@ func TestConfigureAccessPoint(t *testing.T) {
assert.Equal(t, "60", vlans[6][1])
// Should reject a missing WPA key.
_, err := generateAccessPointConfig(&model.Team{Id: 254}, nil, nil, nil, nil, nil)
_, err := ap.generateAccessPointConfig(&model.Team{Id: 254}, nil, nil, nil, nil, nil)
if assert.NotNil(t, err) {
assert.Contains(t, err.Error(), "Invalid WPA key")
}

View File

@@ -148,12 +148,18 @@ func (arena *Arena) LoadSettings() error {
arena.EventSettings = settings
// Initialize the components that depend on settings.
arena.accessPoint = NewAccessPoint(settings.ApAddress, settings.ApUsername, settings.ApPassword)
arena.accessPoint = NewAccessPoint(settings.ApAddress, settings.ApUsername, settings.ApPassword,
settings.ApTeamChannel, settings.ApAdminChannel, settings.ApAdminWpaKey)
arena.networkSwitch = NewNetworkSwitch(settings.SwitchAddress, settings.SwitchPassword)
arena.Plc.SetAddress(settings.PlcAddress)
arena.TbaClient = partner.NewTbaClient(settings.TbaEventCode, settings.TbaSecretId, settings.TbaSecret)
arena.StemTvClient = partner.NewStemTvClient(settings.StemTvEventCode)
err = arena.accessPoint.ConfigureAdminWifi()
if err != nil {
return nil
}
return nil
}

View File

@@ -21,6 +21,9 @@ type EventSettings struct {
ApAddress string
ApUsername string
ApPassword string
ApTeamChannel int
ApAdminChannel int
ApAdminWpaKey string
SwitchAddress string
SwitchPassword string
BandwidthMonitoringEnabled bool
@@ -44,6 +47,9 @@ func (database *Database) GetEventSettings() (*EventSettings, error) {
eventSettings.SelectionRound2Order = "L"
eventSettings.SelectionRound3Order = ""
eventSettings.TBADownloadEnabled = true
eventSettings.ApTeamChannel = 157
eventSettings.ApAdminChannel = 11
eventSettings.ApAdminWpaKey = "1234Five"
err = database.eventSettingsMap.Insert(eventSettings)
if err != nil {

View File

@@ -14,8 +14,8 @@ func TestEventSettingsReadWrite(t *testing.T) {
eventSettings, err := db.GetEventSettings()
assert.Nil(t, err)
assert.Equal(t, EventSettings{Id: 0, Name: "Untitled Event", DisplayBackgroundColor: "#00ff00",
NumElimAlliances: 8, SelectionRound2Order: "L", SelectionRound3Order: "", TBADownloadEnabled: true},
*eventSettings)
NumElimAlliances: 8, SelectionRound2Order: "L", SelectionRound3Order: "", TBADownloadEnabled: true,
ApTeamChannel: 157, ApAdminChannel: 11, ApAdminWpaKey: "1234Five"}, *eventSettings)
eventSettings.Name = "Chezy Champs"
eventSettings.DisplayBackgroundColor = "#ff00ff"

View File

@@ -1,6 +1,6 @@
config wifi-device 'radio1'
option type 'mac80211'
option channel '11'
option channel '{{.AdminChannel}}'
option hwmode '11g'
option path 'soc/soc:pcie-controller/pci0000:00/0000:00:02.0/0000:02:00.0'
option htmode 'HT20'
@@ -15,7 +15,7 @@ config wifi-iface
option encryption 'psk2+ccmp'
option network 'vlan100'
option ssid 'Cheesy Arena'
option key '1234Five'
option key '{{.AdminWpaKey}}'
option macaddr '62:38:e0:12:6b:17'
config wifi-device 'radio0'
@@ -23,13 +23,13 @@ config wifi-device 'radio0'
option hwmode '11a'
option path 'soc/soc:pcie-controller/pci0000:00/0000:00:01.0/0000:01:00.0'
option txpower '23'
option channel '157'
option channel '{{.TeamChannel}}'
option country 'US'
option htmode 'HT20'
option basic_rates '6500,7200'
option short_gi_20 '0'
{{range $vlan, $team := .}}
{{range $vlan, $team := .Networks}}
config wifi-iface
option device 'radio0'
option mode 'ap'

View File

@@ -180,6 +180,37 @@
<input type="password" class="form-control" name="apPassword" value="{{.ApPassword}}">
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">AP Team Channel (5GHz)</label>
<div class="col-lg-7">
<select class="form-control" name="apTeamChannel" value="{{.ApTeamChannel}}">
<option{{if eq .ApTeamChannel 36}} selected{{end}}>36</option>
<option{{if eq .ApTeamChannel 40}} selected{{end}}>40</option>
<option{{if eq .ApTeamChannel 44}} selected{{end}}>44</option>
<option{{if eq .ApTeamChannel 48}} selected{{end}}>48</option>
<option{{if eq .ApTeamChannel 149}} selected{{end}}>149</option>
<option{{if eq .ApTeamChannel 153}} selected{{end}}>153</option>
<option{{if eq .ApTeamChannel 157}} selected{{end}}>157</option>
<option{{if eq .ApTeamChannel 161}} selected{{end}}>161</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">AP Admin Channel (2.4GHz)</label>
<div class="col-lg-7">
<select class="form-control" name="apAdminChannel" value="{{.ApAdminChannel}}">
<option{{if eq .ApAdminChannel 1}} selected{{end}}>1</option>
<option{{if eq .ApAdminChannel 6}} selected{{end}}>6</option>
<option{{if eq .ApAdminChannel 11}} selected{{end}}>11</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">AP Admin WPA Key</label>
<div class="col-lg-7">
<input type="password" class="form-control" name="apAdminWpaKey" value="{{.ApAdminWpaKey}}">
</div>
</div>
<div class="form-group">
<label class="col-lg-5 control-label">Switch Address</label>
<div class="col-lg-7">

View File

@@ -61,6 +61,9 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
eventSettings.ApAddress = r.PostFormValue("apAddress")
eventSettings.ApUsername = r.PostFormValue("apUsername")
eventSettings.ApPassword = r.PostFormValue("apPassword")
eventSettings.ApTeamChannel, _ = strconv.Atoi(r.PostFormValue("apTeamChannel"))
eventSettings.ApAdminChannel, _ = strconv.Atoi(r.PostFormValue("apAdminChannel"))
eventSettings.ApAdminWpaKey = r.PostFormValue("apAdminWpaKey")
eventSettings.SwitchAddress = r.PostFormValue("switchAddress")
eventSettings.SwitchPassword = r.PostFormValue("switchPassword")
eventSettings.BandwidthMonitoringEnabled = r.PostFormValue("bandwidthMonitoringEnabled") == "on"