Arduino:Примеры/YunFirstConfig

Материал из Онлайн справочника
Перейти к навигации Перейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Первая настройка Yun[1]

Этот пример показывает, как подключить устройство Yun к WiFi-сети, используя в качестве интерфейса монитор порта в IDE Arduino.

Загрузите скетч на Yun и откройте монитор порта. Он покажет доступные WiFi-сети, а затем спросит, какой из них вы хотите воспользоваться. Вам нужно будет ввести пароль для этой сети, а затем система попросит вас дать название устройству Yun и пароль к нему. Если соединение к выбранной сети будет выполнено успешно, вам придет подтверждающее сообщение, после чего устройству Yun будет присвоен IP-адрес.

Если вставить этот адрес с адресную строку браузера, откроется панель Yun, содержащая дополнительные настройки и опции.

Если что-то пойдет не так, процедуру можно перезапустить. Если нужной сети не окажется в списке доступных сетей, ее можно будет выбрать вручную, указав SSID и пароль.

Примечание: Для этого скетча требуется, чтобы на устройстве Yun стояла прошивка версии 1.6.2 или новее. Руководство по апгрейду можно прочесть тут, и убедитесь, что у вас стоит самая последняя версия.

Необходимое оборудование

  • Плата или модуль Yun
  • Беспроводная сеть, подключенная к интернету

Цепь

Для этого примера никакой цепи строить не нужно.

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. Вы увидите сообщение – такое же, как на картинке ниже:

EasySetup 1.png

Спустя какое-то время на модуле Yun Shield начнет мигать синий светодиод. Когда сканирование завершится, скетч покажет в мониторе порта список доступных точек доступа. Время, необходимое для сканирования, зависит от количества точек доступа и мощности их сигнала. Чтобы выбрать точку доступа, впишите ее номер в поле ввода. Не забудьте выбрать в выпадающем меню, находящемся в правом нижнем углу окна, пункт «NL» (он добавляет символ новой строки).

EasySetup 2.png

Выбор точки доступа запускает процесс подключения, после чего Yun «прощупает» сеть на предмет того, открытая она или защищенная. Если сеть защищена, вас попросят ввести пароль (или ключ). Для быстрого и безопасного соединения устройство Yun должно иметь название и быть защищено паролем. После этого ваше устройство готово выключить режим точки доступа и инициировать доступ к выбранной WiFi-сети. В конце этого процесса скетч покажет IP-адрес, полученный при помощи DHCP-сервера.

EasySetup 3.png

Если подключение не удастся, скетч сообщит об этом и предложит перезапустить процедуру при помощи сброса Yun.

