mirror of
https://github.com/sensebox/blockly-app
synced 2025-04-08 13:30:28 +02:00
ota-wizard: implement logic for compilation slide
This commit is contained in:
parent
fce63e4ac8
commit
7ae033268b
9 changed files with 181 additions and 44 deletions
|
@ -83,6 +83,7 @@
|
||||||
<plugin name="cordova-plugin-ionic-webview" spec="^2.0.0" />
|
<plugin name="cordova-plugin-ionic-webview" spec="^2.0.0" />
|
||||||
<plugin name="cordova-plugin-ionic-keyboard" spec="^2.0.5" />
|
<plugin name="cordova-plugin-ionic-keyboard" spec="^2.0.5" />
|
||||||
<plugin name="wifiwizard2" spec="~3.1.0" />
|
<plugin name="wifiwizard2" spec="~3.1.0" />
|
||||||
|
<plugin name="cordova-plugin-network-information" spec="2.0.1" />
|
||||||
<engine name="android" spec="7.1.1" />
|
<engine name="android" spec="7.1.1" />
|
||||||
<engine name="browser" spec="5.0.4" />
|
<engine name="browser" spec="5.0.4" />
|
||||||
</widget>
|
</widget>
|
||||||
|
|
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -96,6 +96,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-4.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-4.15.0.tgz",
|
||||||
"integrity": "sha512-WlFcBktHnufiu+SB1u2GemEkDrXE94+LUkg59BQL1Tr0j+7EXcNY20JUUFCnQZP+uTJbUxaYZEa36B8UKBBpbA=="
|
"integrity": "sha512-WlFcBktHnufiu+SB1u2GemEkDrXE94+LUkg59BQL1Tr0j+7EXcNY20JUUFCnQZP+uTJbUxaYZEa36B8UKBBpbA=="
|
||||||
},
|
},
|
||||||
|
"@ionic-native/network": {
|
||||||
|
"version": "4.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ionic-native/network/-/network-4.17.0.tgz",
|
||||||
|
"integrity": "sha512-isAZx0CWIGHxl4u7GYkwkertNrSarNXhQQ4iQgqOefDJUtOj78zJsYNVxUWk1MiqTyQrnV9H7+WHWf62JAR82w=="
|
||||||
|
},
|
||||||
"@ionic-native/splash-screen": {
|
"@ionic-native/splash-screen": {
|
||||||
"version": "4.15.0",
|
"version": "4.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic-native/splash-screen/-/splash-screen-4.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic-native/splash-screen/-/splash-screen-4.15.0.tgz",
|
||||||
|
@ -1959,6 +1964,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/cordova-plugin-ionic-webview/-/cordova-plugin-ionic-webview-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/cordova-plugin-ionic-webview/-/cordova-plugin-ionic-webview-2.2.0.tgz",
|
||||||
"integrity": "sha512-mNTJaIRsz83Vntk2d3jrPCnlqEPQsfOJW6U2AzS7WV1T15Jj/STdXI/Uv1vIyvPVd9h1OLF+yu64ZsmQH2VRMQ=="
|
"integrity": "sha512-mNTJaIRsz83Vntk2d3jrPCnlqEPQsfOJW6U2AzS7WV1T15Jj/STdXI/Uv1vIyvPVd9h1OLF+yu64ZsmQH2VRMQ=="
|
||||||
},
|
},
|
||||||
|
"cordova-plugin-network-information": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cordova-plugin-network-information/-/cordova-plugin-network-information-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-6QQh9DDGq3bUCSI/Jfzvu7zhdpA="
|
||||||
|
},
|
||||||
"cordova-plugin-splashscreen": {
|
"cordova-plugin-splashscreen": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-5.0.2.tgz",
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
"@angular/platform-browser": "5.2.11",
|
"@angular/platform-browser": "5.2.11",
|
||||||
"@angular/platform-browser-dynamic": "5.2.11",
|
"@angular/platform-browser-dynamic": "5.2.11",
|
||||||
"@ionic-native/core": "~4.15.0",
|
"@ionic-native/core": "~4.15.0",
|
||||||
|
"@ionic-native/network": "^4.17.0",
|
||||||
"@ionic-native/splash-screen": "~4.15.0",
|
"@ionic-native/splash-screen": "~4.15.0",
|
||||||
"@ionic-native/status-bar": "~4.15.0",
|
"@ionic-native/status-bar": "~4.15.0",
|
||||||
"@ionic/storage": "2.2.0",
|
"@ionic/storage": "2.2.0",
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
"cordova-plugin-device": "^2.0.2",
|
"cordova-plugin-device": "^2.0.2",
|
||||||
"cordova-plugin-ionic-keyboard": "^2.1.3",
|
"cordova-plugin-ionic-keyboard": "^2.1.3",
|
||||||
"cordova-plugin-ionic-webview": "^2.2.0",
|
"cordova-plugin-ionic-webview": "^2.2.0",
|
||||||
|
"cordova-plugin-network-information": "2.0.1",
|
||||||
"cordova-plugin-splashscreen": "^5.0.2",
|
"cordova-plugin-splashscreen": "^5.0.2",
|
||||||
"cordova-plugin-statusbar": "^2.4.2",
|
"cordova-plugin-statusbar": "^2.4.2",
|
||||||
"cordova-plugin-whitelist": "^1.3.3",
|
"cordova-plugin-whitelist": "^1.3.3",
|
||||||
|
@ -56,11 +58,12 @@
|
||||||
"ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+"
|
"ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+"
|
||||||
},
|
},
|
||||||
"cordova-plugin-ionic-keyboard": {},
|
"cordova-plugin-ionic-keyboard": {},
|
||||||
"wifiwizard2": {}
|
"wifiwizard2": {},
|
||||||
|
"cordova-plugin-network-information": {}
|
||||||
},
|
},
|
||||||
"platforms": [
|
"platforms": [
|
||||||
"android",
|
"android",
|
||||||
"browser"
|
"browser"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,6 @@ import { openSenseApp } from './app.component';
|
||||||
import { HomePage } from '../pages/home/home';
|
import { HomePage } from '../pages/home/home';
|
||||||
import { ApiProvider } from '../providers/api/api';
|
import { ApiProvider } from '../providers/api/api';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { OtaWifiProvider } from '../providers/ota-wifi/ota-wifi';
|
|
||||||
import { OtaWizardPage } from '../pages/ota-wizard/ota-wizard';
|
import { OtaWizardPage } from '../pages/ota-wizard/ota-wizard';
|
||||||
import { OtaWizardPageModule } from '../pages/ota-wizard/ota-wizard.module';
|
import { OtaWizardPageModule } from '../pages/ota-wizard/ota-wizard.module';
|
||||||
|
|
||||||
|
@ -34,7 +33,6 @@ import { OtaWizardPageModule } from '../pages/ota-wizard/ota-wizard.module';
|
||||||
SplashScreen,
|
SplashScreen,
|
||||||
{provide: ErrorHandler, useClass: IonicErrorHandler},
|
{provide: ErrorHandler, useClass: IonicErrorHandler},
|
||||||
ApiProvider,
|
ApiProvider,
|
||||||
OtaWifiProvider
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
||||||
import { OtaWifiProvider } from '../../providers/ota-wifi/ota-wifi';
|
|
||||||
import { OtaWizardPage } from '../ota-wizard/ota-wizard';
|
import { OtaWizardPage } from '../ota-wizard/ota-wizard';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,13 +18,7 @@ export class BlocklyPage {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public navCtrl: NavController,
|
public navCtrl: NavController,
|
||||||
public navParams: NavParams,
|
public navParams: NavParams) {
|
||||||
private otaWifi: OtaWifiProvider) {
|
|
||||||
// otaWifi is here only for testing, should later be encapsulated by OtaWizardComponent
|
|
||||||
console.log('wifi strategy:', otaWifi.strategy)
|
|
||||||
otaWifi.findSenseboxes()
|
|
||||||
.then(console.log)
|
|
||||||
.catch(console.error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ionViewDidLoad() {
|
ionViewDidLoad() {
|
||||||
|
|
|
@ -38,12 +38,33 @@
|
||||||
</ion-grid>
|
</ion-grid>
|
||||||
</ion-slide>
|
</ion-slide>
|
||||||
|
|
||||||
|
<!-- compilation waiting screen -->
|
||||||
<ion-slide>
|
<ion-slide>
|
||||||
<h1>Check internet connection for compilation</h1>
|
<ng-container *ngIf="state.compilation == 'compiling'">
|
||||||
<pre style="text-align: left">
|
<h2>Compiling your sketch...</h2>
|
||||||
- if connected: background: compile code
|
<ion-spinner item-start name="dots"></ion-spinner>
|
||||||
- if not: enable wifi (manually on iOS)
|
</ng-container>
|
||||||
</pre>
|
|
||||||
|
<ng-container *ngIf="state.compilation == 'go-online'">
|
||||||
|
<h2>You are offline.</h2>
|
||||||
|
<p>
|
||||||
|
For compilation, you need to connect to the internet.
|
||||||
|
Please enable a connection.
|
||||||
|
</p>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="state.compilation == 'done'">
|
||||||
|
<h2>Sketch successfully compiled.</h2>
|
||||||
|
<button ion-button large clear icon-end color="primary" (click)="slides.slideNext()">
|
||||||
|
Continue
|
||||||
|
<ion-icon name="arrow-forward"></ion-icon>
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="state.compilation == 'error'">
|
||||||
|
<h2>Error compiling your sketch.</h2>
|
||||||
|
<!-- TODO <p>{{ status }}</p> -->
|
||||||
|
</ng-container>
|
||||||
</ion-slide>
|
</ion-slide>
|
||||||
|
|
||||||
<ion-slide>
|
<ion-slide>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { IonicPageModule } from 'ionic-angular';
|
import { IonicPageModule } from 'ionic-angular';
|
||||||
import { OtaWizardPage } from './ota-wizard';
|
import { OtaWizardPage } from './ota-wizard';
|
||||||
|
import { Network } from '@ionic-native/network';
|
||||||
|
import { OtaWifiProvider } from '../../providers/ota-wifi/ota-wifi';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -9,5 +11,9 @@ import { OtaWizardPage } from './ota-wizard';
|
||||||
imports: [
|
imports: [
|
||||||
IonicPageModule.forChild(OtaWizardPage),
|
IonicPageModule.forChild(OtaWizardPage),
|
||||||
],
|
],
|
||||||
|
providers: [
|
||||||
|
Network,
|
||||||
|
OtaWifiProvider,
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class OtaWizardPageModule {}
|
export class OtaWizardPageModule {}
|
||||||
|
|
|
@ -1,25 +1,132 @@
|
||||||
import { Component } from '@angular/core';
|
import {
|
||||||
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
Component,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core'
|
||||||
|
import {
|
||||||
|
IonicPage,
|
||||||
|
Slides,
|
||||||
|
} from 'ionic-angular'
|
||||||
|
import { Network } from '@ionic-native/network'
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
/**
|
import { OtaWifiProvider, WifiStrategy } from '../../providers/ota-wifi/ota-wifi';
|
||||||
* Generated class for the OtaWizardPage page.
|
|
||||||
*
|
|
||||||
* See https://ionicframework.com/docs/components/#navigation for more info on
|
|
||||||
* Ionic pages and navigation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@IonicPage()
|
@IonicPage()
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page-ota-wizard',
|
selector: 'page-ota-wizard',
|
||||||
templateUrl: 'ota-wizard.html',
|
templateUrl: 'ota-wizard.html',
|
||||||
})
|
})
|
||||||
export class OtaWizardPage {
|
export class OtaWizardPage implements OnInit, OnDestroy {
|
||||||
|
@ViewChild(Slides) slides: Slides
|
||||||
|
onlineSub: Subscription
|
||||||
|
offlineSub: Subscription
|
||||||
|
|
||||||
constructor(public navCtrl: NavController, public navParams: NavParams) {
|
compilationFailed: boolean
|
||||||
|
|
||||||
|
state: OtaState = {
|
||||||
|
isOnline: false,
|
||||||
|
compiledSketch: undefined,
|
||||||
|
compilation: 'compiling',
|
||||||
}
|
}
|
||||||
|
|
||||||
ionViewDidLoad() {
|
constructor(
|
||||||
console.log('ionViewDidLoad OtaWizardPage');
|
private network: Network,
|
||||||
|
private otaWifi: OtaWifiProvider,
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
// try to start compilation already in the background
|
||||||
|
this.compileSketch()
|
||||||
|
|
||||||
|
this.state.isOnline = this.network.type !== 'none'
|
||||||
|
|
||||||
|
this.onlineSub = this.network.onConnect().subscribe(() => {
|
||||||
|
this.state.isOnline = true
|
||||||
|
// trigger compilation, only when needed
|
||||||
|
if (this.state.compilation == 'go-online') this.compileSketch()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.offlineSub = this.network.onDisconnect().subscribe(() => {
|
||||||
|
this.state.isOnline = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy () {
|
||||||
|
this.onlineSub.unsubscribe()
|
||||||
|
this.offlineSub.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// call logic for each slide
|
||||||
|
onSlideChange () {
|
||||||
|
switch (this.slides.getActiveIndex()) {
|
||||||
|
case OtaSlides.Intro:
|
||||||
|
this.slides.lockSwipeToNext(false)
|
||||||
|
break
|
||||||
|
|
||||||
|
case OtaSlides.Compilation:
|
||||||
|
this.handleCompilation()
|
||||||
|
break
|
||||||
|
|
||||||
|
case OtaSlides.WifiSelection:
|
||||||
|
this.handleWifiSelection()
|
||||||
|
break
|
||||||
|
|
||||||
|
case OtaSlides.Status:
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.warn('unknown slide, please define its logic')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleCompilation () {
|
||||||
|
this.slides.lockSwipeToNext(!this.state.compiledSketch)
|
||||||
|
|
||||||
|
// need to go online for compilation. compilation is retriggered via this.onlineSub
|
||||||
|
if (!this.state.compiledSketch && !this.state.isOnline) {
|
||||||
|
switch (this.otaWifi.strategy) {
|
||||||
|
case WifiStrategy.Automatic:
|
||||||
|
// TODO: auto connect to previous network, if available
|
||||||
|
default:
|
||||||
|
this.state.compilation = 'go-online'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleWifiSelection () {
|
||||||
|
this.slides.lockSwipeToNext(true)
|
||||||
|
|
||||||
|
console.log('wifi strategy:', this.otaWifi.strategy)
|
||||||
|
this.otaWifi.findSenseboxes()
|
||||||
|
.then(console.log)
|
||||||
|
.catch(console.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
private compileSketch () {
|
||||||
|
// TODO: mock
|
||||||
|
this.state.compilation = 'compiling'
|
||||||
|
setTimeout(() => {
|
||||||
|
this.state.compiledSketch = 'firmware binary here..'
|
||||||
|
this.state.compilation = 'done'
|
||||||
|
this.slides.lockSwipeToNext(false)
|
||||||
|
}, 4000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type OtaState = {
|
||||||
|
isOnline: boolean,
|
||||||
|
compiledSketch: any,
|
||||||
|
compilation: 'compiling' | 'go-online' | 'done' | 'error',
|
||||||
|
}
|
||||||
|
|
||||||
|
// names for the slide indices for easier access
|
||||||
|
enum OtaSlides {
|
||||||
|
Intro = 0,
|
||||||
|
Compilation = 1,
|
||||||
|
WifiSelection = 2,
|
||||||
|
Status = 3,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,32 +17,30 @@ export class OtaWifiProvider {
|
||||||
public strategy: WifiStrategy
|
public strategy: WifiStrategy
|
||||||
|
|
||||||
constructor(private platform: Platform, private http: HttpClient) {
|
constructor(private platform: Platform, private http: HttpClient) {
|
||||||
this.selectStrategy()
|
this.strategy = this.selectStrategy()
|
||||||
}
|
}
|
||||||
|
|
||||||
private selectStrategy (): WifiStrategy {
|
private selectStrategy (): WifiStrategy {
|
||||||
try {
|
try {
|
||||||
// check if plugin is available (e.g. not in browser builds)
|
// check if plugin is available (e.g. not in browser builds)
|
||||||
WifiWizard2
|
WifiWizard2
|
||||||
|
|
||||||
if (
|
|
||||||
this.platform.is('android') ||
|
|
||||||
this.platform.is('ios') && this.platform.version().major >= 11
|
|
||||||
) {
|
|
||||||
this.strategy = WifiStrategy.Automatic
|
|
||||||
} else {
|
|
||||||
this.strategy = WifiStrategy.Manual
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.strategy = WifiStrategy.Unavailable
|
return WifiStrategy.Unavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.strategy;
|
if (
|
||||||
|
this.platform.is('android') ||
|
||||||
|
this.platform.is('ios') && this.platform.version().major >= 11
|
||||||
|
) {
|
||||||
|
return WifiStrategy.Automatic
|
||||||
|
}
|
||||||
|
|
||||||
|
return WifiStrategy.Manual
|
||||||
}
|
}
|
||||||
|
|
||||||
async findSenseboxes (): Promise<string> {
|
async findSenseboxes (): Promise<string> {
|
||||||
if (this.strategy != WifiStrategy.Automatic)
|
if (this.strategy != WifiStrategy.Automatic)
|
||||||
throw Error('can not search for WiFi networks on this platform')
|
throw new Error('can not search for WiFi networks on this platform')
|
||||||
|
|
||||||
return WifiWizard2.scan()
|
return WifiWizard2.scan()
|
||||||
.then(n => n.filter(n.SSID.includes(SSID_PREFIX)))
|
.then(n => n.filter(n.SSID.includes(SSID_PREFIX)))
|
||||||
|
@ -51,7 +49,7 @@ export class OtaWifiProvider {
|
||||||
|
|
||||||
async connectToSensebox (ssid: string): Promise<any> {
|
async connectToSensebox (ssid: string): Promise<any> {
|
||||||
if (this.strategy != WifiStrategy.Automatic)
|
if (this.strategy != WifiStrategy.Automatic)
|
||||||
throw Error('can not connect to WiFi network on this platform')
|
throw new Error('can not connect to WiFi network on this platform')
|
||||||
|
|
||||||
return this.platform.is('ios')
|
return this.platform.is('ios')
|
||||||
? WifiWizard2.iOSConnectNetwork(ssid)
|
? WifiWizard2.iOSConnectNetwork(ssid)
|
||||||
|
@ -66,7 +64,7 @@ export class OtaWifiProvider {
|
||||||
|
|
||||||
// TODO: replace with "WifiCapabilities".
|
// TODO: replace with "WifiCapabilities".
|
||||||
// makes it easier to check in each functions if required functionality is available
|
// makes it easier to check in each functions if required functionality is available
|
||||||
enum WifiStrategy {
|
export enum WifiStrategy {
|
||||||
Automatic = 'Automatic', // android, iOS 11+
|
Automatic = 'Automatic', // android, iOS 11+
|
||||||
Manual = 'Manual', // older iOS
|
Manual = 'Manual', // older iOS
|
||||||
Unavailable = 'Unavailable', // browser
|
Unavailable = 'Unavailable', // browser
|
||||||
|
|
Loading…
Add table
Reference in a new issue