- 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
"module": false,
"Vue": false,
"SockJS": false,
- "Gauge": false
+ "Gauge": false,
+ "Clusterize": false
}
}
--- /dev/null
+#!/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 <SSID> Set SSID."
+ echo " -p <PASS> Set password."
+ echo " -c <CHANNEL> 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
+++ /dev/null
-#!/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()
'scripts/upgrade-bbctrl',
'scripts/sethostname',
'scripts/reset-video',
+ 'scripts/config-wifi',
],
install_requires = 'tornado sockjs-tornado pyserial pyudev smbus2'.split(),
zip_safe = False,
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
--- /dev/null
+//-/////////////////////////////////////////////////////////////////////////////
+//- //
+//- 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 <http://www.gnu.org/licenses/>. //
+//- //
+//- 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 //
+//- <http://www.gnu.org/licenses/>. //
+//- //
+//- For information regarding this software email: //
+//- "Joseph Coffland" <joseph@buildbotics.com> //
+//- //
+//-/////////////////////////////////////////////////////////////////////////////
+
+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
--- /dev/null
+//-/////////////////////////////////////////////////////////////////////////////
+//- //
+//- 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 <http://www.gnu.org/licenses/>. //
+//- //
+//- 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 //
+//- <http://www.gnu.org/licenses/>. //
+//- //
+//- For information regarding this software email: //
+//- "Joseph Coffland" <joseph@buildbotics.com> //
+//- //
+//-/////////////////////////////////////////////////////////////////////////////
+
+script#admin-network-view-template(type="text/x-template")
+ #admin-network
+ h2 Hostname
+ .pure-form.pure-form-aligned
+ .pure-control-group
+ label(for="hostname") Hostname
+ 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 <strong>{{hostname}}</strong>.
+ 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
+ label(for="username") Username
+ input(name="username", v-model="username", @keyup.enter="set_username")
+ button.pure-button.pure-button-primary(@click="set_username") Set
+
+ .pure-form.pure-form-aligned
+ .pure-control-group
+ label(for="current") Current Password
+ input(name="current", v-model="current", type="password")
+ .pure-control-group
+ label(for="pass1") New Password
+ input(name="pass1", v-model="password", type="password")
+ .pure-control-group
+ label(for="pass2") New Password
+ input(name="pass2", v-model="password2", type="password")
+ button.pure-button.pure-button-primary(@click="set_password") Set
+
+ message(:show.sync="passwordSet")
+ h3(slot="header") Password Set
+ p(slot="body")
+
+ 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")
+++ /dev/null
-//-/////////////////////////////////////////////////////////////////////////////
-//- //
-//- 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 <http://www.gnu.org/licenses/>. //
-//- //
-//- 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 //
-//- <http://www.gnu.org/licenses/>. //
-//- //
-//- For information regarding this software email: //
-//- "Joseph Coffland" <joseph@buildbotics.com> //
-//- //
-//-/////////////////////////////////////////////////////////////////////////////
-
-script#admin-view-template(type="text/x-template")
- #admin
- h2 Hostname
- .pure-form.pure-form-aligned
- .pure-control-group
- label(for="hostname") Hostname
- input(name="hostname", v-model="hostname", @keyup.enter="set_hostname")
- button.pure-button.pure-button-primary(@click="set_hostname") Set
-
- h2 Remote SSH User
- .pure-form.pure-form-aligned
- .pure-control-group
- label(for="username") Username
- input(name="username", v-model="username", @keyup.enter="set_username")
- button.pure-button.pure-button-primary(@click="set_username") Set
-
- .pure-form.pure-form-aligned
- .pure-control-group
- label(for="current") Current Password
- input(name="current", v-model="current", type="password")
- .pure-control-group
- label(for="pass1") New Password
- input(name="pass1", v-model="password", type="password")
- .pure-control-group
- label(for="pass2") New Password
- 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 <strong>{{hostname}}</strong>.
- 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")
-
- message(:show.sync="usernameSet")
- h3(slot="header") Username Set
- p(slot="body")
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")
--- /dev/null
+/******************************************************************************\
+
+ 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 <http://www.gnu.org/licenses/>.
+
+ 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
+ <http://www.gnu.org/licenses/>.
+
+ For information regarding this software email:
+ "Joseph Coffland" <joseph@buildbotics.com>
+
+\******************************************************************************/
+
+'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');
+ }
+ }
+}
--- /dev/null
+/******************************************************************************\
+
+ 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 <http://www.gnu.org/licenses/>.
+
+ 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
+ <http://www.gnu.org/licenses/>.
+
+ For information regarding this software email:
+ "Joseph Coffland" <joseph@buildbotics.com>
+
+\******************************************************************************/
+
+'use strict'
+
+
+var api = require('./api');
+
+
+module.exports = {
+ template: '#admin-network-view-template',
+ props: ['config', 'state'],
+
+
+ data: function () {
+ return {
+ hostnameSet: false,
+ usernameSet: false,
+ passwordSet: false,
+ redirectTimeout: 0,
+ hostname: '',
+ username: '',
+ current: '',
+ password: '',
+ password2: '',
+ wifi_ssid: '',
+ wifi_pass: '',
+ wifiConfirm: false,
+ rebooting: false
+ }
+ },
+
+
+ ready: function () {
+ api.get('hostname').done(function (hostname) {
+ this.hostname = hostname;
+ }.bind(this));
+
+ 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));
+ },
+
+
+ methods: {
+ redirect: function (hostname) {
+ if (0 < this.redirectTimeout) {
+ this.redirectTimeout -= 1;
+ setTimeout(function () {this.redirect(hostname)}.bind(this), 1000);
+
+ } else location.hostname = hostname;
+ },
+
+
+ set_hostname: function () {
+ api.put('hostname', {hostname: this.hostname}).done(function () {
+ this.redirectTimeout = 45;
+ this.hostnameSet = true;
+
+ api.put('reboot').always(function () {
+ var hostname = this.hostname;
+ if (String(location.hostname).endsWith('.local'))
+ hostname += '.local'
+ this.$dispatch('hostname-changed', hostname);
+ this.redirect(hostname);
+ }.bind(this));
+
+ }.bind(this)).fail(function (error) {
+ alert('Set hostname failed: ' + JSON.stringify(error));
+ })
+ },
+
+
+ set_username: function () {
+ api.put('remote/username', {username: this.username}).done(function () {
+ this.usernameSet = true;
+ }.bind(this)).fail(function (error) {
+ alert('Set username failed: ' + JSON.stringify(error));
+ })
+ },
+
+
+ set_password: function () {
+ if (this.password != this.password2) {
+ alert('Passwords to not match');
+ return;
+ }
+
+ if (this.password.length < 6) {
+ alert('Password too short');
+ return;
+ }
+
+ api.put('remote/password', {
+ current: this.current,
+ password: this.password
+ }).done(function () {
+ this.passwordSet = true;
+ }.bind(this)).fail(function (error) {
+ alert('Set password failed: ' + JSON.stringify(error));
+ })
+ },
+
+
+ config_wifi: function () {
+ this.wifiConfirm = false;
+ this.rebooting = true;
+
+ api.put('wifi', {
+ ssid: this.wifi_ssid,
+ pass: this.wifi_pass
+
+ }).fail(function (error) {
+ alert('Failed to configure WiFi: ' + JSON.stringify(error));
+ })
+ }
+ }
+}
+++ /dev/null
-/******************************************************************************\
-
- 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 <http://www.gnu.org/licenses/>.
-
- 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
- <http://www.gnu.org/licenses/>.
-
- For information regarding this software email:
- "Joseph Coffland" <joseph@buildbotics.com>
-
-\******************************************************************************/
-
-'use strict'
-
-
-var api = require('./api');
-
-
-module.exports = {
- template: '#admin-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,
- }
- },
-
-
- 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));
-
- api.get('remote/username').done(function (username) {
- this.username = username;
- }.bind(this));
- },
-
-
- methods: {
- redirect: function (hostname) {
- if (0 < this.redirectTimeout) {
- this.redirectTimeout -= 1;
- setTimeout(function () {this.redirect(hostname)}.bind(this), 1000);
-
- } else {
- location.hostname = hostname;
- this.hostnameSet = false;
- }
- },
-
-
- set_hostname: function () {
- api.put('hostname', {hostname: this.hostname}).done(function () {
- this.redirectTimeout = 45;
- this.hostnameSet = true;
-
- api.put('reboot').always(function () {
- var hostname = this.hostname;
- if (String(location.hostname).endsWith('.local'))
- hostname += '.local';
- this.redirect(hostname);
- }.bind(this));
-
- }.bind(this)).fail(function (error) {
- alert('Set hostname failed: ' + JSON.stringify(error));
- })
- },
-
-
- set_username: function () {
- api.put('remote/username', {username: this.username}).done(function () {
- this.usernameSet = true;
- }.bind(this)).fail(function (error) {
- alert('Set username failed: ' + JSON.stringify(error));
- })
- },
-
-
- set_password: function () {
- if (this.password != this.password2) {
- alert('Passwords to not match');
- return;
- }
-
- if (this.password.length < 6) {
- alert('Password too short');
- return;
- }
-
- api.put('remote/password', {
- current: this.current,
- password: this.password
- }).done(function () {
- this.passwordSet = true;
- }.bind(this)).fail(function (error) {
- alert('Set password failed: ' + JSON.stringify(error));
- })
- },
-
-
- 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');
- }
- }
-}
'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',
events: {
'config-changed': function () {this.modified = true;},
-
+ 'hostname-changed': function (hostname) {this.hostname = hostname},
send: function (msg) {
if (this.status == 'connected') {
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();
},
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())
(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),
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