ember-cordova-beacon
Version:
Range / Monitor beacons for ember cordova apps
252 lines (209 loc) • 7.26 kB
JavaScript
import Ember from 'ember';
const {
A,
Evented,
RSVP,
Service,
inject,
isPresent,
isEmpty
} = Ember;
const { Promise } = RSVP;
export default Service.extend(Evented, {
cordova: inject.service('cordova'),
beacons: A(),
_locationManager: null,
_delegate: null,
locationManager() {
if (this._locationManager) {
return Promise.resolve(this._locationManager);
}
return this.get('cordova').ready().then(() => {
this._locationManager = cordova.plugins.locationManager;
this._delegate = new this._locationManager.Delegate();
this.setup();
return this._locationManager;
});
},
setup() {
this._delegate.didDetermineStateForRegion = function(pluginResult) {
let { uuid, major, minor } = pluginResult.region;
let beacon = this._selectBeacon(uuid, major, minor);
this.trigger('didDetermineStateForRegion', beacon, pluginResult);
}.bind(this);
this._delegate.didStartMonitoringForRegion = function(pluginResult) {
let { uuid, major, minor } = pluginResult.region;
let beacon = this._selectBeacon(uuid, major, minor);
this.trigger('didStartMonitoringForRegion', beacon, pluginResult);
}.bind(this);
this._delegate.didEnterRegion = function(pluginResult) {
let { uuid, major, minor } = pluginResult.region;
let beacon = this._selectBeacon(uuid, major, minor);
this.trigger('didEnterRegion', beacon, pluginResult);
}.bind(this);
this._delegate.didExitRegion = function(pluginResult) {
let { uuid, major, minor } = pluginResult.region;
let beacon = this._selectBeacon(uuid, major, minor);
this.trigger('didExitRegion', beacon, pluginResult);
}.bind(this);
this._delegate.didRangeBeaconsInRegion = function(pluginResult) {
for (let i = 0; i < pluginResult.beacons.length; i++) {
let beacon = pluginResult.beacons[i];
this._updateBeacon(beacon);
this.trigger('didRangeBeaconInRegion', beacon);
}
}.bind(this);
this._locationManager.setDelegate(this._delegate);
// required in iOS 8+
this._locationManager.requestWhenInUseAuthorization();
},
getMonitoredRegions() {
return this.locationManager().then(lm => {
return lm.getMonitoredRegions();
});
},
rangingBeacons: Ember.computed('beacons.@each.isRanging', function() {
return this.get('beacons').filterBy('isRanging', true);
}),
monitoringBeacons: Ember.computed('beacons.@each.isMonitoring', function() {
return this.get('beacons').filterBy('isMonitoring', true);
}),
startMonitoringBeacon(identifier, uuid, major, minor) {
return this.locationManager().then(lm => {
let beacon = this._addBeacon(identifier, uuid, major, minor);
beacon = beacon || {};
return lm.startMonitoringForRegion(beacon.region).then(() => {
beacon.set('isMonitoring', true);
return beacon;
});
}.bind(this));
},
stopMonitoringBeacon(uuid, major, minor) {
return this.locationManager().then(lm => {
let beacon = this._selectBeacon(uuid, major, minor);
beacon = beacon || {};
return lm.stopMonitoringForRegion(beacon.region).then(() => {
beacon.set('isMonitoring', false);
return beacon;
});
}.bind(this));
},
stopMonitoringBeacons(beacons) {
var beaconsToStop = isPresent(beacons) ? beacons : this.get('beacons');
return this.locationManager().then(() => {
let promises = A();
beaconsToStop.forEach(beacon => {
let { uuid, major, minor } = beacon;
promises.pushObject(this.stopMonitoringBeacon(uuid, major, minor));
});
return Promise.all(promises);
});
},
startRangingBeacon(identifier, uuid, major, minor) {
return this.locationManager().then(lm => {
let beacon = this._addBeacon(identifier, uuid, major, minor);
beacon = beacon || {};
return lm.startRangingBeaconsInRegion(beacon.region).then(() => {
beacon.set('isRanging', true);
return beacon;
});
}.bind(this));
},
stopRangingBeacon(uuid, major, minor) {
return this.locationManager().then(lm => {
let beacon = this._selectBeacon(uuid, major, minor);
beacon = beacon || {};
return lm.stopRangingBeaconsInRegion(beacon.region).then(() => {
beacon.set('isRanging', false);
return beacon;
});
}.bind(this));
},
stopRangingBeacons(beacons) {
var beaconsToStop = isPresent(beacons) ? beacons : this.get('beacons');
return this.locationManager().then(() => {
let promises = A();
beaconsToStop.forEach(beacon => {
let { uuid, major, minor } = beacon;
promises.pushObject(this.stopRangingBeacon(uuid, major, minor));
});
return Promise.all(promises);
});
},
getRange(txCalibratedPower, rssi) {
var ratioDb = txCalibratedPower - rssi;
var ratioLinear = Math.pow(10, ratioDb / 10);
var r = Math.sqrt(ratioLinear);
return r;
},
getProximity(range) {
var name = 'unknown';
if (range < 3) {
name = 'immediate';
}
else if (range < 10) {
name = 'near';
}
else if (range < 30) {
name = 'far';
}
return name;
},
_addBeacon(identifier, uuid, major, minor) {
let currentBeacon = this._selectBeacon(uuid, major, minor);
if (currentBeacon) {
return currentBeacon;
}
let beaconRegion = new this._locationManager.BeaconRegion(identifier, uuid, major, minor);
let beacon = Ember.Object.create({
identifier: identifier,
uuid: uuid,
major: major,
minor: minor,
region: beaconRegion,
accuracy: 0,
rssi: 0,
});
this.get('beacons').pushObject(beacon);
return beacon;
},
_updateBeacon(beacon) {
let beacons = this._selectBeacons(beacon.uuid, beacon.major, beacon.minor);
beacons.forEach(item => {
item.set('accuracy', beacon.accuracy);
item.set('rssi', beacon.rssi);
let range = this.getRange(-59, beacon.rssi);
item.set('range', range);
let rangeSet = item.get('rangeSet') || [];
rangeSet.pushObject(range);
if (isEmpty(item.get('proximity')) || rangeSet.length >= 10) {
var sum = rangeSet.reduce(function(a, b) { return a + b; });
var avgRange = sum / rangeSet.length;
item.set('rangeSet', []);
item.set('proximity', this.getProximity(avgRange));
}
});
},
_selectBeacons(uuid, major, minor) {
return this.get('beacons').filter(item => {
return (uuid === item.uuid) && (major === item.major) && (minor === item.minor);
});
},
_selectBeacon(uuid, major, minor) {
let existingBeacons = this._selectBeacons(uuid, major, minor);
return A(existingBeacons).get('firstObject');
},
appendToDeviceLog(message) {
this.locationManager().then(lm => {
lm.appendToDeviceLog(message);
}.bind(this));
},
logToDom(message) {
var e = document.createElement('label');
e.innerText = message;
document.body.appendChild(e);
document.body.appendChild(document.createElement('br'));
document.body.appendChild(document.createElement('br'));
window.scrollTo(0, window.document.height);
}
});