Скетч Arduino с огромным числом датчиков DS18B20. TEST!!!

Использование системы в различных ситуациях, вопросы программирования сценариев.

Модератор: immortal

tsember
Сообщения: 52
Зарегистрирован: Ср фев 04, 2015 12:28 am
Благодарил (а): 54 раза
Поблагодарили: 6 раз

Скетч Arduino с огромным числом датчиков DS18B20. TEST!!!

Сообщение tsember » Вт мар 24, 2015 12:02 pm

Здравствуйте.
Начал осваивать МЖД. Купил ардуино, датчики 18B20. Загрузил скетч (http://smartliving.ru/Main/ArduinoSchema).
Для освоения скетч хороший. Но меня не устраивало, что при подключении нового датчика, постоянно требовалось вносить изменения в код и перезаливать его в плату Arduino (перед этим отключив все шилды), что, согласитесь, крайне не удобно.

Решил написать универсальный скетч (который бы и команды на реле посылал, и всевозможные датчики бы контролировал, а самое главное - чтоб умел самостоятельно найти, определить и отсылать информацию на сервер MJD).

Представляю Вашему вниманию Universal Arduino sketch for MajorDoMo: https://github.com/petertsermber/arduin ... orDoMo.ino

Пока работает только с датчиками 18B20 (но я в ближайшем будущем добавлю поддержку распространенных датчиков: DHT (влажности и температуры), BPM085 (давления и температуры, PIR (датчик движения), а так же модуля управления реле на 4 канала).

Ардуино ищет подключенные с 1-wire шине датчики, определяет их адреса, заносит в массив.
Далее по циклу, с каждого датчика получаем температуру, округляем ее до десятых, сравниваем с прошлой отправленной на сервер температурой. Если дельта больше 0,3 градуса, то отправляем данные на сервер МЖД. Идентификатором на сервере служит адрес датчика в HEX формате. Затем цикл повторяется.
Для "горячего" подключения датчиков требуется всего лишь "железно" подцепить датчик к шине, а в МажорДоМо добавить новый объект с именем типа 28156B15060000A7 (Адрес нового датчика можно узнать в стандартной программе типа Hyper Terminal), в котором существует свойство temp. Ну и должен присутствовать стандартный метод tempSensors-> tempChanged (который присутствует в стандартном дистрибутиве MJD). ВСЕ! Никаких перепрограммирований, перепрошиваний и прочего!

P.S. Я не программист, си++ вообще впервые увидел три недели назад, если что в коде не так, прошу сильно не ругать, а здесь написать.

Спасибо.
За это сообщение автора tsember поблагодарили (всего 5):
Amarok (Вт мар 24, 2015 12:08 pm) • Supermin (Пт мар 27, 2015 4:18 pm) • savenko_egor (Пн мар 30, 2015 11:00 am) • denis (Вс апр 19, 2015 7:30 pm) • astotskiy (Пн апр 27, 2015 10:17 pm)
Рейтинг: 5.81%
karlismoto
Сообщения: 39
Зарегистрирован: Чт окт 16, 2014 11:12 pm
Благодарил (а): 5 раз
Поблагодарили: 0
Контактная информация:

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение karlismoto » Чт мар 26, 2015 10:27 pm

Интересно!
посмотрим что и как :)
Windows7 + MajorDoMo.
HP laptop, MegaD modules, Arduino Megas, DS18B20, DHT-11 and other sensors.
DSC Alarm + envisalink 3
Connect
vova5049
Сообщения: 64
Зарегистрирован: Пт фев 21, 2014 10:56 am
Откуда: Днепропетровск
Благодарил (а): 1 раз
Поблагодарили: 5 раз

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение vova5049 » Пт мар 27, 2015 1:25 am

))) Это, конечно не влияет на функциональность, но в комментарии к 20-ой строке ip-адрес сервера MajorDoMo лучше заменить на маска подсети (netmask)
2*MegaD328, Система на Raspberry Pi 2
Lordserdjo
Сообщения: 5
Зарегистрирован: Вс мар 29, 2015 9:34 pm
Благодарил (а): 0
Поблагодарили: 0

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение Lordserdjo » Вс мар 29, 2015 9:43 pm