Код

  1 /*
  2   Первая настройка Arduino Yún
  3 
  4   При помощи Bridge настраивает WiFi и сетевые параметры на 
  5   Yún101/YunShield/Yún. Для корректной работы скетча Line Ending нужно 
  6   выставить на «NewLine». Если у вашей платы два USB-порта,
  7   используйте штатный USB-порт.
  8 
  9   Цепь:
 10    Arduino Yún/Yún101/YunShield с прошивкой > 1.6.1
 11 
 12   Создан в марте 2016 года Arduino LLC.
 13 
 14   Этот код не защищен авторским правом.
 15 
 16   http://www.arduino.cc/en/Tutorial/YunFirstConfig
 17 */
 18 
 19 #include <Process.h>
 20 
 21 #define MAX_WIFI_LIST 10
 22 
 23 String networks[MAX_WIFI_LIST];
 24 String yunName;
 25 String yunPassword;
 26 
 27 void setup() {
 28   SERIAL_PORT_USBVIRTUAL.begin(9600);  // инициализируем последовательную коммуникацию 
 29   while (!SERIAL_PORT_USBVIRTUAL);     // ничего не делаем, пока не откроется последовательный монитор 
 30 
 31   SERIAL_PORT_USBVIRTUAL.println(F("Hi! Nice to see you!"));  //  "Привет! Рад видеть тебя!"
 32   SERIAL_PORT_USBVIRTUAL.println(F("I'm your Yun101 assistant sketch"));  //  "Я – скетч-помощник для работы с Yun101"
 33   SERIAL_PORT_USBVIRTUAL.println(F("I'll help you configuring your Yun in a matter of minutes"));  //  "Я помогу настроить твою Yun за несколько минут"
 34 
 35   SERIAL_PORT_USBVIRTUAL.println(F("Let's start by communicating with the Linux processor"));  //  "Давай начнем с коммуникации с процессором Linux"
 36   SERIAL_PORT_USBVIRTUAL.println(F("When LED (L13) will light up we'll be ready to go!"));  //  "Если загорелся 13-ый светодиод, значит, все готово!"
 37   SERIAL_PORT_USBVIRTUAL.println(F("Waiting..."));  //  "Ждем..."
 38   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"
 39   pinMode(13, OUTPUT);
 40   digitalWrite(13, LOW);
 41   Bridge.begin();  // начинаем контактировать с процессором Linux 
 42   digitalWrite(13, HIGH);  // когда Bridge будет готова, включаем 13-ый светодиод 
 43 
 44   Process wifiList;
 45   bool master = false;
 46   wifiList.runShellCommand(F("iwinfo | grep \"Mode: Master\""));
 47   while (wifiList.available() > 0) {
 48     wifiList.read();
 49     master = true;
 50   }
 51 
 52   // получаем список доступных сетей:
 53   wifiList.runShellCommand(F("iwinfo wlan0 scan | grep ESSID | cut -d\"\\\"\" -f2"));
 54 
 55   uint8_t num_networks = 0;
 56   uint8_t i = 0;
 57   char c;
 58   bool dropNet = false;
 59 
 60   networks[0].reserve(32);
 61 
 62   while (wifiList.available() > 0) {
 63     c = wifiList.read();
 64     if (c != '\n') {
 65       networks[i] += c;
 66     } else {
 67       // проверяем, нет ли в списке повторяющихся сетей, и если есть, удаляем их: 
 68       for (uint8_t s = 0; s < i; s++) {
 69         if (networks[i].equals(networks[s])) {
 70           dropNet = true;
 71         }
 72       }
 73       if (i <= MAX_WIFI_LIST && dropNet == false) {
 74         networks[i++].reserve(32);
 75       } else {
 76         dropNet = false;
 77         networks[i]="";
 78       }
 79     }
 80   }
 81 
 82   num_networks = i;
 83 
 84   String encryption;
 85   String password;
 86   int chose = 0;
 87 
 88   // если сетей не найдено, запускаем ручную настройку:
 89   if (num_networks == 0) {
 90     SERIAL_PORT_USBVIRTUAL.println(F("Oops, it seems that you have no WiFi network available"));  //  "Упс! Похоже, доступных сетей нет"
 91     SERIAL_PORT_USBVIRTUAL.println(F("Let's configure it manually"));  //  "Значит, запускаем ручную настройку"
 92     SERIAL_PORT_USBVIRTUAL.println(F("SSID of the network you want to connect to: "));  //  "SSID сети, к которой вы хотите подключиться: "
 93     networks[0] = getUserInput(networks[0], false);
 94     SERIAL_PORT_USBVIRTUAL.println(F("Password for the network you want to connect to: "));  //  "Пароль для сети, к которой вы хотите подключиться: "
 95     password = getUserInput(password, true);
 96     SERIAL_PORT_USBVIRTUAL.print(F("Encryption (eg WPA, WPA2, WEP): "));  //  "Шифрование (например, WPA, WPA2, WEP): "
 97     encryption = getUserInput(encryption, false);
 98   } else {
 99     // если сети найдены, показываем их, но сначала показываем их количество:
100     SERIAL_PORT_USBVIRTUAL.print(F("It looks like you have "));  //  "Итак, мы нашли "
101     SERIAL_PORT_USBVIRTUAL.print(num_networks);
102     SERIAL_PORT_USBVIRTUAL.println(F(" networks around you "));  //  " сетей вокруг нас"
103     SERIAL_PORT_USBVIRTUAL.println(F("Which one do you want to connect to?\n"));  //  "К какой из них вы хотите подключиться?\n"
104     for (i = 0; i < num_networks && i < MAX_WIFI_LIST; i++) {
105       SERIAL_PORT_USBVIRTUAL.print(i);
106       SERIAL_PORT_USBVIRTUAL.println(") " + networks[i]);
107     }
108     String selection;
109     selection = getUserInput(selection, false);
110     chose = atoi(selection.c_str());
111   }
112 
113   // извлекаем информацию о шифровании выбранной сети:
114   bool openNet = false;
115   wifiList.runShellCommand("iwinfo wlan0 scan | grep \"" + networks[chose] + "\" -A5 | grep Encryption | cut -f2 -d\":\"");
116   while (wifiList.available() > 0) {
117     c = wifiList.read();
118     encryption += c;
119   }
120 
121   if (encryption.indexOf("none") >= 0) {
122     openNet = true;
123     encryption = "none";
124   }
125   if (encryption.indexOf("WPA2") >= 0) {
126     encryption = "psk2";
127   }
128   if (encryption.indexOf("WPA") >= 0) {
129     encryption = "psk";
130   }
131   if (encryption.indexOf("WEP") >= 0) {
132     encryption = "wep";
133   }
134 
135   if (openNet == false && password.length() == 0) {
136     SERIAL_PORT_USBVIRTUAL.print(F("It looks like you need a password to connect to "));  //  "Похоже, для подключения нужен пароль: "
137     SERIAL_PORT_USBVIRTUAL.println(networks[chose]);
138     SERIAL_PORT_USBVIRTUAL.print(F("Write it here: "));  //  "Пишем его здесь: "
139     password = getUserInput(password, true);
140   }
141 
142   // меняем пароль для устройства Yun:
143   SERIAL_PORT_USBVIRTUAL.println(F("We are almost done! Give a name and a password to your Yun"));  //  "Почти готово! Впишите название и пароль для Yun"
144   SERIAL_PORT_USBVIRTUAL.print(F("Name: "));  //  "Название: "
145   yunName = getUserInput(yunName, false);
146   SERIAL_PORT_USBVIRTUAL.print(F("Password: "));  //  "Пароль: "
147   yunPassword = getUserInput(yunPassword, true);
148 
149   // выбираем код страны:
150   String countryCode;
151   SERIAL_PORT_USBVIRTUAL.println(F("One last question: where do you live?"));  //  "Последний вопрос: где вы живете?"
152   SERIAL_PORT_USBVIRTUAL.print(F("Insert a two letters county code (eg IT, US, DE): "));  //  "Впишите две буквы для кода страны (например, RU, BY, UA и т.д.): "
153   countryCode = getUserInput(countryCode, false);
154 
155   yunName.trim();
156   yunPassword.trim();
157   networks[chose].trim();
158   password.trim();
159   countryCode.trim();
160 
161   // настраиваем Yun при помощи данных, введенных пользователем:
162   wifiConfig(yunName, yunPassword, networks[chose], password, "YUN" + yunName + "AP", countryCode,encryption);
163 
164   SERIAL_PORT_USBVIRTUAL.print(F("Waiting for the Yun to connect to the network"));  //  "Ждем, пока Yun подключится к сети"
165 }
166 
167 bool Connected = false;
168 bool serialTerminalMode = false;
169 int runs = 0;
170 
171 void loop() {
172   if (!serialTerminalMode) {
173     String resultStr = "";
174 
175     if (!Connected) {
176       SERIAL_PORT_USBVIRTUAL.print(".");
177       runs++;
178     }
179 
180     // если подключение занимает более 20 секунд, останавливаем попытки подключения:
181     if (runs > 20) {
182       SERIAL_PORT_USBVIRTUAL.println("");
183       SERIAL_PORT_USBVIRTUAL.println(F("We couldn't connect to the network."));  //  "Подключиться к сети не удалось."
184       SERIAL_PORT_USBVIRTUAL.println(F("Restart the board if you want to execute the wizard again"));  //  "Если вы вновь хотите запустить мастер настройки, перезапустите плату"
185       resultStr = getUserInput(resultStr, false);
186     }
187 
188     // проверяем, есть ли IP-адрес:
189     Process wifiCheck;
190     wifiCheck.runShellCommand(F("/usr/bin/pretty-wifi-info.lua | grep \"IP address\" | cut -f2 -d\":\" | cut -f1 -d\"/\"" ));  // команда, которую вы хотите запустить
191     while (wifiCheck.available() > 0) {
192       char c = wifiCheck.read();
193       resultStr += c;
194     }
195 
196     delay(1000);
197 
198     if (resultStr != "") {
199       // IP-адрес получен, значит, останавливаем блок loop(), 
200       // показываем значение и запускаем терминал:
201       Connected = true;
202       resultStr.trim();
203       SERIAL_PORT_USBVIRTUAL.println("");
204       SERIAL_PORT_USBVIRTUAL.print(F("\nGreat! You can now reach your Yun from a browser typing http://"));  //  "\nОтлично! Теперь вы можете получить доступ к Yun из браузера, вписав туда http://"
205       SERIAL_PORT_USBVIRTUAL.println(resultStr);
206       SERIAL_PORT_USBVIRTUAL.print(F("Press 'Enter' key twice to start a serial terminal"));  //  "Дважды нажмите Enter, чтобы запустить терминал в мониторе порта"
207       resultStr = getUserInput(resultStr, false);
208       serialTerminalMode = true;
209       //startSerialTerminal();
210       SERIAL_PORT_HARDWARE.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); // отсылаем команду выключения Bridge
211       delay(100);
212       SERIAL_PORT_HARDWARE.println("\nreset\n\n");
213       SERIAL_PORT_HARDWARE.flush();
214       SERIAL_PORT_HARDWARE.println("\nreset\n\n");
215       SERIAL_PORT_HARDWARE.write((uint8_t *)"\n", 1);
216     }
217 
218   } else {
219     loopSerialTerminal();
220   }
221 }
222 
223 String getUserInput(String out, bool obfuscated) {
224   /*
225     while (SerialUSB.available() <= 0) {}
226     while (SerialUSB.available() > 0) {
227     char c =  SerialUSB.read();
228     out += c;
229     }
230     return out;
231   */
232   while (SERIAL_PORT_USBVIRTUAL.available() <= 0) {}
233   while (1) {
234     char c = SERIAL_PORT_USBVIRTUAL.read();
235     if (c == '\n' || c == '\r')
236       break;
237     else {
238       if (c != -1) {
239         out += c;
240         if (obfuscated)
241           SERIAL_PORT_USBVIRTUAL.print("*");
242         else
243           SERIAL_PORT_USBVIRTUAL.print(c);
244       }
245     }
246   }
247   SERIAL_PORT_USBVIRTUAL.println("");
248   return out;
249 }
250 
251 void wifiConfig(String yunName, String yunPsw, String wifissid, String wifipsw, String wifiAPname, String countryCode, String encryption) {
252   Process p;
253 
254   p.runShellCommand("blink-start 100"); // запускаем мигание синим светодиодом
255 
256   p.runShellCommand("hostname " + yunName); // меняем текущее имя хоста
257   p.runShellCommand("uci set system.@system[0].hostname='" + yunName + "'"); // меняем имя хоста в UCI
258 
259   p.runShellCommand("uci set arduino.@arduino[0].access_point_wifi_name='" + wifiAPname + "'");
260 
261   // этот блок сбрасывает пароль для WiFi:
262   p.runShellCommand("uci set wireless.@wifi-iface[0].encryption='" + encryption + "'");
263   p.runShellCommand("uci set wireless.@wifi-iface[0].mode='sta'\n");
264   p.runShellCommand("uci set wireless.@wifi-iface[0].ssid='" + wifissid + "'");
265   p.runShellCommand("uci set wireless.@wifi-iface[0].key='" + wifipsw + "'");
266   p.runShellCommand("uci set wireless.radio0.channel='auto'");
267   p.runShellCommand("uci set wireless.radio0.country='" + countryCode + "'");
268   p.runShellCommand("uci delete network.lan.ipaddr");
269   p.runShellCommand("uci delete network.lan.netmask");
270   p.runShellCommand("uci set network.lan.proto='dhcp'");
271 
272   p.runShellCommand("echo -e \"" + yunPsw + "\n" + yunPsw + "\" | passwd root"); // меняем пароли
273   p.runShellCommand("uci commit"); // сохраняем режимы, настроенные через UCI
274   p.runShellCommand("blink-stop"); // запускаем мигание синего светодиода
275 
276   p.runShellCommand("wifi ");
277 }
278 
279 long linuxBaud = 250000;
280 
281 void startSerialTerminal() {
282   SERIAL_PORT_USBVIRTUAL.begin(115200);  // открываем последовательную коммуникацию USB-Serial
283   SERIAL_PORT_HARDWARE.begin(linuxBaud); // открываем последовательную коммуникацию к Linux
284 }
285 
286 boolean commandMode = false;
287 void loopSerialTerminal() {
288   // копируем из USB-CDC в UART
289   int c = SERIAL_PORT_USBVIRTUAL.read();    // считываем из USB-CDC
290   if (c != -1) {                            // есть что-то?
291     if (commandMode == false) {             // если мы не в командном режиме...
292       if (c == '~') {                       // Нажата клавиша '~'?
293         commandMode = true;                 // входим в командный режим
294       } else {
295         SERIAL_PORT_HARDWARE.write(c);      // в противном случае записываем символ в UART
296       }
297     } else {                                // если мы в командном режиме...
298       if (c == '0') {                       // нажата клавиша '0'?
299         SERIAL_PORT_HARDWARE.begin(57600);  // задаем скорость на 57600
300         SERIAL_PORT_USBVIRTUAL.println("Speed set to 57600");  //  "Выставляем скорость на 57600"
301       } else if (c == '1') {                // нажата ли клавиша '1'?
302         SERIAL_PORT_HARDWARE.begin(115200); // задаем скорость на 115200
303         SERIAL_PORT_USBVIRTUAL.println("Speed set to 115200");  //  "Выставляем скорость на 115200"
304       } else if (c == '2') {                // нажата ли клавиша '2'? 
305         SERIAL_PORT_HARDWARE.begin(250000); // задаем скорость на 250000
306         SERIAL_PORT_USBVIRTUAL.println("Speed set to 250000");  //  "Выставляем скорость на 250000"
307       } else if (c == '3') {                // нажата ли клавиша '3'?
308         SERIAL_PORT_HARDWARE.begin(500000); // задаем скорость на 500000
309         SERIAL_PORT_USBVIRTUAL.println("Speed set to 500000");  //  "Выставляем скорость на 500000"
310       } else if (c == '~') {                // нажата ли клавиша '~'?
311         SERIAL_PORT_HARDWARE.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); // отправляем команду выключения Bridge
312         SERIAL_PORT_USBVIRTUAL.println("Sending bridge's shutdown command");  //  "Отправляем команду выключения Bridge"
313       } else {                              // нажата ли какая-либо клавиша?
314         SERIAL_PORT_HARDWARE.write('~');    // записываем '~' на UART
315         SERIAL_PORT_HARDWARE.write(c);      // записываем символ на UART
316       }
317       commandMode = false;                  // во всех случаях выходим из командного режима 
318     }
319   }
320 
321   // копируем из UART в USB-CDC:
322   c = SERIAL_PORT_HARDWARE.read();          // считываем из UART 
323   if (c != -1) {                            // получили что-нибудь?
324     SERIAL_PORT_USBVIRTUAL.write(c);        // записываем на USB-CDC
325   }
326 }

См.также

Внешние ссылки