From 6f6dabca5b9541e83375642da59be21d7338ae7f Mon Sep 17 00:00:00 2001 From: mmcwilliams Date: Wed, 19 Jun 2019 19:23:20 -0400 Subject: [PATCH] Created a PWA frontend. This marks a major milestone in the project, as I will be dropping support of the cordova mobile app and rely entirely on the PWA for bluetooth connectivity going forward. Can't afford an Apple dev license I'll never use and don't want the trouble of maintaining mobile apps on the stores that maybe a handful of people will use. Check intval.sixteenmillimeter.com for this site deployed as an app. --- app/www/index.html | 2 + app/www/static/css/index.css | 17 +- app/www/static/js/index.js | 7 +- app/www/static/js/intval.mobile.js | 2 +- app/www/static/js/intval.pwa.js | 614 +++++++++++++++++------------ 5 files changed, 379 insertions(+), 263 deletions(-) diff --git a/app/www/index.html b/app/www/index.html index 3b00192..5d05602 100644 --- a/app/www/index.html +++ b/app/www/index.html @@ -13,6 +13,7 @@
+
Tap to Connect

INTVAL3

@@ -175,6 +176,7 @@ + diff --git a/app/www/static/css/index.css b/app/www/static/css/index.css index 9749ec1..f871cfc 100644 --- a/app/www/static/css/index.css +++ b/app/www/static/css/index.css @@ -255,8 +255,8 @@ footer{ } footer .icon { - width: 33.33%; - /*width: 50%;*/ + /*width: 33.33%;*/ + width: 50%; height: 50px; float: left; box-sizing: border-box; @@ -427,4 +427,17 @@ body.mobile footer{ } #msg.active{ display: block; +} +#tap{ + display: none; + width: 100%; + height: 100vh; + position: fixed; + left: 0; + top: 0; + color: #fff; + text-align: center; + line-height: 100vh; + text-shadow: 1px 1px 0px #000; + font-size: 24px; } \ No newline at end of file diff --git a/app/www/static/js/index.js b/app/www/static/js/index.js index 015c8be..77aad4b 100644 --- a/app/www/static/js/index.js +++ b/app/www/static/js/index.js @@ -22,7 +22,11 @@ var app = { document.addEventListener('deviceready', this.onDeviceReady.bind(this), false); document.addEventListener('resume', this.onDeviceResume.bind(this), false); document.addEventListener('DOMContentLoaded', event => { - if (typeof cordova === 'undefined') { + if (typeof navigator.bluetooth !== 'undefined' && typeof cordova === 'undefined') { + init(); + pwa.init(); + //getState(); + } else if (typeof cordova === 'undefined') { init(); web.init(); getState(); @@ -37,6 +41,7 @@ var app = { onDeviceReady: function() { init(); mobile.init(); + getState(); }, onDeviceResume : function () { getState(); diff --git a/app/www/static/js/intval.mobile.js b/app/www/static/js/intval.mobile.js index 760d878..73de469 100644 --- a/app/www/static/js/intval.mobile.js +++ b/app/www/static/js/intval.mobile.js @@ -155,7 +155,7 @@ mobile.init = function () { } UI.spinner.init() mobile.ble.scan(); - mobile.cameraValues(); + //mobile.cameraValues(); }; diff --git a/app/www/static/js/intval.pwa.js b/app/www/static/js/intval.pwa.js index 7fda30a..446d259 100644 --- a/app/www/static/js/intval.pwa.js +++ b/app/www/static/js/intval.pwa.js @@ -3,9 +3,9 @@ 'use strict'; -var mobile = {}; +var pwa = {}; -mobile.wble = { +pwa.wble = { BLENO_DEVICE_NAME : 'intval3', DEVICE_ID : 'intval3', SERVICE_ID : '149582bd-d49d-4b5c-acd1-1ae503d09e7a', @@ -13,11 +13,15 @@ mobile.wble = { WIFI_ID : '3fe7d9cf-7bd2-4ff0-97c5-ebe87288c2cc', //wifi only devices : [], device : {}, + peripheral : {}, + service : {}, + characteristics : {}, + descriptors : {}, connected : false, active : false }; -mobile.wifi = { +pwa.wifi = { current : 'null', available : [], ip : null @@ -29,59 +33,76 @@ async function delay (ms) { }) } -mobile.wble.scan = async function () { +pwa.wble.scan = async function () { let device; UI.spinner.show('Scanning for INTVAL3...'); UI.overlay.show(); + document.getElementById('tap').style.display = 'none'; + + pwa.wble.devices = []; + try { - device = await navigator.bluetooth.requestDevice({ - filters: [{ services: [ mobile.wble.SERVICE_ID ] }], - //optionalServices: optionalServices + device = await navigator.bluetooth.requestDevice({ + filters: [{ + name : pwa.wble.DEVICE_ID + }], + optionalServices: [ pwa.wble.SERVICE_ID ] }); - mobile.wble.onDiscover(device); } catch (err) { - mobile.wble.onError(err); + console.error(err); + pwa.wble.onError(err.message); + } + + if (device) { + pwa.wble.onDiscover(device); } - //ble.scan([], 5, mobile.wble.onDiscover, mobile.wble.onError); - mobile.wble.devices = []; await delay(5000); UI.spinner.hide(); UI.overlay.hide(); - if (!mobile.wble.connected) { - mobile.alert('No devices found.') + if (!pwa.wble.connected) { + pwa.alert('No devices found.') settingsPage(); } }; -mobile.wble.onDiscover = function (device) { +pwa.wble.onDiscover = function (device) { if (device && device.name && device.name.indexOf('intval3') !== -1) { console.log('BLE - Discovered INTVAL3'); - console.dir(device); - mobile.wble.devices.push(device); - if (!mobile.wble.connected) { - mobile.wble.connect(device); + //console.dir(device); + pwa.wble.devices.push(device); + if (!pwa.wble.connected) { + pwa.wble.connect(device); } } else { //console.log(`BLE - Discovered Other ${device.id}`); } }; -mobile.wble.connect = async function (device) { +pwa.wble.connect = async function (device) { console.log(`BLE - Connecting to ${device.id}`); + let peripheral; + let service; + try { - await device.gatt.connect() + peripheral = await device.gatt.connect(); } catch (err) { - mobile.wble.onError(err); + pwa.wble.onError(err); } - ble.connect(device.id, (peripheral) => { - mobile.wble.onConnect(peripheral, device); - }, mobile.wble.onError); + try { + service = await peripheral.getPrimaryService(pwa.wble.SERVICE_ID); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + + pwa.wble.onConnect(peripheral, device, service); }; -mobile.wble.onConnect = function (peripheral, device) { +pwa.wble.onConnect = function (peripheral, device, service) { const elem = document.getElementById('bluetooth'); const option = document.createElement('option'); const disconnect = document.getElementById('disconnect'); @@ -89,12 +110,15 @@ mobile.wble.onConnect = function (peripheral, device) { UI.spinner.hide(); UI.overlay.hide(); - console.log(`BLE - Connected to ${device.id}`); - console.log(peripheral); - console.dir(device); - mobile.wble.device = device; - mobile.wble.connected = true; + console.log(`BLE - Connected to ${device.id}`); + //console.dir(peripheral); + //console.dir(device); + + pwa.wble.peripheral = peripheral; + pwa.wble.device = device; + pwa.wble.service = service; + pwa.wble.connected = true; elem.innerHTML = ''; option.text = device.name; @@ -105,22 +129,22 @@ mobile.wble.onConnect = function (peripheral, device) { scan.classList.remove('active'); getState(); - mobile.getWifi(); + pwa.getWifi(); }; -mobile.wble.disconnect = function () { +pwa.wble.disconnect = function () { const elem = document.getElementById('bluetooth'); const option = document.createElement('option'); const disconnect = document.getElementById('disconnect'); const scan = document.getElementById('scan'); let device; - if (!mobile.wble.connected) { + if (!pwa.wble.connected) { console.warn('Not connected to any device'); return false; } - device = mobile.wble.device; + device = pwa.wble.device; console.log(`BLE - Disconnecting from ${device.id}`); - //ble.disconnect(device.id, mobile.wble.onDisconnect, mobile.wble.onDisconnect); + //ble.disconnect(device.id, pwa.wble.onDisconnect, pwa.wble.onDisconnect); elem.innerHTML = ''; option.text = 'N/A'; @@ -132,234 +156,314 @@ mobile.wble.disconnect = function () { UI.overlay.hide(); }; -mobile.wble.onDisconnect = function (res) { +pwa.wble.onDisconnect = function (res) { console.log(`BLE - Disconnected from ${res}`); - mobile.wble.connected = false; - mobile.wble.device = {}; + pwa.wble.connected = false; + pwa.wble.device = {}; }; -mobile.wble.onError = function (err) { +pwa.wble.onError = function (err) { if (err.errorMessage && err.errorMessage === 'Peripheral Disconnected') { console.log('Device disconnected'); - mobile.wble.disconnect() + pwa.wble.disconnect() } else { - mobile.alert(JSON.stringify(err)); + pwa.alert(JSON.stringify(err)); } - /* - Object - errorDescription: "The specified device has disconnected from us." - errorMessage: "Peripheral Disconnected" - id: "E8EF4B8B-0B5E-4E96-B337-E878DB1E3C4B" - name: "intval3_b827ebc7461d" - */ }; -mobile.init = function () { +pwa.wble.read = async function (characteristicId) { + const decoder = new TextDecoder('utf-8'); + let characteristic; + let value; + let json; + + if (typeof pwa.wble.characteristics[characteristicId] === 'undefined') { + try { + characteristic = await pwa.wble.service.getCharacteristic(characteristicId); + pwa.wble.characteristics[characteristicId] = characteristic; + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + } else { + characteristic = pwa.wble.characteristics[characteristicId] + } + + try { + value = await characteristic.readValue(); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + } + + json = decoder.decode(value); + + return JSON.parse(json); +} + +pwa.wble.write = async function ( characteristicId, json) { + const encoder = new TextEncoder('utf-8'); + let characteristic; + let value; + + if (typeof pwa.wble.characteristics[characteristicId] === 'undefined') { + try { + characteristic = await pwa.wble.service.getCharacteristic(characteristicId); + pwa.wble.charactersitics[characteristicId] = characteristic; + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + } else { + characteristic = pwa.wble.characteristics[characteristicId]; + } + + value = JSON.stringify(json); + encoder.encode(value); + + try { + await characteristic.writeValue(encoder.encode(value)) + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + + return true; +} + +pwa.init = function () { const bleInputs = document.querySelectorAll('.ble'); const bolIso = document.querySelector('.iso'); const bolF = document.querySelector('.fstop'); + const tap = document.getElementById('tap'); - document.querySelector('body').classList.add('mobile'); + //document.querySelector('body').classList.add('mobile'); - window.frame = mobile.frame; - window.getState = mobile.getState; - window.setDir = mobile.setDir; - window.setExposure = mobile.setExposure; - window.setDelay = mobile.setDelay; - window.setCounter = mobile.setCounter; - window.sequence = mobile.sequence; - window.reset = mobile.reset; - window.restart = mobile.restart; - window.update = mobile.update; + window.frame = pwa.frame; + window.getState = pwa.getState; + window.setDir = pwa.setDir; + window.setExposure = pwa.setExposure; + window.setDelay = pwa.setDelay; + window.setCounter = pwa.setCounter; + window.sequence = pwa.sequence; + window.reset = pwa.reset; + window.restart = pwa.restart; + window.update = pwa.update; //show ble-specific fields in settings for (let i of bleInputs) { i.classList.add('active'); } - UI.spinner.init() - mobile.wble.scan(); - mobile.cameraValues(); + UI.spinner.init(); + UI.overlay.show(); + + tap.onclick = pwa.wble.scan; + tap.style.display = 'block'; + //pwa.cameraValues(); }; -mobile.getState = function () { - if (!mobile.wble.connected) { - //returning here will prevent error alert +pwa.pairInteraction = function () { + pwa.wble.scan(); +} + +pwa.getState = async function () { + let state; + if (!pwa.wble.connected) { + return false } - /*ble.read(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - mobile.stateSuccess, - mobile.wble.onError);*/ -}; -mobile.stateSuccess = function (data) { - let str = bytesToString(data); - let res = JSON.parse(str); - setState(res); + try { + state = await pwa.wble.read(pwa.wble.CHAR_ID); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + setState(state); }; -mobile.frame = function () { +pwa.frame = async function () { const opts = { type : 'frame' }; - if (!mobile.wble.connected) { - return mobile.alert('Not connected to an INTVAL3 device.'); + if (!pwa.wble.connected) { + return pwa.alert('Not connected to an INTVAL3 device.'); } - if (mobile.wble.active) { + if (pwa.wble.active) { return false; } - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), //check length? - mobile.frameSuccess, - mobile.wble.onError);*/ + document.getElementById('frame').classList.add('focus'); - mobile.wble.active = true; + pwa.wble.active = true; + + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false;`` + } + + pwa.frameSuccess(); }; -mobile.frameSuccess = function () { +pwa.frameSuccess = function () { if (STATE.exposure < 5000) { console.log('Frame finished, getting state.'); - mobile.wble.active = false; + pwa.wble.active = false; document.getElementById('frame').classList.remove('focus'); - mobile.getState(); + pwa.getState(); } else { setTimeout(() => { console.log('Frame finished, getting state.'); - mobile.wble.active = false; + pwa.wble.active = false; document.getElementById('frame').classList.remove('focus'); - mobile.getState(); + pwa.getState(); }, STATE.exposure + 500) } } -mobile.setDir = function () { +pwa.setDir = async function () { const opts = { type : 'dir', dir : !document.getElementById('dir').checked }; - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), //check length? - mobile.dirSuccess, - mobile.wble.onError);*/ + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + + pwa.dirSuccess(); }; -mobile.dirSuccess = function () { +pwa.dirSuccess = function () { console.log('Set direction'); - mobile.getState(); + pwa.getState(); setTimeout(() => { setDirLabel(STATE.dir); }, 50); }; -mobile.setExposure = function () { - let exposure = document.getElementById('exposure').value; - let scaledExposure; - let opts = { + +pwa.setExposure = async function () { + const opts = { type : 'exposure' }; + let exposure = document.getElementById('exposure').value; + let scaledExposure; if (exposure === '' || exposure === null) { exposure = 0; } scaledExposure = scaleTime(exposure, STATE.scale); opts.exposure = scaledExposure; - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), //check length? - mobile.exposureSuccess, - mobile.wble.onError);*/ -}; -mobile.exposureSuccess = function () { - console.log('Set exposure'); - mobile.getState(); + + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + pwa.exposureSuccess(); }; -mobile.setDelay = function () { +pwa.exposureSuccess = function () { + console.log('Set exposure'); + pwa.getState(); +}; + +pwa.setDelay = async function () { const delay = document.getElementById('delay').value; const scaledDelay = scaleTime(delay, STATE.delayScale); - let opts = { + const opts = { type : 'delay', delay : scaledDelay }; - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), //check length? - mobile.delaySuccess, - mobile.wble.onError);*/ + + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + + pwa.delaySuccess(); } -mobile.delaySuccess = function () { +pwa.delaySuccess = function () { console.log('Set delay'); - mobile.getState(); + pwa.getState(); }; -mobile.setCounter = function () { - let opts = { +pwa.setCounter = async function () { + const opts = { type : 'counter', counter : null }; const counter = document.getElementById('counter').value; - function counterPrompt (results) { - let change = results.input1 - if (results.buttonIndex === 1) { - if (change === null || !isNumeric(change)) return false; - opts.counter = change; - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), //check length? - mobile.counterSuccess, - mobile.wble.onError);*/ - } + const change = prompt(`Change counter value?`, counter); + + if (change === null || !isNumeric(change)) return false; + + if (change === counter) return true; + + opts.counter = change; + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; } - navigator.notification.prompt( - `Change counter value?`, - counterPrompt, - 'INTVAL3', - ['Okay', 'Cancel'], - counter); + pwa.counterSuccess(); + }; -mobile.counterSuccess = function () { +pwa.counterSuccess = function () { console.log('Set counter'); - mobile.getState(); + pwa.getState(); }; -mobile.sequence = function () { +pwa.sequence = async function () { const opts = { type : 'sequence' }; const elem = document.getElementById('seq'); - if (!mobile.wble.connected) { - return mobile.alert('Not connected to an INTVAL3 device.'); + if (!pwa.wble.connected) { + return pwa.alert('Not connected to an INTVAL3 device.'); } - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), //check length? - mobile.sequenceSuccess, - mobile.wble.onError);*/ + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + + pwa.sequenceSuccess(); if (!elem.classList.contains('focus')) { elem.classList.add('focus'); } - mobile.wble.active = true; + pwa.wble.active = true; }; -mobile.sequenceSuccess = function () { +pwa.sequenceSuccess = function () { console.log('Sequence state changed'); - mobile.getState(); + pwa.getState(); setTimeout(() => { if (STATE.sequence) { - mobile.wble.active = true; + pwa.wble.active = true; seqState(true); } else { - mobile.wble.active = false; + pwa.wble.active = false; seqState(false); } }, 20); @@ -368,25 +472,28 @@ mobile.sequenceSuccess = function () { //retreive object with list of available Wifi APs, //and state of current connection, if available -mobile.getWifi = function () { +pwa.getWifi = async function () { + let wifiRes; UI.spinner.show('Refreshing WIFI...'); UI.overlay.show(); - /*ble.read(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.WIFI_ID, - mobile.getWifiSuccess, - mobile.wble.onError);*/ + try { + wifiRes = await pwa.wble.read(pwa.wble.WIFI_ID); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false + } + + pwa.getWifiSuccess(wifiRes); }; -mobile.getWifiSuccess = function (data) { +pwa.getWifiSuccess = function (res) { const elem = document.getElementById('available'); const wifi = document.getElementById('wifi'); const password = document.getElementById('password'); const ip = document.getElementById('ip'); let option = document.createElement('option'); - let str = bytesToString(data); - let res = JSON.parse(str); UI.spinner.hide(); UI.overlay.hide(); @@ -436,12 +543,12 @@ mobile.getWifiSuccess = function (data) { ip.classList.remove('active'); } } - mobile.wifi.current = res.current; - mobile.wifi.available = res.available; - mobile.wifi.ip = res.ip; + pwa.wifi.current = res.current; + pwa.wifi.available = res.available; + pwa.wifi.ip = res.ip; }; -mobile.editWifi = function () { +pwa.editWifi = function () { const available = document.getElementById('available'); const wifi = document.getElementById('wifi'); const password = document.getElementById('password'); @@ -452,12 +559,12 @@ mobile.editWifi = function () { password.classList.add('active'); } password.focus(); - if (available.value !== mobile.wifi.current && available.classList.contains('active')) { + if (available.value !== pwa.wifi.current && available.classList.contains('active')) { available.classList.remove('active'); } }; -mobile.setWifi = function () { +pwa.setWifi = async function () { const ssid = document.getElementById('available').value; const pwd = document.getElementById('password').value; const opts = { @@ -468,50 +575,53 @@ mobile.setWifi = function () { UI.overlay.show(); if (ssid === '' || ssid === null || ssid === undefined) { - return mobile.alert('Cannot set wireless credentials with a blank SSID'); + return pwa.alert('Cannot set wireless credentials with a blank SSID'); } if (pwd === '' || pwd === null || pwd === undefined) { - return mobile.alert('Cannot set wireless credentials with a blank passphrase'); + return pwa.alert('Cannot set wireless credentials with a blank passphrase'); } if (pwd.length < 8 || pwd.length > 63) { - return mobile.alert('Passphrase must be 8..63 characters'); + return pwa.alert('Passphrase must be 8..63 characters'); } - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.WIFI_ID, - stringToBytes(JSON.stringify(opts)), - mobile.setWifiSuccess, - mobile.wble.onError);*/ + try { + await pwa.wble.write(pwa.wble.WIFI_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; + } + pwa.setWifiSuccess(); }; -mobile.setWifiSuccess = function () { +pwa.setWifiSuccess = function () { UI.spinner.hide(); UI.overlay.hide(); console.log('Set new wifi credentials'); - setTimeout(mobile.getWifi, 100); + setTimeout(pwa.getWifi, 100); }; -mobile.exif = {} +/* +pwa.exif = {} -mobile.getCamera = function () { +pwa.getCamera = function () { const opts = { quality: 30, sourceType: Camera.PictureSourceType.CAMERA, destinationType: Camera.DestinationType.FILE_URI }; - navigator.camera.getPicture(mobile.cameraSuccess, mobile.cameraError, opts); + navigator.camera.getPicture(pwa.cameraSuccess, pwa.cameraError, opts); }; -mobile.cameraSuccess = function (result) { +pwa.cameraSuccess = function (result) { const thisResult = JSON.parse(result); const metadata = JSON.parse(thisResult.json_metadata); - mobile.cameraExposure(metadata.Exif); + pwa.cameraExposure(metadata.Exif); }; -mobile.cameraError = function (err) { +pwa.cameraError = function (err) { console.error(err); - mobile.alert(JSON.stringify(err)); + pwa.alert(JSON.stringify(err)); }; -mobile.cameraExposure = function (exif) { +pwa.cameraExposure = function (exif) { const cam_exp = document.getElementById('cam_exp'); const cam_f = document.getElementById('cam_f'); const cam_iso = document.getElementById('cam_iso'); @@ -546,7 +656,7 @@ mobile.cameraExposure = function (exif) { let e1; let e2; - mobile.exif = exif; + pwa.exif = exif; //Determine if fstop of phone camera "f" if (target !== f) { @@ -606,7 +716,7 @@ mobile.cameraExposure = function (exif) { ); } - /* + { "Exif": { "DateTimeOriginal": "2018:02:02 16:59:13", @@ -650,107 +760,93 @@ mobile.cameraExposure = function (exif) { "MeteringMode": 5 } } - */ + }; -mobile.refreshExposure = function () { - if (typeof mobile.exif.ExposureTime !== 'undefined') { - mobile.cameraExposure(mobile.exif); +pwa.refreshExposure = function () { + if (typeof pwa.exif.ExposureTime !== 'undefined') { + pwa.cameraExposure(pwa.exif); } }; -mobile.EV = function (fstop, shutter) { +pwa.EV = function (fstop, shutter) { const sec = shutter / 1000; //shutter in ms => seconds const square = Math.pow(fstop, 2); return Math.log(square / sec); -}; +};*/ -mobile.reset = function () { - let opts = { +pwa.reset = async function () { + const opts = { type : 'reset' }; - function resetConfirm (index) { - if (index === 1) { - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), - mobile.resetSuccess, - mobile.wble.onError);*/ + const cont = confirm(`Reset INTVAL3 to default settings and clear counter?`); + if (cont) { + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; } + pwa.resetSuccess(); } - navigator.notification.confirm( - `Reset INTVAL3 to default settings and clear counter?`, - resetConfirm, - 'INTVAL3', - ['Okay', 'Cancel'] - ); + }; -mobile.resetSuccess = function () { +pwa.resetSuccess = function () { console.log('Reset to default settings'); setTimeout(() => { - mobile.getState(); + pwa.getState(); }, 100) }; -mobile.update = function () { - let opts = { +pwa.update = async function () { + const opts = { type : 'update' }; - function updateConfirm (index) { - if (index === 1) { - UI.spinner.show('Updating INTVAL3...'); - UI.overlay.show(); - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), - mobile.updateSuccess, - mobile.wble.onError);*/ + const cont = confirm(`Check for updates? You will be disconnected from the INTVAL3 during this process.`); + if (cont) { + UI.spinner.show('Updating INTVAL3...'); + UI.overlay.show(); + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; } + pwa.updateSuccess(); } - navigator.notification.confirm( - `Check for updates? You will be disconnected from the INTVAL3 during this process.`, - updateConfirm, - 'INTVAL3', - ['Okay', 'Cancel'] - ); }; -mobile.updateSuccess = function () { +pwa.updateSuccess = function () { console.log('Finished updating firmware, restarting...'); }; -mobile.restart = function () { - let opts = { +pwa.restart = async function () { + const opts = { type : 'restart' }; - function restartConfirm (index) { - if (index === 1) { + const cont = confirm(`Restart the INTVAL3? You will be disconnected from it during this process.`); + if (cont) { UI.spinner.show('Restarting INTVAL3...'); UI.overlay.show(); - /*ble.write(mobile.wble.device.id, - mobile.wble.SERVICE_ID, - mobile.wble.CHAR_ID, - stringToBytes(JSON.stringify(opts)), - mobile.restartSuccess, - mobile.wble.onError);*/ + try { + await pwa.wble.write(pwa.wble.CHAR_ID, opts); + } catch (err) { + console.error(err); + pwa.wble.onError(err.message); + return false; } + pwa.restartSuccess(); } - navigator.notification.confirm( - `Restart the INTVAL3? You will be disconnected from it during this process.`, - restartConfirm, - 'INTVAL3', - ['Okay', 'Cancel'] - ); }; -mobile.restartSuccess = function () { +pwa.restartSuccess = function () { console.log('Restarting... '); } -mobile.alert = function (msg) { - if (navigator && navigator.notification) { +pwa.alert = function (msg) { + if (typeof navigator !== 'undefined' && typeof navigator.notification !== 'undefined') { navigator.notification.alert( msg, () => {},