Уроки

Управляем Arduino через Интернет с помощью бесплатного хостинга

Нет комментариев

Создадим простую веб-страницы, разместим ее на хостинге и используем этот сайт для управления устройством на Arduino через Интернет.

О проекте

Что отличает данный урок от других уроков с мигающими светодиодами?

1. Если вы используете bluetooth, то вам нужно быть рядом с вашим Arduino. В нашем проекте мы управляем платой удаленно.

2. Используя другие платформы вы привязаны к их решению - здесь же вы сможете делать все, что захотите. Просто редактируйте свою веб-страницу на хостинге и всё.

3. Вы можете использовать бесплатный хостинг, кроме того можно заказать виртуальный хостинг или VPS, тогда вы вообще сможете решать много различных задач, единственный нюанс, что лучше предварительно изучить рейтинг VPS, прежде чем использовать первый попавшийся.

4. Если вы сохраняете веб-страницу в самом ESP, то вы не можете контролировать его через Интернет.

5. Мы создадим свою собственную систему двусторонней связи.

6. Этот проект можно реализовать с помощью бесплатного хостинга.

7. Нет необходимости использовать какие-либо приложения для Android / iPhone, так как у нас будет веб-страница, которую можно открыть на любом устройстве.

Компоненты

Для создания нашего проекта по управлению Ардуино через сайт в интернете нам понадобятся следующие комплектующие:

  1. NodeMCU ESP8266 × 1
  2. Светодиод LED (общий) × 1
  3. Резистор 221 Ом × 1
  4. Кнопка × 1

Из сторонних сервисов вы будем использовать облако remoteme.org. С помощью данного сервиса можно контролировать и собирать данные с умных устройств Интернета вещей из любой точки мира. Вы можете использовать, в целом, любой подходящий хостинг.

Что такое Remoteme.org?

Мы познакомимся с сайтом remoteme.org. Сайт позволяет использовать несколько вариантов управления вашим Arduino (и не только) через Интернет.

Кроме того сервис позволяет разместить вашу собственную веб-страницу, которая будет отправлять сообщения на ваши устройства совершенно бесплатно. Но в целом, можно заморочиться и использовать платное, но более автономное и безопасное решение.

В рунете очень много хостингов, которые можно посмотреть и выбрать на разных сайтах по обзору хостингов типа рейтинга HostingHUB.ru. Например, вы можете сделать робота Rasbperry Pi с FPV:

Но в этом уроке мы начнем с варианта попроще - моргания светодиода через Интернет.

Основная цель сервиса - соединить все ваши устройства (RPi, Arduino, веб-страницы) в одну служебную шину. Объяснить принцип работы можно на реальном примере с почтальоном.

Почтальон может доставлять два вида писем:

  1. Асинхронные сообщения - это своего рода сообщение, которое мы отправляем и не ждем ответа. Примером такого сообщения может быть «включите свет», «поверните направо». Эти сообщения в системе называются UserMessage.
  2. Синхронные сообщения - это как вызов функций, возвращающих состояние. Вы отправляете сообщение и ждете ответа. Такое сообщение можно использовать, например, чтобы узнать температуру от какого-либо датчика или спросить, горит ли светодиод. Такие сообщения на remoteme.org называются UserSyncMessage.

Есть библиотеки, которые помогают общаться с нашим "почтальоном". Ниже приведен пример JavaScript:

remoteme.sendUserMessageByFasterChannel (123,[1,1,2,3,5,8]);

В приведенном выше коде мы отправляем массив байтов [1, 1, 2, 3, 5, 8] на устройство с идентификатором 123.

remoteme.sendUserSyncMessageWebSocket(123,[6],function(data){
	printTemperature(data[0]);
});

Выше мы отправим число 6 в массиве, а в качестве возврата ожидаем получить температуру от какого-либо датчика. А как обрабатывать сообщения и отвечать на синхронные сообщения? На этот раз пример кода для Arduino:

void setup() {
  ...
  remoteMe.setUserMessageListener(onUserMessage);
  remoteMe.setUserSyncMessageListener(onUserSyncMessage);
 
...
}

 
void onUserSyncMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t* data, uint16_t &returnDataSize, uint8_t *&returnData) {
    if (data[0]==6){
    returnDataSize=1;
    returnData=(uint8_t*)malloc(dataSize);
    returnData[0]=readTemperature();
    
  }
}
 
void onUserMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t *data) {
   doSomething();
  
}

В функции настройки мы устанавливаем, какие функции будут вызываться при поступлении сообщений в Arduino. Далее я покажу, как именно всё это использовать.

Представьте себе систему remoteme.org как почтальона. Наш почтальон знает все ваши устройства и распознает их по deviceId. DeviceId также является адресом устройства.

Если устройство A хочет отправить сообщение на устройство B оно помещает массив байт в конверт, а на конверте само записывает deviceId, так что почтальон знает, куда доставляется это сообщение.

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

Дополнительно remoteme.org дает возможность сохранять данные в базе данных - я покажу, как это сделать в другом уроке.

Вы также можете запускать некоторые скрипты на самом сервере remoteme.org, например, через можно подключить скрипт прогноза погоды на ближайшие дни, отправлять некоторые простые данные, как температура или осадки прямо на Arduino, что потом будет отображаться на некоторых ЖК-дисплеях.

Для отправки сообщений на устройства Вы также можете использовать Rest Api, но на данном этапе мы сосредоточимся на мигании светодиода через интернет с помощью ESP.

Начало работы с сервичом

1. Для начал работы с remoteme.org вам нужен наш собственный аккаунт (он бесплатный).

2. Затем вы должны сгенерировать свой собственный токен, чтобы через него общаться с системой.

Таким образом, Вы следите за тем, чтобы никто без Вашего разрешения не посылал данные на Ваши устройства или не открывал Ваши сайты.

У каждого токена есть имя, это имя поможет Вам распознать Ваш токен (позже Вы сможете удалить токены, и тогда все URL, сгенерированные этим токеном, будут недействительны).

Наши устройства устанавливают с помощью remoteme.org соединения websocket / socket / webRTC. Через эти соединения remoteme.org отправляет и получает сообщения с ваших устройств, веб-страниц.

Вот здесь для выполнения подключений вам и понадобится токен, который будет подключать ваши устройства только к вашей учетной записи.

Все эти подключения вы выполняете с помощью библиотек.

https://github.com/remoteme/RemoteMeArduinoLibrary

Схема соединения

Схема соединений наших комплектующих (см. выше) довольно простая:

Работа устройства

Каждый раз, когда мы нажимаем кнопку:

  • диод меняет свое состояние
  • Arduino отправляет фактическое состояние светодиода Arduino
  • веб-страница получает сообщение и перерисовывает изображение диода

Когда мы нажимаем на светодиод на веб-странице:

  • веб-страница отправляет сообщение в Arduino
  • Arduino изменяет состояние светодиода
  • Arduino отправляет сообщение с фактическим состоянием диода

Когда страница обновляется, она запрашивает у Arduino фактическое состояние диода и отображает это состояние в браузере.

В итоговом видео ниже вы можете увидеть, как это работает. Сама веб-страница открывается в трех браузерах, и все они постоянно показывают фактическое состояние светодиода и позволяют включать и выключать его.

Настройка Remoteme.org и Arduino

Все действия мы делаем через менеджера библиотек в Arduino IDE:

Проверка соединений

Программа, приведенная ниже, не делает ничего, кроме изменения состояния диода при каждом нажатии кнопки.

include <RBD_Timer.h>  
#include <RBD_Button.h>
 
uint8_t LEDpin = D5;
RBD::Button button(D2);
 
boolean currentState = false;
 
void setup() {
  Serial.begin(9600);
 
  
  pinMode(LEDpin, OUTPUT);
  digitalWrite(LEDpin, LOW);
 
}
 
void changeDiodeState(   ) {
  currentState= !currentState;
  digitalWrite(LEDpin, currentState?HIGH:LOW);
 
}
 
void loop() {
  if (button.onPressed()) {
    changeDiodeState();
  }
 
}

Программа Ардуино

Вы можете скопировать программу ниже.

#define WIFI_NAME "ania24"
#define WIFI_PASSWORD "tuchowkrakow"
#define DEVICE_ID 203
#define DEVICE_NAME "diodeWithButtonArduino"
#define TOKEN "~155_D49LDj@aBFhK."

#define WEBPAGE_DEVICE_ID 1001

