Skip to content

Commit

Permalink
Add signal strength and data network type sensors (#4575)
Browse files Browse the repository at this point in the history
* Add signal strength and data network type sensors

* Split signal strength and data network type sensors by SIM

---------

Co-authored-by: Joris Pelgröm <[email protected]>
  • Loading branch information
dshokouhi and jpelgrom authored Sep 11, 2024
1 parent 2214ba9 commit 8270b18
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 6 deletions.
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
Expand Down
1 change: 1 addition & 0 deletions common/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<application>
<receiver android:name=".sensors.SensorUpdateReceiver"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.telephony.CellSignalStrength
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import io.homeassistant.companion.android.common.R as commonR
import io.homeassistant.companion.android.common.util.STATE_UNAVAILABLE
Expand Down Expand Up @@ -48,8 +50,69 @@ class PhoneStateSensorManager : SensorManager {
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC,
updateType = SensorManager.BasicSensor.UpdateType.INTENT
)

val sim1SignalStrength = SensorManager.BasicSensor(
"sim_1_signal_strength",
"sensor",
commonR.string.basic_sensor_name_sim_1_signal_strength,
commonR.string.sensor_description_signal_strength,
"mdi:signal",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val sim2SignalStrength = SensorManager.BasicSensor(
"sim_2_signal_strength",
"sensor",
commonR.string.basic_sensor_name_sim_2_signal_strength,
commonR.string.sensor_description_signal_strength,
"mdi:signal",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val sim1DataNetworkType = SensorManager.BasicSensor(
"sim_1_data_network_type",
"sensor",
commonR.string.basic_sensor_name_sim_1_data_network_type,
commonR.string.sensor_description_data_network_type,
"mdi:signal",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)

val sim2DataNetworkType = SensorManager.BasicSensor(
"sim_2_data_network_type",
"sensor",
commonR.string.basic_sensor_name_sim_2_data_network_type,
commonR.string.sensor_description_data_network_type,
"mdi:signal",
entityCategory = SensorManager.ENTITY_CATEGORY_DIAGNOSTIC
)
}

@SuppressLint("InlinedApi")
@Suppress("DEPRECATION")
private val dataTypeMap = mapOf(
TelephonyManager.NETWORK_TYPE_GPRS to "GPRS",
TelephonyManager.NETWORK_TYPE_EDGE to "EDGE",
TelephonyManager.NETWORK_TYPE_UMTS to "UMTS",
TelephonyManager.NETWORK_TYPE_CDMA to "CDMA",
TelephonyManager.NETWORK_TYPE_EVDO_0 to "EVDO revision 0",
TelephonyManager.NETWORK_TYPE_EVDO_A to "EVDO revision A",
TelephonyManager.NETWORK_TYPE_1xRTT to "1xRTT",
TelephonyManager.NETWORK_TYPE_HSDPA to "HSDPA",
TelephonyManager.NETWORK_TYPE_HSUPA to "HSUPA",
TelephonyManager.NETWORK_TYPE_HSPA to "HSPA",
TelephonyManager.NETWORK_TYPE_IDEN to "iDen",
TelephonyManager.NETWORK_TYPE_EVDO_B to "EVDO revision B",
TelephonyManager.NETWORK_TYPE_LTE to "LTE",
TelephonyManager.NETWORK_TYPE_EHRPD to "eHRPD",
TelephonyManager.NETWORK_TYPE_HSPAP to "HSPA+",
TelephonyManager.NETWORK_TYPE_GSM to "GSM",
TelephonyManager.NETWORK_TYPE_TD_SCDMA to "TD_SCDMA",
TelephonyManager.NETWORK_TYPE_IWLAN to "IWLAN",
TelephonyManager.NETWORK_TYPE_NR to "NR (New Radio) 5G",
TelephonyManager.NETWORK_TYPE_UNKNOWN to STATE_UNKNOWN
)

override fun docsLink(): String {
return "https://companion.home-assistant.io/docs/core/sensors#cellular-provider-sensor"
}
Expand All @@ -59,10 +122,17 @@ class PhoneStateSensorManager : SensorManager {
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
}
override suspend fun getAvailableSensors(context: Context): List<SensorManager.BasicSensor> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
listOf(phoneState, sim_1, sim_2)
} else {
listOf(phoneState)
return when {
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)) ->
listOf(phoneState, sim_1, sim_2, sim1SignalStrength, sim2SignalStrength, sim1DataNetworkType, sim2DataNetworkType)
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)) ->
listOf(phoneState, sim_1, sim_2, sim1DataNetworkType, sim2DataNetworkType)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 -> {
listOf(phoneState, sim_1, sim_2)
}
else -> {
listOf(phoneState)
}
}
}

