From 93d5c756985237216c453cacc6db1b9da0902440 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Mon, 19 Mar 2018 17:32:18 -0700 Subject: [PATCH] Fixed broken hostname change redirect, Split admin page, Added basic Wifi configuration. --- CHANGELOG.md | 4 + jshint.json | 3 +- scripts/config-wifi | 240 ++++++++++++++++++ scripts/jogtest.py | 50 ---- setup.py | 1 + src/jade/index.jade | 8 +- src/jade/templates/admin-general-view.jade | 67 +++++ ...dmin-view.jade => admin-network-view.jade} | 92 ++++--- src/jade/templates/control-view.jade | 3 +- src/js/admin-general-view.js | 122 +++++++++ .../{admin-view.js => admin-network-view.js} | 96 ++----- src/js/app.js | 12 +- src/py/bbctrl/Web.py | 19 ++ src/stylus/style.styl | 5 + 14 files changed, 541 insertions(+), 181 deletions(-) create mode 100755 scripts/config-wifi delete mode 100755 scripts/jogtest.py create mode 100644 src/jade/templates/admin-general-view.jade rename src/jade/templates/{admin-view.jade => admin-network-view.jade} (71%) create mode 100644 src/js/admin-general-view.js rename src/js/{admin-view.js => admin-network-view.js} (64%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c3e8c..c6104b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ Buildbotics CNC Controller Firmware Change Log - Eliminated drift caused by miscounting half microsteps. - Fixed disappearing GCode in Web. - More efficient GCode scrolling with very large files. + - Fully functional soft-limited jogging. + - Added basic Wifi configuration to admin tab. + - Fixed broken hostname change redirect. + - Split admin page. ## v0.3.19 - Fixed stopping problems. #127 diff --git a/jshint.json b/jshint.json index 4a7add2..bb0cbb3 100644 --- a/jshint.json +++ b/jshint.json @@ -9,6 +9,7 @@ "module": false, "Vue": false, "SockJS": false, - "Gauge": false + "Gauge": false, + "Clusterize": false } } diff --git a/scripts/config-wifi b/scripts/config-wifi new file mode 100755 index 0000000..4b6f9a4 --- /dev/null +++ b/scripts/config-wifi @@ -0,0 +1,240 @@ +#!/bin/bash -e + +AP=false +SSID= +PASS= +CHANNEL=7 +REBOOT=false + +WLAN0_CFG=/etc/network/interfaces.d/wlan0 +HOSTAPD_CFG=/etc/hostapd/hostapd.conf +DNSMASQ_CFG=/etc/dnsmasq.conf +DHCPCD_CFG=/etc/dhcpcd.conf +WPA_CFG=/etc/wpa_supplicant/wpa_supplicant.conf + + +function query_ssid() { + if [ -e $WLAN0_CFG ]; then + grep wpa-ssid $WLAN0_CFG | sed 's/^[[:space:]]*wpa-ssid "\([^"]*\)"/\1/' + else + if [ -e $HOSTAPD_CFG ]; then + grep ^ssid $HOSTAPD_CFG | sed 's/^ssid="\(.*\)$"/\1/' + fi + fi +} + + +function configure_wlan0() { + echo "auto wlan0" + echo "allow-hotplug wlan0" + echo "iface wlan0 inet dhcp" + echo " wpa-scan-ssid 1" + echo " wpa-ap-scan 1" + echo " wpa-key-mgmt WPA-PSK" + echo " wpa-proto RSN WPA" + echo " wpa-pairwise CCMP TKIP" + echo " wpa-group CCMP TKIP" + echo " wpa-ssid \"$SSID\"" + if [ ${#PASS} -ne 0 ]; then + echo " wpa-psk \"$PASS\"" + fi +} + + +function configure_wpa() { + echo "country=US" + echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" + echo "update_config=1" + + if [ ${#PASS} -eq 0 ]; then + echo "network={" + echo " ssid=\"$SSID\"" + echo " key_mgmt=NONE" + echo "}" + fi +} + + +function configure_dhcpcd() { + echo "hostname" + echo "clientid" + echo "persistent" + echo "option rapid_commit" + echo "option domain_name_servers, domain_name, domain_search, host_name" + echo "option classless_static_routes" + echo "option ntp_servers" + echo "option interface_mtu" + echo "require dhcp_server_identifier" + echo "slaac private" + + if $AP; then + echo + echo "interface wlan0" + echo " static ip_address=192.168.43.1/24" + fi +} + + +function configure_wifi() { + # Disable AP + service hostapd stop || true + rm -f /etc/default/hostapd + + configure_wlan0 > $WLAN0_CFG + configure_wpa > $WPA_CFG + configure_dhcpcd > $DHCPCD_CFG + service dhcpcd restart +} + + +function configure_dnsmasq() { + echo "interface=wlan0" + echo "domain-needed" + echo "bogus-priv" + echo "dhcp-range=192.168.43.2,192.168.43.20,255.255.255.0,12h" +} + + +function configure_hostapd() { + echo "interface=wlan0" + echo "driver=nl80211" + echo "ssid=$SSID" + echo "hw_mode=g" + echo "channel=$CHANNEL" + echo "wmm_enabled=0" + echo "macaddr_acl=0" + echo "auth_algs=1" + echo "ignore_broadcast_ssid=0" + echo "wpa=2" + echo "wpa_passphrase=$PASS" + echo "wpa_key_mgmt=WPA-PSK" + echo "wpa_pairwise=TKIP" + echo "rsn_pairwise=CCMP" +} + + +function is_installed() { + dpkg-query -W --showformat='${Status}' $1 | + grep "install ok installed" >/dev/null + if [ $? -eq 0 ]; then echo true; else echo false; fi +} + + +function configure_ap() { + # Disable wifi config + rm -f $WLAN0_CFG + + # Install packages + ( + $(is_installed dnsmasq) && + $(is_installed hostapd) && + $(is_installed iptables-persistent) + + ) || ( + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -yq dnsmasq hostapd iptables-persistent + ) + + configure_dhcpcd > $DHCPCD_CFG + configure_dnsmasq > $DNSMASQ_CFG + configure_hostapd > $HOSTAPD_CFG + + echo "DAEMON_CONF=\"/etc/hostapd/hostapd.conf\"" > /etc/default/hostapd + + # Enable IP forwarding + sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf + echo 1 > /proc/sys/net/ipv4/ip_forward + + # Enable IP masquerading + iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + iptables-save > /etc/iptables/rules.v4 + + # Start services + service dhcpcd restart + service dnsmasq restart + service hostapd restart +} + + +function usage() { + echo "Usage: config-wifi [OPTIONS]" + echo + echo "Configure wifi as either a client or access point." + echo + echo "OPTIONS:" + echo + echo " -a Configure access point." + echo " -r Reboot when done." + echo " -s Set SSID." + echo " -p Set password." + echo " -c Set wifi channel." + echo " -g Report SSID and exit." + echo +} + + +# Parse args +while [ $# -ne 0 ]; do + case "$1" in + -a) AP=true ;; + -r) REBOOT=true; ;; + -s) SSID="$2"; shift ;; + -p) PASS="$2"; shift ;; + -c) CHANNEL="$2"; shift ;; + -g) query_ssid; exit 0 ;; + + -h) + usage + exit 0 + ;; + + *) + usage + echo "Unknown argument '$1'" + exit 1 + esac + + shift +done + + +# Check args +function clean_str() { + echo "$1" | tr -d '\n\r"' +} + +SSID=$(clean_str "$SSID") +PASS=$(clean_str "$PASS") + +LANG=C LC_ALL=C # For correct string byte length + +if [ ${#SSID} -eq 0 -o 32 -lt ${#SSID} ]; then + echo "Invalid or missing SSID '$SSID'" + exit 1 +fi + +if [ ${#PASS} -lt 8 -o 128 -lt ${#PASS} ]; then + echo "Invalid passsword" + exit 1 +fi + +echo "$CHANNEL" | grep '^[0-9]\{1,2\}' > /dev/null +if [ $? -ne 0 ]; then + echo "Invalid channel '$CHANNEL'" + exit 1 +fi + + +# Execute +if $AP; then + echo "Configuring Wifi access point" + configure_ap + +else + echo "Configuring Wifi" + configure_wifi +fi + + +if $REBOOT; then nohup reboot & fi diff --git a/scripts/jogtest.py b/scripts/jogtest.py deleted file mode 100755 index 709156b..0000000 --- a/scripts/jogtest.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import tornado.ioloop - -from inevent import InEvent, JogHandler -from inevent.Constants import * - - -class Handler(JogHandler): - def changed(self): - scale = 1.0 - if self.speed == 1: scale = 1.0 / 128.0 - if self.speed == 2: scale = 1.0 / 32.0 - if self.speed == 3: scale = 1.0 / 4.0 - - print(', '.join(list(map(lambda x: '%.3f' % (x * scale), self.axes)))) - sys.stdout.flush() - - -if __name__ == "__main__": - # Load config - config = { - "Logitech Logitech RumblePad 2 USB": { - "deadband": 0.1, - "axes": [ABS_X, ABS_Y, ABS_RZ, ABS_Z], - "dir": [1, -1, -1, 1], - "arrows": [ABS_HAT0X, ABS_HAT0Y], - "speed": [0x120, 0x121, 0x122, 0x123], - "lock": [0x124, 0x125], - }, - - "default": { - "deadband": 0.1, - "axes": [ABS_X, ABS_Y, ABS_RY, ABS_RX], - "dir": [1, -1, -1, 1], - "arrows": [ABS_HAT0X, ABS_HAT0Y], - "speed": [0x133, 0x130, 0x131, 0x134], - "lock": [0x136, 0x137], - } - } - - # Create ioloop - ioloop = tornado.ioloop.IOLoop.current() - - # Listen for input events - handler = Handler(config) - events = InEvent(ioloop, handler, types = "js kbd".split()) - - ioloop.start() diff --git a/setup.py b/setup.py index 561b52b..2c83c27 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ setup( 'scripts/upgrade-bbctrl', 'scripts/sethostname', 'scripts/reset-video', + 'scripts/config-wifi', ], install_requires = 'tornado sockjs-tornado pyserial pyudev smbus2'.split(), zip_safe = False, diff --git a/src/jade/index.jade b/src/jade/index.jade index c25fac1..633687d 100644 --- a/src/jade/index.jade +++ b/src/jade/index.jade @@ -81,7 +81,13 @@ html(lang="en") a.pure-menu-link(href="#gcode") Gcode li.pure-menu-heading - a.pure-menu-link(href="#admin") Admin + a.pure-menu-link(href="#admin-general") Admin + + li.pure-menu-item + a.pure-menu-link(href="#admin-general") General + + li.pure-menu-item + a.pure-menu-link(href="#admin-network") Network li.pure-menu-heading a.pure-menu-link(href="#cheat-sheet") Cheat Sheet diff --git a/src/jade/templates/admin-general-view.jade b/src/jade/templates/admin-general-view.jade new file mode 100644 index 0000000..14afba4 --- /dev/null +++ b/src/jade/templates/admin-general-view.jade @@ -0,0 +1,67 @@ +//-///////////////////////////////////////////////////////////////////////////// +//- // +//- This file is part of the Buildbotics firmware. // +//- // +//- Copyright (c) 2015 - 2018, Buildbotics LLC // +//- All rights reserved. // +//- // +//- This file ("the software") is free software: you can redistribute it // +//- and/or modify it under the terms of the GNU General Public License, // +//- version 2 as published by the Free Software Foundation. You should // +//- have received a copy of the GNU General Public License, version 2 // +//- along with the software. If not, see . // +//- // +//- The software is distributed in the hope that it will be useful, but // +//- WITHOUT ANY WARRANTY; without even the implied warranty of // +//- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // +//- Lesser General Public License for more details. // +//- // +//- You should have received a copy of the GNU Lesser General Public // +//- License along with the software. If not, see // +//- . // +//- // +//- For information regarding this software email: // +//- "Joseph Coffland" // +//- // +//-///////////////////////////////////////////////////////////////////////////// + +script#admin-general-view-template(type="text/x-template") + #admin-general + h2 Firmware + button.pure-button.pure-button-primary(@click="check") Check + button.pure-button.pure-button-primary(@click="upgrade") Upgrade + label.pure-button.pure-button-primary.file-upload + input(type="file", accept=".tar.bz2", @change="upload") + | Upload + + p + input(type="checkbox", v-model="autoCheckUpgrade", + @change="change_auto_check_upgrade") + label(for="auto-check-upgrade")   Automatically check for upgrades + + h2 Configuration + button.pure-button.pure-button-primary(@click="backup") Backup + + label.pure-button.pure-button-primary.file-upload + input(type="file", accept=".json", @change="restore") + | Restore + message(:show.sync="configRestored") + h3(slot="header") Success + p(slot="body") Configuration restored. + + button.pure-button.pure-button-primary(@click="confirmReset = true") + | Reset + message(:show.sync="confirmReset") + h3(slot="header") Reset to default configuration? + p(slot="body") All configuration changes will be lost. + div(slot="footer") + button.pure-button(@click="confirmReset = false") Cancel + button.pure-button.button-success(@click="reset") OK + + message(:show.sync="configReset") + h3(slot="header") Success + p(slot="body") Configuration reset. + + h2 Debugging + a(href="/api/log", target="_blank") + button.pure-button.pure-button-primary View Log diff --git a/src/jade/templates/admin-view.jade b/src/jade/templates/admin-network-view.jade similarity index 71% rename from src/jade/templates/admin-view.jade rename to src/jade/templates/admin-network-view.jade index ff0a9ac..e31cb3a 100644 --- a/src/jade/templates/admin-view.jade +++ b/src/jade/templates/admin-network-view.jade @@ -25,8 +25,8 @@ //- // //-///////////////////////////////////////////////////////////////////////////// -script#admin-view-template(type="text/x-template") - #admin +script#admin-network-view-template(type="text/x-template") + #admin-network h2 Hostname .pure-form.pure-form-aligned .pure-control-group @@ -34,6 +34,14 @@ script#admin-view-template(type="text/x-template") input(name="hostname", v-model="hostname", @keyup.enter="set_hostname") button.pure-button.pure-button-primary(@click="set_hostname") Set + message(:show.sync="hostnameSet") + h3(slot="header") Hostname Set + div(slot="body") + p Hostname was successfuly set to {{hostname}}. + p Rebooting to apply changes. + p Redirecting to new hostname in {{redirectTimeout}} seconds. + div(slot="footer") + h2 Remote SSH User .pure-form.pure-form-aligned .pure-control-group @@ -53,53 +61,6 @@ script#admin-view-template(type="text/x-template") input(name="pass2", v-model="password2", type="password") button.pure-button.pure-button-primary(@click="set_password") Set - h2 Debugging - a(href="/api/log", target="_blank") - button.pure-button.pure-button-primary View Log - - h2 Configuration - button.pure-button.pure-button-primary(@click="backup") Backup - - label.pure-button.pure-button-primary.file-upload - input(type="file", accept=".json", @change="restore") - | Restore - message(:show.sync="configRestored") - h3(slot="header") Success - p(slot="body") Configuration restored. - - button.pure-button.pure-button-primary(@click="confirmReset = true") - | Reset - message(:show.sync="confirmReset") - h3(slot="header") Reset to default configuration? - p(slot="body") All configuration changes will be lost. - div(slot="footer") - button.pure-button(@click="confirmReset = false") Cancel - button.pure-button.button-success(@click="reset") OK - - message(:show.sync="configReset") - h3(slot="header") Success - p(slot="body") Configuration reset. - - h2 Firmware - button.pure-button.pure-button-primary(@click="check") Check - button.pure-button.pure-button-primary(@click="upgrade") Upgrade - label.pure-button.pure-button-primary.file-upload - input(type="file", accept=".tar.bz2", @change="upload") - | Upload - - p - input(type="checkbox", v-model="autoCheckUpgrade", - @change="change_auto_check_upgrade") - label(for="auto-check-upgrade")   Automatically check for upgrades - - message(:show.sync="hostnameSet") - h3(slot="header") Hostname Set - div(slot="body") - p Hostname was successfuly set to {{hostname}}. - p Rebooting to apply changes. - p Redirecting to new hostname in {{redirectTimeout}} seconds. - div(slot="footer") - message(:show.sync="passwordSet") h3(slot="header") Password Set p(slot="body") @@ -107,3 +68,36 @@ script#admin-view-template(type="text/x-template") message(:show.sync="usernameSet") h3(slot="header") Username Set p(slot="body") + + h2 Wifi Setup + .pure-form.pure-form-aligned + .pure-control-group + label(for="ssid") SSID + input(name="ssid", v-model="wifi_ssid") + .pure-control-group + label(for="wifi_pass") Password + input(name="wifi_pass", v-model="wifi_pass", type="password") + button.pure-button.pure-button-primary(@click="wifiConfirm = true") Set + + message(:show.sync="wifiConfirm") + h3(slot="header") Configure Wifi and reboot? + div(slot="body") + p + | After configuring the Wifi settings the controller will + | automatically reboot. + table + tr + th SSID + td  {{wifi_ssid}} + tr + th Auth + td  {{wifi_pass ? 'Password' : 'Open'}} + + div(slot="footer") + button.pure-button(@click="wifiConfirm = false") Cancel + button.pure-button.button-success(@click="config_wifi") OK + + message(:show.sync="rebooting") + h3(slot="header") Rebooting + p(slot="body") Please wait... + div(slot="footer") diff --git a/src/jade/templates/control-view.jade b/src/jade/templates/control-view.jade index 90880ee..cb61a9d 100644 --- a/src/jade/templates/control-view.jade +++ b/src/jade/templates/control-view.jade @@ -209,7 +209,8 @@ script#control-view-template(type="text/x-template") style="display:none", accept=".nc,.gcode,.gc,.ngc") button.pure-button(title="Delete current GCode program.", - @click="deleteGCode = true", :disabled="!state.selected") + @click="deleteGCode = true", + :disabled="!state.selected || is_running || is_stopping") .fa.fa-trash message(:show.sync="deleteGCode") diff --git a/src/js/admin-general-view.js b/src/js/admin-general-view.js new file mode 100644 index 0000000..7ae1af0 --- /dev/null +++ b/src/js/admin-general-view.js @@ -0,0 +1,122 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2018, Buildbotics LLC + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +'use strict' + + +var api = require('./api'); + + +module.exports = { + template: '#admin-general-view-template', + props: ['config', 'state'], + + + data: function () { + return { + configRestored: false, + confirmReset: false, + configReset: false, + latest: '', + autoCheckUpgrade: true + } + }, + + + events: { + latest_version: function (version) {this.latest = version} + }, + + + ready: function () { + this.autoCheckUpgrade = this.config.admin['auto-check-upgrade'] + }, + + + methods: { + backup: function () { + document.getElementById('download-target').src = '/api/config/download'; + }, + + + restore: function (e) { + var files = e.target.files || e.dataTransfer.files; + if (!files.length) return; + + var fr = new FileReader(); + fr.onload = function (e) { + var config; + + try { + config = JSON.parse(e.target.result); + } catch (ex) { + alert("Invalid config file"); + return; + } + + api.put('config/save', config).done(function (data) { + this.$dispatch('update'); + this.configRestored = true; + + }.bind(this)).fail(function (error) { + alert('Restore failed: ' + error); + }) + }.bind(this); + + fr.readAsText(files[0]); + }, + + + reset: function () { + this.confirmReset = false; + api.put('config/reset').done(function () { + this.$dispatch('update'); + this.configReset = true; + + }.bind(this)).fail(function (error) { + alert('Reset failed: ' + error); + }); + }, + + + check: function () {this.$dispatch('check')}, + upgrade: function () {this.$dispatch('upgrade')}, + + + upload: function (e) { + var files = e.target.files || e.dataTransfer.files; + if (!files.length) return; + this.$dispatch('upload', files[0]); + }, + + + change_auto_check_upgrade: function () { + this.config.admin['auto-check-upgrade'] = this.autoCheckUpgrade; + this.$dispatch('config-changed'); + } + } +} diff --git a/src/js/admin-view.js b/src/js/admin-network-view.js similarity index 64% rename from src/js/admin-view.js rename to src/js/admin-network-view.js index 0be0e04..143b157 100644 --- a/src/js/admin-view.js +++ b/src/js/admin-network-view.js @@ -32,38 +32,30 @@ var api = require('./api'); module.exports = { - template: '#admin-view-template', + template: '#admin-network-view-template', props: ['config', 'state'], data: function () { return { - configRestored: false, - confirmReset: false, - configReset: false, hostnameSet: false, usernameSet: false, passwordSet: false, redirectTimeout: 0, - latest: '', hostname: '', username: '', current: '', password: '', password2: '', - autoCheckUpgrade: true, + wifi_ssid: '', + wifi_pass: '', + wifiConfirm: false, + rebooting: false } }, - events: { - latest_version: function (version) {this.latest = version} - }, - - ready: function () { - this.autoCheckUpgrade = this.config.admin['auto-check-upgrade'] - api.get('hostname').done(function (hostname) { this.hostname = hostname; }.bind(this)); @@ -71,6 +63,10 @@ module.exports = { api.get('remote/username').done(function (username) { this.username = username; }.bind(this)); + + api.get('wifi').done(function (config) { + this.wifi_ssid = config.ssid; + }.bind(this)); }, @@ -80,10 +76,7 @@ module.exports = { this.redirectTimeout -= 1; setTimeout(function () {this.redirect(hostname)}.bind(this), 1000); - } else { - location.hostname = hostname; - this.hostnameSet = false; - } + } else location.hostname = hostname; }, @@ -95,7 +88,8 @@ module.exports = { api.put('reboot').always(function () { var hostname = this.hostname; if (String(location.hostname).endsWith('.local')) - hostname += '.local'; + hostname += '.local' + this.$dispatch('hostname-changed', hostname); this.redirect(hostname); }.bind(this)); @@ -136,65 +130,17 @@ module.exports = { }, - backup: function () { - document.getElementById('download-target').src = '/api/config/download'; - }, - - - restore: function (e) { - var files = e.target.files || e.dataTransfer.files; - if (!files.length) return; - - var fr = new FileReader(); - fr.onload = function (e) { - var config; + config_wifi: function () { + this.wifiConfirm = false; + this.rebooting = true; - try { - config = JSON.parse(e.target.result); - } catch (ex) { - alert("Invalid config file"); - return; - } + api.put('wifi', { + ssid: this.wifi_ssid, + pass: this.wifi_pass - api.put('config/save', config).done(function (data) { - this.$dispatch('update'); - this.configRestored = true; - - }.bind(this)).fail(function (error) { - alert('Restore failed: ' + error); - }) - }.bind(this); - - fr.readAsText(files[0]); - }, - - - reset: function () { - this.confirmReset = false; - api.put('config/reset').done(function () { - this.$dispatch('update'); - this.configReset = true; - - }.bind(this)).fail(function (error) { - alert('Reset failed: ' + error); - }); - }, - - - check: function () {this.$dispatch('check')}, - upgrade: function () {this.$dispatch('upgrade')}, - - - upload: function (e) { - var files = e.target.files || e.dataTransfer.files; - if (!files.length) return; - this.$dispatch('upload', files[0]); - }, - - - change_auto_check_upgrade: function () { - this.config.admin['auto-check-upgrade'] = this.autoCheckUpgrade; - this.$dispatch('config-changed'); + }).fail(function (error) { + alert('Failed to configure WiFi: ' + JSON.stringify(error)); + }) } } } diff --git a/src/js/app.js b/src/js/app.js index 7045209..78fecc5 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -114,7 +114,8 @@ module.exports = new Vue({ 'tool-view': require('./tool-view'), 'io-view': require('./io-view'), 'gcode-view': require('./gcode-view'), - 'admin-view': require('./admin-view'), + 'admin-general-view': require('./admin-general-view'), + 'admin-network-view': require('./admin-network-view'), 'help-view': {template: '#help-view-template'}, 'cheat-sheet-view': { template: '#cheat-sheet-view-template', @@ -125,7 +126,7 @@ module.exports = new Vue({ events: { 'config-changed': function () {this.modified = true;}, - + 'hostname-changed': function (hostname) {this.hostname = hostname}, send: function (msg) { if (this.status == 'connected') { @@ -136,8 +137,11 @@ module.exports = new Vue({ connected: function () { - if (this.reloadOnConnect) location.reload(true); - else this.update(); + if (this.reloadOnConnect) { + if (typeof this.hostname != 'undefined') + location.hostname = this.hostname; + location.reload(true); + } else this.update(); }, diff --git a/src/py/bbctrl/Web.py b/src/py/bbctrl/Web.py index 9f7c301..a6d32ff 100644 --- a/src/py/bbctrl/Web.py +++ b/src/py/bbctrl/Web.py @@ -115,6 +115,24 @@ class HostnameHandler(bbctrl.APIHandler): raise HTTPError(400, 'Failed to set hostname') +class WifiHandler(bbctrl.APIHandler): + def get(self): + ssid = '' + try: + ssid = call_get_output(['config-wifi', '-g']) + except: pass + self.write_json({'ssid': ssid}) + + def put(self): + if 'ssid' in self.json and 'pass' in self.json: + if subprocess.call(['config-wifi', '-s', self.json['ssid'], + '-p', self.json['pass']]) == 0: + self.write_json('ok') + return + + raise HTTPError(400, 'Failed to configure wifi') + + class UsernameHandler(bbctrl.APIHandler): def get(self): self.write_json(get_username()) @@ -334,6 +352,7 @@ class Web(tornado.web.Application): (r'/api/log', LogHandler), (r'/api/reboot', RebootHandler), (r'/api/hostname', HostnameHandler), + (r'/api/wifi', WifiHandler), (r'/api/remote/username', UsernameHandler), (r'/api/remote/password', PasswordHandler), (r'/api/config/load', ConfigLoadHandler), diff --git a/src/stylus/style.styl b/src/stylus/style.styl index 7f56035..f8ab2dd 100644 --- a/src/stylus/style.styl +++ b/src/stylus/style.styl @@ -531,6 +531,11 @@ body padding 0.5em +.admin-general-view, .admin-network-view + h2:not(:first-of-type) + margin-top 2em + + .upgrade-version display inline-block border-radius 4px -- 2.27.0