крутой скетч. Даже удивительно что не программист. При отключении датчика температуры от ардуины, мажор домо показывает ноль градусов. Как доработать скетч что бы при отключении была температура -100 допустим или +300, явно невозможная, сигнализирующая, что датчик неисправен?
tsember
Сообщения: 52
Зарегистрирован: Ср фев 04, 2015 12:28 am
Благодарил (а): 54 раза
Поблагодарили: 6 раз

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение tsember » Вс мар 29, 2015 11:43 pm

Lordserdjo писал(а):крутой скетч. Даже удивительно что не программист. При отключении датчика температуры от ардуины, мажор домо показывает ноль градусов. Как доработать скетч что бы при отключении была температура -100 допустим или +300, явно невозможная, сигнализирующая, что датчик неисправен?
Была такая проверка. При температуре DEVICE_DISCONNECTED на сервер отправлялся гет запрос с температурой 200 градусов (предварительно в методе changeTemp увеличил максимальную температуру до 200). Тем самым я понимаю, что датчик отвалился.
Но отказался от этого, так как посчитал, что при отключении датчика мы уберем его и с МЖД?!

Я думал, что скетч никого не заинтересует, поэтому на форуме не появлялся. Рассказываю дальше.
А дальше я пошел еще дальше:
Захотелось мне добавить к объектам температуры свойство с дельтой, при превышении которой идет отправка данных на сервер. У каждого датчика температуры должна быть своя дельта. У одного - 0,2 градуса (минимальная адекватная чувствительность 18в20), у другого - 2 градуса. Для чего это?! Например, один датчик у нас установлен на улице, второй - в комнате.
Первым мы просто регистрируем уличную температуру, а из второго делаем ВЫСОКОТОЧНЫЙ комнатный термостат.
Понятное дело, что и дельта для них должна быть разная.
Думал, чтоб при GET отправке температуры на сервер, так же отправлялась текущая дельта для ДАННОГО датчика. Сервер сравнивает дельты текущую в ардуинке и прописанную в МЖД. Если они не совпадают - отправляем новую дельту на ардуино, а там запускается обработка по присвоению новой дельты для текущего датчика. Как то так.

Но планам не суждено было сбыться.
Если на ардуино запускать web-server (webduino), то по каким то причинам не работает цикл:

