Arduino:Примеры/YunFirstConfig
Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Первая настройка Yun[1]
Этот пример показывает, как подключить устройство Yun к WiFi-сети, используя в качестве интерфейса монитор порта в IDE Arduino.
Загрузите скетч на Yun и откройте монитор порта. Он покажет доступные WiFi-сети, а затем спросит, какой из них вы хотите воспользоваться. Вам нужно будет ввести пароль для этой сети, а затем система попросит вас дать название устройству Yun и пароль к нему. Если соединение к выбранной сети будет выполнено успешно, вам придет подтверждающее сообщение, после чего устройству Yun будет присвоен IP-адрес.
Если вставить этот адрес с адресную строку браузера, откроется панель Yun, содержащая дополнительные настройки и опции.
Если что-то пойдет не так, процедуру можно перезапустить. Если нужной сети не окажется в списке доступных сетей, ее можно будет выбрать вручную, указав SSID и пароль.
Примечание: Для этого скетча требуется, чтобы на устройстве Yun стояла прошивка версии 1.6.2 или новее. Руководство по апгрейду можно прочесть тут, и убедитесь, что у вас стоит самая последняя версия.
Необходимое оборудование
- Плата или модуль Yun
- Беспроводная сеть, подключенная к интернету
Цепь
Для этого примера никакой цепи строить не нужно.
![](/ruwiki/images/1/16/Yun_Fritzing.png)
Наиболее важные части скетча
Библиотеки
- Библиотека Process.h, запускающая процессы (и прочие операции вроде shell-скриптов) на процессоре Linux. В данном случае она используется для получения списка точек доступа и выполнения других действий, позволяющих узнать параметры WiFi.
Функции
- Функция getUserInput(out, obfuscated), берущая данные, которые пользователь вводит через монитор порта, и снова показывающая их в мониторе порта. Переменная obfuscated (тип данных – boolean) используется для того, чтобы при введении пароля печатались звездочки («*»).
- Функция wifiConfig(yunName, yunPsw, wifissid, wifipsw, wifiAPname, countryCode, encryption), выполняющая при помощи библиотеки Process серию команд и скриптов (под Linux), которые настраивают WiFi и сетевые параметры, выбранные пользователем.
- Функция startSerialTerminal(), просто инициализирующая два последовательных порта, которые нужны для выполнения действий, требуемых для этого скетча.
- Функция loopSerialTerminal(), создающая соединение между двумя последовательными портами: один «общается» с PC при помощи USB, а другой – с процессором Linux. У нее есть командный режим, который можно вызвать нажатием на «~». Это выключает Bridge и позволяет выставить разные скорости соединения с чипом Atheros.
Использование
Этот скетч через монитор порта в IDE Arduino запрашивает у пользователя информацию для настройки сетевого соединения. Аппаратный последовательный порт (он находится на 0-ом и 1-ом контактах) уже используется устройством Yun для коммуникации с платой, поэтому данному скетчу для корректной работы потребуется второй последовательный порт. Также стоит подготовить SSID (название точки доступа) и пароль для доступа к WiFi-сети. Загрузите скетч, а затем откройте монитор порта, кликнув на увеличительную лупу в правом верхнем углу IDE Arduino. Вы увидите сообщение – такое же, как на картинке ниже:
![](/ruwiki/images/c/c1/EasySetup_1.png)
Спустя какое-то время на модуле Yun Shield начнет мигать синий светодиод. Когда сканирование завершится, скетч покажет в мониторе порта список доступных точек доступа. Время, необходимое для сканирования, зависит от количества точек доступа и мощности их сигнала. Чтобы выбрать точку доступа, впишите ее номер в поле ввода. Не забудьте выбрать в выпадающем меню, находящемся в правом нижнем углу окна, пункт «NL» (он добавляет символ новой строки).
![](/ruwiki/images/7/7e/EasySetup_2.png)
Выбор точки доступа запускает процесс подключения, после чего Yun «прощупает» сеть на предмет того, открытая она или защищенная. Если сеть защищена, вас попросят ввести пароль (или ключ). Для быстрого и безопасного соединения устройство Yun должно иметь название и быть защищено паролем. После этого ваше устройство готово выключить режим точки доступа и инициировать доступ к выбранной WiFi-сети. В конце этого процесса скетч покажет IP-адрес, полученный при помощи DHCP-сервера.
![](/ruwiki/images/5/5d/EasySetup_3.png)
Если подключение не удастся, скетч сообщит об этом и предложит перезапустить процедуру при помощи сброса Yun.
Код
/*
Первая настройка Arduino Yún
При помощи Bridge настраивает WiFi и сетевые параметры на
Yún101/YunShield/Yún. Для корректной работы скетча Line Ending нужно
выставить на «NewLine». Если у вашей платы два USB-порта,
используйте штатный USB-порт.
Цепь:
Arduino Yún/Yún101/YunShield с прошивкой > 1.6.1
Создан в марте 2016 года Arduino LLC.
Этот код не защищен авторским правом.
http://www.arduino.cc/en/Tutorial/YunFirstConfig
*/
#include <Process.h>
#define MAX_WIFI_LIST 10
String networks[MAX_WIFI_LIST];
String yunName;
String yunPassword;
void setup() {
SERIAL_PORT_USBVIRTUAL.begin(9600); // инициализируем последовательную коммуникацию
while (!SERIAL_PORT_USBVIRTUAL); // ничего не делаем, пока не откроется последовательный монитор
SERIAL_PORT_USBVIRTUAL.println(F("Hi! Nice to see you!")); // "Привет! Рад видеть тебя!"
SERIAL_PORT_USBVIRTUAL.println(F("I'm your Yun101 assistant sketch")); // "Я – скетч-помощник для работы с Yun101"
SERIAL_PORT_USBVIRTUAL.println(F("I'll help you configuring your Yun in a matter of minutes")); // "Я помогу настроить твою Yun за несколько минут"
SERIAL_PORT_USBVIRTUAL.println(F("Let's start by communicating with the Linux processor")); // "Давай начнем с коммуникации с процессором Linux"
SERIAL_PORT_USBVIRTUAL.println(F("When LED (L13) will light up we'll be ready to go!")); // "Если загорелся 13-ый светодиод, значит, все готово!"
SERIAL_PORT_USBVIRTUAL.println(F("Waiting...")); // "Ждем..."
SERIAL_PORT_USBVIRTUAL.println(F("(in the meanwhile, if you are using the IDE's serial monitor, make sure that it's configured to send a \"Newline\")\n")); // "(если используешь монитор порта в IDE Arduino, убедись, что он настроен на отправку символа новой строки (NL)\n"
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Bridge.begin(); // начинаем контактировать с процессором Linux
digitalWrite(13, HIGH); // когда Bridge будет готова, включаем 13-ый светодиод
Process wifiList;
bool master = false;
wifiList.runShellCommand(F("iwinfo | grep \"Mode: Master\""));
while (wifiList.available() > 0) {
wifiList.read();
master = true;
}
// получаем список доступных сетей:
wifiList.runShellCommand(F("iwinfo wlan0 scan | grep ESSID | cut -d\"\\\"\" -f2"));
uint8_t num_networks = 0;
uint8_t i = 0;
char c;
bool dropNet = false;
networks[0].reserve(32);
while (wifiList.available() > 0) {
c = wifiList.read();
if (c != '\n') {
networks[i] += c;
} else {
// проверяем, нет ли в списке повторяющихся сетей, и если есть, удаляем их:
for (uint8_t s = 0; s < i; s++) {
if (networks[i].equals(networks[s])) {
dropNet = true;
}
}
if (i <= MAX_WIFI_LIST && dropNet == false) {
networks[i++].reserve(32);
} else {
dropNet = false;
networks[i]="";
}
}
}
num_networks = i;
String encryption;
String password;
int chose = 0;
// если сетей не найдено, запускаем ручную настройку:
if (num_networks == 0) {
SERIAL_PORT_USBVIRTUAL.println(F("Oops, it seems that you have no WiFi network available")); // "Упс! Похоже, доступных сетей нет"
SERIAL_PORT_USBVIRTUAL.println(F("Let's configure it manually")); // "Значит, запускаем ручную настройку"
SERIAL_PORT_USBVIRTUAL.println(F("SSID of the network you want to connect to: ")); // "SSID сети, к которой вы хотите подключиться: "
networks[0] = getUserInput(networks[0], false);
SERIAL_PORT_USBVIRTUAL.println(F("Password for the network you want to connect to: ")); // "Пароль для сети, к которой вы хотите подключиться: "
password = getUserInput(password, true);
SERIAL_PORT_USBVIRTUAL.print(F("Encryption (eg WPA, WPA2, WEP): ")); // "Шифрование (например, WPA, WPA2, WEP): "
encryption = getUserInput(encryption, false);
} else {
// если сети найдены, показываем их, но сначала показываем их количество:
SERIAL_PORT_USBVIRTUAL.print(F("It looks like you have ")); // "Итак, мы нашли "
SERIAL_PORT_USBVIRTUAL.print(num_networks);
SERIAL_PORT_USBVIRTUAL.println(F(" networks around you ")); // " сетей вокруг нас"
SERIAL_PORT_USBVIRTUAL.println(F("Which one do you want to connect to?\n")); // "К какой из них вы хотите подключиться?\n"
for (i = 0; i < num_networks && i < MAX_WIFI_LIST; i++) {
SERIAL_PORT_USBVIRTUAL.print(i);
SERIAL_PORT_USBVIRTUAL.println(") " + networks[i]);
}
String selection;
selection = getUserInput(selection, false);
chose = atoi(selection.c_str());
}
// извлекаем информацию о шифровании выбранной сети:
bool openNet = false;
wifiList.runShellCommand("iwinfo wlan0 scan | grep \"" + networks[chose] + "\" -A5 | grep Encryption | cut -f2 -d\":\"");
while (wifiList.available() > 0) {
c = wifiList.read();
encryption += c;
}
if (encryption.indexOf("none") >= 0) {
openNet = true;
encryption = "none";
}
if (encryption.indexOf("WPA2") >= 0) {
encryption = "psk2";
}
if (encryption.indexOf("WPA") >= 0) {
encryption = "psk";
}
if (encryption.indexOf("WEP") >= 0) {
encryption = "wep";
}
if (openNet == false && password.length() == 0) {
SERIAL_PORT_USBVIRTUAL.print(F("It looks like you need a password to connect to ")); // "Похоже, для подключения нужен пароль: "
SERIAL_PORT_USBVIRTUAL.println(networks[chose]);
SERIAL_PORT_USBVIRTUAL.print(F("Write it here: ")); // "Пишем его здесь: "
password = getUserInput(password, true);
}
// меняем пароль для устройства Yun:
SERIAL_PORT_USBVIRTUAL.println(F("We are almost done! Give a name and a password to your Yun")); // "Почти готово! Впишите название и пароль для Yun"
SERIAL_PORT_USBVIRTUAL.print(F("Name: ")); // "Название: "
yunName = getUserInput(yunName, false);
SERIAL_PORT_USBVIRTUAL.print(F("Password: ")); // "Пароль: "
yunPassword = getUserInput(yunPassword, true);
// выбираем код страны:
String countryCode;
SERIAL_PORT_USBVIRTUAL.println(F("One last question: where do you live?")); // "Последний вопрос: где вы живете?"
SERIAL_PORT_USBVIRTUAL.print(F("Insert a two letters county code (eg IT, US, DE): ")); // "Впишите две буквы для кода страны (например, RU, BY, UA и т.д.): "
countryCode = getUserInput(countryCode, false);
yunName.trim();
yunPassword.trim();
networks[chose].trim();
password.trim();
countryCode.trim();
// настраиваем Yun при помощи данных, введенных пользователем:
wifiConfig(yunName, yunPassword, networks[chose], password, "YUN" + yunName + "AP", countryCode,encryption);
SERIAL_PORT_USBVIRTUAL.print(F("Waiting for the Yun to connect to the network")); // "Ждем, пока Yun подключится к сети"
}
bool Connected = false;
bool serialTerminalMode = false;
int runs = 0;
void loop() {
if (!serialTerminalMode) {
String resultStr = "";
if (!Connected) {
SERIAL_PORT_USBVIRTUAL.print(".");
runs++;
}
// если подключение занимает более 20 секунд, останавливаем попытки подключения:
if (runs > 20) {
SERIAL_PORT_USBVIRTUAL.println("");
SERIAL_PORT_USBVIRTUAL.println(F("We couldn't connect to the network.")); // "Подключиться к сети не удалось."
SERIAL_PORT_USBVIRTUAL.println(F("Restart the board if you want to execute the wizard again")); // "Если вы вновь хотите запустить мастер настройки, перезапустите плату"
resultStr = getUserInput(resultStr, false);
}
// проверяем, есть ли IP-адрес:
Process wifiCheck;
wifiCheck.runShellCommand(F("/usr/bin/pretty-wifi-info.lua | grep \"IP address\" | cut -f2 -d\":\" | cut -f1 -d\"/\"" )); // команда, которую вы хотите запустить
while (wifiCheck.available() > 0) {
char c = wifiCheck.read();
resultStr += c;
}
delay(1000);
if (resultStr != "") {
// IP-адрес получен, значит, останавливаем блок loop(),
// показываем значение и запускаем терминал:
Connected = true;
resultStr.trim();
SERIAL_PORT_USBVIRTUAL.println("");
SERIAL_PORT_USBVIRTUAL.print(F("\nGreat! You can now reach your Yun from a browser typing http://")); // "\nОтлично! Теперь вы можете получить доступ к Yun из браузера, вписав туда http://"
SERIAL_PORT_USBVIRTUAL.println(resultStr);
SERIAL_PORT_USBVIRTUAL.print(F("Press 'Enter' key twice to start a serial terminal")); // "Дважды нажмите Enter, чтобы запустить терминал в мониторе порта"
resultStr = getUserInput(resultStr, false);
serialTerminalMode = true;
//startSerialTerminal();
SERIAL_PORT_HARDWARE.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); // отсылаем команду выключения Bridge
delay(100);
SERIAL_PORT_HARDWARE.println("\nreset\n\n");
SERIAL_PORT_HARDWARE.flush();
SERIAL_PORT_HARDWARE.println("\nreset\n\n");
SERIAL_PORT_HARDWARE.write((uint8_t *)"\n", 1);
}
} else {
loopSerialTerminal();
}
}
String getUserInput(String out, bool obfuscated) {
/*
while (SerialUSB.available() <= 0) {}
while (SerialUSB.available() > 0) {
char c = SerialUSB.read();
out += c;
}
return out;
*/
while (SERIAL_PORT_USBVIRTUAL.available() <= 0) {}
while (1) {
char c = SERIAL_PORT_USBVIRTUAL.read();
if (c == '\n' || c == '\r')
break;
else {
if (c != -1) {
out += c;
if (obfuscated)
SERIAL_PORT_USBVIRTUAL.print("*");
else
SERIAL_PORT_USBVIRTUAL.print(c);
}
}
}
SERIAL_PORT_USBVIRTUAL.println("");
return out;
}
void wifiConfig(String yunName, String yunPsw, String wifissid, String wifipsw, String wifiAPname, String countryCode, String encryption) {
Process p;
p.runShellCommand("blink-start 100"); // запускаем мигание синим светодиодом
p.runShellCommand("hostname " + yunName); // меняем текущее имя хоста
p.runShellCommand("uci set system.@system[0].hostname='" + yunName + "'"); // меняем имя хоста в UCI
p.runShellCommand("uci set arduino.@arduino[0].access_point_wifi_name='" + wifiAPname + "'");
// этот блок сбрасывает пароль для WiFi:
p.runShellCommand("uci set wireless.@wifi-iface[0].encryption='" + encryption + "'");
p.runShellCommand("uci set wireless.@wifi-iface[0].mode='sta'\n");
p.runShellCommand("uci set wireless.@wifi-iface[0].ssid='" + wifissid + "'");
p.runShellCommand("uci set wireless.@wifi-iface[0].key='" + wifipsw + "'");
p.runShellCommand("uci set wireless.radio0.channel='auto'");
p.runShellCommand("uci set wireless.radio0.country='" + countryCode + "'");
p.runShellCommand("uci delete network.lan.ipaddr");
p.runShellCommand("uci delete network.lan.netmask");
p.runShellCommand("uci set network.lan.proto='dhcp'");
p.runShellCommand("echo -e \"" + yunPsw + "\n" + yunPsw + "\" | passwd root"); // меняем пароли
p.runShellCommand("uci commit"); // сохраняем режимы, настроенные через UCI
p.runShellCommand("blink-stop"); // запускаем мигание синего светодиода
p.runShellCommand("wifi ");
}
long linuxBaud = 250000;
void startSerialTerminal() {
SERIAL_PORT_USBVIRTUAL.begin(115200); // открываем последовательную коммуникацию USB-Serial
SERIAL_PORT_HARDWARE.begin(linuxBaud); // открываем последовательную коммуникацию к Linux
}
boolean commandMode = false;
void loopSerialTerminal() {
// копируем из USB-CDC в UART
int c = SERIAL_PORT_USBVIRTUAL.read(); // считываем из USB-CDC
if (c != -1) { // есть что-то?
if (commandMode == false) { // если мы не в командном режиме...
if (c == '~') { // Нажата клавиша '~'?
commandMode = true; // входим в командный режим
} else {
SERIAL_PORT_HARDWARE.write(c); // в противном случае записываем символ в UART
}
} else { // если мы в командном режиме...
if (c == '0') { // нажата клавиша '0'?
SERIAL_PORT_HARDWARE.begin(57600); // задаем скорость на 57600
SERIAL_PORT_USBVIRTUAL.println("Speed set to 57600"); // "Выставляем скорость на 57600"
} else if (c == '1') { // нажата ли клавиша '1'?
SERIAL_PORT_HARDWARE.begin(115200); // задаем скорость на 115200
SERIAL_PORT_USBVIRTUAL.println("Speed set to 115200"); // "Выставляем скорость на 115200"
} else if (c == '2') { // нажата ли клавиша '2'?
SERIAL_PORT_HARDWARE.begin(250000); // задаем скорость на 250000
SERIAL_PORT_USBVIRTUAL.println("Speed set to 250000"); // "Выставляем скорость на 250000"
} else if (c == '3') { // нажата ли клавиша '3'?
SERIAL_PORT_HARDWARE.begin(500000); // задаем скорость на 500000
SERIAL_PORT_USBVIRTUAL.println("Speed set to 500000"); // "Выставляем скорость на 500000"
} else if (c == '~') { // нажата ли клавиша '~'?
SERIAL_PORT_HARDWARE.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); // отправляем команду выключения Bridge
SERIAL_PORT_USBVIRTUAL.println("Sending bridge's shutdown command"); // "Отправляем команду выключения Bridge"
} else { // нажата ли какая-либо клавиша?
SERIAL_PORT_HARDWARE.write('~'); // записываем '~' на UART
SERIAL_PORT_HARDWARE.write(c); // записываем символ на UART
}
commandMode = false; // во всех случаях выходим из командного режима
}
}
// копируем из UART в USB-CDC:
c = SERIAL_PORT_HARDWARE.read(); // считываем из UART
if (c != -1) { // получили что-нибудь?
SERIAL_PORT_USBVIRTUAL.write(c); // записываем на USB-CDC
}
}