Arduino:Примеры/Bridge

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

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Библиотека Bridge[1]

Этот пример для Arduino Yun, и он демонстрирует использование библиотеки Bridge для доступа к цифровым и аналоговым контактам Arduino при помощи REST-запросов. Другими словами, он показывает, как при помощи REST-запросов, отправляемых через браузер, создать свой собственный API.

Перед запуском этого скетча убедитесь, что ваш компьютер находится в той же сети, что и Yun.

Закончив с программированием платы, вы сможете делать следующие вещи – запрашивать значение контакта, задавать значение контакта, а также задавать статус контакта (входной/выходной).

Итак, если защита паролем для REST отключена, вы можете отсылать Arduino следующие команды, выполненные в виде URL:

Впрочем, если хотите, вместо браузера можно использовать CURL-команды в командной строке.

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

  • Плата Arduino Yun;
  • Компьютер и Yun должны быть расположены в одной сети (проводной или беспроводной);

Необходимое ПО

  • Веб-браузер;

Цепь

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

Код

Этот скетч показывает, как делать REST-запросы к плате Yun, чтобы считывать контактов или задавать контактам те или иные значения. Вам потребуются библиотеки Bridge, YunServer и YunClient:

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

Инстацируем сервер YunServer, который позволит Yun «прослушивать» подключающихся клиентов.

YunServer server;

В секции setup() инициализируем последовательную передачу данных (в отладочных целях), а затем включаем встроенный светодиод, подключенный к 13-ому цифровому контакту, тем самым оповещая об активации библиотеки Bridge. Bridge.begin() – это блокирующая функция, а на ее выполнение уйдет примерно 2 секунды. Когда активация Bridge Полужирное начертаниезавершится, светодиод погаснет.

void setup() {
  Serial.begin(9600);
  pinMode(13,OUTPUT);
  digitalWrite(13, LOW);
  Bridge.begin();
  digitalWrite(13, HIGH);

Во второй части секции setup() мы делаем так, чтобы наш инстацированный YunServer «слушал» входящие соединения, но идущие только от локального хоста, т.е. от компьютера. При этом все подключения, идущие к Linux, будут передаваться процессору 32U4 – для последующего анализа и управления контактами. Все это проходит через порт 5555. Затем начинаем работать с сервером при помощи server.begin().

server.listenOnLocalhost();
  server.begin();
}

В блоке loop() создаем экземпляр YunClient для управления соединением. Если клиент подключается, обрабатываем запросы в пользовательской функции (ее описание – ниже), а по завершении закрываем соединение. В конце блока loop() ставим задержку – чтобы процессор не перетруждался.

void loop() {
  YunClient client = server.accept();

  if (client) {
    process(client);
    client.stop();
  }

  delay(50);
}

Создаем функцию под названием process – она будет принимать YunServer в качестве аргумента. Считываем команду, создавая строку, которая будет хранить в себе входящую информацию. Анализируем REST-команды, определяя их функциональность (т.е. то, на что направлены эти команды – на работу с цифровым контактом, на работу с аналоговым контактом или на то, чтобы задать контакту тот или иной режим работы), а затем передаем информацию соответствующей функции.

void process(YunClient client) {
  String command = client.readStringUntil('/');

  if (command == "digital") {
    digitalCommand(client);
  }
  if (command == "analog") {
    analogCommand(client);
  }
  if (command == "mode") {
    modeCommand(client);
  }
}

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

