From 247c6f1ccd3f875dcee9c6457b2b56b0c30c5b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Pt=C3=A1=C4=8Dek?= Date: Wed, 26 Jul 2023 23:49:57 +0200 Subject: [PATCH] hw sensors --- .../exporter/worker/AndroidCustomExporter.kt | 9 +- .../android/exporter/worker/MetricsEngine.kt | 272 ++++++++++++++---- .../android/exporter/worker/PromWorker.kt | 2 +- 3 files changed, 214 insertions(+), 69 deletions(-) diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/AndroidCustomExporter.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/AndroidCustomExporter.kt index eddc9d4..079a1d0 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/AndroidCustomExporter.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/AndroidCustomExporter.kt @@ -18,7 +18,7 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector // metrics definitions // collectBatteryStatus(mfs) - collectGps(mfs) +// collectGps(mfs) collectSteps(mfs) Log.d(TAG, "Metrics collected") @@ -37,9 +37,9 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector // mfs.add(batteryPercentageGauge) // } - private fun collectGps(mfs: MutableList){ - //TODO - } +// private fun collectGps(mfs: MutableList){ +// //TODO +// } private fun collectSteps(mfs: MutableList){ val gauge = GaugeMetricFamily( @@ -51,7 +51,6 @@ class AndroidCustomExporter(private val metricEngine: MetricsEngine) : Collector metricEngine.hwSensorsValues().numberOfSteps?.let{ gauge.addMetric(listOf(), it.toDouble()) mfs.add(gauge) - Log.d(TAG, "heeeeeeeeeeeeeeeeeeeeeeeeeeeee") } } } diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/MetricsEngine.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/MetricsEngine.kt index 6d5787c..258102f 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/MetricsEngine.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/MetricsEngine.kt @@ -3,108 +3,254 @@ package com.birdthedeveloper.prometheus.android.exporter.worker import android.content.Context -import android.hardware.Sensor import android.content.Intent import android.content.IntentFilter +import android.hardware.Sensor import android.hardware.SensorManager -import android.os.BatteryManager -import android.app.Activity import android.hardware.SensorEvent import android.hardware.SensorEventListener +import android.os.BatteryManager +import android.os.Build +import android.os.CpuUsageInfo +import android.os.HardwarePropertiesManager +import android.os.SystemClock +import android.system.Os +import android.system.OsConstants import android.util.Log private const val TAG = "METRICS_ENGINE" +data class AxisSpecificGauge( + val x : Double, + val y : Double, + val z : Double, +) + class HwSensorsCache( var batteryChargeRatio : Double? = null, var numberOfSteps : Int? = null, + + + var headingDegrees : Double? = null, + var headingAccuracyDegrees : Double? = null, + var hingeAngleDegrees : Double? = null, + var offbodyDetect : Double? = null, + var ambientTemperatureCelsius : Double? = null, + var relativeHumidityPercent : Double? = null, + + var accelerometer : AxisSpecificGauge? = null, + var magneticFieldMicroTesla : AxisSpecificGauge? = null, + var gyroscopeRadiansPerSecond: AxisSpecificGauge? = null, + + var ambientLightLux : Double? = null, + var pressureHectoPascal : Double? = null, + var proximityCentimeters : Double? = null, + + var gravityAcceleration : AxisSpecificGauge? = null, + var linearAcceleration : AxisSpecificGauge? = null, + var rotationVectorValues : AxisSpecificGauge? = null, + var rotationVectorCosinusThetaHalf : Double? = null, + var rotationVectorAccuracyRadians : Double? = null, ); +//TODO for cpu, use HardwarePropertiesManager + +private val supportedSensors : List = listOf( + Sensor.TYPE_HEADING, + Sensor.TYPE_HINGE_ANGLE, + Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT, + Sensor.TYPE_AMBIENT_TEMPERATURE, + Sensor.TYPE_RELATIVE_HUMIDITY, + Sensor.TYPE_ACCELEROMETER, + Sensor.TYPE_MAGNETIC_FIELD, + Sensor.TYPE_GYROSCOPE, + Sensor.TYPE_LIGHT, + Sensor.TYPE_PRESSURE, + Sensor.TYPE_PROXIMITY, + Sensor.TYPE_GRAVITY, + Sensor.TYPE_LINEAR_ACCELERATION, + Sensor.TYPE_ROTATION_VECTOR, +) + +val temperatureTypes : Map = mapOf( + HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY to "battery", + HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU to "cpu", + HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU to "gpu", + HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN to "skin", + +) + class MetricsEngine(private val context: Context) : SensorEventListener { private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager private val hwSensorsCache = HwSensorsCache() + val hwPropertiesManager = context.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE) as HardwarePropertiesManager init { registerAllHwEventHandlers() } - fun hwSensorsValues() : HwSensorsCache{ + fun hwSensorsValues(): HwSensorsCache { return hwSensorsCache } - private fun registerAllHwEventHandlers(){ - Log.d(TAG, "Registering all hw sensors") - val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) - sensor?.let{ - Log.d(TAG, "Sensor exists!") - sensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_NORMAL) - } - //sensorManager.flush(this) - } + private fun registerAllHwEventHandlers() { + Log.d(TAG, "Registering all hardware sensors") - override fun onSensorChanged(event: SensorEvent?) { - Log.d(TAG, "Sensor Changed !!!!!!!!!!!!!!") - if(event == null){ - return - } - if (event.values == null){ - return - } + //TODO test registering and unregistering as optimization - when(event.sensor.type){ - Sensor.TYPE_PROXIMITY -> { - hwSensorsCache.numberOfSteps = event.values[0].toInt() + supportedSensors.forEach { supportedSensor -> + val sensor: Sensor? = sensorManager.getDefaultSensor(supportedSensor) + sensor?.let { + sensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_NORMAL) } } } + fun dispose() { + sensorManager.unregisterListener(this) + } + + override fun onSensorChanged(event: SensorEvent?) { + if (event == null) { + return + } + if (event.values == null) { + return + } + + when (event.sensor.type) { + Sensor.TYPE_HEADING -> { + hwSensorsCache.headingDegrees = event.values[0].toDouble() + hwSensorsCache.headingAccuracyDegrees = event.values[1].toDouble() + } + + Sensor.TYPE_HINGE_ANGLE -> { + hwSensorsCache.hingeAngleDegrees = event.values[0].toDouble() + } + + Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT -> { + hwSensorsCache.offbodyDetect = event.values[0].toDouble() + } + + Sensor.TYPE_AMBIENT_TEMPERATURE -> { + hwSensorsCache.ambientTemperatureCelsius = event.values[0].toDouble() + } + + Sensor.TYPE_RELATIVE_HUMIDITY -> { + hwSensorsCache.relativeHumidityPercent = event.values[0].toDouble() + } + + Sensor.TYPE_ACCELEROMETER -> { + hwSensorsCache.accelerometer = valuesToAxisSpecificGauge(event.values) + } + + Sensor.TYPE_MAGNETIC_FIELD -> { + hwSensorsCache.magneticFieldMicroTesla = valuesToAxisSpecificGauge(event.values) + } + + Sensor.TYPE_GYROSCOPE -> { + hwSensorsCache.gyroscopeRadiansPerSecond = valuesToAxisSpecificGauge(event.values) + } + + Sensor.TYPE_LIGHT -> { + hwSensorsCache.ambientLightLux = event.values[0].toDouble() + } + + Sensor.TYPE_PRESSURE -> { + hwSensorsCache.pressureHectoPascal = event.values[0].toDouble() + } + + Sensor.TYPE_PROXIMITY -> { + hwSensorsCache.proximityCentimeters = event.values[0].toDouble() + } + + Sensor.TYPE_GRAVITY -> { + hwSensorsCache.gravityAcceleration = valuesToAxisSpecificGauge(event.values) + } + + Sensor.TYPE_LINEAR_ACCELERATION -> { + hwSensorsCache.linearAcceleration = valuesToAxisSpecificGauge(event.values) + } + + Sensor.TYPE_ROTATION_VECTOR -> { + hwSensorsCache.rotationVectorValues = valuesToAxisSpecificGauge(event.values) + hwSensorsCache.rotationVectorCosinusThetaHalf = event.values[3].toDouble() + hwSensorsCache.rotationVectorAccuracyRadians = event.values[4].toDouble() + } + } + } + + private fun valuesToAxisSpecificGauge(values: FloatArray): AxisSpecificGauge { + return AxisSpecificGauge( + x = values[0].toDouble(), + y = values[1].toDouble(), + z = values[2].toDouble(), + ) + } + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { - Log.d(TAG, "Sensor accuracy changed.") + // Do nothing } -//TODO - ///TYPE_ACCELEROMETER Yes Yes Yes Yes - //TYPE_AMBIENT_TEMPERATURE Yes n/a n/a n/a - //TYPE_GRAVITY Yes Yes n/a n/a - //TYPE_GYROSCOPE Yes Yes n/a1 n/a1 - //TYPE_LIGHT Yes Yes Yes Yes - //TYPE_LINEAR_ACCELERATION Yes Yes n/a n/a - //TYPE_MAGNETIC_FIELD Yes Yes Yes Yes - //TYPE_ORIENTATION Yes2 Yes2 Yes2 Yes - //TYPE_PRESSURE Yes Yes n/a1 n/a1 - //TYPE_PROXIMITY Yes Yes Yes Yes - //TYPE_RELATIVE_HUMIDITY Yes n/a n/a n/a - //TYPE_ROTATION_VECTOR Yes Yes n/a n/a - //TYPE_TEMPERATURE -// - hardware metrics: -// - basic hw sensors // - network availability // - 4G, 5G -// - gps - glonass beidou ... -// - battery, charging -// node exporter metrics -// - cpu // - ram // - scrape duration // - bluetooth - mac bluetooth -// - nfc // - storage information -// - system information - version .. device name, doba provozu -} -// public fun batteryChargeRatio(): Float { -// val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { intFilter -> -// context.registerReceiver(null, intFilter) -// } -// //val status: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1 -// -// val batteryPct: Float? = batteryStatus?.let { intent -> -// val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) -// val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) -// level * 100 / scale.toFloat() -// } -// -// batteryPct ?: return -1.0f -// return batteryPct -// } + fun batteryChargeRatio(): Float { + val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { intFilter -> + context.registerReceiver(null, intFilter) + } + //val status: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1 + + val batteryRatio: Float? = batteryStatus?.let { intent -> + val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) + val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) + level / scale.toFloat() + } + + batteryRatio ?: return -1.0f + return batteryRatio + } + + fun getNumberOfCpuCores(): Int { + return Os.sysconf(OsConstants._SC_NPROCESSORS_CONF).toInt() + } + + fun getUptimeInSeconds(): Double { + return SystemClock.elapsedRealtime() / 1000.0 + } + + fun cpuUsage() : Array { + return hwPropertiesManager.cpuUsages + } + + fun getDeviceTemperatures() : Map { + val result = mutableMapOf() + temperatureTypes.keys.forEach { type -> + val array = hwPropertiesManager.getDeviceTemperatures( + type, + HardwarePropertiesManager.TEMPERATURE_CURRENT + ) + if(array.isNotEmpty()){ + result[temperatureTypes[type]!!] = array[0].toDouble() + } + } + return result + } + + fun getAndroidOsVersion(): String{ + return Build.VERSION.RELEASE + } + + fun getAndroidModel(): String { + return Build.MODEL + } + + fun getAndroidManufacturer() : String { + return Build.MANUFACTURER + } +} diff --git a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt index d37e6e4..71623a6 100644 --- a/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt +++ b/client/app/src/main/java/com/birdthedeveloper/prometheus/android/exporter/worker/PromWorker.kt @@ -4,7 +4,6 @@ package com.birdthedeveloper.prometheus.android.exporter.worker import android.app.NotificationManager import android.content.Context -import android.hardware.SensorManager import android.util.Log import androidx.core.app.NotificationCompat import androidx.work.CoroutineWorker @@ -117,6 +116,7 @@ class PromWorker( withContext(NonCancellable) { Log.v(TAG, "Canceling prom worker") backgroundDispatcher.close() + metricsEngine.dispose() } } }