void sendAnalogReadings()
{
client.println(F("<h1>Analog Inputs</h1>"));
client.println(F("<table border=’1’>"));
for (int i = 0; i < 5; i++)
{
int reading = analogRead(i);
client.print(F("<tr><td>A")); client.print(i);
client.print(F("</td><td>")); client.print((float) reading / 205.0);
client.println(F(" V</td></tr>"));
}
client.println("</table>");
}
Она выполняет обход всех аналоговых входов, читает их значения и выводит HTML-таблицу с прочитанными значениями в вольтах.
Возможно, вы обратили внимание на то, что sendBody вызывает также функции setValuesFromParams и setPinStates. Первая записывает в массив pinStates состояния HIGH или LOW цифровых выходов, извлекая их из параметров запроса с помощью функции valueOfParam:
int valueOfParam(char param)
{
for (int i = 0; i < strlen(line1); i++)
{
if (line1[i] == param && line1[i+1] == '=')
{
return (line1[i+2] — '0');
}
}
return 0;
}
Функция valueOfParam ожидает получения параметра запроса в виде единственной цифры. Как выглядят эти параметры, можно увидеть, если запустить пример, открыть страницу в браузере и щелкнуть на кнопке Update (Обновить). Адрес URL в адресной строке браузера изменится, и в нем появятся параметры, как показано далее:
192.168.1.10/?0=1&1=0&2=0&3=0&4=0
Список параметров начинается после символа ?. Параметры имеют вид X=Y и отделяются друг от друга символом &. Слева от знака = находится имя параметра (в данном случае цифры от 0 до 4), а справа — значения (в данном примере 1 означает «включено», а 0 — «выключено»). Для простоты параметры в этом примере могут иметь только односимвольные значения. Функция setPinStates устанавливает состояние цифровых выходов в соответствии со значениями элементов массива pinStates.
А теперь вернемся к функции sendBody. Вслед за таблицей со значениями аналоговых входов нужно послать разметку HTML с коллекцией раскрывающихся списков, соответствующих цифровым выходам. В каждом списке нужно выбрать пункт On (Включено) или Off (Выключено) в зависимости от текущего состояния цифрового выхода. Для этого нужно добавить текст «selected» в значение, соответствующее состоянию данного выхода в массиве pinStates.
Код разметки HTML для цифровых выходов заключается в форму, чтобы посетитель мог изменить значения в форме и, щелкнув на кнопке Update (Обновить), сгенерировать новый запрос к этой странице с соответствующими параметрами для установки цифровых выходов. А теперь посмотрим, как выглядит разметка HTML-страницы:
<html><body>
<hq>Analog Inputs</h1>
<table border='1'>
<tr><td>A0</td><td>0.58 V</td></tr>
<tr><td>A1</td><td>0.63 V</td></tr>
<tr><td>A2</td><td>0.60 V</td></tr>
<tr><td>A3</td><td>0.65 V</td></tr>
<tr><td>A4</td><td>0.60 V</td></tr>
</table>
<h1>Output Pins</h1>
<form method='GET'>
<p>Pin 3<select name='0'>
<option value='0'>Off</option>
<option value='1' selected>On</option>
</select></p>
<p>Pin 4<select name='1'>
<option value='0' selected >Off</option>
<option value='1'>On</option>
</select></p>
<p>Pin 5<select name='2'>
<option value='0' selected >Off</option>
<option value='1'>On</option>
</select></p>
<p>Pin 6<select name='3'>
<option value='0' selected >Off</option>
<option value='1'>On</option>
</select></p>
<p>Pin 7<select name='4'>
<option value='0' selected >Off</option>
<option value='1'>On</option>
</select></p>
<input type='submit'> value='Update'/>
</form>
</body></html>
Увидеть этот код можно, воспользовавшись функцией View Source (Исходный код страницы) в браузере.
Использование веб-службы JSON
Для иллюстрации возможности отправки веб-запросов из платы Arduino внешним веб-сайтам я воспользуюсь веб-службой, возвращающей данные о погоде в определенном географическом пункте. Плата будет выводить краткое описание погоды в монитор последовательного порта (рис. 12.6). Описываемый скетч посылает запрос один раз в момент запуска, но его нетрудно изменить, чтобы он запрашивал погоду каждый час и выводил результаты на двухстрочный жидкокристаллический дисплей.
Рис. 12.6. Получение информации о погоде от веб-службы
Скетч для этого примера получился очень коротким, всего 45 строк кода (sketch_12_03_web_request). Наибольший интерес для нас представляет функция hitWebPage:
void hitWebPage()
{
if (client.connect("api.openweathermap.org", 80))
{
client.println("GET /data/2.5/weather?q=Manchester,uk HTTP/1.0");
client.println();
while (client.connected())
{
if (client.available())
{
client.findUntil("description\":\"", "\0");
String description = client.readStringUntil('\"');
Serial.println(description);
}
}
client.stop();
}
}
Прежде всего необходимо подключить клиента к порту 80 сервера. Если соединение благополучно установлено, серверу посылается заголовок запроса:
client.println("GET /data/2.5/weather?q=Manchester,uk HTTP/1.0");
Дополнительная команда println нужна, чтобы отметить конец заголовка запроса и побудить сервер прислать ответ.
Далее в цикле while инструкция if проверяет получение данных от сервера, пока соединение с ним не закрыто. Непосредственное чтение данных из потока помогает избежать необходимости сохранять все данные в памяти. Данные поступают в формате JSON:
{"coord":{"lon":-2.23743,"lat":53.480949},
"sys":{"country":"GB","sunrise":1371094771,
"sunset":1371155927},"weather":[{"id":520, "main":"Rain",
"description":"light intensity shower rain", "icon": "09d"}]
"humidity":87,"temp_min":283.15,"temp_max":285.93},
"wind":{"speed:5.1,"deg":270},"rain":{"1h":0.83},
"clouds":{"all":40},"dt":1371135000,"id":3643123,
"name":"Manchester","cod":200}
Функция hitWebPage с помощью функций findUntil и readStringUntil извлекает фрагмент текста, следующий за словом «description», с двоеточием и двойной кавычкой до следующей двойной кавычки.
Функция findUntil просто игнорирует все, пока не встретит указанную строку. Затем функция readStringUntil читает текст из потока, пока не встретит двойную кавычку.
Библиотека WiFi
Библиотека WiFi, как можно было ожидать, очень похожа на библиотеку Ethernet. Если в скетче заменить Ethernet на WiFi, EthernetServer на WiFiServer и EthernetClient на WiFiClient, остальной код останется почти неизменным.
Создание соединения
Главное отличие библиотеки WiFi от Ethernet заключается в подключении к сети. Прежде всего нужно импортировать библиотеку WiFi:
#include <SPI.h>
#include <WiFi.h>
Чтобы установить соединение с сетью, следует вызвать команду WiFi.begin и передать ей имя беспроводной сети и пароль:
WiFi.begin("MY-NETWORK-NAME", "mypassword");
Пример в разделе «Пример использования WiFi» иллюстрирует еще одно отличие, о котором вы должны знать.
Особые функции в библиотеке WiFi
Библиотека WiFi включает несколько специальных функций. Они перечислены в табл. 12.1.
Полное описание библиотеки WiFi можно найти по адресу http://arduino.cc/en/Reference/WiFi [11].
Таблица 12.1. Специальные функции в библиотеке WiFi
Функция | Описание |
---|---|
WiFi.config | Позволяет установить статические IP-адреса платы, сервера имен (DNS) и шлюза |
WiFi.SSID | Возвращает строку идентификатора беспроводной сети SSID |
WiFi.RSSI | Возвращает значение мощности сигнала типа long |
WiFi.encriptionType | Возвращает числовой код, соответствующий методу шифрования |
WiFi.scanNetworks | Возвращает количество найденных сетей, но никакой дополнительной информации о них не возвращается |
WiFi.macAddress | Помещает MAC-адрес адаптера WiFi в шестибайтный массив, переданный как параметр |
Пример использования WiFi
Для этого примера я изменил скетч sketch_12_02_server, адаптировав его для работы с платой расширения WiFi. Полный исходный код можно найти в скетче sketch_12_04_server_wifi. Я не буду повторять пример целиком, только отмечу отличия от оригинальной версии.