Мини-кейс 6: Arduino IoT Cloud
Сообщество Arduino запустило свою IoT-платформу под названием Arduino IoT Cloud. Arduino IoT Cloud предоставляет комплексное решение, которое упрощает создание подключенных проектов для разработчиков, энтузиастов Интернета вещей и профессионалов от начала до конца. Платформа поддерживает различные методы взаимодействия, включая HTTP REST API, MQTT, инструменты командной строки, Javascript и WebSockets. Вы можете подключить несколько устройств друг к другу и разрешить им обмениваться данными в режиме реального времени. Вы также можете отслеживать данные из любого места, используя простой пользовательский интерфейс. Чтобы узнать больше об облаке Arduino IoT, вы можете просмотреть часть документации.
В этом руководстве мы будем управлять светодиодом с помощью облачной панели Arduino IoT. Аналогичным образом мы отправим данные датчиков на облачную панель управления и визуализируем их в различных красивых виджетах.
Настройка Arduino IoT Cloud DashBoard
Перейдите на сайт cloud.arduino.cc и зарегистрируйтесь.
Перейдите на страницу things и нажмите
+CREATE THING
или+THING
если у вас уже есть проекты.
Создание вещи
Здесь вы можете увидеть раздел настройки, а также раздел скетча и мета данных.
Теперь вам нужно добавить переменные, чтобы их создать нужно нажать на кнопку
«ADD».
Например, для управления светодиодом дадим имя
led
. В типе переменной выберитеLight
, так как нам нужно отправлять команды 1 и 0. Переменная будет автоматически объявлена как CloudLight led. Вы можете назначить разрешение переменной как чтение-запись, так и только чтение. Таким образом, для светодиода вы можете назначить чтение и запись. Наконец, нажмите«ADD VARIABLE»
.Аналогичным образом добавьте еще переменные для датчика широкого спектра газов Амперки MQ-2.
Для сжиженных углеводородных газов, метана, дыма, водорода с типом целых чисел (Integer Number).
Variable Permission установите «Read Only», чтобы значения нельзя было изменять в облаке.
Настройка устройства
Теперь нам нужно настроить устройство. Для этого выберите
«Select Device»
, а после в окне«Associate device»
на кнопку«Set up new device»
. Поскольку ESP8266 является устройством стороннего производителя, мы выберем«Third party device»
. Из списка выберите Плата ESP8266. И из списка моделей выберите тип«Generic ESP8266 Module»
. Затем нажмите«CONTINUE»
.Назовите устройство как угодно.
Идентификатор устройства и секретный ключ созданы. Это очень важные параметры при программировании. Вам нужно скопировать их или просто нажать
«Download PDF»
.Нажмите в окне на галочку
«I saved my Device ID and Secret Key»
и на кнопку«CONTINUE»
. Итак, вы наконец завершили настройку устройства.Вас вернёт к панели управления Think, где нужно будет повторно нажать на
«Select Device»,
а в открывшемся окне
«Associate device»
нажать на«Associate»
рядом с созданным устройством.Настройка сети Теперь нам также необходимо настроить Сеть. Итак, нажмите кнопку
«Configure»
в блоке«Network»
. Введите здесьSSID Wi-Fi
,пароль
исекретный ключ
, которые вы скопировали/скачали ранее. Затем нажмите«SAVE»
.Настройка панели мониторинга
Перейдите в панель управления (Dashboards), чтобы настроить виджеты. Затем нажмите
«Create Dashboard»
.Откроется новая панель управления, которой следует написать имя. Нажать на
Untitled > Rename.
Сверху слева есть тумблер, с помощью которого идёт переключение режима работы панели. Переключается между режимом просмотра и редактирования. Нужно выбрать редактирование.
Нажмите на
«ADD»
. В этом списке виджетов выберите«Switch»
, поскольку мы хотим включать и выключать светодиод.Дайте имя
«Led»
переключателю.Затем нажмите на кнопку
«Link Variable»
и свяжите переменную ссветодиодом (LED)
из списка.Затем нажмите
«LINK VARIABLE»
, а затем
«DONE»
.
Аналогичным образом добавьте ещё оставшиеся виджеты.
Для
mq2_LPG
установите тип виджетаValue
, дайте в окне создания виджета имя виджетаLPG
.Для
mq2_methane
типGauge
и соотвествующее имя виджетаMethane
, а такжеValue range
(диапазон возможных значений).Для mq2_smoke выбрать тип
Chart
и соотвествующее имя виджетаSmoke
.Для
mq2_hydrogen
выберите любой из тех, который были выше и установите соответствующее имя виджетаHydrogen
.
Итак, наша панель управления готова. Вы также можете нажать на кнопку в виде
стрелок
(Arrenge widgets)
и изменить размер виджета или переместить, а если на к кнопку ссмартфоном (Show Mobile Layout)
, то посмотреть и раставить виджеты в виде для мобильного приложения.
Исходный код/программа для модуля WIFI с ESP8266
Зайдите с главной страницы Arduino Cloud в веб-редактор (Sketches). Слева, выберите пункт Sketchbook. И откроется список проектов, которые хранятся в веб. Исходный код для использования облака Arduino IoT с ESP8266 прост в использовании, поскольку некоторые команды и объявления генерируются автоматически.
Перейдите на вкладку скетча. Таким образом, будет создан эскиз по умолчанию, основанный на различных переменных. Определены некоторые заголовочные файлы и установлены параметры для светодиода. Поэтому нам нужно изменить код.
Будут отображаться несколько вкладок. Один из них файл скетч формата Unti
tled.ino, thingProperties.h, ReadMe.adoc, Secret.
Вкладке Secret (файл
arduino_secrets.h
) отображаютсяSECRET_SSID
,SECRET_OPTIONAL_PASS
,SECRET_DEVICE_KEY
, т.е. имя wifi сети, пароль и ключ девайса.Установите для браузера Arduino Create Agent, чтобы веб-редактор мог подключится с устройством для прошивки.
Исходный код/программа для WiFi модуля Амперки
Слева в вкладке
«Libraries»
в поиске найдите библиотеку«GParser»
.Вставьте код в
ino
файл...#include <GParser.h> // Библиотека парсинга данных #include "thingProperties.h" void setup() { Serial.begin(115200); // Инициализация Serial для общения через последовательный порт Serial.setTimeout(5); delay(1500); // This delay gives the chance to wait for a Serial Monitor without blocking if none is found initProperties(); // Defined in thingProperties.h ArduinoCloud.begin(ArduinoIoTPreferredConnection); // Connect to Arduino IoT Cloud /* The following function allows you to obtain more information related to the state of network and IoT Cloud connection and errors the higher number the more granular information you’ll get. The default is 0 (only errors). Maximum is 4 */ setDebugMessageLevel(0); ArduinoCloud.printDebugInfo(); } void loop() { ArduinoCloud.update(); ParseFromSerialInputValues(false); // Парсим и устанавливаем значения } // Парсинг значений из Serial void ParseFromSerialInputValues(bool debug) { if (Serial.available() > 2) { // Если что-то прислали char inputStr[64]; // Массив символов для записи из Serial int amount = Serial.readBytesUntil(';', inputStr, 64); // Считать посимвольно до символа конца пакета точки с запятой и записать количество полученных байт в переменную inputStr[amount] = (char) NULL; // Если отправляющее устройство не отправит нулевой символ, то он не запишется в буффер и вывод строк будет некорректным, решение дописать вручную и т.о. закрываем строку GParser data(inputStr, ','); // Парсим массив символов по символу запятой int am = data.split(); // Получаем количество данных, внимание, ломает строку! for (int i = 0; i < am; i++) { String tmpStr = data[i]; tmpStr.replace(" ", ""); // Удалить пробел, если он был введёт по ошибке tmpStr.trim(); // Удаление ведущими и конечные пробелы char tmpCharArr[tmpStr.length()]; tmpStr.toCharArray(tmpCharArr, tmpStr.length() + 1); if (debug) Serial.println(String(i) + ") " + tmpStr); // Вывести начальную строку GParser data2(tmpCharArr, ':'); // Парсим массив символов по символу запятой int am2 = data2.split(); // Получаем количество данных, внимание, ломает строку! if (am2 > 1) { // Если существует не только ключ, а ещё и значение String key = data2[0]; // Ключ - первое значение int value = data2.getInt(1); // Значение - второе, или data.getInt(1), чтобы получить целое число if (debug) Serial.println("key: " + key + ", value: " + String(value)); // Вывод // Присваивание значений if (key.equals("methane")) { mQ2_Methane = value; } else if (key.equals("lpg")) { mQ2_LPG = value; } else if (key.equals("smoke")) { mQ2_Smoke = value; } else if (key.equals("hydrogen")) { mQ2_Hydrogen = value; } else if (key.equals("led")) { led = value; } } } if (debug) Serial.println(); // Перевод на новую строку для разделения значений, которые были введены } } /* Since LED is READ_WRITE variable, onLEDChange() is executed every time a new value is received from IoT Cloud. */ void onLEDChange() { // Add your code here to act upon LED change Serial.println("led:" + String(led) + ";"); } /* Since MQ2LPG is READ_WRITE variable, onMQ2LPGChange() is executed every time a new value is received from IoT Cloud. */ void onMQ2LPGChange() { // Add your code here to act upon MQ2LPG change } /* Since MQ2Methane is READ_WRITE variable, onMQ2MethaneChange() is executed every time a new value is received from IoT Cloud. */ void onMQ2MethaneChange() { // Add your code here to act upon MQ2Methane change } /* Since MQ2Smoke is READ_WRITE variable, onMQ2SmokeChange() is executed every time a new value is received from IoT Cloud. */ void onMQ2SmokeChange() { // Add your code here to act upon MQ2Smoke change } /* Since MQ2Hydrogen is READ_WRITE variable, onMQ2HydrogenChange() is executed every time a new value is received from IoT Cloud. */ void onMQ2HydrogenChange() { // Add your code here to act upon MQ2Hydrogen change }
В thingProperties.h должно быть что-то вроде:
// Code generated by Arduino IoT Cloud, DO NOT EDIT. #include <ArduinoIoTCloud.h> #include <Arduino_ConnectionHandler.h> const char DEVICE_LOGIN_NAME[] = "8ce30c47-b62e-4150-9232-23349185c875"; const char SSID[] = SECRET_SSID; // Network SSID (name) const char PASS[] = SECRET_OPTIONAL_PASS; // Network password (use for WPA, or use as key for WEP) const char DEVICE_KEY[] = SECRET_DEVICE_KEY; // Secret device password void onLedChange(); CloudLight led; int mq2_hydrogen; int mq2_LPG; int mq2_methane; int mq2_smoke; void initProperties(){ ArduinoCloud.setBoardId(DEVICE_LOGIN_NAME); ArduinoCloud.setSecretDeviceKey(DEVICE_KEY); ArduinoCloud.addProperty(led, READWRITE, ON_CHANGE, onLedChange); ArduinoCloud.addProperty(mq2_hydrogen, READ, ON_CHANGE, NULL); ArduinoCloud.addProperty(mq2_LPG, READ, ON_CHANGE, NULL); ArduinoCloud.addProperty(mq2_methane, READ, ON_CHANGE, NULL); ArduinoCloud.addProperty(mq2_smoke, READ, ON_CHANGE, NULL); } WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
Над кодом есть раскрывающийся список, в которой нужно выбрать
«Select Other Board & Port»
, чтобы выбрать правильную плату для компиляции и загрузки кода. При этом должена одображаться плата Arduino, через которую мы будем загружать.В открывшемся окне нужно выбрать плату, воспользовавшийсь поиском и порт, чтобы в этих двух полях стояли галочки, а после нажимаем на кнопку
«OK»
.Переводим плату в режим загрузки прошивки с помощью комбинации.
Нажимаем на кнопку
«Upload and Save»
и наблюдаем процесс прошивки в окне под кодом.На последовательном мониторе (вкладка
«Monitor»
) вы увидите, что соединение MQTT установлено и устройство подключено к сети WiFi. Он также отображает значения.
Исходный код/программа для Arduino
#include <SoftwareSerial.h> #include <GParser.h> // Библиотека парсинга #include <TroykaMQ.h> // Библиотека для работы с датчиками MQ (Troyka-модуль) #include <EncButton.h> // Библиотека для работы с кнопками #include <TimerMs.h> // Библиоткера работа с таймерами #define BTN_PIN 11 // Пин, к которому подключена кнопка #define BTN_LED_PIN A3 // Пин, к которому подключен светодиод кнопки #define PIN_MQ2 A1 // Пина, к которому подключен датчик #define PIN_MQ2_HEATER 12 // Пина, к которому подключен нагреватель датчика #define EB_DEB_TIME 30 // Таймаут гашения дребезга кнопки (кнопка) #define EB_CLICK_TIME 200 // Таймаут ожидания кликов (кнопка) #define EB_HOLD_TIME 300 // Таймаут удержания (кнопка) #define EB_STEP_TIME 200 // Таймаут импульсного удержания (кнопка) #define DEBUG false // Дебаг для печати SoftwareSerial WiFi_Serial(4, 5); // TX и RX WI-FI модуля MQ2 mq2(PIN_MQ2, PIN_MQ2_HEATER); // Создаём объект для работы с датчиком и передаём ему номер пина выходного сигнала и нагревателя Button btn(BTN_PIN, INPUT); // Создаём объект кнопки TimerMs tmr1(500), tmr2(550), tmr3(600), tmr4(650), tmr5(700); // Таймер на 500 мсек bool btnLedState = false; void setup() { Serial.begin(115200); // Открываем последовательный порт WiFi_Serial.begin(115200); // Последовательный порт для общения с WiFi модулем Serial.setTimeout(5); // Позволяет задать время ожидания данных WiFi_Serial.setTimeout(5); // Позволяет задать время ожидания данных pinMode(BTN_LED_PIN, OUTPUT); // Настраиваем пин светодиода кнопки на вывод mq2.heaterPwrHigh(); // Включаем нагреватель Serial.println(); Serial.println("Heated sensor"); // Сообщение, что пошёл нагрев tmr1.setPeriodMode(); // Установить таймеру режим периода tmr2.setPeriodMode(); // Установить таймеру режим периода tmr3.setPeriodMode(); // Установить таймеру режим периода tmr4.setPeriodMode(); // Установить таймеру режим периода tmr5.setPeriodMode(); // Установить таймеру режим периода tmr1.start(); // Запуск таймера tmr2.start(); // Запуск таймера tmr3.start(); // Запуск таймера tmr4.start(); // Запуск таймера tmr5.start(); // Запуск таймера } // Функция опросы кнопки и выполнения действия void BtnCheck() { btn.tick(); // Опрос состояния кнопки if (btn.press()) { // Реагируем на нажатие кнопки btnLedState = !btnLedState; // Переписать значение в переменной на противоположеное digitalWrite(BTN_LED_PIN, btnLedState); // Переключить состояние на контакте светодиода WiFi_Serial.println("led:" + String(btnLedState)); // Отправить WiFi модулю инфу о светодиде } } void loop() { BtnCheck(); ParseFromSerialInputValues(true); // Считываем по Serial значения BtnCheck(); if (!mq2.isCalibrated() && mq2.heatingCompleted()) { // если прошёл интервал нагрева датчика и калибровка не была совершена mq2.calibrate(); // Выполняем калибровку датчика на чистом воздухе if (DEBUG) Serial.println("Ro: " + String(mq2.getRo())); // Выводим сопротивление датчика в чистом воздухе (Ro) в serial-порт } if (mq2.isCalibrated() && mq2.heatingCompleted()) { // Если прошёл интервал нагрева датчика и калибровка была совершена if (tmr1.tick()) { int ratio = mq2.readRatio(); if (DEBUG) Serial.println("Ratio: " + String(ratio) + " ppm"); // Выводим отношения текущего сопротивление датчика к сопротивлению датчика в чистом воздухе (Rs/Ro) WiFi_Serial.println("ratio:" + String(ratio) + ";"); } BtnCheck(); if (tmr2.tick()) { int lpg = mq2.readLPG(); if (DEBUG) Serial.println("LPG: " + String(lpg) + " ppm"); // Сжиженные углеводородные газы в ppm WiFi_Serial.println("lpg:" + String(lpg) + ";"); } BtnCheck(); if (tmr3.tick()) { int methane = mq2.readMethane(); if (DEBUG) Serial.println("Methane: " + String(methane) + " ppm"); // Метан в ppm WiFi_Serial.println("methane:" + String(methane) + ";"); } BtnCheck(); if (tmr4.tick()) { int smoke = mq2.readSmoke(); if (DEBUG) Serial.println("Smoke: " + String(smoke) + " ppm"); // Дым в ppm WiFi_Serial.println("smoke:" + String(smoke) + ";"); } BtnCheck(); if (tmr5.tick()) { int hydrogen = mq2.readHydrogen(); if (DEBUG) Serial.println("Hydrogen: " + String(hydrogen) + " ppm"); // Водород в ppm WiFi_Serial.println("hydrogen:" + String(hydrogen) + ";"); } BtnCheck(); } } // Парсинг значений из Serial и установка значений void ParseFromSerialInputValues(bool debug) { if (WiFi_Serial.available() > 2) { // Если что-то прислали char inputStr[64]; // Массив символов для записи из Serial int amount = WiFi_Serial.readBytesUntil(';', inputStr, 64); // Считать посимвольно до символа конца пакета точки с запятой и записать количество полученных байт в переменную inputStr[amount] = (char) NULL; // Если отправляющее устройство не отправит нулевой символ, то он не запишется в буффер и вывод строк будет некорректным, решение дописать вручную и т.о. закрываем строку GParser data(inputStr, ','); // Парсим массив символов по символу запятой int am = data.split(); // Получаем количество данных, внимание, ломает строку! for (int i = 0; i < am; i++) { String tmpStr = data[i]; tmpStr.replace(" ", ""); // Удалить пробел, если он был введёт по ошибке tmpStr.trim(); // Удаление ведущими и конечные пробелы char tmpCharArr[tmpStr.length()]; tmpStr.toCharArray(tmpCharArr, tmpStr.length() + 1); if (debug) Serial.println(String(i) + ") " + tmpStr); // Вывести начальную строку GParser data2(tmpCharArr, ':'); // Парсим массив символов по символу запятой int am2 = data2.split(); // Получаем количество данных, внимание, ломает строку! if (am2 > 1) { // Если существует не только ключ, а ещё и значение String key = data2[0]; // Ключ - первое значение float value = data2.getInt(1); // Значение - второе if (debug) Serial.println("key: " + key + ", value: " + String(value)); // Вывод // Присваивание значений и обработка команды if (key.equals("led")) { btnLedState = value; digitalWrite(BTN_LED_PIN, btnLedState); } } } if (debug) Serial.println(); // Перевод на новую строку для разделения значений, которые были введены } }
Соберите устройство и тестируйте
Установите сигнальный пин датчика MQ-2 на A1, а пин E на 12.
Теперь вернитесь на панель управления, чтобы проверить виджет. Как видите, все данные загружаются сюда через определенный интервал.
Также попробуйте приложение для Android.
Модуль WI-Fi Амперки нельзя менять из раза в раз, т.к. при подсоединении модуля к их серверам остаётся какая-то информация о контроллере и если поменять контроллер, то будут ошибки при подсоединении к их серверам.
Если тип данных, который вы ходите записать в облачную переменную отличен от того типа, что установлено в облаке, тогда у вас значение просто не будет изменяться! Напимер, если число float записывать в облачную переменную типа int.
Last updated
Was this helpful?