initial push
31
echo-mobile-app/echo/.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# Specifies intentionally untracked files to ignore when using Git
|
||||
# http://git-scm.com/docs/gitignore
|
||||
|
||||
*~
|
||||
*.sw[mnpcod]
|
||||
.tmp
|
||||
*.tmp
|
||||
*.tmp.*
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
UserInterfaceState.xcuserstate
|
||||
$RECYCLE.BIN/
|
||||
|
||||
*.log
|
||||
log.txt
|
||||
npm-debug.log*
|
||||
|
||||
/.idea
|
||||
/.ionic
|
||||
/.sass-cache
|
||||
/.sourcemaps
|
||||
/.versions
|
||||
/.vscode
|
||||
/coverage
|
||||
/dist
|
||||
/node_modules
|
||||
/platforms
|
||||
/plugins
|
||||
/www
|
187
echo-mobile-app/echo/angular.json
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"defaultProject": "app",
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"app": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "www",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*.svg",
|
||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||
"output": "./svg"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
{
|
||||
"input": "src/theme/variables.scss"
|
||||
},
|
||||
{
|
||||
"input": "src/global.scss"
|
||||
}
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ci": {
|
||||
"progress": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
},
|
||||
"ci": {
|
||||
"progress": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"styles": [],
|
||||
"scripts": [],
|
||||
"assets": [
|
||||
{
|
||||
"glob": "favicon.ico",
|
||||
"input": "src/",
|
||||
"output": "/"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/assets",
|
||||
"output": "/assets"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"progress": false,
|
||||
"watch": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
],
|
||||
"exclude": ["**/node_modules/**"]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "app:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "app:serve:production"
|
||||
},
|
||||
"ci": {
|
||||
"devServerTarget": "app:serve:ci"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionic-cordova-build": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-build",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionic-cordova-serve": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-serve",
|
||||
"options": {
|
||||
"cordovaBuildTarget": "app:ionic-cordova-build",
|
||||
"devServerTarget": "app:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"cordovaBuildTarget": "app:ionic-cordova-build:production",
|
||||
"devServerTarget": "app:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"defaultCollection": "@ionic/angular-toolkit"
|
||||
},
|
||||
"schematics": {
|
||||
"@ionic/angular-toolkit:component": {
|
||||
"styleext": "scss"
|
||||
},
|
||||
"@ionic/angular-toolkit:page": {
|
||||
"styleext": "scss"
|
||||
}
|
||||
}
|
||||
}
|
12
echo-mobile-app/echo/browserslist
Normal file
@@ -0,0 +1,12 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
110
echo-mobile-app/echo/config.xml
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="io.ionic.starter" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>Echo</name>
|
||||
<description>Home Control made by Nick Leeman</description>
|
||||
<author email="hi@ionicframework.com" href="http://ionicframework.com/">Nick Leeman</author>
|
||||
<content src="index.html" />
|
||||
<access origin="*" />
|
||||
<preferance name="android-usesCleartextTraffic" value="true" />
|
||||
<allow-navigation href="*" />
|
||||
<allow-intent href="http://*/*" />
|
||||
<allow-intent href="https://*/*" />
|
||||
<allow-intent href="tel:*" />
|
||||
<allow-intent href="sms:*" />
|
||||
<allow-intent href="mailto:*" />
|
||||
<allow-intent href="geo:*" />
|
||||
<preference name="ScrollEnabled" value="false" />
|
||||
<preference name="android-minSdkVersion" value="19" />
|
||||
<preference name="BackupWebStorage" value="none" />
|
||||
<preference name="SplashMaintainAspectRatio" value="true" />
|
||||
<preference name="FadeSplashScreenDuration" value="300" />
|
||||
<preference name="SplashShowOnlyFirstTime" value="false" />
|
||||
<preference name="SplashScreen" value="screen" />
|
||||
<preference name="SplashScreenDelay" value="3000" />
|
||||
<platform name="android">
|
||||
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:usesCleartextTraffic="true" />
|
||||
<application android:networkSecurityConfig="@xml/network_security_config" />
|
||||
</edit-config>
|
||||
<resource-file src="resources/android/xml/network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" />
|
||||
<allow-intent href="market:*" />
|
||||
<icon density="ldpi" src="resources/android/icon/drawable-ldpi-icon.png" />
|
||||
<icon density="mdpi" src="resources/android/icon/drawable-mdpi-icon.png" />
|
||||
<icon density="hdpi" src="resources/android/icon/drawable-hdpi-icon.png" />
|
||||
<icon density="xhdpi" src="resources/android/icon/drawable-xhdpi-icon.png" />
|
||||
<icon density="xxhdpi" src="resources/android/icon/drawable-xxhdpi-icon.png" />
|
||||
<icon density="xxxhdpi" src="resources/android/icon/drawable-xxxhdpi-icon.png" />
|
||||
<splash density="land-ldpi" src="resources/android/splash/drawable-land-ldpi-screen.png" />
|
||||
<splash density="land-mdpi" src="resources/android/splash/drawable-land-mdpi-screen.png" />
|
||||
<splash density="land-hdpi" src="resources/android/splash/drawable-land-hdpi-screen.png" />
|
||||
<splash density="land-xhdpi" src="resources/android/splash/drawable-land-xhdpi-screen.png" />
|
||||
<splash density="land-xxhdpi" src="resources/android/splash/drawable-land-xxhdpi-screen.png" />
|
||||
<splash density="land-xxxhdpi" src="resources/android/splash/drawable-land-xxxhdpi-screen.png" />
|
||||
<splash density="port-ldpi" src="resources/android/splash/drawable-port-ldpi-screen.png" />
|
||||
<splash density="port-mdpi" src="resources/android/splash/drawable-port-mdpi-screen.png" />
|
||||
<splash density="port-hdpi" src="resources/android/splash/drawable-port-hdpi-screen.png" />
|
||||
<splash density="port-xhdpi" src="resources/android/splash/drawable-port-xhdpi-screen.png" />
|
||||
<splash density="port-xxhdpi" src="resources/android/splash/drawable-port-xxhdpi-screen.png" />
|
||||
<splash density="port-xxxhdpi" src="resources/android/splash/drawable-port-xxxhdpi-screen.png" />
|
||||
</platform>
|
||||
<platform name="ios">
|
||||
<allow-intent href="itms:*" />
|
||||
<allow-intent href="itms-apps:*" />
|
||||
<icon height="57" src="resources/ios/icon/icon.png" width="57" />
|
||||
<icon height="114" src="resources/ios/icon/icon@2x.png" width="114" />
|
||||
<icon height="29" src="resources/ios/icon/icon-small.png" width="29" />
|
||||
<icon height="58" src="resources/ios/icon/icon-small@2x.png" width="58" />
|
||||
<icon height="87" src="resources/ios/icon/icon-small@3x.png" width="87" />
|
||||
<icon height="20" src="resources/ios/icon/icon-20.png" width="20" />
|
||||
<icon height="40" src="resources/ios/icon/icon-20@2x.png" width="40" />
|
||||
<icon height="60" src="resources/ios/icon/icon-20@3x.png" width="60" />
|
||||
<icon height="48" src="resources/ios/icon/icon-24@2x.png" width="48" />
|
||||
<icon height="55" src="resources/ios/icon/icon-27.5@2x.png" width="55" />
|
||||
<icon height="29" src="resources/ios/icon/icon-29.png" width="29" />
|
||||
<icon height="58" src="resources/ios/icon/icon-29@2x.png" width="58" />
|
||||
<icon height="87" src="resources/ios/icon/icon-29@3x.png" width="87" />
|
||||
<icon height="40" src="resources/ios/icon/icon-40.png" width="40" />
|
||||
<icon height="80" src="resources/ios/icon/icon-40@2x.png" width="80" />
|
||||
<icon height="120" src="resources/ios/icon/icon-40@3x.png" width="120" />
|
||||
<icon height="88" src="resources/ios/icon/icon-44@2x.png" width="88" />
|
||||
<icon height="50" src="resources/ios/icon/icon-50.png" width="50" />
|
||||
<icon height="100" src="resources/ios/icon/icon-50@2x.png" width="100" />
|
||||
<icon height="60" src="resources/ios/icon/icon-60.png" width="60" />
|
||||
<icon height="120" src="resources/ios/icon/icon-60@2x.png" width="120" />
|
||||
<icon height="180" src="resources/ios/icon/icon-60@3x.png" width="180" />
|
||||
<icon height="72" src="resources/ios/icon/icon-72.png" width="72" />
|
||||
<icon height="144" src="resources/ios/icon/icon-72@2x.png" width="144" />
|
||||
<icon height="76" src="resources/ios/icon/icon-76.png" width="76" />
|
||||
<icon height="152" src="resources/ios/icon/icon-76@2x.png" width="152" />
|
||||
<icon height="167" src="resources/ios/icon/icon-83.5@2x.png" width="167" />
|
||||
<icon height="172" src="resources/ios/icon/icon-86@2x.png" width="172" />
|
||||
<icon height="196" src="resources/ios/icon/icon-98@2x.png" width="196" />
|
||||
<icon height="1024" src="resources/ios/icon/icon-1024.png" width="1024" />
|
||||
<splash height="480" src="resources/ios/splash/Default~iphone.png" width="320" />
|
||||
<splash height="960" src="resources/ios/splash/Default@2x~iphone.png" width="640" />
|
||||
<splash height="1024" src="resources/ios/splash/Default-Portrait~ipad.png" width="768" />
|
||||
<splash height="768" src="resources/ios/splash/Default-Landscape~ipad.png" width="1024" />
|
||||
<splash height="1125" src="resources/ios/splash/Default-Landscape-2436h.png" width="2436" />
|
||||
<splash height="1242" src="resources/ios/splash/Default-Landscape-736h.png" width="2208" />
|
||||
<splash height="2048" src="resources/ios/splash/Default-Portrait@2x~ipad.png" width="1536" />
|
||||
<splash height="1536" src="resources/ios/splash/Default-Landscape@2x~ipad.png" width="2048" />
|
||||
<splash height="2732" src="resources/ios/splash/Default-Portrait@~ipadpro.png" width="2048" />
|
||||
<splash height="2048" src="resources/ios/splash/Default-Landscape@~ipadpro.png" width="2732" />
|
||||
<splash height="1136" src="resources/ios/splash/Default-568h@2x~iphone.png" width="640" />
|
||||
<splash height="1334" src="resources/ios/splash/Default-667h.png" width="750" />
|
||||
<splash height="2208" src="resources/ios/splash/Default-736h.png" width="1242" />
|
||||
<splash height="2436" src="resources/ios/splash/Default-2436h.png" width="1125" />
|
||||
<splash height="2732" src="resources/ios/splash/Default@2x~universal~anyany.png" width="2732" />
|
||||
<icon height="216" src="resources/ios/icon/icon-108@2x.png" width="216" />
|
||||
<splash height="2688" src="resources/ios/splash/Default-2688h~iphone.png" width="1242" />
|
||||
<splash height="1242" src="resources/ios/splash/Default-Landscape-2688h~iphone.png" width="2688" />
|
||||
<splash height="1792" src="resources/ios/splash/Default-1792h~iphone.png" width="828" />
|
||||
<splash height="828" src="resources/ios/splash/Default-Landscape-1792h~iphone.png" width="1792" />
|
||||
</platform>
|
||||
<plugin name="cordova-plugin-whitelist" spec="1.3.3" />
|
||||
<plugin name="cordova-plugin-statusbar" spec="2.4.2" />
|
||||
<plugin name="cordova-plugin-device" spec="2.0.2" />
|
||||
<plugin name="cordova-plugin-splashscreen" spec="5.0.2" />
|
||||
<plugin name="cordova-plugin-ionic-webview" spec="^4.0.0" />
|
||||
<plugin name="cordova-plugin-ionic-keyboard" spec="^2.0.5" />
|
||||
</widget>
|
28
echo-mobile-app/echo/e2e/protractor.conf.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
14
echo-mobile-app/echo/e2e/src/app.e2e-spec.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('new App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should be blank', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toContain('The world is your oyster.');
|
||||
});
|
||||
});
|
11
echo-mobile-app/echo/e2e/src/app.po.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.deepCss('app-root ion-content')).getText();
|
||||
}
|
||||
}
|
13
echo-mobile-app/echo/e2e/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
7
echo-mobile-app/echo/ionic.config.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "echo",
|
||||
"integrations": {
|
||||
"cordova": {}
|
||||
},
|
||||
"type": "angular"
|
||||
}
|
31
echo-mobile-app/echo/karma.conf.js
Normal file
@@ -0,0 +1,31 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../coverage'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
12580
echo-mobile-app/echo/package-lock.json
generated
Normal file
83
echo-mobile-app/echo/package.json
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"name": "echo",
|
||||
"version": "0.0.1",
|
||||
"author": "Ionic Framework",
|
||||
"homepage": "https://ionicframework.com/",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build --prod",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "~8.1.2",
|
||||
"@angular/core": "~8.1.2",
|
||||
"@angular/forms": "~8.1.2",
|
||||
"@angular/platform-browser": "~8.1.2",
|
||||
"@angular/platform-browser-dynamic": "~8.1.2",
|
||||
"@angular/router": "~8.1.2",
|
||||
"@ionic-native/core": "^5.0.0",
|
||||
"@ionic-native/splash-screen": "^5.0.0",
|
||||
"@ionic-native/status-bar": "^5.0.0",
|
||||
"@ionic/angular": "^4.7.1",
|
||||
"chart.js": "^2.9.3",
|
||||
"cordova-android": "8.1.0",
|
||||
"core-js": "^2.5.4",
|
||||
"ng2-charts": "^2.3.0",
|
||||
"ngx-color": "^5.1.4",
|
||||
"rxjs": "~6.5.1",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect": "~0.801.2",
|
||||
"@angular-devkit/build-angular": "~0.801.2",
|
||||
"@angular-devkit/core": "~8.1.2",
|
||||
"@angular-devkit/schematics": "~8.1.2",
|
||||
"@angular/cli": "~8.1.2",
|
||||
"@angular/compiler": "~8.1.2",
|
||||
"@angular/compiler-cli": "~8.1.2",
|
||||
"@angular/language-service": "~8.1.2",
|
||||
"@ionic/angular-toolkit": "^2.1.1",
|
||||
"@types/jasmine": "~3.3.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "~8.9.4",
|
||||
"codelyzer": "^5.0.0",
|
||||
"cordova-plugin-device": "^2.0.2",
|
||||
"cordova-plugin-ionic-keyboard": "^2.2.0",
|
||||
"cordova-plugin-ionic-webview": "^4.1.3",
|
||||
"cordova-plugin-splashscreen": "^5.0.2",
|
||||
"cordova-plugin-statusbar": "^2.4.2",
|
||||
"cordova-plugin-whitelist": "^1.3.3",
|
||||
"jasmine-core": "~3.4.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~4.1.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
||||
"karma-jasmine": "~2.0.1",
|
||||
"karma-jasmine-html-reporter": "^1.4.0",
|
||||
"protractor": "~5.4.0",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.15.0",
|
||||
"typescript": "~3.4.3"
|
||||
},
|
||||
"description": "An Ionic project",
|
||||
"cordova": {
|
||||
"plugins": {
|
||||
"cordova-plugin-whitelist": {},
|
||||
"cordova-plugin-statusbar": {},
|
||||
"cordova-plugin-device": {},
|
||||
"cordova-plugin-splashscreen": {},
|
||||
"cordova-plugin-ionic-webview": {
|
||||
"ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+"
|
||||
},
|
||||
"cordova-plugin-ionic-keyboard": {}
|
||||
},
|
||||
"platforms": [
|
||||
"android"
|
||||
]
|
||||
}
|
||||
}
|
8
echo-mobile-app/echo/resources/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
These are Cordova resources. You can replace icon.png and splash.png and run
|
||||
`ionic cordova resources` to generate custom icons and splash screens for your
|
||||
app. See `ionic cordova resources --help` for details.
|
||||
|
||||
Cordova reference documentation:
|
||||
|
||||
- Icons: https://cordova.apache.org/docs/en/latest/config_ref/images.html
|
||||
- Splash Screens: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-splashscreen/
|
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 211 KiB |
After Width: | Height: | Size: 325 KiB |
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true">
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">localhost</domain>
|
||||
<domain includeSubdomains="true">86.87.42.42</domain>
|
||||
<domain includeSubdomains="true">192.168.100.231</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
BIN
echo-mobile-app/echo/resources/icon.png
Normal file
After Width: | Height: | Size: 98 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-1024.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-108@2x.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-20.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-20@2x.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-20@3x.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-24@2x.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-27.5@2x.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-29.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-29@2x.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-29@3x.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-40.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-40@2x.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-40@3x.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-44@2x.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-50.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-50@2x.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-60.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-60@2x.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-60@3x.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-72.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-72@2x.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-76.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-76@2x.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-83.5@2x.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-86@2x.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-98@2x.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-small.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-small@2x.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon-small@3x.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
echo-mobile-app/echo/resources/ios/icon/icon@2x.png
Normal file
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 257 KiB |
BIN
echo-mobile-app/echo/resources/ios/splash/Default-2436h.png
Normal file
After Width: | Height: | Size: 470 KiB |
After Width: | Height: | Size: 470 KiB |
After Width: | Height: | Size: 88 KiB |
BIN
echo-mobile-app/echo/resources/ios/splash/Default-667h.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
echo-mobile-app/echo/resources/ios/splash/Default-736h.png
Normal file
After Width: | Height: | Size: 406 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 208 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 335 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 76 KiB |
BIN
echo-mobile-app/echo/resources/ios/splash/Default@2x~iphone.png
Normal file
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 194 KiB |
BIN
echo-mobile-app/echo/resources/ios/splash/Default~iphone.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
echo-mobile-app/echo/resources/splash.png
Normal file
After Width: | Height: | Size: 220 KiB |
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { AirconditioningPage } from './airconditioning.page';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AirconditioningPage
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AirconditioningPageRoutingModule {}
|
@@ -0,0 +1,23 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { AirconditioningPageRoutingModule } from './airconditioning-routing.module';
|
||||
|
||||
import { AirconditioningPage } from './airconditioning.page';
|
||||
|
||||
import { ChartsModule } from 'ng2-charts';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
AirconditioningPageRoutingModule,
|
||||
ChartsModule
|
||||
],
|
||||
declarations: [AirconditioningPage]
|
||||
})
|
||||
export class AirconditioningPageModule {}
|
@@ -0,0 +1,87 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Airconditioning</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-grid>
|
||||
|
||||
<ion-row justify-content-center text-center class="ac-status-row">
|
||||
<ion-col>
|
||||
<div class="ac-status">
|
||||
<h3 class="ac-heading">Current Status:</h3>
|
||||
<ion-badge class="ac-status-badge" color="danger" *ngIf="mainAirConditionerStatus == false">Powered Off</ion-badge>
|
||||
<ion-badge class="ac-status-badge" color="success" *ngIf="mainAirConditionerStatus == true">Powered On</ion-badge>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="status">
|
||||
<ion-icon name="wifi" class="status-icon"></ion-icon><span class="status-heading">Target temperature</span>
|
||||
<p class="status-value">{{getCurrentTargetTemperature()}} °C</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
|
||||
<ion-col>
|
||||
<div class="status">
|
||||
<ion-icon name="thermometer" class="status-icon"></ion-icon><span class="status-heading">Current temperature</span>
|
||||
<p class="status-value">{{getCurrentTemperature()}} °C</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<div class="status">
|
||||
<ion-icon name="water" class="status-icon"></ion-icon><span class="status-heading">Current humidity</span>
|
||||
<p class="status-value">{{getCurrentHumidity()}} %</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
|
||||
<ion-col>
|
||||
<div class="status">
|
||||
<ion-icon name="speedometer" class="status-icon"></ion-icon><span class="status-heading">Current speed</span>
|
||||
<p class="status-value">{{getCurrentSpeed()}}</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<div class="status">
|
||||
<ion-icon name="cog" class="status-icon"></ion-icon><span class="status-heading">Current mode</span>
|
||||
<p class="status-value">{{getCurrentMode()}}</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
</ion-row>
|
||||
|
||||
<ion-row class="control-row">
|
||||
<div class="control-col">
|
||||
<ion-col>
|
||||
<ion-button class="control-button" (click)="switchMainAirConditioner()"><ion-icon class="control-button-icon" name="power"></ion-icon></ion-button>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<ion-button class="control-button" (click)="openTargetTemperaturePicker()"><ion-icon class="control-button-icon" name="wifi"></ion-icon></ion-button>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<ion-button class="control-button" (click)="setMainAirConditionerSpeed()"><ion-icon class="control-button-icon" name="speedometer"></ion-icon></ion-button>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<ion-button class="control-button" (click)="openModePicker()"><ion-icon class="control-button-icon" name="cog"></ion-icon></ion-button>
|
||||
</ion-col>
|
||||
</div>
|
||||
</ion-row>
|
||||
|
||||
</ion-grid>
|
||||
</ion-content>
|
||||
|
@@ -0,0 +1,63 @@
|
||||
.ac-status {
|
||||
background-color:#142a37;
|
||||
border-radius: .3rem;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.ac-heading {
|
||||
margin-top: 0;
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ac-status-row {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.control-row {
|
||||
position:absolute;
|
||||
bottom:20px;
|
||||
left:50%;
|
||||
margin-left:-168px;
|
||||
}
|
||||
|
||||
.control-button {
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.control-button-icon {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.status {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #3e4d5b;
|
||||
padding: 6px;
|
||||
padding-top: 0px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.status-heading {
|
||||
font-size: 15px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 4px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { AirconditioningPage } from './airconditioning.page';
|
||||
|
||||
describe('AirconditioningPage', () => {
|
||||
let component: AirconditioningPage;
|
||||
let fixture: ComponentFixture<AirconditioningPage>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AirconditioningPage ],
|
||||
imports: [IonicModule.forRoot()]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AirconditioningPage);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,206 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { PickerController } from '@ionic/angular';
|
||||
import { ControllerService } from '../services/controller.service';
|
||||
import { UIService } from '../services/ui.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-airconditioning',
|
||||
templateUrl: './airconditioning.page.html',
|
||||
styleUrls: ['./airconditioning.page.scss'],
|
||||
})
|
||||
export class AirconditioningPage implements OnInit {
|
||||
|
||||
echoDevices: Object;
|
||||
echoClimateData: Object;
|
||||
|
||||
mainAirConditioner = this.controllerService.echoDeviceUUIDS['Main Air Conditioner'];
|
||||
mainAirConditionerStatus: Boolean;
|
||||
|
||||
constructor(public pickerController: PickerController, public controllerService: ControllerService, public uiService: UIService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.controllerService.echoDevices.subscribe(data => { this.echoDevices = data});
|
||||
this.controllerService.echoClimateLog.subscribe(data => { this.echoClimateData = data});
|
||||
}
|
||||
|
||||
ionViewWillEnter() {
|
||||
this.controllerService.updateAllData();
|
||||
setInterval(() => this.updateDeviceStatus(), 1000);
|
||||
this.updateDeviceStatus();
|
||||
}
|
||||
|
||||
updateDeviceStatus = async () => {
|
||||
if(this.echoDevices.hasOwnProperty(this.mainAirConditioner)) {
|
||||
if((this.echoDevices[this.mainAirConditioner]['status'] == "on") || (this.echoDevices[this.mainAirConditioner]['status'] == "busy")) {
|
||||
this.mainAirConditionerStatus = true;
|
||||
} else {
|
||||
this.mainAirConditionerStatus = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentSpeed = () => {
|
||||
if(this.echoDevices.hasOwnProperty(this.mainAirConditioner)) {
|
||||
let speed = this.echoDevices[this.mainAirConditioner]['fan_speed'];
|
||||
return speed.charAt(0).toUpperCase() + speed.substring(1);
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentMode = () => {
|
||||
if(this.echoDevices.hasOwnProperty(this.mainAirConditioner)) {
|
||||
let mode = this.echoDevices[this.mainAirConditioner]['mode'];
|
||||
return mode.charAt(0).toUpperCase() + mode.substring(1);
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentTemperature = () => {
|
||||
if(this.echoClimateData.hasOwnProperty('temperature')) {
|
||||
return this.echoClimateData['temperature'].toString().replace('.', ',');
|
||||
} else {
|
||||
return "...";
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentHumidity = () => {
|
||||
if(this.echoClimateData.hasOwnProperty('humidity')) {
|
||||
return this.echoClimateData['humidity'].toString().replace('.', ',');
|
||||
} else {
|
||||
return "...";
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentTargetTemperature = () => {
|
||||
if(this.echoDevices.hasOwnProperty(this.mainAirConditioner)) {
|
||||
return this.echoDevices[this.mainAirConditioner]['target_temperature'].toString();
|
||||
} else {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
setMainAirConditionerSpeed = async () => {
|
||||
let new_speed;
|
||||
|
||||
if (this.echoDevices[this.mainAirConditioner]['mode'] == "low") {
|
||||
new_speed = "high"
|
||||
}
|
||||
|
||||
if (this.echoDevices[this.mainAirConditioner]['mode'] == "high") {
|
||||
new_speed = "low"
|
||||
}
|
||||
|
||||
let response = await this.controllerService.handleDeviceAction(this.mainAirConditioner, "set_fan_speed", new_speed);
|
||||
await this.uiService.presentToast(response['message']);
|
||||
}
|
||||
|
||||
switchMainAirConditioner = async () => {
|
||||
let action;
|
||||
|
||||
if(this.mainAirConditionerStatus == false){
|
||||
action = "on";
|
||||
} else {
|
||||
action = "off";
|
||||
}
|
||||
|
||||
let response = await this.controllerService.handleDeviceAction(this.mainAirConditioner, action);
|
||||
await this.uiService.presentToast(response['message']);
|
||||
}
|
||||
|
||||
|
||||
openModePicker = async () => {
|
||||
|
||||
const picker = await this.pickerController.create({
|
||||
columns: [
|
||||
{
|
||||
name: "Mode",
|
||||
options: [
|
||||
{
|
||||
text: "Cooling",
|
||||
value: "cooling"
|
||||
},
|
||||
{
|
||||
text: "Dehumidifying",
|
||||
value: "dehumidifying"
|
||||
},
|
||||
{
|
||||
text: "Blowing",
|
||||
value: "blowing"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
role: 'cancel'
|
||||
},
|
||||
{
|
||||
text: 'Set mode',
|
||||
handler: (selectedMode) => {
|
||||
console.log(selectedMode)
|
||||
let mode = selectedMode['Mode']['value'];
|
||||
|
||||
this.controllerService.handleDeviceAction(this.mainAirConditioner, 'set_mode', mode)
|
||||
.then((response) => {
|
||||
this.uiService.presentToast(response['message']);
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
await picker.present();
|
||||
}
|
||||
|
||||
openTargetTemperaturePicker = async () => {
|
||||
|
||||
const picker = await this.pickerController.create({
|
||||
columns: [
|
||||
{
|
||||
name: "Temperature",
|
||||
options: this.getPickerTemperatures()
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
role: 'cancel'
|
||||
},
|
||||
{
|
||||
text: 'Set Target Temperature',
|
||||
handler: (selectedTemperature) => {
|
||||
console.log(selectedTemperature);
|
||||
let temperature = selectedTemperature['Temperature']['value'];
|
||||
|
||||
this.controllerService.handleDeviceAction(this.mainAirConditioner, 'set_temperature', temperature)
|
||||
.then((response) => {
|
||||
this.uiService.presentToast(response['message']);
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
await picker.present();
|
||||
}
|
||||
|
||||
getPickerTemperatures = () => {
|
||||
let temps = [];
|
||||
|
||||
for (let index = 16; index < 31; index++) {
|
||||
temps.push({
|
||||
text: index,
|
||||
value: index
|
||||
})
|
||||
}
|
||||
|
||||
return temps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
29
echo-mobile-app/echo/src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./tabnav/tabnav.module').then( m => m.TabnavPageModule)
|
||||
},
|
||||
{
|
||||
path: 'lights',
|
||||
loadChildren: () => import('./lights/lights.module').then( m => m.LightsPageModule)
|
||||
},
|
||||
{
|
||||
path: 'sunblinds',
|
||||
loadChildren: () => import('./sunblinds/sunblinds.module').then( m => m.SunblindsPageModule)
|
||||
},
|
||||
{
|
||||
path: 'airconditioning',
|
||||
loadChildren: () => import('./airconditioning/airconditioning.module').then( m => m.AirconditioningPageModule)
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
|
||||
],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
3
echo-mobile-app/echo/src/app/app.component.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<ion-app>
|
||||
<ion-router-outlet></ion-router-outlet>
|
||||
</ion-app>
|
0
echo-mobile-app/echo/src/app/app.component.scss
Normal file
47
echo-mobile-app/echo/src/app/app.component.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
|
||||
import { Platform } from '@ionic/angular';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
|
||||
import { StatusBar } from '@ionic-native/status-bar/ngx';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
|
||||
let statusBarSpy, splashScreenSpy, platformReadySpy, platformSpy;
|
||||
|
||||
beforeEach(async(() => {
|
||||
statusBarSpy = jasmine.createSpyObj('StatusBar', ['styleDefault']);
|
||||
splashScreenSpy = jasmine.createSpyObj('SplashScreen', ['hide']);
|
||||
platformReadySpy = Promise.resolve();
|
||||
platformSpy = jasmine.createSpyObj('Platform', { ready: platformReadySpy });
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
providers: [
|
||||
{ provide: StatusBar, useValue: statusBarSpy },
|
||||
{ provide: SplashScreen, useValue: splashScreenSpy },
|
||||
{ provide: Platform, useValue: platformSpy },
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should initialize the app', async () => {
|
||||
TestBed.createComponent(AppComponent);
|
||||
expect(platformSpy.ready).toHaveBeenCalled();
|
||||
await platformReadySpy;
|
||||
expect(statusBarSpy.styleDefault).toHaveBeenCalled();
|
||||
expect(splashScreenSpy.hide).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// TODO: add more tests!
|
||||
|
||||
});
|
35
echo-mobile-app/echo/src/app/app.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { Platform } from '@ionic/angular';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
|
||||
import { StatusBar } from '@ionic-native/status-bar/ngx';
|
||||
|
||||
import { ControllerService } from './services/controller.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: 'app.component.html',
|
||||
styleUrls: ['app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
constructor(
|
||||
private platform: Platform,
|
||||
private splashScreen: SplashScreen,
|
||||
private statusBar: StatusBar,
|
||||
private controllerService: ControllerService
|
||||
) {
|
||||
this.initializeApp();
|
||||
}
|
||||
|
||||
initializeApp() {
|
||||
this.platform.ready().then(() => {
|
||||
// Gather main data
|
||||
this.controllerService.updateAllData()
|
||||
.then(() => {
|
||||
this.statusBar.styleDefault();
|
||||
this.splashScreen.hide();
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
}
|
34
echo-mobile-app/echo/src/app/app.module.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
|
||||
import { StatusBar } from '@ionic-native/status-bar/ngx';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
entryComponents: [],
|
||||
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
HttpClientModule
|
||||
],
|
||||
|
||||
providers: [
|
||||
StatusBar,
|
||||
SplashScreen,
|
||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {}
|
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { DashboardPage } from './dashboard.page';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DashboardPage
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class DashboardPageRoutingModule {}
|
20
echo-mobile-app/echo/src/app/dashboard/dashboard.module.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { DashboardPageRoutingModule } from './dashboard-routing.module';
|
||||
|
||||
import { DashboardPage } from './dashboard.page';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
DashboardPageRoutingModule
|
||||
],
|
||||
declarations: [DashboardPage]
|
||||
})
|
||||
export class DashboardPageModule {}
|
81
echo-mobile-app/echo/src/app/dashboard/dashboard.page.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Dashboard</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-grid>
|
||||
|
||||
<ion-row>
|
||||
<ion-col size="2">
|
||||
<img src="../../assets/profile/profile_nick.jpeg" class="profile-picture">
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<p class="welcome-text">Hi, <span class="welcome-name">Nick!</span></p>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="content-box">
|
||||
<p class="time-display">{{currentTimeHour}}:{{currentTimeMinute}}</p>
|
||||
<p class="date-display">{{currentDateDay}} {{currentMonth}}, {{currentYear}}</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<p class="status-text connected" *ngIf="echoConnectionError == false">Phone connected to Echo Main Hub!</p>
|
||||
<p class="status-text not-connected" *ngIf="echoConnectionError == true">Error occured with the connection to Echo Main Hub!</p>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="dashboard-status left-status">
|
||||
<ion-icon name="thermometer" class="status-icon"></ion-icon><span class="status-heading">Temperature</span>
|
||||
<p class="status-value">{{getTemperature()}} °C</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<div class="dashboard-status">
|
||||
<ion-icon name="water" class="status-icon"></ion-icon><span class="status-heading">Humidity</span>
|
||||
<p class="status-value">{{getHumidity()}}%</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
|
||||
<ion-col>
|
||||
<div class="dashboard-status right-status">
|
||||
<ion-icon name="sunny" class="status-icon"></ion-icon><span class="status-heading">Light</span>
|
||||
<p class="status-value">{{getLight()}}%</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col><p class="overview-heading">Connected Devices</p></ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="device">
|
||||
<ion-icon name="bulb" class="device-icon"></ion-icon><span class="device-heading">Main Light</span> <ion-toggle [(ngModel)]="mainLightToggle" (ngModelChange)="switchMainLight()" class="device-toggle" color="success"></ion-toggle>
|
||||
<p class="device-text">Lights</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="device">
|
||||
<ion-icon name="snow" class="device-icon"></ion-icon><span class="device-heading">Airconditioner</span> <ion-toggle [(ngModel)]="mainAirConditionerToggle" (ngModelChange)="switchMainAirConditioner()" class="device-toggle" color="success"></ion-toggle>
|
||||
<p class="device-text">Climate - Set to {{getTargetTemp()}} °C</p>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
</ion-grid>
|
||||
</ion-content>
|
128
echo-mobile-app/echo/src/app/dashboard/dashboard.page.scss
Normal file
@@ -0,0 +1,128 @@
|
||||
.content-box {
|
||||
background-color: #da532f;
|
||||
padding: 10px;
|
||||
padding-top: 0px;
|
||||
border-radius: .4rem;
|
||||
-webkit-box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, .3);
|
||||
-moz-box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, .3);
|
||||
box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
.profile-picture {
|
||||
border-radius: 50%;
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
margin: 0px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.welcome-name {
|
||||
color: #fd5c01;
|
||||
text-shadow: 0px 0px 2px rgba(253, 92, 1, 0.4);
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-size: 70px;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.date-display {
|
||||
margin: 0px;
|
||||
margin-top: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.connected {
|
||||
color: #2fdf75;
|
||||
}
|
||||
|
||||
.not-connected {
|
||||
color: #f04141;
|
||||
}
|
||||
|
||||
.dashboard-status {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #3e4d5b;
|
||||
padding: 6px;
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.left-status {
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
.right-status {
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
|
||||
.status-heading {
|
||||
font-size: 13px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 2px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.status-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.overview-heading {
|
||||
margin-top: 15px;
|
||||
font-size: 19px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.device {
|
||||
background-color:#142a37;
|
||||
border-radius: .3rem;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.device-heading {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.device-text {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.device-icon {
|
||||
font-size: 16px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.device-toggle {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
}
|