Cервер домашней метеостанции на Arduino + Виджет на Android для вывода данных

Одним из первых моих проектов при изучении Arduino была работа с цифровым датчиком температуры DS18B20. Затем я подключил три датчика DS18B20 и отправлял показания на сайт. Не так давно приобрел датчик температуры и влажности и к конкурсу решил создать проект сервера домашней метеостанции, при обращению к которому выдаются результаты с датчиков по JSON и написать виджет к телефону Android, показывающий данные показания. Виджет выводит показания с датчиков при нахождении дома (домашняя сеть), или из любого другого места при подключении телефона к интернету.

Создание домашнего сервера метео на Arduino

Дома подключены три датчика DS18B20 и один датчик DHT11

Схема подключения следующая:
arduino79-1
При написании программы использовались следующие библиотеки Arduino

    Ethernet — библиотека для работы с Ethernet-shield
    spi — взаимодействовать с устройствами поддерживающими SPI протокол
    onewire — взаимодействие с устройствами по протоколу 1-Wire
    dht — Arduino библиотека для работы с датчиками DHT11,DHT22

Создаем web-сервер, присваиваем ip и порт обращения 10001, и при обращении к серверу опрашиваем датчики DS18B20 и DHT11. Чтобы сервер не тратил время на опрос и поиск кодов датчиков DS18B20 я внес уже полученные коды в массив my_addr. Результат сервер отдает в формате JSON.
arduino79-2

Вот код скетча

#include "Ethernet.h"
#include "SPI.h"
#include "OneWire.h"
#include "DHT.h"
#define DHTTYPE DHT11 // DHT 11
DHT dht(8, DHTTYPE);
OneWire ds(7); // on pin 7
byte mac[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
// IP адрес, назначаемый Ethernet shield:
byte ip[] = { 192, 168, 1, 111 };
EthernetServer server(10001);

// коды датчиков DS18B20

byte my_addr[3][8]={{0x28,0x81,0xC4,0xBA,2,0,0,0x3B},
{0x28,0x67,0xE5,0xC7,2,0,0,0xA0},
{0x28,0xF6,0x98,0xBA,2,0,0,0x92}};

void setup() {
Serial.begin(9600);
Serial.println("start");
// инициализация Ethernet shield
Ethernet.begin(mac, ip);
// запуск сервера
server.begin();
Serial.print("server ip ");
Serial.println(Ethernet.localIP());
}

void loop ()
{
EthernetClient client = server.available();
if (client) {
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.print('{');
client.print('"');client.print("meteo");client.print('"');client.println(":");
client.print('{');
for(int j=1;j<4;j++) { //Serial.print("temp");Serial.print(j);Serial.print("="); //int Temp=get_temp(j); //Serial.print(Temp/16);Serial.print(".");Serial.println(((Temp%16)*100)/16); client.print('"');client.print("temp");client.print(j);client.print('"');client.print(":"); client.print('"');client.print(Temp/16); client.print("."); client.print(((Temp%16)*100)/16);client.print('"');client.print(','); } float h = dht.readHumidity(); float t = dht.readTemperature(); //Serial.print('"Humidity4":'); Serial.println(h);Serial.print(" %\t"); //Serial.print('"Temp4":'); Serial.print(t);Serial.println(" *C"); client.print('"');client.print("temp4");client.print('"');client.print(":"); client.print('"');client.print(t);client.print('"');client.print(','); client.print('"');client.print("humidity4");client.print('"');client.print(":"); client.print('"');client.print(h);client.print('"'); client.println("}"); client.print("}"); break; } if (c == '\n') { currentLineIsBlank = true; } else if (c != '\r') { currentLineIsBlank = false; } } } delay(1); client.stop(); } } // получение температуры датчика int get_temp(int nn) { byte i; byte present = 0; byte data[12]; byte addr[8]; int Temp; ds.reset(); ds.select(my_addr[nn-1]); ds.write(0x44,1); // start conversion, with parasite power on at the end delay(1000); // maybe 750ms is enough, maybe not // we might do a ds.depower() here, but the reset will take care of it. present = ds.reset(); ds.select(my_addr[nn-1]); ds.write(0xBE); // Read Scratchpad for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } Temp=(data[1]<<8)+data[0]; Temp=Temp; return Temp; }

Теперь пишем виджет на Android, чтобы на телефоне видеть показания датчиков, находясь в любом месте при наличии соединения с интернет.

Виджеты — это маленькие приложения, которые могут быть размещены на рабочем столе вашего Android-устрйства. Виджет периодически получает новые данные и обновляет свой вид.

Для создания виджета вам необходимо:
1. Создать XML-layout файл со слоем, в котором описывается внешний вид виджета.
2. Создать XML файл метаданных, в котором задаются различные характеристики виджета:

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

3. Создать BroadcastReceiver, который будет использован для обновления виджетов. Этот приёмник расширяет AppWidgetProvider, который обеспечивает жизненный цикл виджета.
4. Изменения в файле AndroidManifest.xml

Рассматривать программирование на Android я здесь не буду, займет слишком много места. Проблем при программировании обнаружилось много, сначала делал для Android 2.1, этот код для Android 2.3 уже давал ошибки при работе со строками, измененный код не пошел для Android 3.2 - изменились методы получения сетевых данных (работа стала возможна только в отдельном потоке), для Android 4.0 проверить не на чем, эмулятор постоянно виснет, а устройств нет. В общем времени для написания программы ушло больше недели. Для тех кому интересно в конце топика выложена ссылка на файлы данного проекта проекта для среды Eclipse.

При запуске виджета он пытается соединиться с внутренней сетью (192.168.1.111:10001 на тот случай, если я нахожусь дома), при неудаче с адресом в сети интернет хх.хх.хх.хх:10001

Если соединение удачно - парсим JSON-ответ выводим данные виджете и обновляем виджет

arduino79-3

При неудаче - сообщение в виджет об отсутствии соединения

arduino79-4

При нажатии на иконку происходит обновление данных.
У меня дома интернет через ADSL-модем, необходимо открыть порт 10001

arduino79-5 (1)

Скетч Arduino
Проект в Eclipse для Android

4 comments

  1. Доброго дня! Напоминаю — с помощью Ethernet shield на Arduino поднят Web-сервер, который при обращении к нему, опрашивает датчики и отдает результат в формате JSON.

  2. I loved as much as you’ll receive carried out right here. The sketch is tasteful, your authored subject matter stylish. nonetheless, you command get got an nervousness over that you wish be delivering the following. unwell unquestionably come more formerly again as exactly the same nearly very often inside case you shield this increase.

  3. Да это более правильное решение. Мне желательно иметь сервер метео в домашней сети — обращение к серверу из ROS и голосовое оповещение о погоде — хотя и здесь можно обращаться к сайту, но на случай отсутствия интернета

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

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

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>