#include <ArduinoHttpClient.h>
#include <RemoteMe.h>
#include <ESP8266WiFi.h>

#include <ESP8266WiFiMulti.h>

#include <RBD_Timer.h>  
#include <RBD_Button.h> 

uint8_t LEDpin = D5;
RBD::Button button(D2);

ESP8266WiFiMulti WiFiMulti;
RemoteMe& remoteMe = RemoteMe::getInstance(TOKEN, DEVICE_ID);
boolean currentState = false;

void setup() {
	Serial.begin(9600);

	WiFiMulti.addAP(WIFI_NAME, WIFI_PASSWORD);
	while (WiFiMulti.run() != WL_CONNECTED) {
		delay(100);
	}


	remoteMe.setUserMessageListener(onUserMessage);
	remoteMe.setUserSyncMessageListener(onUserSyncMessage);


	remoteMe.setupTwoWayCommunication();
	remoteMe.sendRegisterDeviceMessage(DEVICE_NAME);
	pinMode(LEDpin, OUTPUT);
	digitalWrite(LEDpin, LOW);

}

void onUserSyncMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t* data, uint16_t &returnDataSize, uint8_t *&returnData) {
	returnDataSize = 1;
	returnData = (uint8_t*)malloc(returnDataSize);
	Serial.println("received sync message");
	uint16_t pos = 0;
	RemoteMeMessagesUtils::putUint8(returnData, pos, currentState ? 1 : 0);

}

void onUserMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t *data) {
	changeDiodeState();
}

void changeDiodeState() {
	
	currentState= !currentState;

	digitalWrite(LEDpin, currentState?HIGH:LOW);

	uint16_t returnDataSize = 1;
	uint16_t pos = 0;
	uint8_t *data = (uint8_t*)malloc(returnDataSize);
	RemoteMeMessagesUtils::putUint8(data, pos, currentState?1:0);

	remoteMe.sendUserMessage(WEBPAGE_DEVICE_ID, data, returnDataSize);

}

void loop() {
	remoteMe.loop();
	if (button.onPressed()) {
		changeDiodeState();
	}

}

Перед программированием устройств вам необходимо заполнить несколько строк:

  • WIFI_NAME - название Wi-Fi
  • WIFI_PASSWORD - пароль Wi-Fi
  • DEVICE_ID - deviceId также является адресом устройства в системе remoteMe, в нашем случае это 203
  • DEVICE_NAME - имя устройства, которое будет зарегистрировано в системе
  • TOKEN - токен из вкладки токенов в remoteme.org

После заполнения этих полей вы можете загрузить программу в Arduino и запустить ее.

Когда мы перейдем на вкладку устройства, то увидим, что наше устройство уже добавлено, а зеленый значок будет означать, что устройство подключено прямо сейчас.

Как это работает?

Нам нужно создать объект remoteMe, который мы будем использовать для связи с нашей веб-страницей.

RemoteMe& remoteMe = RemoteMe::getInstance(TOKEN, DEVICE_ID);

Константа TOKEN - это токен из вкладки Tokens, DEVICE_ID - это deviceId нашего Arduino, в нашем случае это 203, используя этот адрес, мы будем отправлять сообщения с веб-страницы в Arduino.

Кроме того мы используем:

#define WEBPAGE_DEVICE_ID 1001

1001 - это deviceId нашей будущей веб-страницы.

Функция setup():

WiFiMulti.addAP(WIFI_NAME, WIFI_PASSWORD);
	while (WiFiMulti.run() != WL_CONNECTED) {
		delay(100);
	}

Подключаемся к Wifi и ждем, пока установится соединение.

remoteMe.setUserMessageListener(onUserMessage);
remoteMe.setUserSyncMessageListener(onUserSyncMessage);

Мы устанавливаем, какая функция будет вызываться при приходе сообщения в Arduino.

remoteMe.setupTwoWayCommunication();

Это означает, что нам нужна двусторонняя связь.

remoteMe.sendRegisterDeviceMessage(DEVICE_NAME);

И регистрирует наше устройство на app.remoteme.org. После вызова этой функции устройство будет отображаться на вкладке устройства с заданным именем.

Как это устроено. Веб-страница отправит сообщение на устройство, и эта функция в Arduino будет запущена:

void onUserMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t *data) {
	changeDiodeState();	
}

Как видите, мы не читаем то, что было отправлено в сообщении. Функция changeDiodeState вызывается всегда после получения любого сообщения.

void changeDiodeState(   ) {
	currentState= !currentState;
	digitalWrite(LEDpin, currentState?HIGH:LOW);
 
	uint16_t returnDataSize = 1;
	uint8_t *data = (uint8_t*)malloc(returnDataSize);
	
	uint16_t pos = 0;
	RemoteMeMessagesUtils::putUint8(data, pos, currentState?1:0);
	remoteMe.sendUserMessage(WEBPAGE_DEVICE_ID, data, returnDataSize);
}

Вышеупомянутая функция также вызывается при нажатии кнопки на Arduino. Эта функция, помимо изменения состояния диода, отправляет новое состояние на веб-страницу:

uint16_t returnDataSize = 1;
uint8_t *data = (uint8_t*)malloc(returnDataSize);

В единственный байт сообщения мы помещаем 1 или 0 в зависимости от текущего состояния диода.

uint16_t pos = 0;
RemoteMeMessagesUtils::putUint8(data, pos, currentState?1:0);

Функция putUint8 имеет параметры:

  • массив, в который мы будем сохранять наши данные, которые будут отправлены
  • позиция, в которую данные (в данном случае uint8_t) будут помещены в массив. Параметр pos указан как ссылка, поэтому после записи числа он увеличивается на размер памяти числа. В этом случае он увеличился на 1, но у нас есть несколько похожих функций, таких как put float, double, string
  • и последний параметр 0, если диод не горит и 1, если он горит

Укороченный вариант сохранения параметра в массив будет выглядеть так:

uint16_t returnDataSize = 1;
uint8_t *data = (uint8_t*)malloc(returnDataSize);
data [0]= currentState?1:0

И в конце мы отправляем сообщение на веб-страницу

remoteMe.sendUserMessage(WEBPAGE_DEVICE_ID, data, returnDataSize);

Ниже приведена функция, которая запускается, когда веб-страница запрашивает текущее состояние диода.

void onUserSyncMessage(uint16_t senderDeviceId, uint16_t dataSize, uint8_t* data, uint16_t &returnDataSize, uint8_t *&returnData) {
	returnDataSize = 1;
	returnData = (uint8_t*)malloc(returnDataSize);
	Serial.println("received sync message");
	uint16_t pos = 0;
	RemoteMeMessagesUtils::putUint8(returnData, pos, currentState ? 1 : 0);
 
}

Данные, которые мы хотим вернуть, мы помещаем в returnData, а в returnDataSize мы помещаем размер данных, которые мы хотим отправить обратно.

Подобно функции отправки состояния, здесь мы помещаем единственный байт, который представляет состояние диода.

И последняя функция - loop().

void loop() {
	remoteMe.loop();
 
	if (button.onPressed()) {
		changeDiodeState();
	}
 
}

remoteMe.loop() проверяет, есть ли какие-либо сообщения, ожидающие обработки, проверяет состояние устройства и делает еще кое-что - все, что делает эта функция, вы можете проверить в исходном коде библиотек.

Если вы еще не запрограммировали свой Arduino, вы можете сделать это сейчас.

Отправка сообщений

Теперь мы готовы сохранять сообщения в Arduino. Наш Arduino на вкладке устройств (1 на рис. ниже) должен быть виден и иметь зеленый значок ссылки.

Это означает, что устройство подключено прямо сейчас. Поскольку у нас еще нет веб-страницы, мы будем использовать встроенные функции для отправки сообщений на наше устройство.

Кликните значок с одиночным сообщением (2) и затем:

(3) нам нужно заполнить устройство отправителя - у нас только одно устройство, поэтому мы выбираем его

(4) сообщения, как вы помните из реализации Arduino onUserMessage, мы игнорируем все данные, отправленные в Arduino, поэтому не имеет значения, что мы здесь поместим

И нажмите кнопку «Отправить».

Диод в Arduino будет меняться каждый раз, когда мы отправляем сообщение. Мы также можем протестировать syncUserMessage, поэтому давайте спросим наш Arduino о состоянии диода. Для этого нажмите на значок с двумя сообщениями (2) и затем заполните оставшееся:

