От переводчика. В этой части руководства рассказывается как подключать к страницам Arduino сервера и использовать Javascript компоненты, в данном случае компонент стрелочного индикатора.

Это открывает поистине безграничные возможности для проектирования веб-страниц: вам доступны тысячи готовых Javascript компонентов для реализации различных функций и дизайна веб-интерфейсов для ваших проектов.


В этой части руководства рассматривается создание графического индикатора на веб-странице для отображения состояния одного из аналоговых входов Arduino. Значения индикатора обновляются при помощи Ajax.

Сам индикатор написан на JavaScript и использует HTML5 canvas. Индикатор используется как компонент (без изменений) и просто настраивается для отображения значения одного из аналоговых входов Arduino. Значения индикатора обновляются каждые 200 мс.

В этом видео показана работа сервера Arduino и индикатора, размещённого на веб-странице.

Компонент индикатора


Компонент индикатора «HTML Canvas Gauges» можно скачать на Github. Можно также ознакомиться со статьёй (на английском) в которой даны подробности использования компонента.

В этом уроке используется Javascript код из файла Gauge.min.js (загруженный по вышеприведенной ссылке).

Arduino скетч и веб-страница



Скетч Ардуино


Скетч Arduino для этого урока:

/*--------------------------------------------------------------
  Скетч: eth_websrv_SD_Ajax_gauge

  Описание:  Arduino сервер с SD картой, динамически отображающий на графическом индикаторе состояние аналогового входа при помощи Ajax.

  Оборудование: контроллер Arduino Uno, плата Ethernet Shield, microSD карта памяти 2 ГБ, потенциометр, подключённый на пин A2.
                
  Программное обеспечение: среда разработки Arduino IDE, microSD карта с файлом index.htm
  
  Ссылки:
    - WebServer example by David A. Mellis and modified by Tom Igoe
    - Ethernet library documentation: http://arduino.cc/en/Reference/Ethernet
    - Learning PHP, MySQL & JavaScript by Robin Nixon, O'Reilly publishers
    - SD Card library documentation: http://arduino.cc/en/Reference/SD
    - Gauge from: https://github.com/Mikhus/canv-gauge
  
  Дата создания: 27 марта 2013
  Изменения: 19 июня 2013
 
  Author:       W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 20); // IP-адрес (нужно изменить на актуальный для вашей сети)
EthernetServer server(80);

#define REQ_BUF_SZ   50
char HTTP_req[REQ_BUF_SZ] = {0}; // Хранится как null terminated string
char req_index = 0; // индекс буфера

File webFile;

void setup() {
    // отключение Ethernet
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);

    Serial.begin(115200);
    
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;
    }
    Serial.println("SUCCESS - SD card initialized.");

    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;
    }
    Serial.println("SUCCESS - Found index.htm file.");
    
    Ethernet.begin(mac, ip);
    server.begin();
}

void loop() {
    EthernetClient client = server.available();

    if (client) {
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {
                char c = client.read();  // получаем очередной байт (символ) от клиента
                // сохраняем последний элемент массива 0 (null terminate string)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c; // сохраняем символ HTTP запроса
                    req_index++;
                }

                if (c == '\n' && currentLineIsBlank) {
                    // Посылаем http заголовок
                    client.println("HTTP/1.1 200 OK");
                    // HTML или XML запрос
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();
                        XML_response(client);
                    } else {
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();
                        webFile = SD.open("index.htm");
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read());
                            }
                            webFile.close();
                        }
                    }
                    Serial.print(HTTP_req);
                    // Обнуляем массив (буфер)
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                if (c == '\n') {
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);
        client.stop();
    } // end if (client)
}

// Посылаем XML файл
void XML_response(EthernetClient cl) {
    int analog_val;
    
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
    // read analog pin A2
    analog_val = analogRead(2);
    cl.print("<analog>");
    cl.print(analog_val);
    cl.print("</analog>");
    cl.print("</inputs>");
}

// Обнуление массива
void StrClear(char *str, char length) {
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// Поиск подстроки
// 1, если найдена
// 0, если не найдена
char StrContains(char *str, char *sfind) {
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}

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

Скетч отправляет значение аналогового входа A2 в браузер, которое затем отображается на индикаторе на веб-странице. Состояние индикатора обновляется с помощью Ajax, а значение аналогового входа A2 передаётся как часть XML файла (от Arduino сервера к браузеру).

Веб-страница, размещенная на сервере Arduino, хранится на microSD карте памяти, подключённой к плате Arduino Ethernet Shield.

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


Ниже показано содержание веб-страницы этого примера (без кода самого индикатора).



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

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

Индикатор


Индикатор подключается к веб-странице путем вставки его кода между тегами script в заголовке страницы.

Индикатор отображается в теле страницы (body) с помощью HTML5 тега canvas.

Обновление индикатора


Значение входа A2 Arduino принимается браузером и отображается на веб-странице так же, как и в предыдущей части этого руководства. Также значение входа A2 сохраняется в Javascript переменной data_val, чтобы индикатор мог его использовать.

Значение в data_val передается индикатору с помощью Javascript строки в свойстве data-onready тега canvas:

setInterval( function() {Gauge.Collection.get('an_gauge_1').setValue(data_val);}, 200);

Цифра 200 в вышеприведенной строке предписывает индикатору обновляться каждые 200 миллисекунд.

Интервалы


Индикатор обновляется каждые 200 мс, и периодичность Ajax запросов также установлена на 200 мс.

Интервал для Ajax запросов задаётся в следующей строке Javascript кода:

setTimeout('GetArduinoInputs()', 200);

Такая частота следования Ajax запросов может вызвать проблемы в загруженной или медленной сети. Если у вас появятся какие-то проблемы с этим, попробуйте изменить это значение на 1000, чтобы запросы производились реже, один раз в секунду.

Запуск скетча


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

Скопируйте веб-страницу index.htm (см. ниже) на microSD карту памяти и вставьте ее в слот на плате Arduino Ethernet Shield.

Загрузите вышеприведенный скетч на плату Arduino сервера.

Исходный код веб-страницы


Загрузите исходный код веб-страницы (файл index.htm) здесь:

Arduino_web_gauge.zip (6,3 КБ)

Лицензия на индикатор (MIT) включена в архив в виде текстового файла.

От переводчика о 13-й части


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

В этом примере автор использует «сжатый» и практически нечитаемый вариант Javascript кода индикатора, который целым куском «как есть» вставляет в тело страницы. Такой подход может вызвать некоторые проблемы в понимании у новичков — просто относитесь к этому куску кода как к «чёрному ящику», для нас здесь важным является только механизм обновления переменной data_val, остальное делает «магия» компонента индикатора.

Ну и должно быть понятно, что по такому (или подобному) принципу можно подключить к веб-странице множество других Javascript компонентов.

Часть 1, часть 2, часть 3, часть 4, часть 5, часть 6, часть 7, часть 8, часть 9, часть 10, часть 11, часть 12.


Комментарии (0)