for (int i=0; i<8; i++) // цикл получения бит адреса
{
if (Termometers < 16) { aba = "0"+String(Termometers,HEX); } //если бит меньше 16, то дописываем в начале 0, так же конвертируем в шеснадцатиричный код
else {aba = String(Termometers,HEX);}// в противном случае просто конвертируем в 16ричный код и записываем байт в массив

Смысл его в чем: получает каждый байт адреса датчика температуры, переводит его в шеснадцатиричный код, если цифра получилась одна, то добавляем нолик впереди, и записываем каждый байт адреса в HEX формате в i-ячейку массива адреса.

После склеивания всех ячеек:
aa = aba[0]+aba[1]+aba[2]+aba[3]+aba[4]+aba[5]+aba[6]+aba[7]
получалась переменная aa , в которой содержалось имя датчика , например 28156B15060000A7.

Дак вот. Это цикл никак не хочет дружить с функцией webserver.processConnection(buff, &len); , которая следит за входящими подключениями к ардуино.
Что только не перепробовал. Результата нет.

Решил, что будет 2 ардуино: один - контроллер датчиков, другой - исполнительное устройство .
Конечно можно было сервер оставить, и сделать одно устройство, но тогда бы я лишился фишки, ради которой я все это задумал - отправку адреса датчика на сервер МЖД.
Дельта пока установлена на 0,3 градуса (если дельта 0,4 и более - отправляем новую т.)

Вот такие вот пока дела.
Lordserdjo
Сообщения: 5
Зарегистрирован: Вс мар 29, 2015 9:34 pm
Благодарил (а): 0
Поблагодарили: 0

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение Lordserdjo » Пн мар 30, 2015 9:07 pm

можно вас попросить выложить скетч, где при отваливании датчика посылается на мажордомо 200 градусов
tsember
Сообщения: 52
Зарегистрирован: Ср фев 04, 2015 12:28 am
Благодарил (а): 54 раза
Поблагодарили: 6 раз

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение tsember » Пн мар 30, 2015 11:05 pm

Код: Выделить всё

/**
* Универсальный контроллер сбора данных и исполительное устройство на базе Arduino (к проекту http://smartliving.ru/)
* Platform: Arduino UNO R3 + EthernetShield W5100
* IDE: Arduino 1.6.1
* Author: Peter Tsember by Syktyvkar. 2015
**/

// ----==== ПОДКЛЮЧЕНИЕ БИБЛИОТЕК ====----
  #include <Ethernet.h>                                // (Ethernet Shield)
  #include <SPI.h>                                     // (Для работы с устройствами по протоколу SPI, например с Ethernet Shield)
  #include <Arduino.h>                                 // (Основная библиотека Arduino)
  #include <OneWire.h>                                 // (Шина 1-wire)
  #include <DallasTemperature.h>                       // (Датчик температуры DS18B20)


// ----==== НАСТРОЙКИ СЕТИ ====----
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xE4, 0xDE, 0x35 }; // MAC-адрес контроллера Arduino
  byte ip[] = { 192, 168, 1, 15 };                     // ip-адрес контроллера Arduino
  byte subnet[] = { 255, 255, 255, 0 };                // ip-адрес сервера MajorDoMo
  byte gateway[] = { 192, 168, 1, 250 };               // ip-адрес основного шлюза
  byte dns_server[] = { 192, 168, 1, 250 };            // ip-адрес DNS-сервера
  byte rserver[] = { 192, 168, 1, 123 };               // ip-адрес сервера MajorDoMo
  char buf[100];                                       // Переменная для хранения GET запроса
  char ipbuff[16];                                     // Переменная для IP адреса
  EthernetClient rclient;


// ----==== НАСТРОЙКИ ПОДКЛЮЧЕННЫХ УСТРОЙСТВ ====----
// Вход, на котором находится шина 1-wire с датчиками DS18S20
  #define ONE_WIRE_BUS 2                               // нога 2



// ----==== НАСТРОЙКИ ПЕРЕМЕННЫХ И МАССИВОВ ДАННЫХ ====----
  float current_temp1;                                 // Задаем переменную, в которой будем хранить текущую температуру
  float delta_temp = 0.3;                              // Дельта температур, при превышении которой следует отправлять данные на сервер МЖД
  long requestMillis;                                  // Задаем переменную времени последней передачи данных на сервер
  long interval = 18000000;                            // Задаем максимальный интервал между передачами данных на сервер
  byte numberOfDevices;                                // Количество датчиков DS18B20 на шине 1-wire (Обновляется автоматически)
  DeviceAddress Termometers;                           // Массив с датчиками
  // Размер следующих массивов - предполагаемое максимальное количество датчиков DS18B20.
  // По умолчанию - 30. Нужно больше?! Увеличиваете числа и перезаливаете скетч
  byte na[30];                                         // Массив с порядковыми номерами датчиков температуры DS18B20
  String aa[30];                                       // Массив с HEX-адресами датчиков температуры DS18B20
  float ta[30];                                        // Массив с последней отправленной температурой датчиков DS18B20


// Инициализация веб-сервера на 80 порту, а так же шины 1-wire и датчиков температуры DS18B20
  OneWire oneWire(ONE_WIRE_BUS);
  DallasTemperature sensors(&oneWire);