После нажатия кнопки «Отправить» мы получим ответ от arduino (6) - 1, если светодиод горит, и 0, если нет.

Между нажатием кнопки отправки и нажатием на кнопку Arduino вы можете изменить состояние диода и проверить, возвращает ли Arduino правильный номер.

Веб-страница

Идентификатор устройства нашей веб-страницы должен быть 1001 и это есть в файле для Ардуино:

#define WEBPAGE_DEVICE_ID 1001

Наконец, мы создадим нашу страницу для управления Arduino. в Arduino мы устанавливаем, что состояние диода будет отправлено на устройство с идентификатором 1001, поэтому на веб-странице должен быть этот идентификатор устройства.

Создайте новую веб-страницу: Новое устройство -> Новая веб-страница (New Device -> New WebPage) и заполните, как показано ниже.

Теперь давайте добавим файлы на нашу веб-страницу, откройте их на GitHub.

Затем перетащите три файла (index.html, script.js, styles.css) на свою веб-страницу в «Перетащите сюда свои файлы» (англ. - Drop Your files here).

Проанализируем код:

var remoteme;
 
function setup(){
	remoteme = new RemoteMe({
		automaticlyConnectWS: true,
		automaticlyConnectWebRTC:false,
		webSocketConnectionChange: webSocketConnectionChange,
		webRTCConnectionChange: undefined,
		onUserMessage: onUserMessage,
		mediaConstraints: {'mandatory': {'OfferToReceiveAudio': false, 'OfferToReceiveVideo': false}}
	});
}

Создаем переменную remoteMe и инициализируем ее.
Наиболее важные параметры:

automaticlyConnectWS: true,

Автоматическое создание соединения WebSocket:

onUserMessage: onUserMessage,

Указываем, какая функция будет вызываться, когда Arduino что-то отправит на нашу веб-страницу. Кроме того:

webSocketConnectionChange: webSocketConnectionChange,

Указываем функцию после изменения состояния подключения:

function webSocketConnectionChange(state){
	if (state==WebsocketConnectingStatusEnum.CONNECTED){
		remoteme.sendUserSyncMessageWebSocket(arduinoId,[],function(data){
			var data = new RemoteMeData(data);
			changeDiode(data.popUint8());
		});
	}
}

После подключения WebSocket мы запросили у Arduino текущее состояние диода.

remoteme.sendUserSyncMessageWebSocket

Первый параметр - это Arduino deviceId, затем пустой массив - потому что не имеет значения, что будет внутри сообщений, в конце функции, которые будут вызываться после получения ответа от Arduino.

function(data){
      var data = new RemoteMeData(data);
      changeDiode(data.popUint8());
   }

Мы взяли первый байт возвращаемых данных, а затем на основе этого включили или выключили диод.

function changeDiode(state){
	$("#led").css("background-color",state==0?"white":"red");
}

Также, когда мы нажали кнопку на Arduino, он отправит сообщение, которое на сайте мы получим с помощью этой javascript функции.

function onUserMessage(sender,data){
	var data = new RemoteMeData(data);
	changeDiode(data.popUint8())
}

Как и в предыдущей функции, мы читаем первый байт и меняем состояние диода.

Давай откроем нашу веб-страницу:

И мы увидим:

После нажатия на этот кружок состояние диода изменится. Вы также можете обновить веб-страницу и посмотреть, показывает ли она правильное состояние диода.

Теперь мы можем открыть нашу веб-страницу с мобильного телефона. Вместо входа в систему remoteme.org мы подготовим специальную ссылку, которая будет отображать нашу веб-страницу без входа в систему на основе токенов:

Щелкните index.html, затем «Получить анонимную ссылку…» (англ. - get anonymous link), затем значок QR и отсканируйте QR-код.

На своем мобильном телефоне вы увидите ту же веб-страницу, и вы можете поиграться с ней.

Итоговое видео

В этом уроке мы узнали как управлять Arduino через браузер. На видео я показал небольшую демонстрацию того, что я сделал. Теперь вы понимаете что происходит в видео и как это работает.

Оригинал

Опубликовал 29 сентября 2020 в 01:03
Уроки,

Добавить комментарий

Ваш E-mail не будет никому виден. Обязательные поля отмечены *