android icon indicating copy to clipboard operation
android copied to clipboard

Concurrent Local-Only Wifi Support

Open bencorrado opened this issue 1 year ago • 2 comments

Is your feature request related to a problem? Please describe.

Home Assistant is designed with a focus on local control. If a Home Assistant server is on a local only network (no internet access) in recent versions of Android (tested in 13 & 14, but I believe 12 is also an issue), the Android device will drop the WiFi network and only stay connected to the mobile network if one is present. This forces a user to disable the LTE on their phone to connect to the Wi-Fi network and control their Home Assistant Server. This is a very frustrating user experience for offline servers of Home Assistant when using the Android app with LTE connection.

Describe the solution you'd like

I would like to take advantage of Concurrent local-only and internet connection in more recent Android SDKs. This allows for the internet to be provided by LTE or a primary WiFi network, while the app connects to a secondary WiFi that does not have internet access for local only access. It was designed for IoT support, but should work well with an offline Home Assistant server.

We would allow a checkbox next to Home network WiFi SSD entry screen to allow users to designate if a Wi-Fi network may only have local access (no internet).

We could then use the SSID from the local access only network to connect to the server by using WifiNetworkSpecifier.Builder() similar to this:

fun connectToLocalOnlyNetwork(ssid: String, context: Context) {
    val wifiNetworkSpecifier = WifiNetworkSpecifier.Builder()
        .setSsid(ssid)
        .build()

    val networkRequest = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) // Ensure it's not a VPN
        .setNetworkSpecifier(wifiNetworkSpecifier)
        .build()

    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            super.onAvailable(network)
            // Local-only WiFi is connected
        }

        override fun onUnavailable() {
            super.onUnavailable()
            // Failed to connect
        }
    }

    connectivityManager.requestNetwork(networkRequest, networkCallback)
}

We would want to enable the checkbox to support this only on devices with Android 10 or later and maybe only for devices where WifiManager#isStaConcurrencyForLocalOnlyConnectionsSupported() is true. However, that might just need to be a warning that selecting local support will disconnect their other WiFi in order to connect to Home Assistant if it is false.

I think the primary issue to determine is how to create the connection to the local only WiFi network for just regular metrics updates and not drain the battery with a WiFi scan if it is disconnected. Testing is certainly required for that.

Describe alternatives you've considered, if any

The primary alternative here is turning off LTE access to connect to a WiFi network. We could also consider Concurrent restricted and internet connection or a bindProcessToNetwork(), but I think both of these have drawbacks that Concurrent local-only and internet connection do not have.

Additional context

This is related to #675 which was closed due to a lack of support at the time from Android SDK to support this.

bencorrado avatar Oct 20 '23 19:10 bencorrado

+1

nima-1102 avatar Jun 08 '24 00:06 nima-1102

+1 for this as well.

My ISP had a prolonged outage which meant DNS stopped working and thus Android phone quickly shoveled all data over LTE. I had to explicitly disable mobile data before I could load home assistant web interface.

kquinsland avatar Jun 23 '24 22:06 kquinsland