// ---=== ПОИСК ДАТЧИКОВ ТЕМПЕРАТУРЫ DS18B20 НА ШИНЕ 1-WIRE ===---
void TempSensorSearch()
{
  sensors.begin();                                   // Инициализация датчиков DS18B20
  sensors.requestTemperatures();                     // Перед каждым получением температуры надо ее запросить
  sensors.setResolution(Termometers, 12);            // Установка чувствительности на 12 бит 
//   Serial.print("Vsego datchikov: ");
   numberOfDevices = sensors.getDeviceCount(); 
//   Serial.println(numberOfDevices);                  // вывод на экран общего количества найденых датчиков
   
  for(byte i=0;i<numberOfDevices; i++) {            // цикл для записи в массивы данных
     if(sensors.getAddress(Termometers, i))          // если адрес датчика под индексом i определен, то:
      {        
      String aba[8];                                 // Создаем массив с байтами адреса 
       for (int i=0; i<8; i++)                        // цикл получения бит адреса
        { 
          if (Termometers[i] < 16) { aba[i] = "0"+String(Termometers[i],HEX); } //если бит меньше 16, то дописываем в начале 0, так же конвертируем в шеснадцатиричный код
          else {aba[i] = String(Termometers[i],HEX);}// в противном случае просто конвертируем в 16ричный код и записываем байт в массив
        }
      aa[i] = aba[0]+aba[1]+aba[2]+aba[3]+aba[4]+aba[5]+aba[6]+aba[7]; // Записываем полный адрес в массив адресов aa[], в ячейку i.      
//    Serial.print("Sensor "); Serial.print(i, DEC); Serial.print(" with address: "); // Датчик под номером i с адресом:
  //  Serial.println(aa[i]);                           // Выводим на экран i ячейку с 16-ричным адресом устройства  
       }
     }
}  
 
 
// ---=== ПОЛУЧЕНИЕ И ОБРАБОТКА ТЕМПЕРАТУРЫ ===---
void TempSensorSend()
{
for(byte i=0;i<numberOfDevices; i++)                 // цикл для получения, обработки, округления и отправки температуры каждого датчика DS18B20
    { 
      // Устройство отдало реальное значение температуры (или осталось старое)
      // Округление полученной температуры до десятых
      // Пример: 23.899 => 238.99 => 239.49 => 239 => 23.9) // При округлении изменился первый разряд, после запятой. Правило работает.
       float tempC = sensors.getTempCByIndex(i) * 10;
       tempC = tempC + 0.5;
       tempC = (int)tempC;
       tempC =  tempC / 10;
    float delta = fabsf(ta[i]-tempC);                // Выделяем дельту температуры, между текущей и в последний раз отправленной темп.
    if ((delta > delta_temp)                         // Если разница между прошлым и текущим значением темп. больше обозначенной дельты...
    || ((millis() - requestMillis) > interval))      // Если последняя передача данных на сервер была более 30 минут назад (например температура не менялась)...
     {  
     int temp1 = (tempC - (int)tempC) * 10;          // выделяем дробную часть
     int str_len = aa[i].length() + 1; char char_array[str_len]; aa[i].toCharArray(char_array, str_len);      // Конвертируем строку с адресом в массив символов
     sprintf(buf, "GET /objects/?object=%s&op=m&m=tempChanged&t=%0d.%d", char_array, (int)tempC, abs(temp1)); // Формируем GET запрос
      sendHTTPRequest();                             // И передаем на сервер
      requestMillis = millis();                      // Засекаем время последней передачи данных на сервер
      ta[i]=tempC;                                   // Задаем текущую температуру предыщущей.
     }
    }
}


// ---=== ФУНКЦИЯ ОТПРАВКИ ДАННЫХ (HTTP-ЗАПРОСА) НА СЕРВЕР MAJORDOMO ===---
void sendHTTPRequest() 
{ Serial.println (buf);
/*  if (rclient.connect(rserver, 80)) 
  { 
   Serial.println("OK"); 
   Serial.println(buf);                                 // Вывод на экран сгенерированного GET запроса
   rclient.print(buf);
   rclient.println(" HTTP/1.0");
   rclient.print("Host: ");
   sprintf(ipbuff, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
   rclient.println(ipbuff);                             // ip адрес нашего контроллера в текстовом виде
   rclient.print("Content-Type: text/html\n");
   rclient.println("Connection: close\n");
   \(10);
   rclient.stop();
  } else 
  { Serial.println("FAILED SENDING"); } */
}