Expand All @@ -76,6 +146,14 @@ class PhoneStateSensorManager : SensorManager {
checkPhoneState(context)
updateSimSensor(context, 0)
updateSimSensor(context, 1)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
updateSignalStrength(context, 0)
updateSignalStrength(context, 1)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
updateDataNetworkType(context, 0)
updateDataNetworkType(context, 1)
}
}

@SuppressLint("MissingPermission")
Expand Down Expand Up @@ -165,4 +243,83 @@ class PhoneStateSensorManager : SensorManager {
)
}
}

@RequiresApi(Build.VERSION_CODES.Q)
private fun updateSignalStrength(context: Context, slotIndex: Int) {
val signalStrengthSensor = when (slotIndex) {
0 -> sim1SignalStrength
1 -> sim2SignalStrength
else -> throw IllegalArgumentException("Invalid sim slot: $slotIndex")
}
if (!isEnabled(context, signalStrengthSensor)) {
return
}

val baseTelephonyManager =
context.applicationContext.getSystemService<TelephonyManager>()!!
val subscription = context.applicationContext.getSystemService<SubscriptionManager>()
?.getActiveSubscriptionInfoForSimSlotIndex(slotIndex)

var state = STATE_UNAVAILABLE
var attrs = mapOf<String, Any?>()

subscription?.let {
val telephonyManager = baseTelephonyManager.createForSubscriptionId(subscription.subscriptionId)
val signalQuality = when (telephonyManager.signalStrength?.level) {
CellSignalStrength.SIGNAL_STRENGTH_POOR -> "poor"
CellSignalStrength.SIGNAL_STRENGTH_GOOD -> "good"
CellSignalStrength.SIGNAL_STRENGTH_MODERATE -> "moderate"
CellSignalStrength.SIGNAL_STRENGTH_GREAT -> "great"
else -> STATE_UNKNOWN
}
val signal = telephonyManager.signalStrength?.cellSignalStrengths?.firstOrNull()
state = signal?.dbm?.toString() ?: STATE_UNKNOWN
attrs = mapOf(
"asu" to signal?.asuLevel,
"quality" to signalQuality
)
}

onSensorUpdated(
context,
signalStrengthSensor,
state,
signalStrengthSensor.statelessIcon,
attrs
)
}

@RequiresApi(Build.VERSION_CODES.N)
private fun updateDataNetworkType(context: Context, slotIndex: Int) {
val dataNetworkTypeSensor = when (slotIndex) {
0 -> sim1DataNetworkType
1 -> sim2DataNetworkType
else -> throw IllegalArgumentException("Invalid sim slot: $slotIndex")
}
if (!isEnabled(context, dataNetworkTypeSensor)) {
return
}

val baseTelephonyManager =
context.applicationContext.getSystemService<TelephonyManager>()!!
val subscription = context.applicationContext.getSystemService<SubscriptionManager>()
?.getActiveSubscriptionInfoForSimSlotIndex(slotIndex)

var state = STATE_UNAVAILABLE
var attrs = mapOf<String, Any?>()

subscription?.let {
val telephonyManager = baseTelephonyManager.createForSubscriptionId(subscription.subscriptionId)
state = dataTypeMap.getOrDefault(telephonyManager.dataNetworkType, STATE_UNKNOWN)
attrs = mapOf("options" to dataTypeMap.values.toList())
}

onSensorUpdated(
context,
dataNetworkTypeSensor,
state,
dataNetworkTypeSensor.statelessIcon,
attrs
)
}
}
6 changes: 6 additions & 0 deletions common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1277,4 +1277,10 @@
<string name="state_update_available">Update available</string>
<string name="state_up_to_date">Up-to-date</string>
<string name="sensor_name_health_connect">Health Connect sensors</string>
<string name="basic_sensor_name_sim_1_signal_strength">Signal strength (SIM 1)</string>
<string name="basic_sensor_name_sim_2_signal_strength">Signal strength (SIM 2)</string>
<string name="sensor_description_signal_strength">Get the most recently available signal strength information. Due to power saving this information may not always be current.</string>
<string name="basic_sensor_name_sim_1_data_network_type">Data network type (SIM 1)</string>
<string name="basic_sensor_name_sim_2_data_network_type">Data network type (SIM 2)</string>
<string name="sensor_description_data_network_type">The radio technology (network type) currently in use on the device for data transmission</string>
</resources>
1 change: 0 additions & 1 deletion wear/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
<uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Expand Down

0 comments on commit 8270b18

Please sign in to comment.