Skip to content

Commit

Permalink
Merge branch 'simulate_ble_scans' of https://github.com/shankari/e-mi…
Browse files Browse the repository at this point in the history
…ssion-phone into ble-ui-changes
  • Loading branch information
JGreenlee committed Apr 14, 2024
2 parents 3fd2863 + 463c2a5 commit d61a4af
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 34 deletions.
46 changes: 35 additions & 11 deletions www/js/bluetooth/BluetoothCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const BluetoothCard = ({ device, isClassic, isScanningBLE }: Props) => {
bgColor = device.in_range ? `rgba(200,250,200,1)` : `rgba(250,200,200,1)`;
}

async function fakeMonitorCallback() {
async function fakeMonitorCallback(state: String) {
// If we don't do this, the results start accumulating in the device object
// first call, we put a result into the device
// second call, the device already has a result, so we put another one in...
Expand All @@ -33,18 +33,29 @@ const BluetoothCard = ({ device, isClassic, isScanningBLE }: Props) => {
window['cordova'].plugins.locationManager.getDelegate().didDetermineStateForRegion({
region: deviceWithoutResult,
eventType: 'didDetermineStateForRegion',
state: 'CLRegionStateInside',
state: state,
});
let timer: ReturnType<typeof setTimeout> = setTimeout(fakeRangeCallback, 500);
}

async function fakeRangeCallback() {
// If we don't do this, the results start accumulating in the device object
// first call, we put a result into the device
// second call, the device already has a result, so we put another one in...
const deviceWithMajorMinor = { ...device, major: 1234, minor: 4567 };
const deviceWithBeacons = { ...device };
deviceWithBeacons.monitorResult = undefined;
deviceWithBeacons.rangeResult = undefined;
const beacons = [
{
uuid: device.uuid,
major: device.major | 4567,
minor: device.minor | 1945,
proximity: 'ProximityNear',
accuracy: Math.random() * 1.33,
rssi: Math.random() * -62,
},
];
deviceWithBeacons.minor = device.minor | 4567;
deviceWithBeacons.minor = device.minor | 4567;
window['cordova'].plugins.locationManager.getDelegate().didRangeBeaconsInRegion({
region: deviceWithMajorMinor,
region: deviceWithBeacons,
beacons: beacons,
eventType: 'didRangeBeaconsInRegion',
state: 'CLRegionStateInside',
});
Expand All @@ -65,9 +76,22 @@ const BluetoothCard = ({ device, isClassic, isScanningBLE }: Props) => {
<Text style={{ backgroundColor: colors.secondaryContainer }} variant="bodyMedium">
{device.rangeResult}
</Text>
<Button mode="elevated" onPress={fakeMonitorCallback}>
Fake callback
</Button>
<Text
style={{ backgroundColor: colors.danger, color: colors.background }}
variant="bodyLarge">
Simulate by sending UI transitions
</Text>
<Card.Actions style={{ backgroundColor: colors.danger, color: colors.background }}>
<Button mode="elevated" onPress={() => fakeMonitorCallback('CLRegionStateInside')}>
Region Enter
</Button>
<Button mode="elevated" onPress={fakeRangeCallback}>
Range
</Button>
<Button mode="elevated" onPress={() => fakeMonitorCallback('CLRegionStateOutside')}>
Region Exit
</Button>
</Card.Actions>
</Card.Content>
</Card>
);
Expand Down
138 changes: 115 additions & 23 deletions www/js/bluetooth/BluetoothScanPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { DateTime } from 'luxon';
import { StyleSheet, Modal, ScrollView, SafeAreaView, View, Text } from 'react-native';
import { gatherBluetoothClassicData } from './bluetoothScanner';
import { logWarn, displayError, displayErrorMsg, logDebug } from '../plugin/logger';
Expand All @@ -11,6 +12,7 @@ import {
BluetoothClassicDevice,
BLEDeviceList,
} from '../types/bluetoothDevices';
import { forceTransition } from '../control/ControlCollectionHelper';

/**
* The implementation of this scanner page follows the design of
Expand Down Expand Up @@ -90,10 +92,22 @@ const BluetoothScanPage = ({ ...props }: any) => {
...prevDevices,
[uuid]: {
...prevDevices[uuid],
monitorResult: result,
monitorResult: status ? result : undefined,
rangeResult: undefined,
in_range: status,
},
}));
let { monitorResult: _, in_range: _, ...noResultDevice } = sampleBLEDevices[uuid];
window['cordova']?.plugins?.BEMDataCollection.mockBLEObjects(
status ? 'REGION_ENTER' : 'REGION_EXIT',
uuid,
undefined,
undefined,
1,
);
if (!status) {
forceTransition('BLE_BEACON_LOST');
}
}

function setRangeStatus(uuid: string, result: string) {
Expand All @@ -104,6 +118,57 @@ const BluetoothScanPage = ({ ...props }: any) => {
rangeResult: result,
},
}));
// we don't want to exclude monitorResult and rangeResult from the values
// that we save because they are the current or previous result, just
// in a different format
// https://stackoverflow.com/a/34710102
let {
monitorResult: _,
rangeResult: _,
in_range: _,
...noResultDevice
} = sampleBLEDevices[uuid];
let parsedResult = JSON.parse(result);
parsedResult.beacons.forEach((beacon) => {
window['cordova']?.plugins?.BEMDataCollection.mockBLEObjects(
'RANGE_UPDATE',
uuid,
beacon.major,
beacon.minor,
5,
);
});
// we only check for the transition on "real" callbacks to avoid excessive
// spurious callbacks on android
if (parsedResult.beacons.length > 0) {
// if we have received 3 range responses for the same beacon in the
// last 5 minutes, we generate the transition. we read without metadata
// (last param)
let nowSec = DateTime.now().toUnixInteger();
let tq = { key: 'write_ts', startTs: nowSec - 5 * 60, endTs: nowSec };
let readBLEReadingsPromise = window[
'cordova'
]?.plugins?.BEMUserCache.getSensorDataForInterval('background/bluetooth_ble', tq, false);
readBLEReadingsPromise.then((bleResponses) => {
// we add 5 entries at a time, so if we want 3 button presses,
// we really want 15 entries
let lastFifteenResponses = bleResponses.slice(0, 15);
if (!lastFifteenResponses.every((x) => x.eventType == 'RANGE_UPDATE')) {
console.log(
'Last three entries ' +
lastFifteenResponses.map((x) => x.eventType) +
' are not all RANGE_UPDATE, skipping transition',
);
return;
}

forceTransition('BLE_BEACON_FOUND');
});
}
}

async function simulateLocation(state: String) {
forceTransition(state);
}

// BLE LOGIC
Expand All @@ -127,18 +192,21 @@ const BluetoothScanPage = ({ ...props }: any) => {
window['cordova'].plugins.locationManager.appendToDeviceLog(
'[DOM] didDetermineStateForRegion: ' + pluginResultStr,
);
const beaconRegion = new window['cordova'].plugins.locationManager.BeaconRegion(
STATIC_ID,
pluginResult.region.uuid,
pluginResult.region.major,
pluginResult.region.minor,
);
window['cordova'].plugins.locationManager
.startRangingBeaconsInRegion(beaconRegion)
.fail(function (e) {
logWarn(e);
})
.done();
if (pluginResult.state == 'CLRegionStateInside') {
const beaconRegion = new window['cordova'].plugins.locationManager.BeaconRegion(
STATIC_ID,
pluginResult.region.uuid,
pluginResult.region.major,
pluginResult.region.minor,
);
console.log('About to start ranging beacons for region ', beaconRegion);
window['cordova'].plugins.locationManager
.startRangingBeaconsInRegion(beaconRegion)
.fail(function (e) {
logWarn(e);
})
.done();
}
};

delegate.didStartMonitoringForRegion = function (pluginResult) {
Expand Down Expand Up @@ -317,19 +385,43 @@ const BluetoothScanPage = ({ ...props }: any) => {
value={newUUID || ''}
onChangeText={(t) => setNewUUID(t.toUpperCase())}
/>
<TextInput
label="Major (optional)"
value={newMajor || ''}
onChangeText={(t) => setNewMajor(t)}
/>
<TextInput
label="Minor (optional)"
value={newMinor || ''}
onChangeText={(t) => setNewMinor(t)}
/>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<TextInput
label="Major (optional)"
value={newMajor || ''}
onChangeText={(t) => setNewMajor(t)}
/>
<TextInput
label="Minor (optional)"
value={newMinor || ''}
onChangeText={(t) => setNewMinor(t)}
/>
</View>
<Button disabled={!newUUID} onPress={() => addNewUUID(newUUID, newMajor, newMinor)}>
Add New Beacon To Scan
</Button>
<View
style={{
flexDirection: 'column',
alignItems: 'center',
backgroundColor: colors.danger,
color: colors.background,
}}>
<Text
style={{ backgroundColor: colors.danger, color: colors.background }}
variant="bodyLarge">
Simulate by sending UI transitions
</Text>

<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Button mode="elevated" onPress={() => simulateLocation('EXITED_GEOFENCE')}>
Geofence exit
</Button>
<Button mode="elevated" onPress={() => simulateLocation('STOPPED_MOVING')}>
Stopped Moving
</Button>
</View>
</View>
</SafeAreaView>
</Modal>
</>
Expand Down

0 comments on commit d61a4af

Please sign in to comment.