В настоящее время я работаю над проектом, в котором у меня есть приложение для Android, которому необходимо подключиться к устройству IoT и отправить ему некоторую информацию. Устройство IoT использует микроконтроллер SAMD21 с модулем Wi-Fi ATWINC1500. ATWINC1500 способен создавать точку доступа Wi-Fi, к которой я должен иметь возможность подключиться с устройства Android. Он не поддерживает прямые Wi-Fi (p2p) соединения и не поддерживает Bluetooth. В настоящее время на устройстве IoT я создаю точку доступа, а затем запускаю сервер для прослушивания входящих подключений. Просто для информации: точка доступа Wi-Fi в настоящее время открыта без пароля или ключа.
Моя упрощенная программа такова:
- На устройстве Android просканируйте доступные сети Wi-Fi и найдите ту, которая соответствует имени точки доступа, созданной устройством IoT.
- Подключитесь к точке доступа IoT-устройства
- Создайте TcpClient и подключитесь к серверу на устройстве IoT (IP-адрес 192.168.1.1).
- Отправьте некоторую информацию на устройство IoT.
Что касается Android, я использую C # с Xamarin. У меня есть несколько разных тестовых устройств: планшет 10 под управлением Android 10 и телефон 5 под управлением Android 8.1. Я изучил документацию Android, а также несколько других сообщений о переполнении стека, в которых подробно рассказывается о том, как программно подключить устройство Android к точке доступа Wi-Fi. Вот лишь несколько других сообщений о переполнении стека, которые я прочитал:
- Подключиться к Wi-Fi Android Q
- Как программно подключиться к Wi-Fi
- Как подключиться к программно для конкретной сети Wi-Fi в Android?
- Android Q, программно подключайтесь к другой точке доступа Wi-Fi для Интернета < / а>
- Android 10 / API 29: как подключить телефон к настроенной сети?
К сожалению, даже после просмотра всех этих источников у меня были неоднозначные результаты. Это срабатывает иногда, но только в меньшей степени. Это также осложняется тем, что Android имеет отдельные API для подключения к Wi-Fi в зависимости от того, какая версия Android работает на устройстве.
Вот мой основной способ подключения к точке доступа Wi-Fi:
public void ConnectToWifiNetwork(string ssid)
{
if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Q)
{
var wifi_network_specifier = (new WifiNetworkSpecifier.Builder()).SetSsid(ssid).Build();
var network_request = (new NetworkRequest.Builder()).AddTransportType(TransportType.Wifi)
.SetNetworkSpecifier(wifi_network_specifier).Build();
connectivity_manager.RequestNetwork(network_request, network_callback);
}
else if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
{
//See if the desired network configuration already exists
var configured_networks = wifi_manager.ConfiguredNetworks;
var specified_network = configured_networks.Where(x => x.Ssid.Contains(ssid)).FirstOrDefault();
int network_id = -1;
//If no network configuration already exists....
if (specified_network == null)
{
//Create a wifi configuration with the appropriate SSID
specified_network = new WifiConfiguration();
specified_network.Ssid = '"' + ssid + '"';
specified_network.AllowedKeyManagement.Set((int)Android.Net.Wifi.KeyManagementType.None);
//Add the configuration to the wifi manager's list of configured networks
network_id = wifi_manager.AddNetwork(specified_network);
}
else
{
//Otherwise, if a network configuration does already exist, grab the network ID
network_id = specified_network.NetworkId;
}
//If we have a valid network ID...
if (network_id != -1)
{
//Let's attempt to connect to the network
wifi_manager.Disconnect();
wifi_manager.EnableNetwork(network_id, true);
wifi_manager.Reconnect();
//Now let's bind to the network we just connected to
var network_request = (new NetworkRequest.Builder()).AddTransportType(TransportType.Wifi).Build();
connectivity_manager.RequestNetwork(network_request, network_callback);
}
}
}
Обратите внимание, что переменные connectivity_manager
и wifi_manager
определены в другом месте кода, и они относятся к типам соответственно ConnectivityManager
и WifiManager
. Кроме того, переменная network_callback
также определена в другом месте кода и имеет тип WifiConnectorNetworkCallback
, который я определил как таковой:
class WifiConnectorNetworkCallback : ConnectivityManager.NetworkCallback
{
WifiConnector source;
public WifiConnectorNetworkCallback(WifiConnector p)
{
source = p;
}
public override void OnAvailable(Network network)
{
source.connectivity_manager.BindProcessToNetwork(network);
source.WifiNetworkConnected?.Invoke(source, new EventArgs());
}
public override void OnUnavailable()
{
base.OnUnavailable();
}
}
Наконец, вы заметите, что когда вызывается метод OnAvailable, он вызывает обработчик событий. В методе, вызываемом обработчиком событий, я фактически создаю TcpClient и пытаюсь подключиться к серверу на устройстве IoT. Это определяется как таковое:
private void WifiNetworkConnected(object sender, EventArgs e)
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Parse("192.168.1.1"), 80);
//Create a network stream to send data
NetworkStream writer = client.GetStream();
//Write some data
string data = "test";
writer.Write(Encoding.ASCII.GetBytes(data), 0, data.Length);
//Disconnect from the server
writer.Close();
client.Close();
}
Теперь я обнаружил, что программа может вести себя по-разному. Если я запускаю приложение на своем устройстве Android 8.1, типичные 3 строки кода, которые встречаются во многих других вопросах / ответах StackOverflow, не работают для подключения к Wi-Fi. AP:
wifi_manager.Disconnect();
wifi_manager.EnableNetwork(network_id, true);
wifi_manager.Reconnect();
Я должен включить вызов RequestNetwork
из класса ConnectivityManager
, чтобы он вообще мог подключиться к точке доступа Wi-Fi, поэтому существует эта строка кода:
connectivity_manager.RequestNetwork(network_request, network_callback);
Но даже при использовании вызова RequestNetwork
как на Android 8.1, так и на Android 10 он по-прежнему не работает полностью. Если бы я просто остановился на этом и попытался создать TcpClient и подключиться к серверу на AP, я бы получил исключение Network Unreachable.
Поэтому после долгих исследований и копаний я решил добавить следующую строку кода в метод OnAvailable
после вызова RequestNetwork
:
parent.connectivity_manager.BindProcessToNetwork(network);
Кажется, это помогает иногда. Это увеличило мою успешность подключения к AP с помощью TcpClient с 0% до, может быть, 10% или 20%, но, к сожалению, теперь я часто получаю исключение Connection Refused.
Теперь есть один способ, которым я, кажется, добился 100% успеха: если я вручную подключаюсь к точке доступа Wi-Fi с помощью приложения настроек Android, а затем я возвращаюсь в мое приложение для Android и создайте TcpClient, он каждый раз работает успешно. Из-за этого я не думаю, что есть ошибка на стороне микроконтроллера IoT. Похоже, что что-то происходит в Android, где, если я вручную подключаюсь к AP, он работает нормально, но, используя код, описанный выше для подключения к AP, я продолжаю получать либо Network Unreachable, либо Connection Отказано в исключениях.
Может ли кто-нибудь помочь прояснить, почему я получаю эти исключения? Я пропустил какой-то шаг при подключении к точке доступа? Спасибо за любую помощь!