# Интернет вещей с ESP8266 – быстрый старт
## Постановка задачи
Начнем создавать отдельные элементы «Умного дома». Как вы уже поняли наша система будет работать на базе протокола MQTT.
Все контроллеры получают доступ к интернету по Wi-Fi, соединяются с MQTT сервером, подписываются на отдельные топики и/или публикуют в топики информацию.
Управляющий сервер также подписывается на нужные топики и может по наступлению определенных событий публиковать в топики информацию или отправлять оповещения через интернет каким-либо способом.
В дальнейшем вам будет предложено создать несколько элементов «Умного дома», а пока же мы научимся управлять портами ввода-вывода нашего контроллера
(хотя это вы уже умеете), и главное научимся работать с протоколом MQTT.
Мы будем мигать встроенным светодиодом с помощью MQTT через внешний сервер и управлять им из различных приложений.
## Собираем схему
В реальных задачах вам придется собирать некоторую (пусть и достаточно простую) схему устройства. Сейчас же нам будет достаточно светодиода,
установленного на плате контроллера WeMos D1. Так что можем сказать, что у нас все собрано
![wemos_for_blink](/assets/images/iot/wemos_for_blink.png)
## Создаем прошивку для микроконтроллера
Теперь нужно написть программу. Библиотека для работы с MQTT () у нас подключена.
Если нет - вернитесь назад и посмотрите как это сделать. Возможно, в ваших задачах потребуется подключать какие-то новые библиотеки,
и вы будете делать это самостоятельно.
Для начала работы с MQTT скачайте архив [00_led_mqtt][1], содержащий готовый скетч.
Распакуйте его (рекомендуем сразу в папку `/home/student/Arduino/`)
![unzip](/assets/images/iot/arduino/led/unzip.png)
и откройте его в среде Arduino IDE.
![unzip](/assets/images/iot/arduino/led/00_led_mqtt.gif)
Обратите внимание, что в этом примере есть несколько вкладок:
`00_led_blink` - содержит известные вам функции `setup()` и `loop()`, определяющие основное поведение любой программы Arduino,
а также функцию `callback()`, в которой мы обрабатываем сообщения от MQTT брокера.
```c
//
// 00_led_blink.ino
//
#include
#include
#include "config.h"
WiFiClient espClient;
PubSubClient client(espClient);
String clientId = String(ESP.getChipId());
int delayMS = 30000; // Задаержка в мс между публикацией сообщений
long lastMsg = 0; // Время публикации предыдущего сообщения (мс)
int value = 0; // Переменная для формирования публикуемого сообщения
// Функция обработки входящих сообщений
void callback(char* topic, byte* payload, unsigned int length) {
// Печать информации о полученном сообщенийй
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// Если получено сообщение и у нас подписка на несколько топиков, то определяем в каком топике сообщение опубликовано
if (strcmp(topic, mqtt_topic_in) == 0) {
// Определяем поведение MCU при различных значениях сообщения (payload)
if ((char)payload[0] == '0') {
digitalWrite(BUILTIN_LED, HIGH); // BUILTIN_LED имеет подтягивающий резистор, HIGH = OFF, LOW = ON
}
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW);
}
}
}
// Функция настройки MCU
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Установка BUILTIN_LED как порт вывода
digitalWrite(BUILTIN_LED, HIGH); // BUILTIN_LED имеет подтягивающий резистор, HIGH = OFF, LOW = ON
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
// Основная функция - вызывается на каждой итерации цикла работы MCU
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Публикация сообщения с заданной периодичностью
long now = millis();
if (now - lastMsg > delayMS) {
lastMsg = now;
++value;
// Формирование сообщения и его публикация
char msg[200];
snprintf (msg, sizeof(msg), "heartbeat #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish(mqtt_topic_out, msg);
}
}
```
Файл `config.h` содержит в себе основные настройки. Приведите его в соответствие с указаниями инструктора.
```c
//
// config.h
//
// Настройки WiFi
#define wifi_ssid "804.Guest"
#define wifi_pass "guest67n23"
// Сервер MQTT
#define mqtt_server "192.168.80.100"
#define mqtt_port 1883
#define mqtt_login "eecs-susu"
#define mqtt_pass "IoT_2019"
// MQTT топики
#define mqtt_topic_status "esp8266/15/status"
#define mqtt_topic_out "esp8266/15/heartbeat"
#define mqtt_topic_in "esp8266/15/led"
```
В файле `functions.ino` размещены функции, которые потребуются при выполнении всех заданий.
Они будут мало чем отличаться, но если возникнет необходимость их изменить, то комментарии к коду подскажут что делать.
```c
//
// functions.ino
//
// Функция установления соединения по WiFi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print(F("Connecting to "));
Serial.println(wifi_ssid);
Serial.println(wifi_pass);
WiFi.begin(wifi_ssid, wifi_pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println(F("."));
WiFi.printDiag(Serial);
}
randomSeed(micros());
Serial.println("");
Serial.println(F("WiFi connected"));
Serial.println(F("IP address: "));
Serial.println(WiFi.localIP());
}
// Функция установления подключения к MQTT брокеру
void reconnect() {
while (!client.connected()) {
Serial.println(F("Attempting MQTT connection..."));
Serial.print(F("Client ID:"));
Serial.print(clientId);
Serial.print(F(" "));
Serial.print(mqtt_login);
Serial.print(F(" "));
Serial.print(mqtt_pass);
Serial.print(F(" "));
if (client.connect(clientId.c_str(), mqtt_login, mqtt_pass)) {
Serial.println(F("connected"));
// Публикация сообщения с идентификаторм клиента в топик, заданный значением 'mqtt_topic_status'
client.publish(mqtt_topic_status, clientId.c_str());
// Подписка на сообщения в топике, заданном значением mqtt_topic_in
client.subscribe(mqtt_topic_in);
// Если нужно подписаться на несколько топиков, то для каждого из них вызываем client.subscribe()
} else {
Serial.print(F("failed, rc="));
Serial.print(client.state());
Serial.println(F("try again in 5 seconds"));
delay(5000);
}
}
}
```
Чтобы во время нашей работы команды не мешали друг другу, измените в файле `config.h` MQTT топики, с которыми работаете - вместо числа 15 запишите номер вашей команды!
Например, для команды №8 эти строки буду выглядеть так:
```c
// MQTT топики
#define mqtt_topic_status "esp8266/8/status"
#define mqtt_topic_out "esp8266/8/heartbeat"
#define mqtt_topic_in "esp8266/8/led"
```
После компиляции программы и заливки ее в контроллер вы сможете, направляя 1 или 0 в топик, указанный в `mqtt_topic_in`,
управлять со своего компьютера, мобильного телефона или через WEB поведением светодиода.
При этом в топике, указанном в `mqtt_topic_out` будут периодически появляться сообщения от контроллера, сигнализирующие что он на связи.
[1]: https://aiu.susu.ru/assets/components/fileattach/connector.php?action=web/download&ctx=web&fid=VXXL6gCr6EhMYDDElEhj_TJ2eP1OTuWO
## Работа с MQTT
Самым простым клиентом будет **MQTT.fx**. Его можно скачать с . Для наших компьютеров понадобится 64-разрядный пакет для Debian.
![wemos_for_blink](/assets/images/iot/mqttfx_download.png)
Скачайте его в каталог `Загрузки`, после чего запустите приложение **Terminal** (нажмите на клавиатуре комбинацию клавиш Ctrl+Alt+T).
В терминале наберите:
```sh
sudo dpkg -i ~/Загрузки/mqttfx-1.7.1-64bit.deb
```
Во время ввода этой команды вас попросят ввести пароль - его вам скажет инструктор. Обратите внимание, что при вводе пароля ни он, ни какие другие символы (например, звездочки) не отображаются!
Если все прошло успешно - терминал можно закрыть, он нам больше не понадобится.
Далее, запускаем **MQTT.fx**. Теперь необходимо настроить подключения к серверу, для чего следует нажать на иконку с шестерёнкой.
![mqttfx_01](/assets/images/iot/mqttfx_01.png)
Настроим соединение
![mqttfx_02](/assets/images/iot/mqttfx_02.png)
Для этого следует:
1. Добавить новое соединение
2. Указать его название
3. Ввести имя сервера (предоставит инструктор)
4. Ввести порт на сервере (предоставит инструктор)
5. Сгенерировать уникальный ИД клиента
6. Переключиться на ввод логина и пароля!
![mqttfx_03](/assets/images/iot/mqttfx_03.png)
7. Ввести логин (предоставит инструктор)
8. Ввести пароль (предоставит инструктор)
И сохранить изменения нажатием кнопки **ОК**.
Далее требуется подключиться к серверу нажатием кнопки **Connect**
### Публикация и подписка
Теперь для того, чтобы управлять светодиодом достаточно на вкладке **Publish** ввести имя топика,
указанное в настройках прошивки в значении параметра **mqtt_topic_in** (у нас это `esp8266/15/led`),
в текстовое поле написать **0** или **1** и нажать кнопку **Publish**. Остальные настройки менять не надо.
![mqttfx_pub](/assets/images/iot/mqttfx_pub.png)
Для контроля работоспособности устройства на вкладке **Subscribe** можно подписаться на топики, указанные в параметрах **mqtt_topic_status** и **mqtt_topic_out**
![mqttfx_sub](/assets/images/iot/mqttfx_sub.png)
## Управляем со смартфона
MQTT клиент может быть установлен и на смартфоне, а значит можно управлять нашим устройством прямо с него.
Для Android есть достаточно много таких клиентов. Вот лишь несколько:
+ [IoT MQTT Panel](https://play.google.com/store/apps/details?id=snr.lab.iotmqttpanel.prod)
+ [Linear MQTT Dashboard](https://play.google.com/store/apps/details?id=com.ravendmaster.linearmqttdashboard)
+ [MQTT Dash \(IoT, Smart Home\)](https://play.google.com/store/apps/details?id=net.routix.mqttdash)
C iOS дела обстоят несколько хуже - вот список того, что удалось вообще найти:
+ [MQTTool](https://itunes.apple.com/ru/app/mqttool/id1085976398?mt=8)
+ [IoT OnOff](https://itunes.apple.com/ru/app/iot-onoff/id1267226555?mt=8)
+ [MQTT Terminal](https://itunes.apple.com/ru/app/mqtt-terminal/id1404331673?mt=8)
+ [Cayenne - IoT Project Builder](https://itunes.apple.com/ru/app/cayenne-iot-project-builder/id1057997711?mt=8)
+ [Visual Home](https://itunes.apple.com/ru/app/visual-home/id1347968525?mt=8)
Рассмотрим на примере [IoT MQTT Panel](https://play.google.com/store/apps/details?id=snr.lab.iotmqttpanel.prod) как создать конфигурацию приложения для управления нашим устройством.
Разумется приложение нужно установить. Можно воспользоваться QR-кодом для доступа к [ ![Google.Play](https://www.gstatic.com/android/market_images/web/play_prism_hlock_1x.png) ](https://play.google.com/store)
![iot_mqtt_panel_qr](/assets/images/iot/android/iot_mqtt_panel_qr.svg)
После запуска приложения будет предложено создать подключение
![Andr_01](/assets/images/iot/android/a01.png)
Необходимо указать имя соединения, придумать идентификатор клиента и задать параметры MQTT брокера, как и в случае с MQTT.fx.
![Andr_02](/assets/images/iot/android/a02.png)
Для задания имени пользователя и пароля необходимо раскрыть раздел **Advanced options**
![Andr_03](/assets/images/iot/android/a03.png)
Так как это у нас первый запуск приложения, то нам сразу же будет предложено добавить новое устройство, что мы и сделаем (у нас оно называется IoT course)
![Andr_04](/assets/images/iot/android/a04.png)
Теперь соединение у нас создано, нажмем на его имя (**SmartHome**)
![Andr_05](/assets/images/iot/android/a05.png)
Нас предупредят, что наше устройство не содержит ни одной панели управления - нажмем на **Add Panel**
![Andr_06](/assets/images/iot/android/a06.png)
Выберем переключатель (**Switch**)
![Andr_07](/assets/images/iot/android/a07.png)
и настроем его - укажем имя элемента, топик (используйте номер своей команды вместо указанного на рисунке), а также значения для состояний **on** и **off**
Пролистываем экран до конца, и нажимаем **Create**
![Andr_08](/assets/images/iot/android/a08.png)
![Andr_09](/assets/images/iot/android/a09.png)
Получившийся элемент занимает слишком много места на экране, поэтому уменьшим его ширину
![Andr_10](/assets/images/iot/android/a10.png)
![Andr_11](/assets/images/iot/android/a11.png)
Добавим еще одну панель к нашему устройству - нажмем на кнопку **+**
![Andr_12](/assets/images/iot/android/a12.png)
Выберем **LED Indicator** и настроим его
![Andr_13](/assets/images/iot/android/a13.png)
![Andr_14](/assets/images/iot/android/a14.png)
Теперь если установить соединение, то мы сможем с мобильного телефона включать и отключать светодиод на плате WeMos D1, а его состояние будет отображаться на экране
![Andr_15](/assets/images/iot/android/a15.png)
![Andr_16](/assets/images/iot/android/a16.png)
Мы можем построить граяик изменения некоторой величины. Но светодиод и переключатель могут принимать всего два состояния - включено и выключено, а потому график получится весьма скучным.
Наш MQTT брокер принимает данные не только от ваших контроллеров WeMos D1, но и от других датчиков: температуры и влажности.
Для получения информации с них необходимо подписаться на топик `devices/lora/807b859000282cbe` (если что-то изменится, то об этом скажет инструктор).
Добавим к устройству панель **Line Graph** для отображения температуры в помещении. Данные от датчика передаются в формате JSON в объекте **data**
![Andr_17](/assets/images/iot/android/a17.png)
![Andr_18](/assets/images/iot/android/a18.png)
![Andr_19](/assets/images/iot/android/a19.png)
И добавим **Gauge** для отображения влажности
![Andr_20](/assets/images/iot/android/a20.png)
![Andr_21](/assets/images/iot/android/a21.png)
![Andr_22](/assets/images/iot/android/a22.png)
Еще добавим **Text Log** и настроем его на вывод сообщений от наших контроллеров. Обратите внимание, что здесь мы использовали шаблон,
и у нас будут отображаться все события, связанные со светодиодами всех контроллеров, которые у нас задействованы сегодня.
![Andr_23](/assets/images/iot/android/a23.png)
![Andr_24](/assets/images/iot/android/a24.png)
Наше готовое приложение
![Andr_25](/assets/images/iot/android/a25.png)
## Серверное приложение
### Установка Node-RED
Возможно, что **Node-RED** уже был установлен, и часть действий, описанных ниже - пустая трата времени. Тем не менее пройти все шаги все равно будет полезным.
Чтобы предыдущие настройки нам не мешались - удалим их командой
```bash
rm -rf ~/.node-red/
```
Установим **NodeJS** и программу управления пакетами **npm**, для чего запустим **Terminal** и в нем введем:
```bash
sudo apt install nodejs npm
```
Установим собственно сервер **Node-RED** и вспомогательную утилиту **node-red-admin**.
```bash
sudo npm install -g --unsafe-perm node-red node-red-admin
```
Менеджер **npm** обычно устанавливает пакеты в текущий каталог.
В данной команде использован флаг `–g (globally)`, который выполнит глобальную установку указанных пакетов и поместит их в стандартный каталог системы, например в `/usr/local/bin`.
Флаг `—unsafe-perm` помогает избежать некоторых ошибок, которые могут возникнуть при попытке npm скомпилировать встроенные модули (написанные на компилируемых языках, например C или C++).
Если установка завершилась успешно, то должно будет выглядеть примерно так:
![nodered_install](/assets/images/iot/nodered_install.png)
Node-RED использует порт 1880 - разрешим подключения по этому порту
```bash
sudo ufw allow 1880
```
Заодно узнаем какой у нашего компьютера IP-адрес:
```bash
ifconfig | grep 'inet 192.'
```
![ifconfig](/assets/images/iot/ifconfig.png)
В нашем случае - это **192.168.1.41**.
Если же в ответ вы получите сообщение, что утилита `ifconfig` не установлена, установите ее командой
```bash
sudo apt-get install net-tools
```
и повторите предыдущий запрос.
Запустим Node-RED командой
```bash
node-red
```
В терминале появится приветственное сообщение типа *Welcome to Node-RED* и информационное сообщение **Server now running**.
![nodered_run](/assets/images/iot/nodered_run.png)
Теперь запускаем любой браузер и переходим по адресу, который мы определили ранее (**192.168.1.41**),
и задаем номер порта 1880:
![nodered_browser](/assets/images/iot/nodered_browser.png)
Чтобы остановить сервер, в терминале, в котором запускали Node-RED, нужно нажать сочетание клавиш Ctrl+C. Но мы пока этого делать не будем.
### Интерфейс Node-RED
Основная единица работы с логикой приложения для Node-RED - это **поток** (**flow**).
Он состоит из **узлов** (**node**) - блоков (минимальных единиц логики), которые можно собирать вместе в большую и сложную систему обработки событий.
С левой стороны экрана находится палитра элементов с группой блоков. Группы блоков разделены на подгруппы по функциональности.
Если выбрать узел, то справа на **боковой панели**, во вкладке **info** будет показана информация о том, как этот узел работает.
В центре экрана находится основная рабочая область, где создаются потоки.
Над боковой панелью имеется кнопка **Deploy**, предназначенная для развертывания системы автоматизации - запуска получившейся программы на исполнение.
![nodered_sections](/assets/images/iot/nodered_sections.png)
Нам нужно будет сделать еще несколько предварительных настроек.
Сначала надо установить дополнение `node-red-dashboard`. В правом верхнем углу страницы расположена кнопка вызова меню. Нас интересует
меню **Manage palette**.
![nodered_add_ui_menu](/assets/images/iot/nodered_add_ui_menu.png)
В появившемся окне по вертикаливыберем раздел **Palette**, а по горизонтали - раздел **Install**
![nodered_add_ui_install](/assets/images/iot/nodered_add_ui_install.png)
В поле поиска введите `node-red-dashboard` и нажмите **Install**, расположенную рядом с найденным компонентом.
В появившемся окне нажмите **Install**
![nodered_add_ui_confirm](/assets/images/iot/nodered_add_ui_confirm.png)
После завершения установки можно закрыть всплывающие окна (кнопка **Close**) и перейти к созданию приложения.
### Базовые узлы
Узлы в палитре группируются по разделам. Самые важные для работы приложения разделы:
- **input** - поступление входящих сигналов
- **output** - отправляют сигналы в результате принятых решений
- **function** - позволяют применить дополнительные преобразования к данным и принимать решения
- **social** - отсылка/прием сообщений (в базовой поставке) с email и twitter, после установки дополнительных плагинов можно расширить возможности еще больше.
- **dashboard** - появляется после установки `node-red-dashboard`, содержит компоненты для постройки визуального интерфейса.
### Наш первый поток
Ранее мы настраивали работу контроллера с сервером по MQTT, теперь сделаем полный цикл настройки для работы с помощью Node-RED.
Первым делом надо добавить кнопку, которая будет зажигать светодиод.
Из палитры в разделе **dashboard** с помощью перетаскивания добавляем два узла **button** ![](/assets/images/iot/nodered/node_dashboard_button.png) - для включения и выключения,
а из раздела **output** узел **mqtt** ![](/assets/images/iot/nodered/node_output_mqtt.png)
Потом соединяем выходы узлов **button** со входом узла **mqtt** мышкой.
![](/assets/images/iot/nodered/flow_two_button_mqtt.png)
Двойным щелчком по верхнему узлу **button** откроем диалог редактирования.
![](/assets/images/iot/nodered/node_input_button_edit_before_on.png)
Выбираем **Add new ui_group...** и кнопкой ![](/assets/images/iot/nodered/node_input_button_pencil.png) открываем диалог создания новой группы элементов, в которой будет размещаться наша кнопка.
![](/assets/images/iot/nodered/node_input_button_add_dashboard_group.png)
Дадим этой группе имя **First ROW** и аналогичным образом добавим колонку (**Tab**)
![](/assets/images/iot/nodered/node_input_button_add_dashboard_tab.png)
Указывае имя (**Home**) и жмем **Add**, закрывая диалог добавления колонки. Аналогично, нажатием **Add** закроем диалог создания группы элементов.
Теперь для элемента **button**, с которым мы работаем, укажем метку (**Label**), подсказку (**Tooltip**),
и самое главное - значение, которое будет отсылаться при нажатии на эту кнопку - **Payload**, а также **Name**.
В итоге диалог будет выглядеть так:
![](/assets/images/iot/nodered/node_input_button_edit_after_on.png)
Закрываем его нажатием **Done**.
Аналогичным образом нужно настроить нижнюю кнопку (только создавать новые группы и столбцы не надо, достаточно их просто выбрать из выпадающего меню):
![](/assets/images/iot/nodered/node_input_button_edit_after_off.png)
Для узла MQTT потребуется настроить **Server** - аналогично рассмотренным выше случаям выбираем **Add new mqtt-brocker...**
![](/assets/images/iot/nodered/node_output_mqtt_edit_before.png)
И настраиваем его параметры на вкладке **Connection**
![](/assets/images/iot/nodered/node_output_mqtt_server_connection.png)
и вкладке **Security**
![](/assets/images/iot/nodered/node_output_mqtt_server_security.png)
Эти значения вам уже должны быть известны - они сегодня использовались уже много раз.
Также для узла **mqtt** необходимо указать **Topic**, куда он будет отсылать значения (**Topic** тот же, что и в прошивке в параметре **mqtt_topic_in**),
и еще укажем имя (**Name**), чтобы легко отыскать этот блок в потоке.
![](/assets/images/iot/nodered/node_output_mqtt_edit_after.png)
Чтобы сразу посмотреть на результат, можно нажать кнопку **Deploy** ![](/assets/images/iot/nodered/menu_deploy.png).
Это сохраняет текущий поток и применяет настройки на сервере.
![](/assets/images/iot/nodered/flow_two_button_mqtt_connected.png)
Чтобы посмотреть результат выберите в меню пункт **View > Dashboard**
![](/assets/images/iot/nodered/menu_view_dashboard.png)
а затем на боковой панели на вкладке **Site** воспользуйтесь кнопкой ![](/assets/images/iot/nodered/button_dashboard_out.png) для перехода к графическому интерфейсу.
Заодно на этой же панели **dashboard** во вкладках можно настроить дополнительные параметры отображения.
![](/assets/images/iot/nodered/menu_dashboard_site.png)
Вообще, хорошей идеей будет держать две вкладки открытыми одновременно - с редактором и графическим интерфейсом.
![](/assets/images/iot/nodered/dashboard_two_buttons.png)
Если запустить **MQTT.fx**, то можно будет наблюдать как при нажатии кнопок в браузере на MQTT сервер отправляется значение нажатой кнопки.
Если включен контроллер и все правильно настроено, то зажигающийся светодиод можно будет наблюдать и на нем.
Время реакции на команду будет менее 1 секунды.
### Добавим график
Теперь дополним наш поток узлом для приёма сообщений - **input/mqtt** ![](/assets/images/iot/nodered/node_input_mqtt.png) и
узлом для вывода графики **dashboard/chart** ![](/assets/images/iot/nodered/node_dashboard_chart.png)
В итоге должно получиться так (**параметры сервера и топика не забываем использовать свои**):
**input/mqtt:**
![](/assets/images/iot/nodered/node_input_mqtt_edit.png)
**dashboard/chart:**
![](/assets/images/iot/nodered/node_dashboard_chart_edit.png)
Так как данные у нас передаются в формате JSON, то нам надо их декодировать. С этой целью добавим узел
**function/json** ![](/assets/images/iot/nodered/node_function_json.png) и установим его параметры следующим образом:
![](/assets/images/iot/nodered/node_function_json_edit.png)
В итоге на выходе этого блока у нас будет получаться JavaScript-объект, из которого нам нужно получить значение поля **temperature**.
Добавим еще один блок - **function/function** ![](/assets/images/iot/nodered/node_function_function.png) и напишем для него небольшой код:
```javascript
var value = msg.payload.data.temperature;
msg.payload = value;
return msg;
```
Должно получится так:
![](/assets/images/iot/nodered/node_function_function_edit.png)
После нажатия **Deploy** ![](/assets/images/iot/nodered/menu_deploy.png) должно получиться примерно так:
![](/assets/images/iot/nodered/flow_two_button_mqtt_chart.png)
А в графическом интерфейсе (не забываем обновить страницу нажатием **F5** на клавиатуре):
![](/assets/images/iot/nodered/dashboard_two_buttons_chart.png)
Конечно, более простым методом будет сделать всё управление единственным светодиодом при помощи одной кнопки,
для этого есть **dashboard/switch** ![](/assets/images/iot/nodered/node_dashboard_switch.png):
![](/assets/images/iot/nodered/node_dashboard_switch_edit.png)
![](/assets/images/iot/nodered/flow_two_buttons_chart_switch.png)
Не забываем про **Deploy** ![](/assets/images/iot/nodered/menu_deploy.png)
Результат:
![](/assets/images/iot/nodered/dashboard_two_buttons_chart_switch.png)
Если потребуется изменить порядок, добавить группы, колонки или ссылки, изменить размещение визуальных компонентов на экране, можно использовать **sidebar dashboard** и на вкладке **Layout** настроить всё:
![](/assets/images/iot/nodered/menu_dashboard_layout.png)
Так как ваш смартфон и сервер **Node-RED** сейчас фактически находятся в одной локальной сети, то вы можете подключиться со смартфона к вашему серверу,
используя любой браузер, вводя в адресной строке те же самые данные, что и в браузере на компьютере:
```bash
192.168.1.41:1880/ui
```
[**<<< Назад**](iot/summer) | [**Далее >>>**](iot/summer/tasks)