// ---=== ФУНКЦИЯ НАСТРОЙКИ ===---
void setup()
  {
  Serial.begin(9600);                                   // Инициализируем Serial (монитор последовательного порта)
  Serial.println("Start");
  Ethernet.begin(mac, ip, dns_server, gateway, subnet); // Инициализируем Ethernet Shield/
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  }


// ---=== ЦИКЛИЧЕСКАЯ ФУНКЦИЯ ===---
void loop() {

  TempSensorSearch();
  TempSensorSend();
} 
Это почти последняя версия моего кода. Но тут без проверки на дисконнект датчика.


А если хотите проверить на условие дисконнекта, тогда в функции TempSensorSend() (смотрите по текущему моему скетчу) вначале нужно проверить:

Код: Выделить всё

 if (tempC == DEVICE_DISCONNECTED) { 
    // Устройство отсоединено
    Serial.println("Termometer is DEVICE_DISCONNECTED");
    // формирование запроса на сервер, что датчик не отвечает
tempC = 200;
     sprintf(buf, "GET /objects/?object=%s&op=m&m=tempChanged&t=%0d.%d", (int)tempC, abs(temp1)); // Формируем GET запрос
      sendHTTPRequest();                             // И передаем на сервер
      requestMillis = millis();                      // Засекаем время последней передачи данных на сервер
      ta[i]=tempC;  
  } else { ...
дальше пошел основной код
Этот код написал Вам "на лету". Возможно какая то переменная не совпадет, но ничего сложного.
Иными словами: перед тем, как округлять температуру до десятых и формировать запрос на ее отправку, мы сначала проверяем не отключен ли датчик. Если отключен, библиотека отправит сообщение DEVICE_DISCONNECTED. Если так, то отправляем на сервер 200 градусов. Надеюсь, я ответил на Ваш вопрос?!
tsember
Сообщения: 52
Зарегистрирован: Ср фев 04, 2015 12:28 am
Благодарил (а): 54 раза
Поблагодарили: 6 раз

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение tsember » Пн мар 30, 2015 11:08 pm

Lordserdjo писал(а):крутой скетч. Даже удивительно что не программист.
P.S. Я не программист, серьезно, просто через чур развито "чувство прекрасного". Люблю когда все красиво. Стараюсь сразу делать хорошо, а плохо и так получится.
tsember
Сообщения: 52
Зарегистрирован: Ср фев 04, 2015 12:28 am
Благодарил (а): 54 раза
Поблагодарили: 6 раз

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение tsember » Пн мар 30, 2015 11:09 pm

tsember писал(а):

Код: Выделить всё


// ---=== ФУНКЦИЯ ОТПРАВКИ ДАННЫХ (HTTP-ЗАПРОСА) НА СЕРВЕР MAJORDOMO ===---
void sendHTTPRequest() 
{ Serial.println (buf);
/*  if (rclient.connect(rserver, 80)) 
  { 
   Serial.println("OK"); 
   Serial.println(buf);                                 // Вывод на экран сгенерированного GET запроса
   rclient.print(buf);
   rclient.println(" HTTP/1.0");
   rclient.print("Host: ");
   sprintf(ipbuff, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
   rclient.println(ipbuff);                             // ip адрес нашего контроллера в текстовом виде
   rclient.print("Content-Type: text/html\n");
   rclient.println("Connection: close\n");
   \(10);
   rclient.stop();
  } else 
  { Serial.println("FAILED SENDING"); } */
}

[/quote]
В настоящее время ардуино передает данные через USB через arduino gate. Поэтому основная функция отправки по ethernet закоментирована.
Lordserdjo
Сообщения: 5
Зарегистрирован: Вс мар 29, 2015 9:34 pm
Благодарил (а): 0
Поблагодарили: 0

Re: Скетч Arduino с огромным числом датчиков DS18B20. TEST!!

Сообщение Lordserdjo » Вт мар 31, 2015 1:22 pm

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