function startApp() { var i18n = new VueI18n({ locale: navigator.language, fallbackLocale: 'en', messages: messages }); var app = new Vue({ el: '#app', i18n: i18n, data: { loading: true, saving: false, savingSteps: false, loadingIndicator: '|', uploadProgress: false, activeTab: 'status', version: { systemID: 'loading...', version: 'loading...', }, wifiStatus: { ap: { enabled: false, ip: '0.0.0.0' }, station: { enabled: false, status: 0, ip: '0.0.0.0' } }, searchingLocation: false, triggers: { }, connection: { hostname: null, accesspoint: true, station: false, ssid: null, password: null, dhcp: true, ip: null, subnetmask: null, gateway: null }, system: { lat: null, lng: null, pins: { ledAP: null, ledSTA: null, apButton: null, pwmSDA: null, pwmSCL: null }, pwmAddress: null, pwmFrequency: null, mapsAPIKey: '' }, allSteps: true, allStepsValue: 0, steps: [], location: '' }, created: function() { var self = this; document.title = i18n.t('title'); var hash = window.location.hash.substr(1); if (hash) self.activeTab = hash; self.startLoadingIndicator(); self.updateWiFiStatus(); self.disableStepsChanged = false; self.savingStepsTimer = false; axios.get('/api/version') .then(function(response) { if (typeof response.data == 'object') self.version = response.data; }) .catch(function(error) { console.log(error); }); // TODO retrieve system settings axios.all([ axios.get('/api/connection') .then(function(response) { if (typeof response.data == 'object') self.connection = response.data; }) .catch(function(error) { console.log(error); }), axios.get('/api/system') .then(function(response) { if (typeof response.data == 'object') self.system = response.data; }) .catch(function(error) { console.log(error); }), axios.get('/api/steps') .then(function(response) { if (Array.isArray(response.data)) { var allSteps = true; var allStepsValue = false; var total = 0; var steps = []; for (var i = 0; i < response.data.length; i++) { var value = response.data[i]; if (allStepsValue === false) allStepsValue = value; else if (value !== allStepsValue) allSteps = false; steps.push({ value: value }); total += value; } self.steps = steps; self.allStepsValue = Math.floor(total / steps.length); self.allSteps = allSteps; } }) ]) .then(axios.spread(function(acct, perms) { self.stopLoadingIndicator(); self.loading = false; })); }, methods: { applyConnection: function() { var self = this; if (self.saving) return; self.saving = true; axios.post('/api/connection', { hostname: self.connection.hostname, accesspoint: self.connection.accesspoint, station: self.connection.station, ssid: self.connection.ssid, password: self.connection.password, dhcp: self.connection.dhcp, ip: self.connection.ip, subnetmask: self.connection.subnetmask, gateway: self.connection.gateway, }) .then(function(response) { }) .catch(function(error) { console.log(error); }) .then(function() { self.saving = false; }) }, applySystem: function() { var self = this; if (self.saving) return; self.saving = true; axios.post('/api/system', self.system) .then(function(response) { }) .catch(function(error) { console.log(error); }) .then(function() { self.saving = false; }); }, startLoadingIndicator: function() { var self = this; self.loadingStage = 0; self.loadingTimer = setInterval(function() { self.loadingStage++; switch (self.loadingStage) { case 1: self.loadingIndicator = '/'; break; case 2: self.loadingIndicator = '-'; break; case 3: self.loadingIndicator = '\\'; break; case 4: self.loadingIndicator = '|'; self.loadingStage = 0; break; } }, 250); }, stopLoadingIndicator: function() { clearInterval(this.loadingTimer); }, getWiFiStationStatus: function() { if (!this.wifiStatus.station.enabled) return 'disconnected'; switch (this.wifiStatus.station.status) { case 0: // WL_IDLE_STATUS case 2: // WL_SCAN_COMPLETED return 'connecting'; case 1: // WL_NO_SSID_AVAIL case 4: // WL_CONNECT_FAILED case 5: // WL_CONNECTION_LOST return 'error'; case 3: // WL_CONNECTED return 'connected'; case 6: // WL_DISCONNECTED default: return 'disconnected'; } }, getWiFiStationStatusText: function() { if (!this.wifiStatus.station.enabled) return i18n.t('wifiStatus.stationmode.disabled'); switch (this.wifiStatus.station.status) { case 0: // WL_IDLE_STATUS return i18n.t('wifiStatus.stationmode.idle'); case 1: // WL_NO_SSID_AVAIL return i18n.t('wifiStatus.stationmode.noSSID'); case 2: // WL_SCAN_COMPLETED return i18n.t('wifiStatus.stationmode.scanCompleted'); case 3: // WL_CONNECTED return this.wifiStatus.station.ip; case 4: // WL_CONNECT_FAILED return i18n.t('wifiStatus.stationmode.connectFailed'); case 5: // WL_CONNECTION_LOST return i18n.t('wifiStatus.stationmode.connectionLost'); case 6: // WL_DISCONNECTED default: return i18n.t('wifiStatus.stationmode.disconnected'); } }, updateWiFiStatus: function() { var self = this; if (!self.saving) { axios.get('/api/connection/status') .then(function(response) { if (typeof response.data == 'object') self.wifiStatus = response.data; }) .catch(function(error) { console.log(error); }) .then(function() { setTimeout(self.updateWiFiStatus, 5000); }); } else setTimeout(self.updateWiFiStatus, 5000); }, uploadFirmware: function() { var self = this; if (self.saving) return; self.saving = true; self.uploadProgress = 0; var data = new FormData(); data.append('file', document.getElementById('firmwareFile').files[0]); var config = { timeout: 360000, onUploadProgress: function(progressEvent) { self.uploadProgress = Math.round((progressEvent.loaded * 100) / progressEvent.total); } }; axios.post('/api/firmware', data, config) .then(function(response) { // TODO show "now updating, please wait" console.log("Update sent"); }) .catch(function(error) { console.log(error); //output.innerHTML = err.message; // TODO show error }) .then(function() { self.uploadProgress = false; self.saving = false; document.getElementById('firmware').reset(); }); }, stepsChanged: function() { var self = this; if (self.loading || self.disableStepsChanged) return; if (self.savingStepsTimer === false) self.savingStepsTimer = setTimeout(function() { self.updateSteps(); }, 200); }, updateSteps: function() { var self = this; self.savingSteps = true; self.savingStepsTimer = false; self.disableStepsChanged = true; if (self.allSteps) { var newSteps = []; for (var i = 0; i < self.steps.length; i++) newSteps.push({ value: self.allStepsValue }); self.steps = newSteps; } else { var total = 0; for (var i = 0; i < self.steps.length; i++) total += self.steps[i].value; self.allStepsValue = Math.floor(total / self.steps.length); } var steps = []; for (var i = 0; i < self.steps.length; i++) steps.push(self.steps[i].value); self.disableStepsChanged = false; axios.post('/api/steps', { // TODO configurable transitionTime: 1000, values: steps }) .then(function(response) { }) .catch(function(error) { console.log(error); }) .then(function() { self.savingSteps = false; }); }, searchLocation: function() { var self = this; if (!self.location) return; self.searchingLocation = true; axios.get('https://maps.googleapis.com/maps/api/geocode/json', { params: { address: self.location, key: self.system.mapsAPIKey }}) .then(function(response) { if (Array.isArray(response.data.results) && response.data.results.length > 0) { var location = response.data.results[0].geometry.location; self.system.lat = location.lat; self.system.lng = location.lng; } }) .catch(function(error) { console.log(error); }) .then(function() { self.searchingLocation = false; }); } }, watch: { // The sync: true ensures we can wrap the internal updates with disableStepsChanged allSteps: { handler: function() { this.stepsChanged(); }, sync: true }, allStepsValue: { handler: function() { this.stepsChanged(); }, sync: true }, steps: { handler: function() { this.stepsChanged(); }, deep: true, sync: true }, activeTab: function(newValue) { window.location.hash = '#' + newValue; } } }); }