This is a container, presenting a common interface from potential multiple configurations.
DaemonConfig is an example of a configuration creator.
A configuration creator, for an automated usage, that is without feedback to a user.
package my.package.ble
import android.app.Activity
import android.content.Context
import android.util.Log
import fr.maxcom.beacon.configuration.DeviceFilter
import fr.maxcom.beacon.configuration.ScanMode
import fr.maxcom.beacon.device.BeaconDevice
import fr.maxcom.beacon.device.BeaconRegion
import fr.maxcom.beacon.device.EddystoneDevice
import fr.maxcom.beacon.device.EddystoneNamespace
import fr.maxcom.beacon.error.ScanError
import fr.maxcom.beacon.manager.listeners.IDeviceListener
import fr.maxcom.beacon.manager.listeners.AScanStatusListener
import fr.maxcom.beacon.manager.listeners.ISpaceListener
import fr.maxcom.beacon.plugin.IExplorerPlugin
import fr.maxcom.beacon.plugin.IPluginDeviceListener
import fr.maxcom.beacon.plugin.IProcessorPlugin
import fr.maxcom.beacon.plugin.manufacturer.AccSysParserPlugin
import fr.maxcom.beacon.plugin.manufacturer.ElaParserPlugin
import fr.maxcom.beacon.plugin.manufacturer.InvirtusProcessorPlugin
import fr.maxcom.beacon.plugin.manufacturer.MinewExplorerPlugin
import fr.maxcom.beacon.processor.BeaconProcessor
import fr.maxcom.beacon.processor.EddystoneProcessor
import fr.maxcom.beacon.processor.IProcessor
import fr.maxcom.beacon.rssi.CappedAverageRssiCalculator
import my.package.BuildConfig
import java.util.StringJoiner
import java.util.UUID
object DaemonConfig {
private val TAG = DaemonConfig::class.java.simpleName
// to call at the application creation, MainApplication/onCreate()
fun init(
context: Context,
eventListener: IEventListener,
activityClass: Class<out Activity?>
) {
if (BuildConfig.DEBUG) Log.d(TAG, "init")
val cfg = Configuration.instance
with(cfg) {
this.activityClass = activityClass
//scanFrequency = ScanFrequency.MONITORING // default is ScanFrequency.RANGING
scanMode = ScanMode.LOW_LATENCY // default is BALANCED
rssiCalculator = CappedAverageRssiCalculator(5)
reminderIntervalSeconds = 10 * 60
devicesUpdateEventSlowdown = 14 * 1000
scanStatusListener = object : AScanStatusListener {
override fun onScanStart() {
Log.i(TAG, "onScanStart")
}
override fun onScanStop() {
Log.i(TAG, "onScanStop")
}
override fun onScanFailed(errorCode: Int, errorReason: String) {
// is already in logcat
}
override fun onScanError(scanError: ScanError) {
// is already in logcat
}
// onCycle*() are called only if ScanFrequency is set to something other than RANGING
override fun onCycleResume() {
if (BuildConfig.DEBUG) Log.d(TAG, "onCycleResume")
}
override fun onCyclePause() {
if (BuildConfig.DEBUG) Log.d(TAG, "onCyclePause")
}
}
}
// may be recycled to serve more than one time
val filters: MutableList<DeviceFilter> = ArrayList()
// iBeacon settings
val beaconProcessor = BeaconProcessor(
object : IDeviceListener<BeaconDevice, BeaconRegion> {
override fun onDiscovered(device: BeaconDevice, space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.d(TAG, "onDiscovered: $device, region: $space")
writeEvent("+", device)
}
override fun onKnown(device: BeaconDevice, space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.v(TAG, "onKnown: $device, region: $space")
writeEvent("=", device)
}
override fun onKnownReminder(device: BeaconDevice, space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.d(TAG, "onKnownReminder: $device, region: $space")
writeEvent(".", device)
}
override fun onUpdated(devices: List<BeaconDevice>, space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.d(TAG, "onUpdated: $devices, region: $space")
}
override fun onLost(device: BeaconDevice, space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.d(TAG, "onLost: $device, region: $space")
writeEvent("-", device)
}
private fun writeEvent(type: String, device: BeaconDevice) {
val now = System.currentTimeMillis()
val sj = StringJoiner(",")
sj
.add(now.toString()) // long
.add(type)
.add(device.major.toString()) // int
.add(device.minor.toString()) // int
.add(device.distance.toString()) // int
val extras: Map<String, String> = device.extras
if (extras.isNotEmpty()) for ((key, value) in extras) sj.add(key + "_" + value)
eventListener.onEvent(sj.toString())
}
},
object : ISpaceListener<BeaconRegion> {
override fun onEntered(space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.d(TAG, "onEntered: $space")
}
override fun onExited(space: BeaconRegion) {
if (BuildConfig.DEBUG) Log.d(TAG, "onExited: $space")
}
}
)
// if the processor has eventually an empty collection, BeaconRegion.EVERYWHERE will be assumed
val regions: MutableCollection<BeaconRegion> = HashSet()
regions.add(BeaconRegion.Builder()
.name("MyApp") // TODO set your own value
.proximity(Configuration.APP_UUID)
.build())
// optionally add some regions, for example to observe a few extra development beacon tags
/*
Example for an 'Ultra-Thin Beacon U1' tag from Meeblue, Inc.:
regions.add(BeaconRegion.Builder()
.name("Meeblue")
.proximity(UUID.fromString("d35b76e2-e01c-9fac-ba8d-7ce20bdba0c6"))
.build())
Example for a tag from Minew Technologies Co.:
regions.add(BeaconRegion.Builder()
.name("Minew")
.proximity(UUID.fromString("e2c56db5-dffb-48d2-b060-d0f5a71096e0"))
.build())
*/
beaconProcessor.setBeaconRegions(regions)
// optionally set some filters, in particular in development phase to avoid being flooded with too many frames
filters.clear()
filters.add(DeviceFilter().setDeviceName("L ID 003D4F")) // Example of a 'BLUE LITE ID' tag from Ela Innovation
filters.add(DeviceFilter().setDeviceName("S ID 002A3B")) // Example of a 'BLUE SLIM ID' tag from Ela Innovation
filters.add(DeviceFilter().setDeviceAddress("AC:23:3F:A1:B2:C3")) // Example of a tag from Minew Technologies
(beaconProcessor as IProcessor).setDeviceFilters(filters)
cfg.addProcessor(beaconProcessor)
// Eddystone settings
val eddystoneProcessor = EddystoneProcessor(
object : IDeviceListener<EddystoneDevice, EddystoneNamespace> {
override fun onDiscovered(device: EddystoneDevice, space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.d(TAG, "onDiscovered: $device, namespace: $space")
writeEvent("+", device)
}
override fun onKnown(device: EddystoneDevice, space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.v(TAG, "onKnown: $device, namespace: $space")
writeEvent("=", device)
}
override fun onKnownReminder(device: EddystoneDevice, space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.d(TAG, "onKnownReminder: $device, namespace: $space")
writeEvent(".", device)
}
override fun onUpdated(devices: List<EddystoneDevice>, space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.d(TAG, "onUpdated: $devices, namespace: $space")
}
override fun onLost(device: EddystoneDevice, space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.d(TAG, "onLost: $device, namespace: $space")
writeEvent("-", device)
}
private fun writeEvent(type: String, device: EddystoneDevice) {
val now = System.currentTimeMillis()
val sj = StringJoiner(",")
sj
.add(now.toString()) // long
.add(type)
.add(device.instance)
.add(device.distance.toString()) // int
val extras: Map<String, String> = device.extras
if (extras.isNotEmpty()) for ((key, value) in extras) sj.add(key + "_" + value)
eventListener.onEvent(sj.toString())
}
},
object : ISpaceListener<EddystoneNamespace> {
override fun onEntered(space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.d(TAG, "onEntered: $space")
}
override fun onExited(space: EddystoneNamespace) {
if (BuildConfig.DEBUG) Log.d(TAG, "onExited: $space")
}
}
)
// if the processor has eventually an empty collection, EddystoneNamespace.EVERYWHERE will be assumed
val namespaces: MutableCollection<EddystoneNamespace> = HashSet()
namespaces.add(EddystoneNamespace.Builder()
.name("MyApp") // TODO set your own value
.namespace("00112233445566778899") // TODO set your own value
.build())
eddystoneProcessor.setEddystoneNamespaces(namespaces)
// optionally set some filters, in particular in development phase to avoid being flooded with too many frames
filters.clear()
filters.add(DeviceFilter().setDeviceName("L ID 003D4F")) // Example of a 'BLUE LITE ID' tag from Ela Innovation
filters.add(DeviceFilter().setDeviceName("S ID 002A3B")) // Example of a 'BLUE SLIM ID' tag from Ela Innovation
filters.add(DeviceFilter().setDeviceAddress("AC:23:3F:A1:B2:C3")) // Example of a tag from Minew Technologies
(eddystoneProcessor as IProcessor).setDeviceFilters(filters)
cfg.addProcessor(eddystoneProcessor)
// Plugins settings, if wanted ...
// Processor Plugin
val invirtusPlugin = InvirtusProcessorPlugin(
object : IPluginDeviceListener<InvirtusProcessorPlugin.Device> {
override fun onDiscovered(device: InvirtusProcessorPlugin.Device) {
if (BuildConfig.DEBUG) Log.d(TAG, "onDiscovered: $device")
}
override fun onUpdated(device: InvirtusProcessorPlugin.Device) {
if (BuildConfig.DEBUG) Log.d(TAG, "onUpdated: $device")
}
override fun onLost(device: InvirtusProcessorPlugin.Device) {
if (BuildConfig.DEBUG) Log.d(TAG, "onLost: $device")
}
}
)
// optionally set some filters, in particular in development phase to avoid being flooded with too many frames
filters.clear()
filters.add(DeviceFilter().setDeviceAddress("F2:18:FF:A1:B2:C3"))
(invirtusPlugin as IProcessorPlugin).setDeviceFilters(filters)
cfg.addProcessorPlugin(invirtusPlugin)
// Explorer Plugin
val minewPlugin = MinewExplorerPlugin()
// optionally set some filters, in particular in development phase to avoid being flooded with too many frames
filters.clear()
filters.add(DeviceFilter().setDeviceAddress("AC:23:3F:A1:B2:C3"))
(minewPlugin as IExplorerPlugin).setDeviceFilters(filters)
cfg.addExplorerPlugin(minewPlugin)
// Parser Plugins
val elaPlugin = ElaParserPlugin()
val accSysPlugin = AccSysParserPlugin()
cfg.addParserPlugin(elaPlugin)
.addParserPlugin(accSysPlugin)
}
}