void digitalCommand(YunClient client) {
  int pin, value;

Анализируем запрос клиента на предмет информации о контакте при помощи функции client.pareInt().

Если после числа, обозначающего контакт, стоит символ «/», это значит, что у этого URL дальше имеется либо «0», либо «1». То есть при помощи этих значений контакту передается либо значение HIGH, либо значение LOW. Если символа «/» нет, то просто считываем значение с указанного контакта.

pin = client.parseInt();

  if (client.read() == '/') {
    value = client.parseInt();
    digitalWrite(pin, value);
  } 
  else {
    value = digitalRead(pin);
  }

Шлем клиенту текстовое сообщение о том, что значение такого-то цифрового контакта стало таким-то (например, «Pin D13 set to 1»,т.е. «значение 13-ого цифрового контакта стало 1»), попутно меняя в базе данных значение ключа на то, которое было указано в клиентском запросе.

«Упаковываем» это сообщение в конструкцию F(), благодаря чему оно будет выводиться из flash-памяти. Тем самым мы экономим место в SRAM, что особенно полезно, если вы работаете длинными строками вроде URL. Ключ делаем составным, он будет включать в себя тип контакта (т.е. «D») и его номер (т.е. «2», «5», «13» и т.д.). Например, ключ «D2» будет означать 2-ой цифровой контакт. Значением (value) будет любая величина, которая либо задается клиентом, либо считывается с контакта.

client.print(F("Pin D"));
  client.print(pin);
  client.print(F(" set to "));
  client.println(value);

  String key = "D";
  key += pin;
  Bridge.put(key, String(value));
}

Теперь задаем функцию, которая будет аналогичным образом управляться с аналоговыми запросами, только в ключе вместо D поставим A.

void analogCommand(YunClient client) {
  int pin, value;

  pin = client.parseInt();

  if (client.read() == '/') {
    value = client.parseInt();
    analogWrite(pin, value);

    // Отсылаем клиенту обратное сообщение
    client.print(F("Pin D"));
    client.print(pin);
    client.print(F(" set to analog "));
    client.println(value);

    String key = "D";
    key += pin;
    Bridge.put(key, String(value));
  }
  else {
    value = analogRead(pin);

    client.print(F("Pin A"));
    client.print(pin);
    client.print(F(" reads analog "));
    client.println(value);

    String key = "A";
    key += pin;
    Bridge.put(key, String(value));
  }
}

Создаем еще одну функцию, которая будет заниматься запросами, которые будут задавать для контакта его тип – входной (INPUT) или выходной (OUTPUT). Принимаем YunClient как аргумент и создаем локальную переменную, которая будет хранить номер контакта. Далее считываем значение контакта – точно таким же образом, как в функциях для работы с цифровыми и аналоговыми контактами.

void modeCommand(YunClient client) {
  int pin;
  pin = client.parseInt();

Делаем проверку, чтобы убедиться, что URL правильный.

if (client.read() != '/') {
    client.println(F("error"));
    return;
  }

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

String mode = client.readStringUntil('\r');

  if (mode == "input") {
    pinMode(pin, INPUT);
    // Отсылаем клиенту обратное сообщение:
    client.print(F("Pin D"));
    client.print(pin);
    client.print(F(" configured as INPUT!"));
    return;
  }

  if (mode == "output") {
    pinMode(pin, OUTPUT);
    // Отсылаем клиенту обратное сообщение:
    client.print(F("Pin D"));
    client.print(pin);
    client.print(F(" configured as OUTPUT!"));
    return;
  }

  client.print(F("error: invalid mode "));
  client.print(mode);
}

Полная версия скетча – ниже:

// Несколько примеров того, какими могут быть команды для этого скетча:
//
// "digital/13"     -> digitalRead(13)
// "digital/13/1"   -> digitalWrite(13, HIGH)
// "analog/2/123"   -> analogWrite(2, 123)
// "analog/2"       -> analogRead(2)
// "mode/13/input"  -> pinMode(13, INPUT)
// "mode/13/output" -> pinMode(13, OUTPUT)

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

// Включаем «прослушку» порта 5555 – веб-сервер на Yun будет отправлять туда для нас все HTTP-запросы.

YunServer server;

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

  // Активируем библиотеку Bridge:
  pinMode(13,OUTPUT);
  digitalWrite(13, LOW);
  Bridge.begin();
  digitalWrite(13, HIGH);

  // Начинаем «прослушивать» входящие соединения, но идущие только от локального хоста, 
  // т.е. подключения от внешней сети игнорируем:
  server.listenOnLocalhost();
  server.begin();
}

