Lab works 5. Розробка пристрою для Alterozoom IoT на базі мікроконтролера Arduino

Мета роботи

Навчитися розробляти пристрої, сумісні з концепцією IoT від Alterozoom
Завдання  роботи

1.Установка біблітекі для протоколу взаємодії з додатком Alterozoom.
2.Розробка скетчу.
3.Перевірка взаємодії з пристроєм через монітор послідовного порту.

Інструменти для виконанню роботи

1.Комп'ютер з підключенням до мережі Internet.

2.Плата Arduino з USB виходом (наприклад, Arduino Uno).

Теоретична частина

Для спрощення розробки пристроїв IoT і уніфікації їх підключення до платформи Alterozoom був розроблений простий текстовий протокол для взаємодії пристрою з комп'ютером через різні канали зв'язку, призначені для послідовної передачі інформації. Протокол призначений для організації взаємодії двох пристроїв (точка-точка) за допомогою обміну простими текстовими повідомленнями. Використання текстових повідомлень спрощує розробку і налагодження пристрою, так як дозволяє взаємодіяти з ним без спеціалізованого ПЗ з командного рядка або монітора послідовного порту. Опис протоколу можна знайти за посиланням: http://wl.unn.ru/ftp/public/IoT/Alterozoom/Alterozoom IoT protocol ptp.pdf

Так само була розроблена бібліотека для Arduino IDE, що реалізує даний протокол.

Виконання роботи

Установка бібліотеки для протоколу взаємодії з додатком Alterozoom

Завантажуємо архів з бібліотекою для Arduino IDE за посиланням: http://wl.unn.ru/ftp/public/IoT/Alterozoom/ARpc.zip Встановлюємо бібліотеку через менеджер бібліотек: вибираємо пункт меню "Скетч -> Управління бібліотеками -> Додати. ZIP бібліотеку "і знаходимо скачаний архів ARpc.zip.

Розробка скетчу

В рамках роботи буде створено скетч, що дозволяє блимати світлодіодом з інтерфейсу програми Alterozoom і передавальний раз на пів-секунди "вимірювання" (згенерований двовимірний сигнал (sin (t); cos (t))). Так само у пристрої буде ще один "датчик" - лічильник миганий світлодіодом.

Для взаємодії з комп'ютером через послідовний порт ми створимо об'єкт класу ARpc і визначимо для нього дві callback-функції - одна для обробки команд від ПК, друга для відправки повідомлень на комп'ютер. Дані функції будуть викликатися самою бібліотекою при необхідності. Для однозначної ідентифікації пристрою так само необхідно вказати ідентифікатор і ім'я пристрою. А для забезпечення можливість управління пристроєм необхідно розробити xml-опис панелі управління пристроєм.

Створюємо новий скетч і зберігаємо під ім'ям AlterozoomTest. Перевіряємо, що правильно вказана плата і порт. Підключаємо до скетчу бібліотеку ARpc (Скетч -> Підключити бібліотеку -> ARpc). На початку файлу повинен був з'явитися потрібний #include <ARpc.h>.

