Android SBeacon Framework Driving Behavior - scopetech/Mobile-Public GitHub Wiki
Driving Behavior Detection
The SBeacon SDK provides real-time detection of harsh driving events including acceleration, braking, cornering, and collision incidents.
Overview
The driving behavior feature uses the beacon's built-in accelerometer to detect when G-forces exceed configured thresholds. Events are:
- Detected in real-time during active trips via notifications
- Stored on the beacon (up to 80 events in circular buffer)
- Retrievable on-demand for synchronization with your backend
Event Types
enum class DrivingBehaviorType(val rawValue: Int) {
HARSH_ACCELERATION(4), // Excessive forward G-force
HARSH_BRAKING(5), // Excessive backward G-force (deceleration)
HARSH_CORNERING(6), // Excessive lateral G-force
ACCIDENT(8) // G-forces exceeding accident threshold
}
| Event | Description | Default Threshold |
|---|---|---|
| Harsh Acceleration | Rapid speed increase | 0.25g (250 milli-Gs) |
| Harsh Braking | Rapid deceleration | 0.40g (400 milli-Gs) |
| Harsh Cornering | Sharp turns | 0.45g (450 milli-Gs) |
| Accident | Collision detection | Configured separately |
Prerequisites
Before using driving behavior detection:
- Beacon must be paired - See Beacon Pairing
- Beacon must be calibrated - See Calibration
- Feature must be enabled - Disabled by default
Enable/Disable Feature
val bleManager = BLEManager.retrieveInstance(context)
// Enable driving behavior detection with all filters
bleManager.enableDrivingBehavior(beaconMac)
// Disable driving behavior detection
bleManager.disableDrivingBehavior(beaconMac)
The enable command sets:
- Driving Behavior: Enabled
- High Pass Filter: Enabled (removes gravity offset)
- Low Pass Filter: Enabled (smooths readings)
Configuration
Reading Current Configuration
bleManager.requestDrivingBehaviorConfig(beaconMac)
// Handle configuration response
private val eventsReceiver = object : IBFHelper.EventsReceiver() {
override fun onDrivingBehaviorConfigReceived(
beaconMac: String,
config: DrivingBehaviorConfig
) {
Log.d("DB", """
Enabled: ${config.enabled}
High Pass Filter: ${config.highPassFilterEnabled}
Low Pass Filter: ${config.lowPassFilterEnabled}
Cornering Threshold: ${config.corneringThreshold} mG
Braking Threshold: ${config.brakingThreshold} mG
Acceleration Threshold: ${config.accelerationThreshold} mG
Duration Threshold: ${config.durationThreshold} ms
""".trimIndent())
}
}
// Register in onResume
override fun onResume() {
super.onResume()
IBFHelper.registerEventsReceiver(requireContext(), eventsReceiver)
}
Setting Thresholds
Configure detection sensitivity using threshold values in milli-Gs (1000 mG = 1g):
// Configure all thresholds at once
bleManager.configureDrivingBehaviorThresholds(
beaconMac = beaconMac,
corneringThreshold = 450, // 0.45g - lateral G-force
brakingThreshold = 400, // 0.40g - deceleration
accelerationThreshold = 250, // 0.25g - acceleration
durationThreshold = 500 // 500ms minimum duration
)
// Or set individual thresholds
bleManager.setCorneringThreshold(beaconMac, 500) // 0.50g
bleManager.setBrakingThreshold(beaconMac, 350) // 0.35g
bleManager.setAccelerationThreshold(beaconMac, 300) // 0.30g
bleManager.setDurationThreshold(beaconMac, 400) // 400ms
Threshold Ranges
| Parameter | Min | Max | Default | Unit |
|---|---|---|---|---|
| Cornering | 50 | 5000 | 450 | milli-Gs |
| Braking | 50 | 5000 | 400 | milli-Gs |
| Acceleration | 50 | 5000 | 250 | milli-Gs |
| Duration | 1 | 10000 | 500 | milliseconds |
Note: Lower threshold values = more sensitive detection. Higher values = less sensitive.
Using DrivingBehaviorConfig
For complete control, use the DrivingBehaviorConfig data class:
val config = DrivingBehaviorConfig(
enabled = true,
highPassFilterEnabled = true,
lowPassFilterEnabled = true,
corneringThreshold = 450,
brakingThreshold = 400,
accelerationThreshold = 250,
durationThreshold = 500
)
// Validate before writing
if (config.isValid()) {
bleManager.writeDrivingBehaviorConfig(beaconMac, config)
}
Real-Time Events
During an active trip, the beacon sends immediate notifications when harsh driving is detected:
private val eventsReceiver = object : IBFHelper.EventsReceiver() {
override fun onRealTimeDrivingBehaviorEvent(
beaconMac: String,
eventType: DrivingBehaviorType,
timestamp: Long
) {
Log.d("DB", "Real-time event: $eventType at $timestamp")
when (eventType) {
DrivingBehaviorType.HARSH_ACCELERATION -> {
showWarning("Harsh acceleration detected!")
}
DrivingBehaviorType.HARSH_BRAKING -> {
showWarning("Harsh braking detected!")
}
DrivingBehaviorType.HARSH_CORNERING -> {
showWarning("Sharp turn detected!")
}
DrivingBehaviorType.ACCIDENT -> {
showAlert("Potential collision detected!")
}
}
}
}
Real-Time Event Properties
| Property | Type | Description |
|---|---|---|
beaconMac |
String | MAC address of reporting beacon |
eventType |
DrivingBehaviorType | Type of event detected |
timestamp |
Long | Client timestamp (milliseconds) |
Retrieving Stored Events
The beacon stores up to 80 driving behavior events in a circular buffer. Retrieve them for detailed analysis:
// Request stored events
bleManager.requestDrivingBehaviorEvents(beaconMac)
// Handle response
private val eventsReceiver = object : IBFHelper.EventsReceiver() {
override fun onDrivingBehaviorEventsReceived(
beaconMac: String,
events: ArrayList<DrivingBehaviorEvent>
) {
Log.d("DB", "Received ${events.size} stored events")
events.forEach { dbEvent ->
Log.d("DB", """
Index: ${dbEvent.recordIndex}
Type: ${dbEvent.eventType}
Time: ${Date(dbEvent.timestamp)}
Duration: ${dbEvent.durationMs}ms
Avg Magnitude: ${dbEvent.averageMagnitude}g
Max Magnitude: ${dbEvent.maxMagnitude}g
Avg X (lateral): ${dbEvent.averageX}g
Avg Y (longitudinal): ${dbEvent.averageY}g
Avg Z (vertical): ${dbEvent.averageZ}g
""".trimIndent())
}
}
}
DrivingBehaviorEvent Properties
| Property | Type | Description |
|---|---|---|
recordIndex |
Int | Buffer index (0-79) |
eventType |
DrivingBehaviorType | Event classification |
timestamp |
Long | Unix timestamp (milliseconds) |
durationMs |
Int | Event duration in milliseconds |
averageMagnitude |
Float | Average G-force magnitude |
maxMagnitude |
Float | Peak G-force magnitude |
averageX |
Float | Lateral G-force (side-to-side) |
averageY |
Float | Longitudinal G-force (forward/back) |
averageZ |
Float | Vertical G-force (up/down) |
beaconMacAddress |
String | Source beacon MAC |
Clearing Events
After syncing events to your backend, clear them from the beacon:
// Clear all events
bleManager.clearAllDrivingBehaviorEvents(beaconMac)
// Or clear a specific event by index
bleManager.clearDrivingBehaviorEvent(beaconMac, index = 5)
// Handle confirmation
private val eventsReceiver = object : IBFHelper.EventsReceiver() {
override fun onDrivingBehaviorEventsClearConfirmed(
beaconMac: String,
clearedIndex: Int
) {
if (clearedIndex == 0xFF) {
Log.d("DB", "All events cleared")
} else {
Log.d("DB", "Event $clearedIndex cleared")
}
}
}
Axis Reference
The accelerometer measures G-forces on three axes:
| Axis | Direction | Positive Value | Example |
|---|---|---|---|
| X | Lateral | Right turn | Sharp right corner |
| Y | Longitudinal | Forward | Hard acceleration |
| Z | Vertical | Upward | Speed bump |
Note: The beacon must be properly calibrated for accurate axis measurements. See Calibration.
Best Practices
- Always calibrate first - Uncalibrated beacons produce inaccurate readings
- Start with default thresholds - Adjust based on real-world testing
- Consider vehicle type - Sports cars may need higher thresholds than sedans
- Enable both filters - High-pass removes gravity, low-pass smooths noise
- Clear events after sync - Prevent buffer overflow and duplicate processing
- Handle events gracefully - Real-time events may arrive rapidly during aggressive driving
Complete Example
class DrivingBehaviorFragment : Fragment() {
private val bleManager by lazy { BLEManager.retrieveInstance(requireContext()) }
private var currentBeaconMac: String? = null
private val eventsReceiver = object : IBFHelper.EventsReceiver() {
override fun onRealTimeDrivingBehaviorEvent(
beaconMac: String,
eventType: DrivingBehaviorType,
timestamp: Long
) {
// Handle real-time harsh driving alert
Log.w("DB", "Alert: $eventType")
showWarning(eventType)
}
override fun onDrivingBehaviorEventsReceived(
beaconMac: String,
events: ArrayList<DrivingBehaviorEvent>
) {
// Process and sync events to backend
lifecycleScope.launch {
uploadToServer(events)
// Clear after successful sync
bleManager.clearAllDrivingBehaviorEvents(beaconMac)
}
}
override fun onDrivingBehaviorConfigReceived(
beaconMac: String,
config: DrivingBehaviorConfig
) {
Log.d("DB", "Config: $config")
updateUI(config)
}
}
override fun onResume() {
super.onResume()
IBFHelper.registerEventsReceiver(requireContext(), eventsReceiver)
}
override fun onPause() {
super.onPause()
IBFHelper.unregisterEventsReceiver(requireContext(), eventsReceiver)
}
fun setupDrivingBehavior(beaconMac: String) {
currentBeaconMac = beaconMac
// Enable feature with custom thresholds
bleManager.enableDrivingBehavior(beaconMac)
bleManager.configureDrivingBehaviorThresholds(
beaconMac = beaconMac,
corneringThreshold = 400,
brakingThreshold = 350,
accelerationThreshold = 300,
durationThreshold = 500
)
}
private fun showWarning(eventType: DrivingBehaviorType) {
// Show UI alert
}
private suspend fun uploadToServer(events: ArrayList<DrivingBehaviorEvent>) {
// Upload events to your backend
}
private fun updateUI(config: DrivingBehaviorConfig) {
// Update UI with config
}
}
Related Pages
- Calibration - Required before using driving behavior detection
- Event Handling - Complete event subscription guide
- Trip Management - Trip lifecycle and events
- Data Models - DrivingBehaviorEvent and related models