void loop() {
  // «Забираем» клиентов, идущих от сервера:
  YunClient client = server.accept();

  // Появился ли новый клиент?
  if (client) {
    // Обрабатываем запрос:
    process(client);

    // Закрываем соединение и освобождаем ресурсы:
    client.stop();
  }

  delay(50); // Задержка каждые 50 миллисекунд
}

void process(YunClient client) {
  // Считываем команду:
  String command = client.readStringUntil('/');

  // Это «цифровая» (digital) команда?
  if (command == "digital") {
    digitalCommand(client);
  }

  // Это «аналоговая» (analog) команда?
  if (command == "analog") {
    analogCommand(client);
  }

  // Это команда для смены режима (mode)?
  if (command == "mode") {
    modeCommand(client);
  }
}

void digitalCommand(YunClient client) {
  int pin, value;

  // Считываем номер контакта
  pin = client.parseInt();

  // Если следующим символом является «/», это значит, 
  // что полученный запрос идет вместе с некоторым значением 
  // и выглядит примерно так: «/digital/13/1»
  if (client.read() == '/') {
    value = client.parseInt();
    digitalWrite(pin, value);
  } 
  else {
    value = digitalRead(pin);
  }

  // Отсылаем клиенту обратное сообщение:
  client.print(F("Pin D")); // "Контакту D"
  client.print(pin);
  client.print(F(" set to ")); // " присвоено значение "
  client.println(value);

  // Обновляем ключ в базе данных на текущее значение контакта:  
  String key = "D";
  key += pin;
  Bridge.put(key, String(value));
}

void analogCommand(YunClient client) {
  int pin, value;

  // Считываем номер контакта:
  pin = client.parseInt();

  // Если следующим символом является «/», это значит, 
  // что полученный запрос идет вместе с некоторым значением 
  // и выглядит примерно так: "/analog/5/120»
  if (client.read() == '/') {
    // Считываем это значение и выполняем команду:
    value = client.parseInt();
    analogWrite(pin, value);

    // Отсылаем клиенту обратное сообщение:
    client.print(F("Pin D")); // "Контакту D"
    client.print(pin);
    client.print(F(" set to analog ")); // " присвоено аналоговое значение "
    client.println(value);

    // Обновляем ключ в базе данных на текущее значение контакта:  
    String key = "D";
    key += pin;
    Bridge.put(key, String(value));
  }
  else {
    // Считываем номер аналогового контакта:
    value = analogRead(pin);

    // Отсылаем клиенту обратное сообщение:
    client.print(F("Pin A")); // "С контакта A"
    client.print(pin);
    client.print(F(" reads analog ")); // " считано аналоговое значение "
    client.println(value);

    // Обновляем ключ в базе данных на текущее значение контакта:
    String key = "A";
    key += pin;
    Bridge.put(key, String(value));
  }
}

void modeCommand(YunClient client) {
  int pin;

  // Считываем номер контакта:
  pin = client.parseInt();

  // Если «/» не является следующим символом, то URL неправильный:
  if (client.read() != '/') {
    client.println(F("error")); // "ошибка"
    return;
  }

  String mode = client.readStringUntil('\r');

  if (mode == "input") {
    pinMode(pin, INPUT);
    // Отсылаем клиенту обратное сообщение:
    client.print(F("Pin D")); // "Контакт D"
    client.print(pin);
    client.print(F(" configured as INPUT!")); // " сделан входным!"
    return;
  }

  if (mode == "output") {
    pinMode(pin, OUTPUT);
    // Отсылаем клиенту обратное сообщение:
    client.print(F("Pin D")); // "Контакт D"
    client.print(pin);
    client.print(F(" configured as OUTPUT!")); // " сделан выходным!"
    return;
  }

  client.print(F("error: invalid mode ")); // "Ошибка. Вы указали неверную команду для того, чтобы задать режим – "
  client.print(mode);
}

См.также

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