Генеруємо унікальний ідентифікатор в форматі UUID (наприклад, можна скористатися сервісом https://www.uuidgenerator.net/version4, при відкритті сторінки вгорі буде готовий UUID). Додаємо дві глобальних змінних для ідентифікатора і назви пристрою:

const char *deviceName="led_blink_test";//имя устройства
const char *deviceId="{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}";//идентификатор устройства

xxxxxxxxxxxx-xxxxxxxx-xxxxxxxxxxxx замінюємо на отриманий UUID, фігурні дужки повинні залишитися.

Так само визначаємо дополнітелной глобальні змінні

int ledPin=13;//пин светодиода
unsigned long blinksCount=0;//число миганий

Для того, щоб в подальшому для пристрою був доступний інтерфейс управління пристроєм, необхідно розробити xml-опис. Детально про це можна почитати в pdf-описі (посилання з теоретичної частини). Для нашого сценарію необхідна одна кнопка, передає на контролер команду "blink", яка описується в такий спосіб:

const char *interfaceStr="<controls><group title=\"Device controls\"><control sync=\"0\" title=\"Blink\" command=\"blink\"/></group></controls>";

Так само для отримання даних з пристрою необхідно підготувати опис датчиків. Для нашого пристрою воно виглядає ось так:

const char *sensorsDef="<sensors>"
"<sensor name=\"blinks_count\" type=\"single\"/>"//датчик blinks_count
"<sensor name=\"sin_x\" type=\"single\"><constraints dims=\"2\"/></sensor>"//датчик sin_x (двумерный)
"</sensors>";

Визначаємо функцію обробки команд, що передаються пристрою. Бібліотека буде викликати цю функцію, коли на пристрій будуть приходити команди, наприклад, введені нами в моніторі порту. Ця функція приймає команду, аргументи команди, кількість аргументів і покажчик на об'єкт класу ARpc, від якого прийшла команда:

void processCommand(const char *cmd,const char *args[],int argsCount,ARpc *parser)
{
    if(strcmp(cmd,"blink")==0)//проверяем, что cmd == "blink"
    {
        //мигаем
        digitalWrite(13,HIGH);
        delay(200);
        digitalWrite(13,LOW);
        delay(200);
        ++blinksCount;
        //генерируем "измерение"
        parser->writeMeasurement("blinks_count",String(blinksCount).c_str());
        //сообщаем библиотеке что команда обработана
        parser->writeOk();
    }
    else parser->writeErr("Unknown cmd");//неизвестная команда

Тут ми обробляємо одну команду - "blink", при приході якої кліпаємо штатним світлодіодом на 13 порту і передаємо нове "вимір" лічильника миганий.
Визначаємо функцію для передачі повідомлень до ПК через послідовний порт:

void arpcWriteCallback(const char *str)
{
    Serial.print(str);
}

Ця функція викликається, коли бібліотеці потрібно передати будь-які дані від пристрою. В даному випадку це дані, які ми побачимо в моніторі порту. Зверніть увагу, що не використовується println, так як ця функція додає зайвий новий рядок, який буде заважати нормальній обробці повідомлень.

Далі ми оголошуємо об'єкт класу ARpc і передаємо йому посилання на створені вище змінні і функції:

ARpc parser(300,&processCommand,&arpcWriteCallback,deviceId,deviceName);

Далі готується функція для генерації відліків sin і cos

int t=0;
void writeSinVal()
{
    String sinVal;
    sinVal+=String(sin(0.1*t));
    sinVal+="|";
    sinVal+=String(cos(0.1*t));
    parser.writeMeasurement("sin_x",sinVal.c_str());
    ++t;
}

300 - розмір буфера для одного повідомлення. Неможливо передати на контролер повідомлення розміру більше зазначеного.
Розмір буфера потрібно підбирати, виходячи з доступного обсягу пам'яті. На мікроконтролерах з великим об'ємом пам'яті можна використовувати більший розмір буфера.

Проходімоо ініціальзацію Піна і послідовного порту в функції setup () і встановити опис датчиків і інтерфейсу управління:

void setup()
{
    Serial.begin(9600);
    pinMode(13,OUTPUT);
    parser.setControlsInterface(interfaceStr);
    parser.setSensorsDescription(sensorsDef);
}

І нарешті, в функції loop () необхідно перевіряти послідовний порт на наявність нових даних, передавати їх об'єкту parser, згенерувати новий відлік sin, після чого зробити затримку на пів-секунди, щоб відліки НЕ генерувалися занадто часто.

void loop()
{
    while(Serial.available())
        parser.putChar(Serial.read());
    writeSinVal();
    delay(500);
}

Завантажуємо отриманий скетч на мікроконтролер.

Перевірка взаємодії з пристроєм через монітор послідовного порту.

Відкриваємо монітор порту. У ньому повинні регулярно з'являтися повідомлення "meas" з новими значеннями sin і cos.

Перевіряємо, щоб внизу було вибрано "Новий рядок", а не "Немає кінця рядка".
Пишемо в поле введення "identify" і натискаємо Надіслати. У відповідь має з'явитися повідомлення deviceinfo.

 

У цьому повідомленні повинні бути ідентифікатор і ім'я пристрою, зазначені в скетчі.
Додаткове завдання: передати повідомлення на пристрій з командою миготіння светодиодом "blink", запросити з пристрою список датчиків і опис інтерфейсу управління.