├── README.md ├── app ├── Gateway │ ├── .gitignore │ ├── SeekBarPreference │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── robobunny │ │ │ │ └── SeekBarPreference.java │ │ │ └── res │ │ │ └── layout │ │ │ └── seek_bar_preference.xml │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── libs │ │ │ └── cordova-3.7.1.jar │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── edu │ │ │ │ └── umich │ │ │ │ └── eecs │ │ │ │ └── lab11 │ │ │ │ └── gateway │ │ │ │ └── ApplicationTest.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ ├── com │ │ │ │ └── megster │ │ │ │ │ └── cordova │ │ │ │ │ └── ble │ │ │ │ │ └── central │ │ │ │ │ ├── BLECentralPlugin.java │ │ │ │ │ ├── BLECommand.java │ │ │ │ │ ├── Helper.java │ │ │ │ │ ├── Peripheral.java │ │ │ │ │ └── UUIDHelper.java │ │ │ ├── edu │ │ │ │ └── umich │ │ │ │ │ └── eecs │ │ │ │ │ └── lab11 │ │ │ │ │ └── gateway │ │ │ │ │ ├── BetterEditText.java │ │ │ │ │ ├── Gateway.java │ │ │ │ │ ├── GatewayService.java │ │ │ │ │ ├── GattSpecs.java │ │ │ │ │ ├── Peripheral.java │ │ │ │ │ ├── PhoneServices.java │ │ │ │ │ ├── PwsClient.java │ │ │ │ │ ├── StartOnBoot.java │ │ │ │ │ ├── UiList.java │ │ │ │ │ └── WebViewActivity.java │ │ │ └── org │ │ │ │ └── apache │ │ │ │ └── cordova │ │ │ │ ├── batterystatus │ │ │ │ └── BatteryListener.java │ │ │ │ ├── camera │ │ │ │ ├── CameraLauncher.java │ │ │ │ ├── ExifHelper.java │ │ │ │ └── FileHelper.java │ │ │ │ ├── devicemotion │ │ │ │ └── AccelListener.java │ │ │ │ ├── deviceorientation │ │ │ │ └── CompassListener.java │ │ │ │ ├── dialogs │ │ │ │ └── Notification.java │ │ │ │ ├── file │ │ │ │ ├── ContentFilesystem.java │ │ │ │ ├── DirectoryManager.java │ │ │ │ ├── EncodingException.java │ │ │ │ ├── FileExistsException.java │ │ │ │ ├── FileHelper.java │ │ │ │ ├── FileUtils.java │ │ │ │ ├── Filesystem.java │ │ │ │ ├── InvalidModificationException.java │ │ │ │ ├── LocalFilesystem.java │ │ │ │ ├── LocalFilesystemURL.java │ │ │ │ ├── NoModificationAllowedException.java │ │ │ │ └── TypeMismatchException.java │ │ │ │ ├── globalization │ │ │ │ ├── Globalization.java │ │ │ │ └── GlobalizationError.java │ │ │ │ ├── mediacapture │ │ │ │ ├── Capture.java │ │ │ │ └── FileHelper.java │ │ │ │ ├── networkinformation │ │ │ │ └── NetworkManager.java │ │ │ │ └── splashscreen │ │ │ │ └── SplashScreen.java │ │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── layout │ │ │ └── activity_gateway.xml │ │ │ ├── menu │ │ │ ├── gateway.xml │ │ │ └── menu_ui_list.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ ├── values │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ ├── config.xml │ │ │ └── preferences.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle └── Peripheral │ ├── .gitignore │ ├── .idea │ ├── .name │ ├── compiler.xml │ ├── copyright │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ ├── scopes │ │ └── scope_settings.xml │ └── vcs.xml │ ├── SeekBarPreference │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── robobunny │ │ │ └── SeekBarPreference.java │ │ └── res │ │ └── layout │ │ └── seek_bar_preference.xml │ ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── edu │ │ │ └── umich │ │ │ └── eecs │ │ │ └── lab11 │ │ │ └── peripheral │ │ │ └── ApplicationTest.java │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── edu │ │ │ └── umich │ │ │ └── eecs │ │ │ └── lab11 │ │ │ └── peripheral │ │ │ ├── BetterEditText.java │ │ │ └── Demo.java │ │ └── res │ │ ├── drawable-hdpi │ │ └── ic_launcher.png │ │ ├── drawable-mdpi │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ │ ├── menu │ │ └── menu_demo.xml │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── activity_demo.xml │ │ └── demo_preferences.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── datacloud ├── README.md └── node-express │ ├── bin │ └── www │ ├── main.js │ ├── package.json │ ├── public │ └── stylesheets │ │ └── style.css │ ├── routes │ ├── index.js │ └── users.js │ ├── ui_examples │ ├── light │ │ ├── cordova.js │ │ ├── cordova_plugins.js │ │ ├── img │ │ │ └── bulb.png │ │ ├── index.html │ │ ├── js │ │ │ └── index.js │ │ └── plugins │ │ │ └── com.megster.cordova.ble │ │ │ └── www │ │ │ └── ble.js │ ├── temperature │ │ ├── cordova.js │ │ ├── cordova_plugins.js │ │ ├── index.html │ │ ├── js │ │ │ └── index.js │ │ └── plugins │ │ │ └── com.megster.cordova.ble │ │ │ └── www │ │ │ └── ble.js │ └── uart │ │ ├── cordova.js │ │ ├── cordova_plugins.js │ │ ├── index.html │ │ ├── js │ │ └── index.js │ │ └── plugins │ │ └── com.megster.cordova.ble │ │ └── www │ │ └── ble.js │ └── views │ ├── error.jade │ ├── index.jade │ └── layout.jade ├── demo_test.py ├── demo_vis.py ├── example.html ├── index.html ├── json ├── gatt.js ├── known.json └── services.json ├── peripherals.html ├── raw.html └── squall └── software └── apps ├── iotgw ├── Makefile └── main.c ├── temperature ├── Makefile └── main.c └── uartgw ├── Makefile ├── ble_nus.c ├── ble_nus.h ├── bsp.c ├── bsp.h └── main.c /README.md: -------------------------------------------------------------------------------- 1 | iot-gateway 2 | =========== 3 | 4 | Our implementation of the gateway described in "[The Internet of Things Has a Gateway Problem](http://dl.acm.org/citation.cfm?id=2699344)". 5 | 6 | - `/app/Gateway` : the Android Gateway app implementing BLE Profile Proxy. 7 | - `/app/Peripheral` : an Android Peripheral app to advertise & test API for BLE peripherals. 8 | - `/datacloud` : a simple responsive server implemention using NodeJS; demonstrates API for servers. 9 | - `/squall` : [squall](https://github.com/helena-project/squall) apps that use Gateway API. 10 | - [`index.html`](http://htmlpreview.github.io/?https://github.com/lab11/iot-gateway/blob/master/index.html) : log of received data at the gateway, data cloud, and incentive cloud 11 | - [`example.html`](http://htmlpreview.github.io/?https://github.com/lab11/iot-gateway/blob/master/example.html) : example visualization of data from the Tessel app 12 | - [`raw.html`](http://htmlpreview.github.io/?https://github.com/lab11/iot-gateway/blob/master/raw.html) : raw output of data sent to data cloud (when received at GATD) 13 | 14 | 15 | API 16 | --- 17 | 18 | To use Gateway, a peripheral specifies the following in the advertisement service data: 19 | - Shortened Destination URL (up to 14 characters), sans protocol [14 bytes] 20 | - Incentive Program Level (0-15) [.5 bytes] 21 | - Reliability Level (0-15) [.5 bytes] 22 | - Gateway Services Requested [1 byte] 23 | - Time Access (0/1) 24 | - GPS Access (0/1) 25 | - Accelerometer Access (0/1) 26 | - Ambient Light Sensor Access (0/1) 27 | - User Text Input Request (0/1) 28 | - User Camera Input Request (0/1) 29 | - Web UI Display Request (0/1) 30 | - IP Over BLE Request (Reserved) (0/1) 31 | - Custom App Data (up to 10 bytes) 32 | 33 | For instance, if a peripheral advertised `676f6f2e676c2f6a524d7845300077C0BEEF`, it would be parsed as: 34 | - Destination: `676f6f2e676c2f6a524d784530000` -> `"goo.gl/jRMxE0"` 35 | - resolves to http://gatewaycloud.elasticbeanstalk.com, a data server expecting POSTs from Gateway 36 | - Incentive Program Level: `7` 37 | - Reliability: `7` 38 | - Gateway Services Requested : `C0` -> Time Access & GPS Access 39 | - Custom App Data: `BEEF` 40 | 41 | -------------------------------------------------------------------------------- /app/Gateway/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | .idea 4 | *.iml 5 | *.iws 6 | .DS_Store 7 | /build 8 | -------------------------------------------------------------------------------- /app/Gateway/SeekBarPreference/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/Gateway/SeekBarPreference/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.0.0' 7 | } 8 | } 9 | apply plugin: 'android-library' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | android { 16 | compileSdkVersion 20 17 | buildToolsVersion "20.0.0" 18 | 19 | defaultConfig { 20 | minSdkVersion 8 21 | targetSdkVersion 20 22 | } 23 | } 24 | 25 | dependencies { 26 | } 27 | -------------------------------------------------------------------------------- /app/Gateway/SeekBarPreference/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/Gateway/SeekBarPreference/src/main/res/layout/seek_bar_preference.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 19 | 25 | 26 | 27 | 32 | 33 | 34 | 41 | 42 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/Gateway/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/Gateway/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | // Add the support lib that is appropriate for SDK 18 9 | compile 'com.loopj.android:android-async-http:1.4.6' 10 | // compile 'com.google.code.gson:gson:2.3' 11 | compile project(':SeekBarPref') 12 | compile 'com.loopj.android:android-async-http:1.4.5' 13 | compile 'com.android.support:appcompat-v7:20.+' 14 | // compile 'com.google.android.gms:play-services:6.1.+' 15 | } 16 | 17 | android { 18 | compileSdkVersion 20 19 | buildToolsVersion "20.0.0" 20 | 21 | defaultConfig { 22 | applicationId "edu.umich.eecs.lab11.gateway" 23 | minSdkVersion 19 24 | targetSdkVersion 20 25 | versionCode 1 26 | versionName "1.0" 27 | } 28 | buildTypes { 29 | release { 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | } 34 | 35 | dependencies { 36 | compile fileTree(dir: 'libs', include: ['*.jar']) 37 | } 38 | dependencies { 39 | compile 'com.android.support:support-v4:20.+' 40 | } 41 | -------------------------------------------------------------------------------- /app/Gateway/app/libs/cordova-3.7.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Gateway/app/libs/cordova-3.7.1.jar -------------------------------------------------------------------------------- /app/Gateway/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/Gateway/app/src/androidTest/java/edu/umich/eecs/lab11/gateway/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/Gateway/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 24 | 25 | 29 | 30 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/com/megster/cordova/ble/central/BLECommand.java: -------------------------------------------------------------------------------- 1 | package com.megster.cordova.ble.central; 2 | 3 | import org.apache.cordova.CallbackContext; 4 | 5 | import java.util.UUID; 6 | 7 | /** 8 | * Android BLE stack is async but doesn't queue commands, so it ignore additional commands when processing. WTF? 9 | * This is an object to encapsulate the command data for queuing 10 | */ 11 | class BLECommand { 12 | // Types 13 | public static int READ = 10000; 14 | public static int REGISTER_NOTIFY = 10001; 15 | // BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE 16 | // BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT 17 | 18 | private CallbackContext callbackContext; 19 | private UUID serviceUUID; 20 | private UUID characteristicUUID; 21 | private byte[] data; 22 | private int type; 23 | 24 | 25 | public BLECommand(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID, int type) { 26 | this.callbackContext = callbackContext; 27 | this.serviceUUID = serviceUUID; 28 | this.characteristicUUID = characteristicUUID; 29 | this.type = type; 30 | } 31 | 32 | public BLECommand(CallbackContext callbackContext, UUID serviceUUID, UUID characteristicUUID, byte[] data, int type) { 33 | this.callbackContext = callbackContext; 34 | this.serviceUUID = serviceUUID; 35 | this.characteristicUUID = characteristicUUID; 36 | this.data = data; 37 | this.type = type; 38 | } 39 | 40 | public int getType() { 41 | return type; 42 | } 43 | 44 | public CallbackContext getCallbackContext() { 45 | return callbackContext; 46 | } 47 | 48 | public UUID getServiceUUID() { 49 | return serviceUUID; 50 | } 51 | 52 | public UUID getCharacteristicUUID() { 53 | return characteristicUUID; 54 | } 55 | 56 | public byte[] getData() { 57 | return data; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/com/megster/cordova/ble/central/Helper.java: -------------------------------------------------------------------------------- 1 | // (c) 2104 Don Coleman 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package com.megster.cordova.ble.central; 16 | 17 | import android.bluetooth.BluetoothGattCharacteristic; 18 | import android.bluetooth.BluetoothGattDescriptor; 19 | 20 | import org.json.JSONArray; 21 | 22 | public class Helper { 23 | 24 | public static JSONArray decodeProperties(BluetoothGattCharacteristic characteristic) { 25 | 26 | // NOTE: props strings need to be consistent across iOS and Android 27 | JSONArray props = new JSONArray(); 28 | int properties = characteristic.getProperties(); 29 | 30 | if ((properties & BluetoothGattCharacteristic.PROPERTY_BROADCAST) != 0x0 ) { 31 | props.put("Broadcast"); 32 | } 33 | 34 | if ((properties & BluetoothGattCharacteristic.PROPERTY_READ) != 0x0 ) { 35 | props.put("Read"); 36 | } 37 | 38 | if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0x0 ) { 39 | props.put("WriteWithoutResponse"); 40 | } 41 | 42 | if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0x0 ) { 43 | props.put("Write"); 44 | } 45 | 46 | if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0x0 ) { 47 | props.put("Notify"); 48 | } 49 | 50 | if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0x0 ) { 51 | props.put("Indicate"); 52 | } 53 | 54 | if ((properties & BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE) != 0x0 ) { 55 | // Android calls this "write with signature", using iOS name for now 56 | props.put("AuthenticateSignedWrites"); 57 | } 58 | 59 | if ((properties & BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS) != 0x0 ) { 60 | props.put("ExtendedProperties"); 61 | } 62 | 63 | // iOS only? 64 | // 65 | // if ((p & CBCharacteristicPropertyNotifyEncryptionRequired) != 0x0) { // 0x100 66 | // [props addObject:@"NotifyEncryptionRequired"]; 67 | // } 68 | // 69 | // if ((p & CBCharacteristicPropertyIndicateEncryptionRequired) != 0x0) { // 0x200 70 | // [props addObject:@"IndicateEncryptionRequired"]; 71 | // } 72 | 73 | return props; 74 | } 75 | 76 | public static JSONArray decodePermissions(BluetoothGattCharacteristic characteristic) { 77 | 78 | // NOTE: props strings need to be consistent across iOS and Android 79 | JSONArray props = new JSONArray(); 80 | int permissions = characteristic.getPermissions(); 81 | 82 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_READ) != 0x0 ) { 83 | props.put("Read"); 84 | } 85 | 86 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_WRITE) != 0x0 ) { 87 | props.put("Write"); 88 | } 89 | 90 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED) != 0x0 ) { 91 | props.put("ReadEncrypted"); 92 | } 93 | 94 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED) != 0x0 ) { 95 | props.put("WriteEncrypted"); 96 | } 97 | 98 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM) != 0x0 ) { 99 | props.put("ReadEncryptedMITM"); 100 | } 101 | 102 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM) != 0x0 ) { 103 | props.put("WriteEncryptedMITM"); 104 | } 105 | 106 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED) != 0x0 ) { 107 | props.put("WriteSigned"); 108 | } 109 | 110 | if ((permissions & BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM) != 0x0 ) { 111 | props.put("WriteSignedMITM"); 112 | } 113 | 114 | return props; 115 | } 116 | 117 | public static JSONArray decodePermissions(BluetoothGattDescriptor descriptor) { 118 | 119 | // NOTE: props strings need to be consistent across iOS and Android 120 | JSONArray props = new JSONArray(); 121 | int permissions = descriptor.getPermissions(); 122 | 123 | if ((permissions & BluetoothGattDescriptor.PERMISSION_READ) != 0x0 ) { 124 | props.put("Read"); 125 | } 126 | 127 | if ((permissions & BluetoothGattDescriptor.PERMISSION_WRITE) != 0x0 ) { 128 | props.put("Write"); 129 | } 130 | 131 | if ((permissions & BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED) != 0x0 ) { 132 | props.put("ReadEncrypted"); 133 | } 134 | 135 | if ((permissions & BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED) != 0x0 ) { 136 | props.put("WriteEncrypted"); 137 | } 138 | 139 | if ((permissions & BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM) != 0x0 ) { 140 | props.put("ReadEncryptedMITM"); 141 | } 142 | 143 | if ((permissions & BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM) != 0x0 ) { 144 | props.put("WriteEncryptedMITM"); 145 | } 146 | 147 | if ((permissions & BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED) != 0x0 ) { 148 | props.put("WriteSigned"); 149 | } 150 | 151 | if ((permissions & BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM) != 0x0 ) { 152 | props.put("WriteSignedMITM"); 153 | } 154 | 155 | return props; 156 | } 157 | 158 | } 159 | 160 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/com/megster/cordova/ble/central/UUIDHelper.java: -------------------------------------------------------------------------------- 1 | // (c) 2104 Don Coleman 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package com.megster.cordova.ble.central; 16 | 17 | import java.util.UUID; 18 | import java.util.regex.Matcher; 19 | import java.util.regex.Pattern; 20 | 21 | public class UUIDHelper { 22 | 23 | // base UUID used to build 128 bit Bluetooth UUIDs 24 | public static final String UUID_BASE = "0000XXXX-0000-1000-8000-00805f9b34fb"; 25 | 26 | // handle 16 and 128 bit UUIDs 27 | public static UUID uuidFromString(String uuid) { 28 | 29 | if (uuid.length() == 4) { 30 | uuid = UUID_BASE.replace("XXXX", uuid); 31 | } 32 | return UUID.fromString(uuid); 33 | } 34 | 35 | // return 16 bit UUIDs where possible 36 | public static String uuidToString(UUID uuid) { 37 | String longUUID = uuid.toString(); 38 | Pattern pattern = Pattern.compile("0000(.{4})-0000-1000-8000-00805f9b34fb", Pattern.CASE_INSENSITIVE); 39 | Matcher matcher = pattern.matcher(longUUID); 40 | if (matcher.matches()) { 41 | // 16 bit UUID 42 | return matcher.group(1); 43 | } else { 44 | return longUUID; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/edu/umich/eecs/lab11/gateway/BetterEditText.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.content.Context; 4 | import android.preference.EditTextPreference; 5 | import android.text.TextUtils; 6 | import android.util.AttributeSet; 7 | 8 | public class BetterEditText extends EditTextPreference { 9 | 10 | public BetterEditText(Context context, AttributeSet attrs, int defStyle) { 11 | super(context, attrs, defStyle); 12 | } 13 | 14 | public BetterEditText(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | public BetterEditText(Context context) { 19 | super(context); 20 | } 21 | 22 | // According to ListPreference implementation 23 | @Override 24 | public CharSequence getSummary() { 25 | String text = getText(); 26 | if (TextUtils.isEmpty(text)) { 27 | return getEditText().getHint(); 28 | } else { 29 | CharSequence summary = super.getSummary(); 30 | if (summary != null) { 31 | return String.format(summary.toString(), text); 32 | } else { 33 | return null; 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/edu/umich/eecs/lab11/gateway/Gateway.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | import android.hardware.Sensor; 7 | import android.hardware.SensorManager; 8 | import android.os.Bundle; 9 | import android.preference.PreferenceActivity; 10 | import android.preference.PreferenceFragment; 11 | import android.preference.PreferenceManager; 12 | 13 | public class Gateway extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { 14 | 15 | // private static final int REQUEST_ENABLE_BT = 1; 16 | // private static final int REQUEST_IMAGE_CAPTURE = 2; 17 | private SharedPreferences cur_settings; 18 | private Intent gatewayIntent; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | getFragmentManager().beginTransaction().replace(android.R.id.content, new GatewayFragment()).commit(); 24 | cur_settings = PreferenceManager.getDefaultSharedPreferences(this); 25 | if(cur_settings.getBoolean("master_agreement",false) && !GatewayService.isInstanceCreated()) { 26 | gatewayIntent = new Intent(this,GatewayService.class); 27 | startService(gatewayIntent); 28 | } 29 | 30 | } 31 | 32 | @Override 33 | protected void onResume() { 34 | super.onResume(); 35 | cur_settings.registerOnSharedPreferenceChangeListener(this); 36 | } 37 | 38 | @Override 39 | protected void onPause() { 40 | super.onPause(); 41 | cur_settings.unregisterOnSharedPreferenceChangeListener(this); 42 | } 43 | 44 | // @Override 45 | // protected void onActivityResult(int requestCode, int resultCode, Intent data) { 46 | // // User chose not to enable Bluetooth. 47 | // if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { 48 | // finish(); 49 | // return; 50 | // } 51 | // if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { 52 | // Bundle extras = data.getExtras(); 53 | // Bitmap bm = (Bitmap) extras.get("data"); 54 | // ByteArrayOutputStream baos = new ByteArrayOutputStream(); 55 | // bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); 56 | // popup_pic_string = Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT); 57 | // } 58 | // super.onActivityResult(requestCode, resultCode, data); 59 | // } 60 | 61 | @Override 62 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { 63 | if(s.equals("master_agreement")) 64 | if (cur_settings.getBoolean("master_agreement", false)) { 65 | gatewayIntent = new Intent(this,GatewayService.class); 66 | startService(gatewayIntent); 67 | } else if (GatewayService.isInstanceCreated()) stopService(GatewayService.getIntent()); 68 | } 69 | 70 | /** 71 | * Settings Fragment: Pulls information from preference xml & automatically updates on change 72 | */ 73 | public static class GatewayFragment extends PreferenceFragment { 74 | private SensorManager mSensorManager; 75 | @Override 76 | public void onCreate(Bundle savedInstanceState) { 77 | super.onCreate(savedInstanceState); 78 | addPreferencesFromResource(R.xml.preferences); 79 | mSensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE); 80 | // if (mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE) == null) getPreferenceManager().findPreference("temp_agreement").setEnabled(false); 81 | // if (mSensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY) == null) getPreferenceManager().findPreference("humidity_agreement").setEnabled(false); 82 | if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) == null) getPreferenceManager().findPreference("accel_agreement").setEnabled(false); 83 | if (mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) == null) getPreferenceManager().findPreference("ambient_agreement").setEnabled(false); 84 | } 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/edu/umich/eecs/lab11/gateway/Peripheral.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.util.Log; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Created by nklugman on 11/19/14. 9 | */ 10 | public class Peripheral { 11 | 12 | public String[] FLAGS; 13 | public ArrayList DATA_TO_PEEK = new ArrayList(); 14 | public boolean TRANSPARENT; 15 | 16 | public enum QOS_ENUM { 17 | REQ_ALL, REQ_ALL_NO_RATE, 18 | REQ_ALL_NO_SENSORS, REQ_ALL_NO_SENSORS_NOT_INCL_GPS, 19 | REQ_NONE_BUT_CONNECTION, REQ_NONE_BUT_SERVICE, REQ_NONE 20 | } 21 | 22 | public enum ENUM { 23 | url, transparent, rate, sensors, qos, 24 | time, gps, accel, ambient, text, pic, ui, ip, 25 | program_need, program_type, 26 | data_blob, dev_address, dev_name 27 | } 28 | 29 | public enum SENSOR_ENUM { 30 | time, gps, accel, ambient, text, pic, ui, ip 31 | } 32 | 33 | public void empty() { 34 | FLAGS = new String[50]; 35 | DATA_TO_PEEK.clear(); 36 | } 37 | 38 | public String hexToBinary(final String hexStr) { 39 | StringBuilder binStr = new StringBuilder(); 40 | String[] conversionTable = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"}; 41 | for (int i = 0; i < hexStr.length(); i++) binStr.append(conversionTable[Character.digit(hexStr.charAt(i), 16)]); 42 | return binStr.toString(); 43 | } 44 | 45 | public Peripheral() { 46 | //UUID_FLAGS = new int[7]; 47 | //SENSOR_FLAGS = new int[8]; 48 | //ADV_FLAGS = new int[2]; 49 | FLAGS = new String[50]; 50 | // TRANSPARENT = false; 51 | } 52 | 53 | public Peripheral(String devName, String devAddress, int rssi, String a, String fullURL) { 54 | FLAGS = new String[50]; 55 | 56 | String final_binary_str = hexToBinary(a.substring(28)); 57 | Log.w("PARSE_FINAL", final_binary_str); 58 | // String RATE = final_binary_str.substring(1, 4); 59 | String PROGRAM_TYPE = final_binary_str.substring(0,4); 60 | String RELIABILITY = final_binary_str.substring(4, 8); 61 | String SENSORS = final_binary_str.substring(8, 16); 62 | String DATA = a.substring(32); 63 | 64 | TRANSPARENT = SENSORS.equals("00000000"); 65 | FLAGS[Peripheral.ENUM.url.ordinal()] = fullURL; 66 | // FLAGS[Peripheral.ENUM.rate.ordinal()] = RATE; 67 | FLAGS[Peripheral.ENUM.qos.ordinal()] = RELIABILITY; 68 | FLAGS[Peripheral.ENUM.program_type.ordinal()] = PROGRAM_TYPE; 69 | FLAGS[Peripheral.ENUM.data_blob.ordinal()] = DATA; 70 | FLAGS[Peripheral.ENUM.dev_address.ordinal()] = devAddress; 71 | FLAGS[Peripheral.ENUM.dev_name.ordinal()] = devName; 72 | if (!TRANSPARENT) { 73 | FLAGS[Peripheral.ENUM.sensors.ordinal()] = SENSORS; 74 | FLAGS[Peripheral.ENUM.time.ordinal()] = String.valueOf(SENSORS.charAt(0)); 75 | FLAGS[Peripheral.ENUM.gps.ordinal()] = String.valueOf(SENSORS.charAt(1)); 76 | FLAGS[Peripheral.ENUM.accel.ordinal()] = String.valueOf(SENSORS.charAt(2)); // Can change to peripheral.SENSOR_ENUM.x.ordinal() 77 | FLAGS[Peripheral.ENUM.ambient.ordinal()] = String.valueOf(SENSORS.charAt(3)); 78 | FLAGS[Peripheral.ENUM.text.ordinal()] = String.valueOf(SENSORS.charAt(4)); 79 | FLAGS[Peripheral.ENUM.pic.ordinal()] = String.valueOf(SENSORS.charAt(5)); 80 | FLAGS[Peripheral.ENUM.ui.ordinal()] = String.valueOf(SENSORS.charAt(6)); 81 | FLAGS[Peripheral.ENUM.ip.ordinal()] = String.valueOf(SENSORS.charAt(7)); 82 | } 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/edu/umich/eecs/lab11/gateway/StartOnBoot.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.preference.PreferenceManager; 8 | 9 | public class StartOnBoot extends BroadcastReceiver { 10 | @Override 11 | public void onReceive(Context context, Intent intent) { 12 | SharedPreferences cur_settings = PreferenceManager.getDefaultSharedPreferences(context); 13 | if(cur_settings.getBoolean("master_agreement",false)) { 14 | Intent serviceIntent = new Intent(context,GatewayService.class); 15 | context.startService(serviceIntent); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/edu/umich/eecs/lab11/gateway/UiList.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.app.Activity; 4 | import android.app.ListFragment; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.graphics.Color; 8 | import android.os.Bundle; 9 | import android.preference.PreferenceManager; 10 | import android.view.LayoutInflater; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.BaseAdapter; 16 | import android.widget.ListView; 17 | import android.widget.TextView; 18 | 19 | import java.util.ArrayList; 20 | import java.util.HashSet; 21 | 22 | 23 | public class UiList extends Activity { 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | getFragmentManager().beginTransaction().add(android.R.id.content, new UiListFragment()).commit(); 29 | } 30 | 31 | @Override 32 | public boolean onCreateOptionsMenu(Menu menu) { 33 | getMenuInflater().inflate(R.menu.menu_ui_list, menu); 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean onOptionsItemSelected(MenuItem item) { 39 | if (item.getItemId() == R.id.action_settings) { 40 | this.startActivity(new Intent(this, Gateway.class)); 41 | return true; 42 | } 43 | return super.onOptionsItemSelected(item); 44 | } 45 | 46 | public static class UiListFragment extends ListFragment implements SharedPreferences.OnSharedPreferenceChangeListener { 47 | 48 | private SharedPreferences preferences; 49 | private UiListAdapter uiListAdapter; 50 | private ArrayList devices; 51 | private static UiListFragment instance = null; 52 | 53 | @Override 54 | public void onActivityCreated(Bundle savedInstanceState) { 55 | super.onActivityCreated(savedInstanceState); 56 | preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); 57 | if(preferences.getBoolean("master_agreement",false) && !GatewayService.isInstanceCreated()) { 58 | Intent gatewayIntent = new Intent(getActivity(),GatewayService.class); 59 | getActivity().startService(gatewayIntent); 60 | } 61 | } 62 | 63 | @Override 64 | public void onResume() { 65 | super.onResume(); 66 | preferences.registerOnSharedPreferenceChangeListener(this); 67 | devices = new ArrayList(preferences.getStringSet("ui_devices",new HashSet())); 68 | uiListAdapter = new UiListAdapter(); 69 | setListAdapter(uiListAdapter); 70 | instance = this; 71 | if (!preferences.getBoolean("master_agreement",false)) startActivity(new Intent(getActivity(), Gateway.class)); 72 | } 73 | 74 | @Override 75 | public void onPause() { 76 | super.onPause(); 77 | preferences.unregisterOnSharedPreferenceChangeListener(this); 78 | devices.clear(); 79 | instance = null; 80 | } 81 | 82 | @Override 83 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { 84 | System.out.println("CHANGE : " + s); 85 | if (s.equals("ui_devices")) { 86 | devices = new ArrayList(preferences.getStringSet(s,new HashSet())); 87 | uiListAdapter.notifyDataSetChanged(); 88 | } 89 | } 90 | 91 | @Override 92 | public void onListItemClick(ListView l, View v, int position, long id) { 93 | super.onListItemClick(l, v, position, id); 94 | String [] strings = ((String) uiListAdapter.getItem(position)).split(" @ "); 95 | String address = strings[0].split(" ")[0]; 96 | String url = strings[1]; 97 | String name = ""; 98 | try {name = strings[0].split(" ")[1].replaceAll("[()]","");} catch (Exception e) {} 99 | popupWebView(address, name, url); 100 | } 101 | 102 | public static UiListFragment getInstance() { 103 | return instance; 104 | } 105 | 106 | public void popupWebView(String deviceAddress,String deviceName,String ui) { 107 | Intent intent = new Intent(getActivity(), WebViewActivity.class); 108 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 109 | intent.putExtra("deviceAddress", deviceAddress); 110 | intent.putExtra("deviceName", deviceName); 111 | intent.putExtra("ui", ui); 112 | getActivity().startActivity(intent); 113 | } 114 | 115 | // Adapter for holding devices found through scanning. 116 | public class UiListAdapter extends BaseAdapter { 117 | 118 | private LayoutInflater inflater; 119 | 120 | public UiListAdapter() { 121 | super(); 122 | inflater = getActivity().getLayoutInflater(); 123 | } 124 | 125 | @Override 126 | public int getCount() { 127 | return devices.size(); 128 | } 129 | 130 | @Override 131 | public Object getItem(int i) { 132 | return devices.get(i); 133 | } 134 | 135 | @Override 136 | public long getItemId(int i) { 137 | return i; 138 | } 139 | 140 | @Override 141 | public View getView(int i, View view, ViewGroup viewGroup) { 142 | // General ListView optimization code. 143 | if (view == null) view = inflater.inflate(android.R.layout.simple_list_item_2, null); 144 | String [] strings = ((String) getItem(i)).split(" @ "); 145 | try { 146 | ((TextView) view.findViewById(android.R.id.text1)).setTextColor(Color.parseColor("#8BC34A")); 147 | ((TextView) view.findViewById(android.R.id.text1)).setText(strings[0]); 148 | ((TextView) view.findViewById(android.R.id.text2)).setText(strings[1]); 149 | } catch (Exception e) {} 150 | return view; 151 | } 152 | } 153 | 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/edu/umich/eecs/lab11/gateway/WebViewActivity.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.gateway; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import android.preference.PreferenceManager; 7 | import android.webkit.JavascriptInterface; 8 | 9 | import org.apache.cordova.CordovaActivity; 10 | 11 | import java.util.Calendar; 12 | 13 | public class WebViewActivity extends CordovaActivity { 14 | 15 | private String data; 16 | private String deviceAddress; 17 | private String deviceName; 18 | private String ui; 19 | private SharedPreferences cur_settings; 20 | 21 | @Override 22 | public void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | super.init(); 25 | super.appView.addJavascriptInterface(new JavaScriptInterface(super.getActivity()), "gateway"); 26 | cur_settings = PreferenceManager.getDefaultSharedPreferences(this); 27 | data = getIntent().getStringExtra("data"); 28 | deviceAddress = getIntent().getStringExtra("deviceAddress"); 29 | deviceName = getIntent().getStringExtra("deviceName"); 30 | ui = getIntent().getStringExtra("ui"); 31 | // if (ui.length()==0) updateData(deviceName, data); 32 | // else webView.loadData(ui, "text/html", "UTF-8"); 33 | loadUrl(ui); 34 | } 35 | 36 | @Override 37 | protected void onPause() { 38 | super.onPause(); 39 | cur_settings.edit().putBoolean("pause",false).apply(); 40 | } 41 | 42 | @Override 43 | protected void onResume() { 44 | super.onResume(); 45 | cur_settings.edit().putBoolean("pause",true).apply(); 46 | } 47 | 48 | public class JavaScriptInterface { 49 | Context mContext; 50 | 51 | JavaScriptInterface(Context c) { 52 | mContext = c; 53 | } 54 | 55 | @JavascriptInterface 56 | public String getDeviceId(){ 57 | return deviceAddress; 58 | } 59 | 60 | @JavascriptInterface 61 | public String getDeviceName() { return deviceName; } 62 | } 63 | 64 | public void updateData(String deviceName, String data) { 65 | Calendar c = Calendar.getInstance(); 66 | String customHtml = "DEVICE:
"+deviceName+"

DATA:
"+data+"

RECEIVED:
"+ c.getTime().toString() +""; 67 | // webView.loadData(customHtml, "text/html", "UTF-8"); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/batterystatus/BatteryListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.batterystatus; 20 | 21 | import android.content.BroadcastReceiver; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.content.IntentFilter; 25 | import android.util.Log; 26 | 27 | import org.apache.cordova.CallbackContext; 28 | import org.apache.cordova.CordovaPlugin; 29 | import org.apache.cordova.PluginResult; 30 | import org.json.JSONArray; 31 | import org.json.JSONException; 32 | import org.json.JSONObject; 33 | 34 | public class BatteryListener extends CordovaPlugin { 35 | 36 | private static final String LOG_TAG = "BatteryManager"; 37 | 38 | BroadcastReceiver receiver; 39 | 40 | private CallbackContext batteryCallbackContext = null; 41 | 42 | /** 43 | * Constructor. 44 | */ 45 | public BatteryListener() { 46 | this.receiver = null; 47 | } 48 | 49 | /** 50 | * Executes the request. 51 | * 52 | * @param action The action to execute. 53 | * @param args JSONArry of arguments for the plugin. 54 | * @param callbackContext The callback context used when calling back into JavaScript. 55 | * @return True if the action was valid, false if not. 56 | */ 57 | public boolean execute(String action, JSONArray args, CallbackContext callbackContext) { 58 | if (action.equals("start")) { 59 | if (this.batteryCallbackContext != null) { 60 | callbackContext.error( "Battery listener already running."); 61 | return true; 62 | } 63 | this.batteryCallbackContext = callbackContext; 64 | 65 | // We need to listen to power events to update battery status 66 | IntentFilter intentFilter = new IntentFilter(); 67 | intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 68 | if (this.receiver == null) { 69 | this.receiver = new BroadcastReceiver() { 70 | @Override 71 | public void onReceive(Context context, Intent intent) { 72 | updateBatteryInfo(intent); 73 | } 74 | }; 75 | webView.getContext().registerReceiver(this.receiver, intentFilter); 76 | } 77 | 78 | // Don't return any result now, since status results will be sent when events come in from broadcast receiver 79 | PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT); 80 | pluginResult.setKeepCallback(true); 81 | callbackContext.sendPluginResult(pluginResult); 82 | return true; 83 | } 84 | 85 | else if (action.equals("stop")) { 86 | removeBatteryListener(); 87 | this.sendUpdate(new JSONObject(), false); // release status callback in JS side 88 | this.batteryCallbackContext = null; 89 | callbackContext.success(); 90 | return true; 91 | } 92 | 93 | return false; 94 | } 95 | 96 | /** 97 | * Stop battery receiver. 98 | */ 99 | public void onDestroy() { 100 | removeBatteryListener(); 101 | } 102 | 103 | /** 104 | * Stop battery receiver. 105 | */ 106 | public void onReset() { 107 | removeBatteryListener(); 108 | } 109 | 110 | /** 111 | * Stop the battery receiver and set it to null. 112 | */ 113 | private void removeBatteryListener() { 114 | if (this.receiver != null) { 115 | try { 116 | webView.getContext().unregisterReceiver(this.receiver); 117 | this.receiver = null; 118 | } catch (Exception e) { 119 | Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e); 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * Creates a JSONObject with the current battery information 126 | * 127 | * @param batteryIntent the current battery information 128 | * @return a JSONObject containing the battery status information 129 | */ 130 | private JSONObject getBatteryInfo(Intent batteryIntent) { 131 | JSONObject obj = new JSONObject(); 132 | try { 133 | obj.put("level", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, 0)); 134 | obj.put("isPlugged", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_PLUGGED, -1) > 0 ? true : false); 135 | } catch (JSONException e) { 136 | Log.e(LOG_TAG, e.getMessage(), e); 137 | } 138 | return obj; 139 | } 140 | 141 | /** 142 | * Updates the JavaScript side whenever the battery changes 143 | * 144 | * @param batteryIntent the current battery information 145 | * @return 146 | */ 147 | private void updateBatteryInfo(Intent batteryIntent) { 148 | sendUpdate(this.getBatteryInfo(batteryIntent), true); 149 | } 150 | 151 | /** 152 | * Create a new plugin result and send it back to JavaScript 153 | * 154 | * @param connection the network info to set as navigator.connection 155 | */ 156 | private void sendUpdate(JSONObject info, boolean keepCallback) { 157 | if (this.batteryCallbackContext != null) { 158 | PluginResult result = new PluginResult(PluginResult.Status.OK, info); 159 | result.setKeepCallback(keepCallback); 160 | this.batteryCallbackContext.sendPluginResult(result); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/DirectoryManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.file; 20 | 21 | import android.os.Environment; 22 | import android.os.StatFs; 23 | 24 | import java.io.File; 25 | 26 | /** 27 | * This class provides file directory utilities. 28 | * All file operations are performed on the SD card. 29 | * 30 | * It is used by the FileUtils class. 31 | */ 32 | public class DirectoryManager { 33 | 34 | @SuppressWarnings("unused") 35 | private static final String LOG_TAG = "DirectoryManager"; 36 | 37 | /** 38 | * Determine if a file or directory exists. 39 | * @param name The name of the file to check. 40 | * @return T=exists, F=not found 41 | */ 42 | public static boolean testFileExists(String name) { 43 | boolean status; 44 | 45 | // If SD card exists 46 | if ((testSaveLocationExists()) && (!name.equals(""))) { 47 | File path = Environment.getExternalStorageDirectory(); 48 | File newPath = constructFilePaths(path.toString(), name); 49 | status = newPath.exists(); 50 | } 51 | // If no SD card 52 | else { 53 | status = false; 54 | } 55 | return status; 56 | } 57 | 58 | /** 59 | * Get the free disk space 60 | * 61 | * @return Size in KB or -1 if not available 62 | */ 63 | public static long getFreeDiskSpace(boolean checkInternal) { 64 | String status = Environment.getExternalStorageState(); 65 | long freeSpace = 0; 66 | 67 | // If SD card exists 68 | if (status.equals(Environment.MEDIA_MOUNTED)) { 69 | freeSpace = freeSpaceCalculation(Environment.getExternalStorageDirectory().getPath()); 70 | } 71 | else if (checkInternal) { 72 | freeSpace = freeSpaceCalculation("/"); 73 | } 74 | // If no SD card and we haven't been asked to check the internal directory then return -1 75 | else { 76 | return -1; 77 | } 78 | 79 | return freeSpace; 80 | } 81 | 82 | /** 83 | * Given a path return the number of free KB 84 | * 85 | * @param path to the file system 86 | * @return free space in KB 87 | */ 88 | private static long freeSpaceCalculation(String path) { 89 | StatFs stat = new StatFs(path); 90 | long blockSize = stat.getBlockSize(); 91 | long availableBlocks = stat.getAvailableBlocks(); 92 | return availableBlocks * blockSize / 1024; 93 | } 94 | 95 | /** 96 | * Determine if SD card exists. 97 | * 98 | * @return T=exists, F=not found 99 | */ 100 | public static boolean testSaveLocationExists() { 101 | String sDCardStatus = Environment.getExternalStorageState(); 102 | boolean status; 103 | 104 | // If SD card is mounted 105 | if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) { 106 | status = true; 107 | } 108 | 109 | // If no SD card 110 | else { 111 | status = false; 112 | } 113 | return status; 114 | } 115 | 116 | /** 117 | * Create a new file object from two file paths. 118 | * 119 | * @param file1 Base file path 120 | * @param file2 Remaining file path 121 | * @return File object 122 | */ 123 | private static File constructFilePaths (String file1, String file2) { 124 | File newPath; 125 | if (file2.startsWith(file1)) { 126 | newPath = new File(file2); 127 | } 128 | else { 129 | newPath = new File(file1 + "/" + file2); 130 | } 131 | return newPath; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/EncodingException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package org.apache.cordova.file; 21 | 22 | @SuppressWarnings("serial") 23 | public class EncodingException extends Exception { 24 | 25 | public EncodingException(String message) { 26 | super(message); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/FileExistsException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package org.apache.cordova.file; 21 | 22 | @SuppressWarnings("serial") 23 | public class FileExistsException extends Exception { 24 | 25 | public FileExistsException(String msg) { 26 | super(msg); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/FileHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.file; 20 | 21 | import android.database.Cursor; 22 | import android.net.Uri; 23 | import android.webkit.MimeTypeMap; 24 | 25 | import org.apache.cordova.CordovaInterface; 26 | import org.apache.cordova.LOG; 27 | 28 | import java.io.FileInputStream; 29 | import java.io.IOException; 30 | import java.io.InputStream; 31 | import java.util.Locale; 32 | 33 | public class FileHelper { 34 | private static final String LOG_TAG = "FileUtils"; 35 | private static final String _DATA = "_data"; 36 | 37 | /** 38 | * Returns the real path of the given URI string. 39 | * If the given URI string represents a content:// URI, the real path is retrieved from the media store. 40 | * 41 | * @param uriString the URI string of the audio/image/video 42 | * @param cordova the current application context 43 | * @return the full path to the file 44 | */ 45 | @SuppressWarnings("deprecation") 46 | public static String getRealPath(String uriString, CordovaInterface cordova) { 47 | String realPath = null; 48 | 49 | if (uriString.startsWith("content://")) { 50 | String[] proj = { _DATA }; 51 | Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null); 52 | int column_index = cursor.getColumnIndexOrThrow(_DATA); 53 | cursor.moveToFirst(); 54 | realPath = cursor.getString(column_index); 55 | if (realPath == null) { 56 | LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString); 57 | } 58 | } else if (uriString.startsWith("file://")) { 59 | realPath = uriString.substring(7); 60 | if (realPath.startsWith("/android_asset/")) { 61 | LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString); 62 | realPath = null; 63 | } 64 | } else { 65 | realPath = uriString; 66 | } 67 | 68 | return realPath; 69 | } 70 | 71 | /** 72 | * Returns the real path of the given URI. 73 | * If the given URI is a content:// URI, the real path is retrieved from the media store. 74 | * 75 | * @param uri the URI of the audio/image/video 76 | * @param cordova the current application context 77 | * @return the full path to the file 78 | */ 79 | public static String getRealPath(Uri uri, CordovaInterface cordova) { 80 | return FileHelper.getRealPath(uri.toString(), cordova); 81 | } 82 | 83 | /** 84 | * Returns an input stream based on given URI string. 85 | * 86 | * @param uriString the URI string from which to obtain the input stream 87 | * @param cordova the current application context 88 | * @return an input stream into the data at the given URI or null if given an invalid URI string 89 | * @throws IOException 90 | */ 91 | public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException { 92 | if (uriString.startsWith("content")) { 93 | Uri uri = Uri.parse(uriString); 94 | return cordova.getActivity().getContentResolver().openInputStream(uri); 95 | } else if (uriString.startsWith("file://")) { 96 | int question = uriString.indexOf("?"); 97 | if (question > -1) { 98 | uriString = uriString.substring(0,question); 99 | } 100 | if (uriString.startsWith("file:///android_asset/")) { 101 | Uri uri = Uri.parse(uriString); 102 | String relativePath = uri.getPath().substring(15); 103 | return cordova.getActivity().getAssets().open(relativePath); 104 | } else { 105 | return new FileInputStream(getRealPath(uriString, cordova)); 106 | } 107 | } else { 108 | return new FileInputStream(getRealPath(uriString, cordova)); 109 | } 110 | } 111 | 112 | /** 113 | * Removes the "file://" prefix from the given URI string, if applicable. 114 | * If the given URI string doesn't have a "file://" prefix, it is returned unchanged. 115 | * 116 | * @param uriString the URI string to operate on 117 | * @return a path without the "file://" prefix 118 | */ 119 | public static String stripFileProtocol(String uriString) { 120 | if (uriString.startsWith("file://")) { 121 | uriString = uriString.substring(7); 122 | } 123 | return uriString; 124 | } 125 | 126 | public static String getMimeTypeForExtension(String path) { 127 | String extension = path; 128 | int lastDot = extension.lastIndexOf('.'); 129 | if (lastDot != -1) { 130 | extension = extension.substring(lastDot + 1); 131 | } 132 | // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185). 133 | extension = extension.toLowerCase(Locale.getDefault()); 134 | if (extension.equals("3ga")) { 135 | return "audio/3gpp"; 136 | } 137 | return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 138 | } 139 | 140 | /** 141 | * Returns the mime type of the data specified by the given URI string. 142 | * 143 | * @param uriString the URI string of the data 144 | * @return the mime type of the specified data 145 | */ 146 | public static String getMimeType(String uriString, CordovaInterface cordova) { 147 | String mimeType = null; 148 | 149 | Uri uri = Uri.parse(uriString); 150 | if (uriString.startsWith("content://")) { 151 | mimeType = cordova.getActivity().getContentResolver().getType(uri); 152 | } else { 153 | mimeType = getMimeTypeForExtension(uri.getPath()); 154 | } 155 | 156 | return mimeType; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/InvalidModificationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | 21 | package org.apache.cordova.file; 22 | 23 | @SuppressWarnings("serial") 24 | public class InvalidModificationException extends Exception { 25 | 26 | public InvalidModificationException(String message) { 27 | super(message); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/LocalFilesystemURL.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.file; 20 | 21 | import android.net.Uri; 22 | 23 | import java.util.List; 24 | 25 | public class LocalFilesystemURL { 26 | 27 | public static final String FILESYSTEM_PROTOCOL = "cdvfile"; 28 | 29 | Uri URL; 30 | String filesystemName; 31 | String fullPath; 32 | 33 | public LocalFilesystemURL(Uri URL) { 34 | this.URL = URL; 35 | this.filesystemName = this.filesystemNameForLocalURL(URL); 36 | this.fullPath = this.fullPathForLocalURL(URL); 37 | } 38 | 39 | private String fullPathForLocalURL(Uri URL) { 40 | if (FILESYSTEM_PROTOCOL.equals(URL.getScheme()) && "localhost".equals(URL.getHost())) { 41 | String path = URL.getPath(); 42 | if (URL.getQuery() != null) { 43 | path = path + "?" + URL.getQuery(); 44 | } 45 | return path.substring(path.indexOf('/', 1)); 46 | } else if ("content".equals(URL.getScheme())) { 47 | String path = '/' + URL.getHost() + URL.getPath(); 48 | // Re-encode path component to handle Android 4.4+ Content URLs 49 | return Uri.encode(path,"/"); 50 | } 51 | return null; 52 | } 53 | 54 | private String filesystemNameForLocalURL(Uri URL) { 55 | if (FILESYSTEM_PROTOCOL.equals(URL.getScheme()) && "localhost".equals(URL.getHost())) { 56 | List pathComponents = URL.getPathSegments(); 57 | if (pathComponents != null && pathComponents.size() > 0) { 58 | return pathComponents.get(0); 59 | } 60 | return null; 61 | } else if ("content".equals(URL.getScheme())) { 62 | return "content"; 63 | } 64 | return null; 65 | } 66 | 67 | public LocalFilesystemURL(String strURL) { 68 | this(Uri.parse(strURL)); 69 | } 70 | 71 | public String toString() { 72 | return "cdvfile://localhost/" + this.filesystemName + this.fullPath; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/NoModificationAllowedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package org.apache.cordova.file; 21 | 22 | @SuppressWarnings("serial") 23 | public class NoModificationAllowedException extends Exception { 24 | 25 | public NoModificationAllowedException(String message) { 26 | super(message); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/file/TypeMismatchException.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | 21 | package org.apache.cordova.file; 22 | 23 | @SuppressWarnings("serial") 24 | public class TypeMismatchException extends Exception { 25 | 26 | public TypeMismatchException(String message) { 27 | super(message); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/globalization/GlobalizationError.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package org.apache.cordova.globalization; 21 | 22 | import org.json.JSONException; 23 | import org.json.JSONObject; 24 | 25 | /** 26 | * @description Exception class representing defined Globalization error codes 27 | * @Globalization error codes: 28 | * GlobalizationError.UNKNOWN_ERROR = 0; 29 | * GlobalizationError.FORMATTING_ERROR = 1; 30 | * GlobalizationError.PARSING_ERROR = 2; 31 | * GlobalizationError.PATTERN_ERROR = 3; 32 | */ 33 | public class GlobalizationError extends Exception{ 34 | /** 35 | * 36 | */ 37 | private static final long serialVersionUID = 1L; 38 | public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR"; 39 | public static final String FORMATTING_ERROR = "FORMATTING_ERROR"; 40 | public static final String PARSING_ERROR = "PARSING_ERROR"; 41 | public static final String PATTERN_ERROR = "PATTERN_ERROR"; 42 | 43 | int error = 0; //default unknown error thrown 44 | /** 45 | * Default constructor 46 | */ 47 | public GlobalizationError() {} 48 | /** 49 | * Create an exception returning an error code 50 | * 51 | * @param s 52 | */ 53 | public GlobalizationError(String s) { 54 | if (s.equalsIgnoreCase(FORMATTING_ERROR)){ 55 | error = 1; 56 | }else if (s.equalsIgnoreCase(PARSING_ERROR)){ 57 | error = 2; 58 | }else if (s.equalsIgnoreCase(PATTERN_ERROR)){ 59 | error = 3; 60 | } 61 | } 62 | /** 63 | * get error string based on error code 64 | * 65 | * @param String msg 66 | */ 67 | public String getErrorString(){ 68 | String msg = ""; 69 | switch (error){ 70 | case 0: 71 | msg = UNKNOWN_ERROR; 72 | break; 73 | case 1: 74 | msg = FORMATTING_ERROR; 75 | break; 76 | case 2: 77 | msg = PARSING_ERROR; 78 | break; 79 | case 3: 80 | msg = PATTERN_ERROR; 81 | break; 82 | } 83 | return msg; 84 | } 85 | /** 86 | * get error code 87 | * 88 | * @param String msg 89 | */ 90 | public int getErrorCode(){ 91 | return error; 92 | } 93 | 94 | /** 95 | * get the json version of this object to return to javascript 96 | * @return 97 | */ 98 | public JSONObject toJson() { 99 | JSONObject obj = new JSONObject(); 100 | try { 101 | obj.put("code", getErrorCode()); 102 | obj.put("message", getErrorString()); 103 | } catch (JSONException e) { 104 | // never happens 105 | } 106 | return obj; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/java/org/apache/cordova/mediacapture/FileHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.mediacapture; 20 | 21 | import android.net.Uri; 22 | import android.webkit.MimeTypeMap; 23 | 24 | import org.apache.cordova.CordovaInterface; 25 | 26 | import java.util.Locale; 27 | 28 | // TODO: Replace with CordovaResourceApi.getMimeType() post 3.1. 29 | public class FileHelper { 30 | public static String getMimeTypeForExtension(String path) { 31 | String extension = path; 32 | int lastDot = extension.lastIndexOf('.'); 33 | if (lastDot != -1) { 34 | extension = extension.substring(lastDot + 1); 35 | } 36 | // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185). 37 | extension = extension.toLowerCase(Locale.getDefault()); 38 | if (extension.equals("3ga")) { 39 | return "audio/3gpp"; 40 | } 41 | return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 42 | } 43 | 44 | /** 45 | * Returns the mime type of the data specified by the given URI string. 46 | * 47 | * @param uriString the URI string of the data 48 | * @return the mime type of the specified data 49 | */ 50 | public static String getMimeType(Uri uri, CordovaInterface cordova) { 51 | String mimeType = null; 52 | if ("content".equals(uri.getScheme())) { 53 | mimeType = cordova.getActivity().getContentResolver().getType(uri); 54 | } else { 55 | mimeType = getMimeTypeForExtension(uri.getPath()); 56 | } 57 | 58 | return mimeType; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Gateway/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Gateway/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Gateway/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Gateway/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/layout/activity_gateway.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/menu/gateway.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/menu/menu_ui_list.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gateway 5 | Settings 6 | ListActivity 7 | 8 | Nearby Interactive Devices 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Summon 39 | 40 | Application that opens Web App urls advertised by nearby BLE peripherals 41 | 42 | 43 | Lab11, University of Michigan 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/Gateway/app/src/main/res/xml/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 45 | 46 | 47 | 52 | 57 | 58 | 59 | 64 | 65 | 66 | 67 | 72 | 73 | 76 | 77 | -------------------------------------------------------------------------------- /app/Gateway/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.0.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Gateway/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Settings specified in this file will override any Gradle settings 5 | # configured through the IDE. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/Gateway/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Gateway/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/Gateway/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Dec 16 12:10:06 EST 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /app/Gateway/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /app/Gateway/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/Gateway/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':SeekBarPref' 2 | project(':SeekBarPref').projectDir = new File('SeekBarPreference') -------------------------------------------------------------------------------- /app/Peripheral/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | .idea 4 | *.iml 5 | *.iws 6 | .DS_Store 7 | /build 8 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/.name: -------------------------------------------------------------------------------- 1 | Peripheral -------------------------------------------------------------------------------- /app/Peripheral/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Android API 8 Platform 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/Peripheral/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/Peripheral/SeekBarPreference/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/Peripheral/SeekBarPreference/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.0.0' 7 | } 8 | } 9 | apply plugin: 'android-library' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | android { 16 | compileSdkVersion 21 17 | buildToolsVersion '21.1.1' 18 | 19 | defaultConfig { 20 | minSdkVersion 8 21 | targetSdkVersion 20 22 | } 23 | } 24 | 25 | dependencies { 26 | } 27 | -------------------------------------------------------------------------------- /app/Peripheral/SeekBarPreference/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/Peripheral/SeekBarPreference/src/main/res/layout/seek_bar_preference.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 19 | 25 | 26 | 27 | 32 | 33 | 34 | 41 | 42 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/Peripheral/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/Peripheral/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion '21.1.1' 6 | 7 | defaultConfig { 8 | applicationId "edu.umich.eecs.lab11.peripheral" 9 | minSdkVersion 21 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile project(':SeekBarPreference') 24 | } 25 | -------------------------------------------------------------------------------- /app/Peripheral/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/thomas/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/androidTest/java/edu/umich/eecs/lab11/peripheral/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.peripheral; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/java/edu/umich/eecs/lab11/peripheral/BetterEditText.java: -------------------------------------------------------------------------------- 1 | package edu.umich.eecs.lab11.peripheral; 2 | 3 | import android.content.Context; 4 | import android.preference.EditTextPreference; 5 | import android.text.TextUtils; 6 | import android.util.AttributeSet; 7 | 8 | public class BetterEditText extends EditTextPreference { 9 | 10 | public BetterEditText(Context context, AttributeSet attrs, int defStyle) { 11 | super(context, attrs, defStyle); 12 | } 13 | 14 | public BetterEditText(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | public BetterEditText(Context context) { 19 | super(context); 20 | } 21 | 22 | // According to ListPreference implementation 23 | @Override 24 | public CharSequence getSummary() { 25 | String text = getText(); 26 | if (TextUtils.isEmpty(text)) { 27 | return getEditText().getHint(); 28 | } else { 29 | CharSequence summary = super.getSummary(); 30 | if (summary != null) { 31 | return String.format(summary.toString(), text); 32 | } else { 33 | return null; 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Peripheral/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Peripheral/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Peripheral/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Peripheral/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/menu/menu_demo.xml: -------------------------------------------------------------------------------- 1 | 3 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Peripheral 5 | View Spec 6 | Reset Options 7 | Send Demo Advertisement 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/xml/activity_demo.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 |
9 | 10 |
13 | 14 |
16 | 17 | -------------------------------------------------------------------------------- /app/Peripheral/app/src/main/res/xml/demo_preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 45 | 46 | 47 | 51 | 55 | 59 | 63 | 67 | 71 | 75 | 80 | 81 | 82 | 87 | 88 | 89 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /app/Peripheral/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.0.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Peripheral/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/Peripheral/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lab11/iot-gateway/327cf283bf5ffc2696d3468f6e5bfc42c41a238f/app/Peripheral/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/Peripheral/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Dec 18 02:11:43 EST 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /app/Peripheral/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /app/Peripheral/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/Peripheral/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':SeekBarPreference' 2 | -------------------------------------------------------------------------------- /datacloud/README.md: -------------------------------------------------------------------------------- 1 | Example implementation of a responding "data cloud" for demonstrating bidirectional operation. 2 | 3 | Currently running at http://gatewaycloud.elasticbeanstalk.com on Node.js. 4 | 5 | The interesting stuff is in routes/index.js. 6 | -------------------------------------------------------------------------------- /datacloud/node-express/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../main'); 8 | var debug = require('debug')('node-express:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /datacloud/node-express/main.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var routes = require('./routes/index'); 9 | var users = require('./routes/users'); 10 | 11 | var app = express(); 12 | 13 | // view engine setup 14 | app.set('views', path.join(__dirname, 'views')); 15 | app.set('view engine', 'jade'); 16 | 17 | // uncomment after placing your favicon in /public 18 | //app.use(favicon(__dirname + '/public/favicon.ico')); 19 | app.use(logger('dev')); 20 | app.use(bodyParser.json()); 21 | app.use(bodyParser.urlencoded({ extended: false })); 22 | app.use(cookieParser()); 23 | app.use(express.static(path.join(__dirname, 'public'))); 24 | app.use('/temperature',express.static(path.join(__dirname, 'ui_examples/temperature'))); 25 | app.use('/light',express.static(path.join(__dirname, 'ui_examples/light'))); 26 | app.use('/uart',express.static(path.join(__dirname, 'ui_examples/uart'))); 27 | 28 | app.use('/', routes); 29 | app.use('/users', users); 30 | 31 | // catch 404 and forward to error handler 32 | app.use(function(req, res, next) { 33 | var err = new Error('Not Found'); 34 | err.status = 404; 35 | next(err); 36 | }); 37 | 38 | // error handlers 39 | 40 | // development error handler 41 | // will print stacktrace 42 | if (app.get('env') === 'development') { 43 | app.use(function(err, req, res, next) { 44 | res.status(err.status || 500); 45 | res.render('error', { 46 | message: err.message, 47 | error: err 48 | }); 49 | }); 50 | } 51 | 52 | // production error handler 53 | // no stacktraces leaked to user 54 | app.use(function(err, req, res, next) { 55 | res.status(err.status || 500); 56 | res.render('error', { 57 | message: err.message, 58 | error: {} 59 | }); 60 | }); 61 | 62 | 63 | module.exports = app; 64 | -------------------------------------------------------------------------------- /datacloud/node-express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-express", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.10.2", 10 | "cookie-parser": "~1.3.3", 11 | "debug": "~2.1.1", 12 | "express": "~4.11.1", 13 | "jade": "~1.9.1", 14 | "morgan": "~1.5.1", 15 | "serve-favicon": "~2.2.0", 16 | "request": "~2.53.0" 17 | } 18 | } -------------------------------------------------------------------------------- /datacloud/node-express/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } -------------------------------------------------------------------------------- /datacloud/node-express/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | // var io = require('socket.io')(require('http').Server(express)); 5 | 6 | var CCUUID = "00002000-0000-1000-8000-00805f9b34fb"; 7 | var CCDATAUUID = "00002b00-0000-1000-8000-00805f9b34fb"; 8 | var CCREADYUUID = "00002b04-0000-1000-8000-00805f9b34fb"; 9 | 10 | var hex2a = function(hexx) { 11 | var hex = hexx.toString();//force conversion 12 | var str = ''; 13 | for (var i = 0, s; i < hex.length; i += 2) str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); 14 | return str; 15 | } 16 | 17 | /* GET home page. */ 18 | router.get('/', function(req, res, next) { res.render('index', { title: 'Gateway Cloud' }); }); 19 | 20 | 21 | /* POST response */ 22 | router.post('/', function(req, res) { 23 | console.log(JSON.stringify(req.body,null,4)); 24 | 25 | 26 | /* OPO */ 27 | 28 | if (typeof req.body.NAME != "undefined" && req.body.NAME == "Opo") { 29 | 30 | if (typeof req.body.ATTRIBUTES == "undefined") { 31 | res.send(JSON.stringify({ 32 | "name" : req.body.NAME, 33 | "device_id" : req.body.DEVICE_ID, 34 | "services":[ 35 | { 36 | "uuid": CCUUID, 37 | "characteristics":[ 38 | {"uuid":CCDATAUUID,"action":"indicate","ccmanager_uuid":CCREADYUUID,"time":60000,"response":"accumulate"} 39 | ] 40 | } 41 | ] 42 | })); 43 | } else { 44 | res.send("RE-RESPOND SUCCESSFUL! DISCONNECT BLE NOW!"); 45 | data = req.body; 46 | data["OPO"] = req.body.ATTRIBUTES[0]; 47 | request.post({ 48 | url:'http://gatd.eecs.umich.edu:8081/SgYPCHTR5a', 49 | headers:{"content-type":"application/json"}, 50 | body:JSON.stringify(data)}, 51 | function(error,response,body){console.log(body);}); 52 | } 53 | } 54 | 55 | 56 | /* TESSEL */ 57 | 58 | else if (typeof req.body.DEVICE_ID != "undefined" && req.body.DEVICE_ID == "00:07:80:79:31:67") 59 | if (typeof req.body.ATTRIBUTES == "undefined") { 60 | res.send(JSON.stringify({ 61 | "device_id" : "00:07:80:79:31:67", 62 | "services":[ 63 | { 64 | "uuid":"08c8c7a0-6cc5-11e3-981f-0800200c9a66", 65 | "characteristics":[ 66 | {"uuid":"50888c10-6cc5-11e3-981f-0800200c9a66","action":"read","value":""} 67 | ] 68 | } 69 | , { 70 | "uuid":"d752c5fb-1380-4cd5-b0ef-cac7d72cff20", 71 | "characteristics":[ 72 | {"uuid":"883f1e6b-76f6-4da1-87eb-6bdbdb617888","action":"read","value":""}, 73 | {"uuid":"21819AB0-C937-4188-B0DB-B9621E1696CD","action":"read","value":""}, 74 | {"uuid":"57b09eae-a369-4677-bf6e-92a95baa3a38","action":"read","value":""}, 75 | {"uuid":"6696f92e-f3c0-4d85-84dd-798b0ceff2e9","action":"read","value":""}, 76 | {"uuid":"488b0448-3aaf-44c6-90ec-c85fd5d9f616","action":"read","value":""}, 77 | {"uuid":"e101b160-a59b-4f24-97df-6821337b45b2","action":"read","value":""}, 78 | {"uuid":"7834933b-3f6d-44b3-b38e-8b67a7ed6702","action":"read","value":""}, 79 | {"uuid":"b08e1773-fbb6-428d-9e4c-d6322f7bf5fe","action":"read","value":""}, 80 | {"uuid":"c98e8fd3-5be7-43e0-b35a-951f1a07c25c","action":"write","value":1,"format":"uint8"}, 81 | {"uuid":"977840be-8d5c-4805-a329-2f9ddc8db3a3","action":"read","value":""}, 82 | {"uuid":"bb2ed798-9d0b-41a6-a753-31b16f93281e","action":"read","value":""}, 83 | {"uuid":"4a0efa07-e181-4a7f-bd72-094df3e97132","action":"read","value":""} 84 | ] 85 | } 86 | ] 87 | // "ui":"TESSEL

Room Temperature : 78°

Humidity: 15%

TIME:
10:30 AM" 88 | })); 89 | } else { 90 | res.send("RE-RESPOND SUCCESSFUL! DISCONNECT BLE NOW!"); 91 | data = {"ID":req.body.DEVICE_ID,"version":hex2a(req.body.ATTRIBUTES[0].value)} 92 | for (i=1; i 2 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | BLE Light 27 | 31 | 32 | 33 |

BBB2909 Light

34 | 35 |

36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/light/js/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /* 21 | * Connects to light bulb, and reads/writes the switch characteristic to turn it on or off 22 | */ 23 | 24 | var deviceID = ""; 25 | 26 | var light = { 27 | service: 'FF10', // light service uuid 28 | onoff: 'FF11', // light switch characteristic uuid 29 | }; 30 | 31 | var app = { 32 | initialize: function() { 33 | this.bindEvents(); 34 | }, 35 | bindEvents: function() { 36 | document.addEventListener('deviceready', this.onDeviceReady, false); 37 | document.addEventListener('pause', this.onPause, false); 38 | document.addEventListener('resume', this.onDeviceReady, false); 39 | bulb.addEventListener('touchstart', this.onToggle, false); // if bulb image touched, goto: onToggle 40 | }, 41 | onDeviceReady: function() { 42 | deviceID = window.gateway.getDeviceId(); // get device ID from Gateway 43 | deviceName = window.gateway.getDeviceName(); // get device name from Gateway 44 | document.querySelector("img").className = "Dis"; // bulb image in 'disconnected' mode 45 | ble.isEnabled(app.onEnable,function(){ // if BLE enabled, goto: onEnable 46 | document.querySelector("#console").innerHTML = "Bluetooth Off."; // else, alert user 47 | }); 48 | }, 49 | onEnable: function() { 50 | document.querySelector("#console").innerHTML = "Searching..."; 51 | ble.stopScan(); 52 | ble.startScan([], app.onDiscover, app.onDeviceReady); // start BLE scan; if device discovered, goto: onDiscover 53 | }, 54 | onDiscover: function(device) { 55 | if (device.id == deviceID) { 56 | document.querySelector("#console").innerHTML = "Found! Connecting..."; 57 | ble.connect(deviceID, app.onConnect, app.onDeviceReady); // if device matches, connect; if connected, goto: onConnect 58 | } 59 | }, 60 | onConnect: function(device) { 61 | document.querySelector("#console").innerHTML = "Connected! Syncing..."; 62 | ble.read(deviceID, light.service, light.onoff, app.onRead, app.onRWError); // read switch characteristic; if read is good, goto: onRead 63 | }, 64 | onRead: function(data) { 65 | document.querySelector("img").className = ((new Uint8Array(data))[0]===0x1) ? "On" : "Off"; // bulb image in 'on' or 'off' mode 66 | document.querySelector("#console").innerHTML = document.querySelector("img").className; // display text: "On" or "Off" 67 | }, 68 | onToggle: function(event) { 69 | if (event.target.className!="Dis") { // if image touched & bulb connected, 70 | data = new Uint8Array(1); 71 | data[0] = (event.target.className=="Off") ? 0x1 : 0x0; // set up switch toggle write 72 | ble.write(deviceID, light.service, light.onoff, data.buffer, app.onRead(data), app.onRWError); // write switch characteristic; if good, goto: onRead 73 | } 74 | }, 75 | onPause: function() { // if user leaves app, stop BLE 76 | ble.disconnect(deviceID,function(){deviceID="";}); 77 | ble.stopScan(); 78 | }, 79 | onRWError: function() { // on error, try restarting BLE 80 | ble.isEnabled(deviceID,function(){},app.onDeviceReady); 81 | ble.isConnected(deviceID,function(){},app.onDeviceReady); 82 | } 83 | }; 84 | 85 | app.initialize(); // start the app -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/light/plugins/com.megster.cordova.ble/www/ble.js: -------------------------------------------------------------------------------- 1 | cordova.define("com.megster.cordova.ble.ble", function(require, exports, module) { // (c) 2014 Don Coleman 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* global cordova, module */ 16 | "use strict"; 17 | 18 | var stringToArrayBuffer = function(str) { 19 | var ret = new Uint8Array(str.length); 20 | for (var i = 0; i < str.length; i++) { 21 | ret[i] = str.charCodeAt(i); 22 | } 23 | // TODO would it be better to return Uint8Array? 24 | return ret.buffer; 25 | }; 26 | 27 | var base64ToArrayBuffer = function(b64) { 28 | return stringToArrayBuffer(atob(b64)); 29 | }; 30 | 31 | function massageMessageNativeToJs(message) { 32 | if (message.CDVType == 'ArrayBuffer') { 33 | message = base64ToArrayBuffer(message.data); 34 | } 35 | return message; 36 | } 37 | 38 | // Cordova 3.6 doesn't unwrap ArrayBuffers in nested data structures 39 | // https://github.com/apache/cordova-js/blob/94291706945c42fd47fa632ed30f5eb811080e95/src/ios/exec.js#L107-L122 40 | function convertToNativeJS(object) { 41 | Object.keys(object).forEach(function (key) { 42 | var value = object[key]; 43 | object[key] = massageMessageNativeToJs(value); 44 | if (typeof(value) === 'object') { 45 | convertToNativeJS(value); 46 | } 47 | }); 48 | } 49 | 50 | module.exports = { 51 | 52 | scan: function (services, seconds, success, failure) { 53 | var successWrapper = function(peripheral) { 54 | convertToNativeJS(peripheral); 55 | success(peripheral); 56 | }; 57 | cordova.exec(successWrapper, failure, 'BLE', 'scan', [services, seconds]); 58 | }, 59 | 60 | startScan: function (services, success, failure) { 61 | var successWrapper = function(peripheral) { 62 | convertToNativeJS(peripheral); 63 | success(peripheral); 64 | }; 65 | cordova.exec(successWrapper, failure, 'BLE', 'startScan', [services]); 66 | }, 67 | 68 | stopScan: function (success, failure) { 69 | cordova.exec(success, failure, 'BLE', 'stopScan', []); 70 | }, 71 | 72 | 73 | // this will probably be removed 74 | list: function (success, failure) { 75 | cordova.exec(success, failure, 'BLE', 'list', []); 76 | }, 77 | 78 | connect: function (device_id, success, failure) { 79 | var successWrapper = function(peripheral) { 80 | convertToNativeJS(peripheral); 81 | success(peripheral); 82 | }; 83 | cordova.exec(successWrapper, failure, 'BLE', 'connect', [device_id]); 84 | }, 85 | 86 | disconnect: function (device_id, success, failure) { 87 | cordova.exec(success, failure, 'BLE', 'disconnect', [device_id]); 88 | }, 89 | 90 | // characteristic value comes back as ArrayBuffer in the success callback 91 | read: function (device_id, service_uuid, characteristic_uuid, success, failure) { 92 | cordova.exec(success, failure, 'BLE', 'read', [device_id, service_uuid, characteristic_uuid]); 93 | }, 94 | 95 | // value must be an ArrayBuffer 96 | write: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 97 | cordova.exec(success, failure, 'BLE', 'write', [device_id, service_uuid, characteristic_uuid, value]); 98 | }, 99 | 100 | // value must be an ArrayBuffer 101 | writeWithoutResponse: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 102 | cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]); 103 | }, 104 | 105 | // value must be an ArrayBuffer 106 | writeCommand: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 107 | console.log("WARNING: writeCommand is deprecated, use writeWithoutResponse"); 108 | cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]); 109 | }, 110 | 111 | // success callback is called on notification 112 | notify: function (device_id, service_uuid, characteristic_uuid, success, failure) { 113 | console.log("WARNING: notify is deprecated, use startNotification"); 114 | cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]); 115 | }, 116 | 117 | // success callback is called on notification 118 | startNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) { 119 | cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]); 120 | }, 121 | 122 | // success callback is called when the descriptor 0x2902 is written 123 | stopNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) { 124 | cordova.exec(success, failure, 'BLE', 'stopNotification', [device_id, service_uuid, characteristic_uuid]); 125 | }, 126 | 127 | // success callback is called on indication. 128 | indicate: function (device_id, service_uuid, characteristic_uuid, success, failure) { 129 | cordova.exec(success, failure, 'BLE', 'indicate', [device_id, service_uuid, characteristic_uuid]); 130 | }, 131 | 132 | isConnected: function (device_id, success, failure) { 133 | cordova.exec(success, failure, 'BLE', 'isConnected', [device_id]); 134 | }, 135 | 136 | isEnabled: function (success, failure) { 137 | cordova.exec(success, failure, 'BLE', 'isEnabled', []); 138 | } 139 | 140 | }; 141 | 142 | }); 143 | -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/temperature/cordova_plugins.js: -------------------------------------------------------------------------------- 1 | cordova.define('cordova/plugin_list', function(require, exports, module) { 2 | module.exports = [ 3 | { 4 | "file": "plugins/com.megster.cordova.ble/www/ble.js", 5 | "id": "com.megster.cordova.ble.ble", 6 | "clobbers": [ 7 | "ble" 8 | ] 9 | } 10 | ]; 11 | module.exports.metadata = 12 | // TOP OF METADATA 13 | { 14 | "com.megster.cordova.ble": "0.1.7" 15 | } 16 | // BOTTOM OF METADATA 17 | }); -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/temperature/index.html: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | BLE Temperature 27 | 28 | 29 | 30 |

Temperature

31 |

32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/temperature/js/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /* 21 | * Displays temperature readings from a peripheral's advertisement 22 | */ 23 | 24 | var app = { 25 | initialize: function() { 26 | this.bindEvents(); 27 | document.querySelector("#console").innerHTML = "-°C"; 28 | document.querySelector("#console").className = "0"; 29 | }, 30 | bindEvents: function() { 31 | document.addEventListener('deviceready', this.onDeviceReady, false); 32 | document.addEventListener('resume', this.onDeviceReady, false); 33 | document.addEventListener('pause', this.onPause, false); 34 | }, 35 | onDeviceReady: function() { 36 | deviceId = window.gateway.getDeviceId(); // get device ID from Gateway 37 | document.querySelector("#title").innerHTML = window.gateway.getDeviceName() + " Temperature"; // get device name from Gateway & set title 38 | ble.isEnabled(app.onEnable,function(){ document.querySelector("#console").innerHTML = "BLE OFF"; }); // if BLE enabled, goto: onEnable 39 | }, 40 | onEnable: function() { 41 | ble.stopScan(); 42 | ble.startScan([], app.onDiscover, app.onDeviceReady); // start BLE scan; if device discovered, goto: onDiscover 43 | }, 44 | onDiscover: function(device) { 45 | if (device.id == deviceId) app.display(device); // if discovered device matches, goto: display 46 | }, 47 | onPause: function() { 48 | ble.stopScan(); // if user leaves app, stop BLE 49 | }, 50 | display: function(device) { 51 | value = app.getServiceData(device.advertising)[16] // get temperature value from the advertisement 52 | current = document.querySelector("#console").className; // rest of function is just for fancy display effects 53 | delta = (current-value)/100; 54 | i = 0; 55 | dig = function () { 56 | current -= delta; 57 | document.querySelector("#console").className = Math.round(current); 58 | document.querySelector("#console").innerHTML = Math.round(current) + "°C"; 59 | if(i++<100) setTimeout(function () {dig()},10); 60 | }; 61 | if (isNaN(parseInt(current))) { 62 | document.querySelector("#console").innerHTML = value + "°C"; 63 | document.querySelector("#console").className = value; 64 | } else if (current != value) dig(); 65 | document.querySelector('body').style.background = 'rgb(' + Math.round(9.75 * value) + ',' + 96 + ',' + Math.round(255 - (9.75*value)) + ')'; 66 | }, 67 | getServiceData:function(device) { // searches BLE advertisement for ServiceData 68 | scanRecord = new Uint8Array(device); 69 | index = 0; 70 | while (index < scanRecord.length) { 71 | length = scanRecord[index++]; 72 | if (length == 0) return new Uint8Array(20); // returns nothing if there is no ServiceData 73 | type = scanRecord[index]; 74 | if (type == 0) return new Uint8Array(20); // return nothing if advertisement is invalid 75 | data = scanRecord.subarray(index + 1, index + length); 76 | if (type==22 && data[0]>=' ') return data; // returns ServiceData 77 | index += length; //advance 78 | } 79 | } 80 | }; 81 | 82 | app.initialize(); // start the app -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/temperature/plugins/com.megster.cordova.ble/www/ble.js: -------------------------------------------------------------------------------- 1 | cordova.define("com.megster.cordova.ble.ble", function(require, exports, module) { // (c) 2014 Don Coleman 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* global cordova, module */ 16 | "use strict"; 17 | 18 | var stringToArrayBuffer = function(str) { 19 | var ret = new Uint8Array(str.length); 20 | for (var i = 0; i < str.length; i++) { 21 | ret[i] = str.charCodeAt(i); 22 | } 23 | // TODO would it be better to return Uint8Array? 24 | return ret.buffer; 25 | }; 26 | 27 | var base64ToArrayBuffer = function(b64) { 28 | return stringToArrayBuffer(atob(b64)); 29 | }; 30 | 31 | function massageMessageNativeToJs(message) { 32 | if (message.CDVType == 'ArrayBuffer') { 33 | message = base64ToArrayBuffer(message.data); 34 | } 35 | return message; 36 | } 37 | 38 | // Cordova 3.6 doesn't unwrap ArrayBuffers in nested data structures 39 | // https://github.com/apache/cordova-js/blob/94291706945c42fd47fa632ed30f5eb811080e95/src/ios/exec.js#L107-L122 40 | function convertToNativeJS(object) { 41 | Object.keys(object).forEach(function (key) { 42 | var value = object[key]; 43 | object[key] = massageMessageNativeToJs(value); 44 | if (typeof(value) === 'object') { 45 | convertToNativeJS(value); 46 | } 47 | }); 48 | } 49 | 50 | module.exports = { 51 | 52 | scan: function (services, seconds, success, failure) { 53 | var successWrapper = function(peripheral) { 54 | convertToNativeJS(peripheral); 55 | success(peripheral); 56 | }; 57 | cordova.exec(successWrapper, failure, 'BLE', 'scan', [services, seconds]); 58 | }, 59 | 60 | startScan: function (services, success, failure) { 61 | var successWrapper = function(peripheral) { 62 | convertToNativeJS(peripheral); 63 | success(peripheral); 64 | }; 65 | cordova.exec(successWrapper, failure, 'BLE', 'startScan', [services]); 66 | }, 67 | 68 | stopScan: function (success, failure) { 69 | cordova.exec(success, failure, 'BLE', 'stopScan', []); 70 | }, 71 | 72 | 73 | // this will probably be removed 74 | list: function (success, failure) { 75 | cordova.exec(success, failure, 'BLE', 'list', []); 76 | }, 77 | 78 | connect: function (device_id, success, failure) { 79 | var successWrapper = function(peripheral) { 80 | convertToNativeJS(peripheral); 81 | success(peripheral); 82 | }; 83 | cordova.exec(successWrapper, failure, 'BLE', 'connect', [device_id]); 84 | }, 85 | 86 | disconnect: function (device_id, success, failure) { 87 | cordova.exec(success, failure, 'BLE', 'disconnect', [device_id]); 88 | }, 89 | 90 | // characteristic value comes back as ArrayBuffer in the success callback 91 | read: function (device_id, service_uuid, characteristic_uuid, success, failure) { 92 | cordova.exec(success, failure, 'BLE', 'read', [device_id, service_uuid, characteristic_uuid]); 93 | }, 94 | 95 | // value must be an ArrayBuffer 96 | write: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 97 | cordova.exec(success, failure, 'BLE', 'write', [device_id, service_uuid, characteristic_uuid, value]); 98 | }, 99 | 100 | // value must be an ArrayBuffer 101 | writeWithoutResponse: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 102 | cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]); 103 | }, 104 | 105 | // value must be an ArrayBuffer 106 | writeCommand: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 107 | console.log("WARNING: writeCommand is deprecated, use writeWithoutResponse"); 108 | cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]); 109 | }, 110 | 111 | // success callback is called on notification 112 | notify: function (device_id, service_uuid, characteristic_uuid, success, failure) { 113 | console.log("WARNING: notify is deprecated, use startNotification"); 114 | cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]); 115 | }, 116 | 117 | // success callback is called on notification 118 | startNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) { 119 | cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]); 120 | }, 121 | 122 | // success callback is called when the descriptor 0x2902 is written 123 | stopNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) { 124 | cordova.exec(success, failure, 'BLE', 'stopNotification', [device_id, service_uuid, characteristic_uuid]); 125 | }, 126 | 127 | // success callback is called on indication. 128 | indicate: function (device_id, service_uuid, characteristic_uuid, success, failure) { 129 | cordova.exec(success, failure, 'BLE', 'indicate', [device_id, service_uuid, characteristic_uuid]); 130 | }, 131 | 132 | isConnected: function (device_id, success, failure) { 133 | cordova.exec(success, failure, 'BLE', 'isConnected', [device_id]); 134 | }, 135 | 136 | isEnabled: function (success, failure) { 137 | cordova.exec(success, failure, 'BLE', 'isEnabled', []); 138 | }, 139 | 140 | enable: function (success, failure) { 141 | cordova.exec(success, failure, "BLE", "enable", []); 142 | }, 143 | 144 | showBluetoothSettings: function (success, failure) { 145 | cordova.exec(success, failure, "BLE", "showBluetoothSettings", []); 146 | } 147 | 148 | }; 149 | 150 | }); 151 | -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/uart/cordova_plugins.js: -------------------------------------------------------------------------------- 1 | cordova.define('cordova/plugin_list', function(require, exports, module) { 2 | module.exports = [ 3 | { 4 | "file": "plugins/com.megster.cordova.ble/www/ble.js", 5 | "id": "com.megster.cordova.ble.ble", 6 | "clobbers": [ 7 | "ble" 8 | ] 9 | } 10 | ]; 11 | module.exports.metadata = 12 | // TOP OF METADATA 13 | { 14 | "com.megster.cordova.ble": "0.1.7" 15 | } 16 | // BOTTOM OF METADATA 17 | }); -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/uart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | BLUART 27 | 28 | 29 | 30 |

31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/uart/js/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /* 21 | * Connects to light bulb, and reads/writes the switch characteristic to turn it on or off 22 | */ 23 | 24 | var deviceID = ""; 25 | 26 | var uart = { 27 | service: '6E400001-B5A3-F393-E0A9-E50E24DCCA9E', // uart service uuid 28 | tx: '6E400002-B5A3-F393-E0A9-E50E24DCCA9E', // uart tx characteristic uuid 29 | rx: '6E400003-B5A3-F393-E0A9-E50E24DCCA9E', // uart rx characteristic uuid 30 | }; 31 | 32 | var app = { 33 | initialize: function() { 34 | this.bindEvents(); 35 | }, 36 | bindEvents: function() { 37 | document.addEventListener('deviceready', this.onDeviceReady, false); 38 | document.addEventListener('pause', this.onPause, false); 39 | document.addEventListener('resume', this.onDeviceReady, false); 40 | input.addEventListener('change', this.onChange, false); // user inputted message event 41 | }, 42 | onDeviceReady: function() { 43 | // deviceID = "E0:44:D5:5D:84:F2"; 44 | deviceID = window.gateway.getDeviceId(); // get device ID from Gateway 45 | ble.isEnabled(app.onEnable, app.log("BLE","Bluetooth Off.")); // if BLE enabled, goto: onEnable 46 | }, 47 | onEnable: function() { 48 | app.log("BLE","Searching..."); 49 | ble.stopScan(); 50 | ble.startScan([], app.onDiscover, app.onDeviceReady); // start BLE scan; see a device? goto: onDiscover 51 | }, 52 | onDiscover: function(device) { 53 | if (device.id == deviceID) { 54 | app.log("BLE","Found! Connecting..."); 55 | ble.connect(deviceID, app.onConnect, app.onDeviceReady); // if device matches, connect; goto: onConnect 56 | } 57 | }, 58 | onConnect: function(device) { 59 | ble.startNotification(deviceID, uart.service, uart.rx, function(d){app.log("RX",app.bytesToString(d))}, app.onError); // request rx notifications; on rx, goto:onData 60 | }, 61 | onChange: function(event) { 62 | if (input.value!="") 63 | ble.write(deviceID, uart.service, uart.tx, app.stringToBytes(input.value), app.log("TX",input.value), app.onError); // write tx message; if good, goto: onRead 64 | input.value = ""; 65 | }, 66 | onPause: function() { // if user leaves app, stop BLE 67 | app.log("BLE","Disconnecting.") 68 | ble.disconnect(deviceID,function(){deviceID="";}); 69 | ble.stopScan(); 70 | }, 71 | onError: function(e) { // on error, try restarting BLE 72 | app.log("ERR",e); 73 | ble.isEnabled(deviceID,function(){},app.onDeviceReady); 74 | ble.isConnected(deviceID,function(){},app.onDeviceReady); 75 | }, 76 | stringToBytes: function(string) { 77 | array = new Uint8Array(string.length); 78 | for (i = 0, l = string.length; i < l; i++) array[i] = string.charCodeAt(i); 79 | return array.buffer; 80 | }, 81 | bytesToString: function(buffer) { 82 | return String.fromCharCode.apply(null, new Uint8Array(buffer)); 83 | }, 84 | log: function(tag,string) { 85 | document.querySelector("#console").innerHTML+= "["+(new Date()).toLocaleTimeString()+"] " + tag + " : " + string + "
"; 86 | } 87 | }; 88 | 89 | app.initialize(); // start the app -------------------------------------------------------------------------------- /datacloud/node-express/ui_examples/uart/plugins/com.megster.cordova.ble/www/ble.js: -------------------------------------------------------------------------------- 1 | cordova.define("com.megster.cordova.ble.ble", function(require, exports, module) { // (c) 2014 Don Coleman 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* global cordova, module */ 16 | "use strict"; 17 | 18 | var stringToArrayBuffer = function(str) { 19 | var ret = new Uint8Array(str.length); 20 | for (var i = 0; i < str.length; i++) { 21 | ret[i] = str.charCodeAt(i); 22 | } 23 | // TODO would it be better to return Uint8Array? 24 | return ret.buffer; 25 | }; 26 | 27 | var base64ToArrayBuffer = function(b64) { 28 | return stringToArrayBuffer(atob(b64)); 29 | }; 30 | 31 | function massageMessageNativeToJs(message) { 32 | if (message.CDVType == 'ArrayBuffer') { 33 | message = base64ToArrayBuffer(message.data); 34 | } 35 | return message; 36 | } 37 | 38 | // Cordova 3.6 doesn't unwrap ArrayBuffers in nested data structures 39 | // https://github.com/apache/cordova-js/blob/94291706945c42fd47fa632ed30f5eb811080e95/src/ios/exec.js#L107-L122 40 | function convertToNativeJS(object) { 41 | Object.keys(object).forEach(function (key) { 42 | var value = object[key]; 43 | object[key] = massageMessageNativeToJs(value); 44 | if (typeof(value) === 'object') { 45 | convertToNativeJS(value); 46 | } 47 | }); 48 | } 49 | 50 | module.exports = { 51 | 52 | scan: function (services, seconds, success, failure) { 53 | var successWrapper = function(peripheral) { 54 | convertToNativeJS(peripheral); 55 | success(peripheral); 56 | }; 57 | cordova.exec(successWrapper, failure, 'BLE', 'scan', [services, seconds]); 58 | }, 59 | 60 | startScan: function (services, success, failure) { 61 | var successWrapper = function(peripheral) { 62 | convertToNativeJS(peripheral); 63 | success(peripheral); 64 | }; 65 | cordova.exec(successWrapper, failure, 'BLE', 'startScan', [services]); 66 | }, 67 | 68 | stopScan: function (success, failure) { 69 | cordova.exec(success, failure, 'BLE', 'stopScan', []); 70 | }, 71 | 72 | 73 | // this will probably be removed 74 | list: function (success, failure) { 75 | cordova.exec(success, failure, 'BLE', 'list', []); 76 | }, 77 | 78 | connect: function (device_id, success, failure) { 79 | var successWrapper = function(peripheral) { 80 | convertToNativeJS(peripheral); 81 | success(peripheral); 82 | }; 83 | cordova.exec(successWrapper, failure, 'BLE', 'connect', [device_id]); 84 | }, 85 | 86 | disconnect: function (device_id, success, failure) { 87 | cordova.exec(success, failure, 'BLE', 'disconnect', [device_id]); 88 | }, 89 | 90 | // characteristic value comes back as ArrayBuffer in the success callback 91 | read: function (device_id, service_uuid, characteristic_uuid, success, failure) { 92 | cordova.exec(success, failure, 'BLE', 'read', [device_id, service_uuid, characteristic_uuid]); 93 | }, 94 | 95 | // value must be an ArrayBuffer 96 | write: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 97 | cordova.exec(success, failure, 'BLE', 'write', [device_id, service_uuid, characteristic_uuid, value]); 98 | }, 99 | 100 | // value must be an ArrayBuffer 101 | writeWithoutResponse: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 102 | cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]); 103 | }, 104 | 105 | // value must be an ArrayBuffer 106 | writeCommand: function (device_id, service_uuid, characteristic_uuid, value, success, failure) { 107 | console.log("WARNING: writeCommand is deprecated, use writeWithoutResponse"); 108 | cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]); 109 | }, 110 | 111 | // success callback is called on notification 112 | notify: function (device_id, service_uuid, characteristic_uuid, success, failure) { 113 | console.log("WARNING: notify is deprecated, use startNotification"); 114 | cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]); 115 | }, 116 | 117 | // success callback is called on notification 118 | startNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) { 119 | cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]); 120 | }, 121 | 122 | // success callback is called when the descriptor 0x2902 is written 123 | stopNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) { 124 | cordova.exec(success, failure, 'BLE', 'stopNotification', [device_id, service_uuid, characteristic_uuid]); 125 | }, 126 | 127 | // success callback is called on indication. 128 | indicate: function (device_id, service_uuid, characteristic_uuid, success, failure) { 129 | cordova.exec(success, failure, 'BLE', 'indicate', [device_id, service_uuid, characteristic_uuid]); 130 | }, 131 | 132 | isConnected: function (device_id, success, failure) { 133 | cordova.exec(success, failure, 'BLE', 'isConnected', [device_id]); 134 | }, 135 | 136 | isEnabled: function (success, failure) { 137 | cordova.exec(success, failure, 'BLE', 'isEnabled', []); 138 | }, 139 | 140 | enable: function (success, failure) { 141 | cordova.exec(success, failure, "BLE", "enable", []); 142 | }, 143 | 144 | showBluetoothSettings: function (success, failure) { 145 | cordova.exec(success, failure, "BLE", "showBluetoothSettings", []); 146 | } 147 | 148 | }; 149 | 150 | }); 151 | -------------------------------------------------------------------------------- /datacloud/node-express/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /datacloud/node-express/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} -------------------------------------------------------------------------------- /datacloud/node-express/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content -------------------------------------------------------------------------------- /demo_test.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | def send_message(temp): 4 | MESSAGE = '{\n "temp": '+str(temp)+'\n}' 5 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 6 | sock.sendto(MESSAGE, (UDP_IP, UDP_PORT)) 7 | 8 | UDP_IP = "127.0.0.1" 9 | UDP_PORT = 5911 10 | 11 | for x in range(40, 150): 12 | send_message(x) 13 | 14 | -------------------------------------------------------------------------------- /demo_vis.py: -------------------------------------------------------------------------------- 1 | import socket, json 2 | 3 | def print_graph(temp): 4 | tick_str = "" 5 | for tick in range(0, temp-40): 6 | tick_str += "-" 7 | print "temp: " + str(temp) + " " + tick_str 8 | 9 | 10 | UDP_IP = "127.0.0.1" 11 | UDP_PORT = 5911 12 | 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 14 | sock.bind((UDP_IP, UDP_PORT)) 15 | 16 | while True: 17 | data, addr = sock.recvfrom(1024) 18 | rec = json.loads(data) 19 | print_graph(rec['temp']) 20 | 21 | 22 | -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 54 |
55 |
56 |
57 |
58 |
59 | PERIPHERAL DATA
60 | via Smartphone Gateway
61 | Temperature 0°F
62 | Humidity 0%
63 | Firmware v0
64 | Last Update:
65 |
66 |
68 |
69 |
70 |
71 | 72 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | IOT Gateway Log 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 |

AT GATEWAY (RECEIVED AT DEBUG CLOUD)

19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
TIMESTAMPPERIPHERAL IDNAMERSSISEND TOQOSPROGDATASENSORS
37 |
38 |

RECEIVED AT DATA CLOUD

39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |
TIMESTAMPDATAGW TIMELOCATIONACCELLIGHTTEXTIMAGE
56 |
57 |

RECEIVED AT INCENTIVE CLOUD

58 |
59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
TIMESTAMPPERIPHERAL IDPROGRAM IPPROGRAM NAMEPROGRAM PAYTOTAL SIZETHIS SIZE
72 |
73 | 98 | 99 | -------------------------------------------------------------------------------- /json/gatt.js: -------------------------------------------------------------------------------- 1 | known = { "8880" : "MetaWatch (Inferred)" 2 | , "ff10" : "RoboSmart Light Bulb (Inferred)" 3 | , "ff20" : "RoboSmart Light Bulb (Inferred)" 4 | , "fff0" : "isSmart Light Bough (Inferred)" 5 | , "39e1fa0084a811e2afba0002a5d5c51b" : "Parrot Flower Power (Inferred)" 6 | , "426c7565746f6f74682042756c620000" : "Bluetooth Bulb (Inferred)" 7 | , "4b455254747211e1a5750002a5d58001" : "COOKOO Watch (Inferred)" 8 | , "6a8730836c064dfabb5469b2240f9e9f" : "tod (Inferred)" 9 | , "adabfb006e7d4601bda2bffaa68956ba" : "Fitbit (Inferred)" 10 | , "bec26202a8d84a9480fc9ac1de37daa6" : "StickNFind (Inferred)" 11 | }; 12 | services = { 13 | "1800" : { "name" : "Generic Access" 14 | , "type" : "org.bluetooth.service.generic_access" 15 | } 16 | , "1801" : { "name" : "Generic Attribute" 17 | , "type" : "org.bluetooth.service.generic_attribute" 18 | } 19 | , "1802" : { "name" : "Immediate Alert" 20 | , "type" : "org.bluetooth.service.immediate_alert" 21 | } 22 | , "1803" : { "name" : "Link Loss" 23 | , "type" : "org.bluetooth.service.link_loss" 24 | } 25 | , "1804" : { "name" : "Tx Power" 26 | , "type" : "org.bluetooth.service.tx_power" 27 | } 28 | , "1805" : { "name" : "Current Time Service" 29 | , "type" : "org.bluetooth.service.current_time" 30 | } 31 | , "1806" : { "name" : "Reference Time Update Service" 32 | , "type" : "org.bluetooth.service.reference_time_update" 33 | } 34 | , "1807" : { "name" : "Next DST Change Service" 35 | , "type" : "org.bluetooth.service.next_dst_change" 36 | } 37 | , "1808" : { "name" : "Glucose" 38 | , "type" : "org.bluetooth.service.glucose" 39 | } 40 | , "1809" : { "name" : "Health Thermometer" 41 | , "type" : "org.bluetooth.service.health_thermometer" 42 | } 43 | , "180a" : { "name" : "Device Information" 44 | , "type" : "org.bluetooth.service.device_information" 45 | } 46 | , "180d" : { "name" : "Heart Rate" 47 | , "type" : "org.bluetooth.service.heart_rate" 48 | } 49 | , "180e" : { "name" : "Phone Alert Status Service" 50 | , "type" : "org.bluetooth.service.phone_alert_service" 51 | } 52 | , "180f" : { "name" : "Battery Service" 53 | , "type" : "org.bluetooth.service.battery_service" 54 | } 55 | , "1810" : { "name" : "Blood Pressure" 56 | , "type" : "org.bluetooth.service.blood_pressuer" 57 | } 58 | , "1811" : { "name" : "Alert Notification Service" 59 | , "type" : "org.bluetooth.service.alert_notification" 60 | } 61 | , "1812" : { "name" : "Human Interface Device" 62 | , "type" : "org.bluetooth.service.human_interface_device" 63 | } 64 | , "1813" : { "name" : "Scan Parameters" 65 | , "type" : "org.bluetooth.service.scan_parameters" 66 | } 67 | , "1814" : { "name" : "Running Speed and Cadence" 68 | , "type" : "org.bluetooth.service.running_speed_and_cadence" 69 | } 70 | , "1815" : { "name" : "Automation IO" 71 | , "type" : "org.bluetooth.service.automation_io" 72 | } 73 | , "1816" : { "name" : "Cycling Speed and Cadence" 74 | , "type" : "org.bluetooth.service.cycling_speed_and_cadence" 75 | } 76 | , "1818" : { "name" : "Cycling Power" 77 | , "type" : "org.bluetooth.service.cycling_power" 78 | } 79 | , "1819" : { "name" : "Location and Navigation" 80 | , "type" : "org.bluetooth.service.location_and_navigation" 81 | } 82 | , "181a" : { "name" : "Environmental Sensing" 83 | , "type" : "org.bluetooth.service.environmental_sensing" 84 | } 85 | , "181b" : { "name" : "Body Composition" 86 | , "type" : "org.bluetooth.service.body_composition" 87 | } 88 | , "181c" : { "name" : "User Data" 89 | , "type" : "org.bluetooth.service.user_data" 90 | } 91 | , "181d" : { "name" : "Weight Scale" 92 | , "type" : "org.bluetooth.service.weight_scale" 93 | } 94 | , "181e" : { "name" : "Bond Management" 95 | , "type" : "org.bluetooth.service.bond_management" 96 | } 97 | , "181f" : { "name" : "Continuous Glucose Monitoring" 98 | , "type" : "org.bluetooth.service.continuous_glucose_monitoring" 99 | } 100 | , "1820" : { "name" : "Internet Protocol Support" 101 | , "type" : "org.bluetooth.service.internet_protocol_support" 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /json/known.json: -------------------------------------------------------------------------------- 1 | { "8880" : "MetaWatch (Inferred)" 2 | , "ff10" : "RoboSmart Light Bulb (Inferred)" 3 | , "ff20" : "RoboSmart Light Bulb (Inferred)" 4 | , "fff0" : "isSmart Light Bough (Inferred)" 5 | , "39e1fa0084a811e2afba0002a5d5c51b" : "Parrot Flower Power (Inferred)" 6 | , "426c7565746f6f74682042756c620000" : "Bluetooth Bulb (Inferred)" 7 | , "4b455254747211e1a5750002a5d58001" : "COOKOO Watch (Inferred)" 8 | , "6a8730836c064dfabb5469b2240f9e9f" : "tod (Inferred)" 9 | , "adabfb006e7d4601bda2bffaa68956ba" : "Fitbit (Inferred)" 10 | , "bec26202a8d84a9480fc9ac1de37daa6" : "StickNFind (Inferred)" 11 | } -------------------------------------------------------------------------------- /json/services.json: -------------------------------------------------------------------------------- 1 | { 2 | "1800" : { "name" : "Generic Access" 3 | , "type" : "org.bluetooth.service.generic_access" 4 | } 5 | , "1801" : { "name" : "Generic Attribute" 6 | , "type" : "org.bluetooth.service.generic_attribute" 7 | } 8 | , "1802" : { "name" : "Immediate Alert" 9 | , "type" : "org.bluetooth.service.immediate_alert" 10 | } 11 | , "1803" : { "name" : "Link Loss" 12 | , "type" : "org.bluetooth.service.link_loss" 13 | } 14 | , "1804" : { "name" : "Tx Power" 15 | , "type" : "org.bluetooth.service.tx_power" 16 | } 17 | , "1805" : { "name" : "Current Time Service" 18 | , "type" : "org.bluetooth.service.current_time" 19 | } 20 | , "1806" : { "name" : "Reference Time Update Service" 21 | , "type" : "org.bluetooth.service.reference_time_update" 22 | } 23 | , "1807" : { "name" : "Next DST Change Service" 24 | , "type" : "org.bluetooth.service.next_dst_change" 25 | } 26 | , "1808" : { "name" : "Glucose" 27 | , "type" : "org.bluetooth.service.glucose" 28 | } 29 | , "1809" : { "name" : "Health Thermometer" 30 | , "type" : "org.bluetooth.service.health_thermometer" 31 | } 32 | , "180a" : { "name" : "Device Information" 33 | , "type" : "org.bluetooth.service.device_information" 34 | } 35 | , "180d" : { "name" : "Heart Rate" 36 | , "type" : "org.bluetooth.service.heart_rate" 37 | } 38 | , "180e" : { "name" : "Phone Alert Status Service" 39 | , "type" : "org.bluetooth.service.phone_alert_service" 40 | } 41 | , "180f" : { "name" : "Battery Service" 42 | , "type" : "org.bluetooth.service.battery_service" 43 | } 44 | , "1810" : { "name" : "Blood Pressure" 45 | , "type" : "org.bluetooth.service.blood_pressuer" 46 | } 47 | , "1811" : { "name" : "Alert Notification Service" 48 | , "type" : "org.bluetooth.service.alert_notification" 49 | } 50 | , "1812" : { "name" : "Human Interface Device" 51 | , "type" : "org.bluetooth.service.human_interface_device" 52 | } 53 | , "1813" : { "name" : "Scan Parameters" 54 | , "type" : "org.bluetooth.service.scan_parameters" 55 | } 56 | , "1814" : { "name" : "Running Speed and Cadence" 57 | , "type" : "org.bluetooth.service.running_speed_and_cadence" 58 | } 59 | , "1815" : { "name" : "Automation IO" 60 | , "type" : "org.bluetooth.service.automation_io" 61 | } 62 | , "1816" : { "name" : "Cycling Speed and Cadence" 63 | , "type" : "org.bluetooth.service.cycling_speed_and_cadence" 64 | } 65 | , "1818" : { "name" : "Cycling Power" 66 | , "type" : "org.bluetooth.service.cycling_power" 67 | } 68 | , "1819" : { "name" : "Location and Navigation" 69 | , "type" : "org.bluetooth.service.location_and_navigation" 70 | } 71 | , "181a" : { "name" : "Environmental Sensing" 72 | , "type" : "org.bluetooth.service.environmental_sensing" 73 | } 74 | , "181b" : { "name" : "Body Composition" 75 | , "type" : "org.bluetooth.service.body_composition" 76 | } 77 | , "181c" : { "name" : "User Data" 78 | , "type" : "org.bluetooth.service.user_data" 79 | } 80 | , "181d" : { "name" : "Weight Scale" 81 | , "type" : "org.bluetooth.service.weight_scale" 82 | } 83 | , "181e" : { "name" : "Bond Management" 84 | , "type" : "org.bluetooth.service.bond_management" 85 | } 86 | , "181f" : { "name" : "Continuous Glucose Monitoring" 87 | , "type" : "org.bluetooth.service.continuous_glucose_monitoring" 88 | } 89 | , "1820" : { "name" : "Internet Protocol Support" 90 | , "type" : "org.bluetooth.service.internet_protocol_support" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /peripherals.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | BLE Device Log 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
ADDRESSDEVICETIMELOCATIONADVERTISEMENTSERVICES
35 |
36 | 45 | 113 | 114 | -------------------------------------------------------------------------------- /raw.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /squall/software/apps/iotgw/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = $(shell basename "$(realpath ./)") 2 | 3 | APPLICATION_SRCS = $(notdir $(wildcard ./*.c)) 4 | APPLICATION_SRCS += softdevice_handler.c 5 | APPLICATION_SRCS += ble_advdata.c 6 | APPLICATION_SRCS += ble_debug_assert_handler.c 7 | APPLICATION_SRCS += ble_srv_common.c 8 | APPLICATION_SRCS += twi_hw_master.c 9 | APPLICATION_SRCS += led.c 10 | 11 | DEVICE = NRF51 12 | 13 | ifndef TARGET 14 | TARGET = SQUALL 15 | endif 16 | 17 | TARGET_UPPER = $(shell echo $(TARGET) | tr a-z A-Z) 18 | TARGET_LOWER = $(shell echo $(TARGET) | tr A-Z a-z) 19 | BOARD = BOARD_$(TARGET_UPPER) 20 | 21 | APPLICATION_SRCS += $(TARGET_LOWER).c 22 | 23 | USE_SOFTDEVICE = s110 24 | 25 | SDK_VERSION = 7 26 | SDK_PATH ?= $(HOME)/code/nrf51822_sdk/sdk7/ 27 | TEMPLATE_PATH ?= ../../nrf51-pure-gcc-setup/template/ 28 | 29 | LIBRARY_PATHS += ../../include 30 | SOURCE_PATHS += ../../src 31 | 32 | CFLAGS = -Os 33 | CFLAGS += $(MFLAGS) 34 | GDB_PORT_NUMBER = 2331 35 | 36 | include $(TEMPLATE_PATH)Makefile 37 | -------------------------------------------------------------------------------- /squall/software/apps/temperature/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = $(shell basename "$(realpath ./)") 2 | 3 | APPLICATION_SRCS = $(notdir $(wildcard ./*.c)) 4 | APPLICATION_SRCS += softdevice_handler.c 5 | APPLICATION_SRCS += ble_advdata.c 6 | APPLICATION_SRCS += ble_debug_assert_handler.c 7 | APPLICATION_SRCS += ble_srv_common.c 8 | APPLICATION_SRCS += twi_hw_master.c 9 | APPLICATION_SRCS += led.c app_gpiote.c app_timer.c 10 | 11 | DEVICE = NRF51 12 | 13 | ifndef TARGET 14 | TARGET = SQUALL 15 | endif 16 | 17 | TARGET_UPPER = $(shell echo $(TARGET) | tr a-z A-Z) 18 | TARGET_LOWER = $(shell echo $(TARGET) | tr A-Z a-z) 19 | BOARD = BOARD_$(TARGET_UPPER) 20 | 21 | APPLICATION_SRCS += $(TARGET_LOWER).c 22 | 23 | USE_SOFTDEVICE = s110 24 | 25 | SDK_VERSION = 7 26 | SDK_PATH ?= $(HOME)/code/nrf51822_sdk/sdk7/ 27 | TEMPLATE_PATH ?= ../../nrf51-pure-gcc-setup/template/ 28 | 29 | LIBRARY_PATHS += ../../include 30 | SOURCE_PATHS += ../../src 31 | 32 | CFLAGS = -Os 33 | CFLAGS += $(MFLAGS) 34 | GDB_PORT_NUMBER = 2331 35 | 36 | include $(TEMPLATE_PATH)Makefile 37 | -------------------------------------------------------------------------------- /squall/software/apps/uartgw/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = $(shell basename "$(realpath ./)") 2 | 3 | APPLICATION_SRCS = $(notdir $(wildcard ./*.c)) 4 | APPLICATION_SRCS += softdevice_handler.c 5 | APPLICATION_SRCS += ble_advdata.c 6 | APPLICATION_SRCS += ble_debug_assert_handler.c 7 | APPLICATION_SRCS += ble_srv_common.c 8 | APPLICATION_SRCS += led.c 9 | APPLICATION_SRCS += app_error.c simple_uart.c ble_conn_params.c 10 | APPLICATION_SRCS += app_timer.c app_gpiote.c 11 | 12 | DEVICE = NRF51 13 | 14 | ifndef TARGET 15 | TARGET = SQUALL 16 | endif 17 | 18 | TARGET_UPPER = $(shell echo $(TARGET) | tr a-z A-Z) 19 | BOARD = BOARD_$(TARGET_UPPER) 20 | 21 | USE_SOFTDEVICE = s110 22 | 23 | SDK_VERSION = 7 24 | SDK_PATH ?= $(HOME)/workspace/nrf51822/nrf51822_sdk/sdk7/ 25 | TEMPLATE_PATH ?= ../../nrf51-pure-gcc-setup/template/ 26 | SOFTDEVICE ?= $(HOME)/workspace/nrf51822/softdevices/s110_7.1.0/s110_nrf51822_7.1.0_softdevice.hex 27 | 28 | LIBRARY_PATHS += ./ 29 | LIBRARY_PATHS += ../../include 30 | SOURCE_PATHS += ../../src 31 | 32 | CFLAGS = -Os 33 | CFLAGS += $(MFLAGS) 34 | GDB_PORT_NUMBER = 2331 35 | 36 | include $(TEMPLATE_PATH)Makefile 37 | -------------------------------------------------------------------------------- /squall/software/apps/uartgw/ble_nus.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | /**@file 14 | * 15 | * @defgroup ble_sdk_srv_nus Nordic UART Service - Experimental 16 | * @{ 17 | * @ingroup ble_sdk_srv 18 | * @brief Nordic UART Service implementation. 19 | * 20 | * @details The Nordic UART Service is a simple GATT based service with a TX and RX 21 | * characteristics. Data received from the peer will be passed to the application and the 22 | * data received from the application of this service will be sent to the peer as Handle 23 | * Value Notifications. This module is intended to demonstrate how custom GATT based 24 | * service and characteristics can be implemented using the S110 SoftDevice. This service 25 | * is used by the application to send and receive ASCII text strings to and from the 26 | * peer. 27 | * 28 | * @note The application must propagate S110 SoftDevice events to the Nordic UART Service module 29 | * by calling the ble_nus_on_ble_evt() function from the @ref ble_stack_handler callback. 30 | */ 31 | 32 | #ifndef BLE_NUS_H__ 33 | #define BLE_NUS_H__ 34 | 35 | #include "ble.h" 36 | #include "ble_srv_common.h" 37 | #include 38 | #include 39 | 40 | #define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */ 41 | #define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0002 /**< The UUID of the TX Characteristic. */ 42 | #define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0003 /**< The UUID of the RX Characteristic. */ 43 | #define BLE_UUID_NUS_READ_CHARACTERISTIC 0x0004 44 | 45 | #define BLE_NUS_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3) /**< Maximum length of data (in bytes) that can be transmitted by the Nordic UART service module to the peer. */ 46 | 47 | #define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */ 48 | #define BLE_NUS_MAX_TX_CHAR_LEN 20 /**< Maximum length of the TX Characteristic (in bytes). */ 49 | #define BLE_NUS_MAX_READ_CHAR_LEN 500 50 | 51 | // Forward declaration of the ble_nus_t type. 52 | typedef struct ble_nus_s ble_nus_t; 53 | 54 | /**@brief Nordic UART Service event handler type. */ 55 | typedef void (*ble_nus_data_handler_t) (ble_nus_t * p_nus, uint8_t * data, uint16_t length); 56 | 57 | /**@brief Nordic UART Service init structure. 58 | * 59 | * @details This structure contains the initialization information for the service. The application 60 | * needs to fill this structure and pass it to the service using the @ref ble_nus_init 61 | * function. 62 | */ 63 | typedef struct 64 | { 65 | ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */ 66 | } ble_nus_init_t; 67 | 68 | /**@brief Nordic UART Service structure. 69 | * 70 | * @details This structure contains status information related to the service. 71 | */ 72 | typedef struct ble_nus_s 73 | { 74 | uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */ 75 | uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the S110 SoftDevice). */ 76 | ble_gatts_char_handles_t tx_handles; /**< Handles related to the TX characteristic. (as provided by the S110 SoftDevice)*/ 77 | ble_gatts_char_handles_t rx_handles; /**< Handles related to the RX characteristic. (as provided by the S110 SoftDevice)*/ 78 | ble_gatts_char_handles_t read_handles; 79 | uint16_t conn_handle; /**< Handle of the current connection (as provided by the S110 SoftDevice). This will be BLE_CONN_HANDLE_INVALID if not in a connection. */ 80 | bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/ 81 | ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */ 82 | } ble_nus_t; 83 | 84 | /**@brief Function for initializing the Nordic UART Service. 85 | * 86 | * @param[out] p_nus Nordic UART Service structure. This structure will have to be supplied 87 | * by the application. It will be initialized by this function and will 88 | * later be used to identify this particular service instance. 89 | * @param[in] p_nus_init Information needed to initialize the service. 90 | * 91 | * @return NRF_SUCCESS on successful initialization of service, otherwise an error code. 92 | * This function returns NRF_ERROR_NULL if either of the pointers p_nus or p_nus_init 93 | * is NULL. 94 | */ 95 | uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init); 96 | 97 | /**@brief Nordic UART Service BLE event handler. 98 | * 99 | * @details The Nordic UART service expects the application to call this function each time an 100 | * event is received from the S110 SoftDevice. This function processes the event if it 101 | * is relevant for it and calls the Nordic UART Service event handler of the 102 | * application if necessary. 103 | * 104 | * @param[in] p_nus Nordic UART Service structure. 105 | * @param[in] p_ble_evt Event received from the S110 SoftDevice. 106 | */ 107 | void ble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt); 108 | 109 | /**@brief Function for sending a string to the peer. 110 | * 111 | * @details This function will send the input string as a RX characteristic notification to the 112 | * peer. 113 | * 114 | * @param[in] p_nus Pointer to the Nordic UART Service structure. 115 | * @param[in] string String to be sent. 116 | * @param[in] length Length of string. 117 | * 118 | * @return NRF_SUCCESS if the DFU Service has successfully requested the S110 SoftDevice to 119 | * send the notification. Otherwise an error code. 120 | * This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a 121 | * peer or if the notification of the RX characteristic was not enabled by the peer. 122 | * It returns NRF_ERROR_NULL if the pointer p_nus is NULL. 123 | */ 124 | uint32_t ble_nus_send_string(ble_nus_t * p_nus, uint8_t * string, uint16_t length); 125 | 126 | uint32_t ble_nus_set_read_string(ble_nus_t* p_nus, uint8_t* string, uint16_t length); 127 | 128 | #endif // BLE_NUS_H__ 129 | 130 | /** @} */ 131 | --------------------------------------------------------------------------------