"Умный дом" на Arduino - часть вторая

Умный дом на Arduino

Продолжение «Умного дома» на базе Arduino.



Перед прочтением необходимо ознакомиться с первой частью.



В этой части будет описано, плавное управление освещением (диммер, далее ШИМ) и сохранение значений в энергонезависимую память EEPROM.

То есть, после отключения питания и последующего включения, включится то, что работало до обесточивания.
Использование EEPROM полезно там, где существуют перебои с энергоснабжением (например дача).


Посмотреть, понажимать и подвигать можно здесь...

Видео
Управлял с ipadа, было крайне не удобно. И почему-то не видно зелёных кругов, а они есть )))




Нажатие на кнопки будет включать/отключать соответствующие пины, а управление ползунками будет увеличивать/уменьшать ШИМ на D5 и D6.

Внутри индикаторов расположены полукруглые кнопки с помощью которых можно мгновенно отключить и включить ШИМ. При включении вернётся то значение ШИМа, которое было установлено при отключении.


По ходу статьи, будет даваться более детальное описание.



На всякий случай:

Установка OpenWrt на роутер.

Установка сервера Lighttpd.

Подключение Ардуино к роутеру.


Все действия справедливы для любого роутера с OpenWrt или компьютера с image


Ардуина...


В первую очередь нужно обнулить EEPROM. Прошейте в ардуино этот скетч:


#include <EEPROM.h>

void setup()
{
  // write a 0 to all 512 bytes of the EEPROM
  for (int i = 0; i < 512; i++)
    EEPROM.write(i, 0);

  // turn the LED on when we're done
  digitalWrite(13, HIGH);
}

void loop()
{
}

Теперь все ячейки EEPROM равны нулю.


Залейте в ардуину основной скетч:


#include <EEPROM.h>

byte d2 = EEPROM.read(2);     // флаги (состояние пинов) хранится в EEPROM, считываем их
byte d3 = EEPROM.read(3);
byte d4 = EEPROM.read(4);
int shim1 = EEPROM.read(5); // значение ШИМ хранится в EEPROM, считываем их
int shim2 = EEPROM.read(6);
byte d11 = EEPROM.read(11);
byte d12 = EEPROM.read(12);
byte d13 = EEPROM.read(13);

byte descript[5]; // массив

void setup() 
{
  Serial.begin(57600);
  pinMode(2, OUTPUT); 
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  
  if(d2) digitalWrite(2, HIGH); else digitalWrite(2, LOW); // если до перезагрузки d2 была включена, то включаем, если нет, то нет 
  delay(500); // чтобы не включалось всё сразу, делаем паузы
  if(d3) digitalWrite(3, HIGH); else digitalWrite(3, LOW);
  delay(500);
  if(d4) digitalWrite(4, HIGH); else digitalWrite(4, LOW);
  delay(500);
  analogWrite(5, shim1 * 2.55); // включаем ШИМ d5
  delay(500);
  analogWrite(6, shim2 * 2.55); // включаем ШИМ d6
  delay(500);
  if(d11) digitalWrite(11, HIGH); else digitalWrite(11, LOW);
  delay(500);
  if(d12) digitalWrite(12, HIGH); else digitalWrite(12, LOW);
  delay(500);
  if(d13) digitalWrite(13, HIGH); else digitalWrite(13, LOW);
}
  
void loop() 
{  
  if (Serial.available()>4) // ждём дескриптор и нужный символ
   {
    if (Serial.read()=='Y') // проверяем первый символ, если это 'Y', то продолжаем принимать, если нет, то выходим из цикла чтения
     {
      for (byte i=0; i < 5; i++)
        {
           descript[i] = Serial.read(); // добавляем символы в массив   
        } 
        
    if((descript[0] =='+') && (descript[1] =='=') && (descript[2] =='Z')) // проверяем дескриптор
     {
      switch (descript[3])
       {
         case 'o': // обновление
         glavnaia(); // отправка ответа
         break;
         
         case 'A': // d2 вкл
         digitalWrite(2, HIGH); // вкл d2
         d2 = 1; // ставим флаг в единицу (вкл)
         EEPROM.write(2, d2); // записываем состояние d2 в ячейку №2 EEPROM 
         glavnaia(); // отправка ответа
         break;
         
         case 'a': // d2 откл
         digitalWrite(2, LOW); // откл d2
         d2 = 0; // ставим флаг в ноль (откл)
         EEPROM.write(2, d2); // записываем состояние d2 в ячейку №2 EEPROM 
         glavnaia(); // отправка ответа
         break; 
 
         case 'B': // d3
         digitalWrite(3, HIGH);
         d3 = 1;
         EEPROM.write(3, d3);
         glavnaia();
         break;
         
         case 'b': // d3
         digitalWrite(3, LOW);
         d3 = 0;
         EEPROM.write(3, d3);
         glavnaia();
         break;          
  
         case 'C': // d4
         digitalWrite(4, HIGH);
         d4 = 1;
         EEPROM.write(4, d4);
         glavnaia();
         break;
         
         case 'c': // d4
         digitalWrite(4, LOW);
         d4 = 0;
         EEPROM.write(4, d4);
         glavnaia();
         break;   
  
         case 'D': // d5 прибавляем shim1
         shim1++; // прибавляем
         if(shim1 > 100) shim1 = 100;  // если больше ста, то будет сто
         EEPROM.write(5, shim1); // записываем значение в ячейку №5 EEPROM 
         analogWrite(5, shim1 * 2.55); // включаем ШИМ D5 
         glavnaia(); // функция отправки ответа
         break;
         
         case 'd': // d5 убавляем shim1
         shim1--;
         if(shim1 < 1) shim1 = 0;
         EEPROM.write(5, shim1);
         analogWrite(5, shim1 * 2.55);
         glavnaia();
         break; 
  
         case 'E': // d6 прибавляем shim2
         shim2++;
         if(shim2 > 100) shim2 = 100;
         EEPROM.write(6, shim2);
         analogWrite(6, shim2 * 2.55);
         glavnaia();
         break;
         
         case 'e': // d6 убавляем shim2
         shim2--;
         if(shim2 < 1) shim2 = 0;
         EEPROM.write(6, shim2);
         analogWrite(6, shim2 * 2.55);
         glavnaia();
         break;   
  
         case 'F': // мгновенное включение ШИМ на D5
         shim1 = EEPROM.read(5); // считываем значение ШИМ из EEPROM
         analogWrite(5, shim1 * 2.55); // включаем ШИМ D5
         glavnaia();
         break;
         
         case 'f': // мгновенное отключение ШИМ на D5
         shim1 = 0;
         analogWrite(5, shim1); // отключаем ШИМ D5, но НЕ записываем в EEPROM
         glavnaia();
         break;  
 
         case 'G': // мгновенное включение ШИМ на D6
         shim2 = EEPROM.read(6); // считываем значение ШИМ из EEPROM
         analogWrite(6, shim2 * 2.55); // включаем ШИМ D6
         glavnaia();
         break;
         
         case 'g': // мгновенное отключение ШИМ на D6
         shim2 = 0;
         analogWrite(6, shim2); // отключаем ШИМ D6, но НЕ записываем в EEPROM
         glavnaia();
         break;  
 
         case 'J': // d11
         digitalWrite(11, HIGH);
         d11 = 1;
         EEPROM.write(11, d11);
         glavnaia();
         break;
         
         case 'j': // d11
         digitalWrite(11, LOW);
         d11 = 0;
         EEPROM.write(11, d11);
         glavnaia();
         break;  
        
         case 'K': // d12
         digitalWrite(12, HIGH);
         d12 = 1;
         EEPROM.write(12, d12);
         glavnaia();
         break;
         
         case 'k': // d12
         digitalWrite(12, LOW);
         d12 = 0;
         EEPROM.write(12, d12);
         glavnaia();
         break;         
      
         case 'M': // d13
         digitalWrite(13, HIGH);
         d13 = 1;
         EEPROM.write(13, d13);
         glavnaia();
         break;
         
         case 'm': // d13
         digitalWrite(13, LOW);
         d13 = 0;
         EEPROM.write(13, d13);
         glavnaia();
         break;
 
         default:
         glavnaia();
       }
     }
   
    else // если дескриптор ложный, то очищаем буфер
      {
        for(byte i=0; i < 255; i++) 
         {
           Serial.read();    
         } 
      } 
     }    // конец if (Serial.read()=='Y')
   }    // конец чтение порта
 
} // конец loop


void glavnaia() // отправка данных
 {
      Serial.print(d2);//0
      Serial.print(",");
      Serial.print(d3);//1
      Serial.print(",");
      Serial.print(d4);//2
      Serial.print(",");
      Serial.print(0);//3  //  пока отключаем, потом пригодится 
      Serial.print(",");
      Serial.print(0);//4  //  пока отключаем, потом пригодится 
      Serial.print(",");
      Serial.print(0);//5 //  пока отключаем, потом пригодится 
      Serial.print(",");
      Serial.print(0);//6 //  пока отключаем, потом пригодится 
      Serial.print(",");
      Serial.print(0);//7  //  пока отключаем, потом пригодится 
      Serial.print(",");
      Serial.print(0);//8 //  пока отключаем, потом пригодится 
      Serial.print(",");
      Serial.print(d11);//9
      Serial.print(",");
      Serial.print(d12);//10
      Serial.print(",");
      Serial.print(d13);//11 
      Serial.print(",");
      Serial.print(shim1); // 12 отсылается 
      Serial.print(",");
      Serial.println(shim2); // 13 отсылается 14 значений разделённых запятой
 }

Протокол обмена данными с ардуиной описан здесь.

Как работает

Кнопки:

Кнопки умный дом stD

Нажатие на кнопку (например D13) включит светодиод и запишет в EEPROM единицу. В веб-интерфейс отправится флаг 1 сообщающий о том, что включение выполнено. Кнопка подсветится.

При повторном нажатии, светодиод погаснет и в EEPROM запишется ноль. В веб-интерфейс отправится флаг 0 сообщающий о том, что отключение выполнено. Кнопка поменяет цвет.

Говоря иными словами, в веб-интерфейсе отображается только гарантированно выполненная команда.


...
         case 'M': // d13
         digitalWrite(13, HIGH); // включили
         d13 = 1; // установили флаг
         EEPROM.write(13, d13); // записали его в память
         glavnaia(); // функция отправки ответа
         break;
         
         case 'm': // d13
         digitalWrite(13, LOW);
         d13 = 0;
         EEPROM.write(13, d13);
         glavnaia();
         break;
...


Если включить D13 и обесточить ардуину, то при последующем включении ардуина прочитает соответствующую ячейку памяти:


...
byte d13 = EEPROM.read(13);
...

И если там была единица, то в блоке void setup(), автоматически включится светодиод:


...
  delay(500);
  if(d13) digitalWrite(13, HIGH); else digitalWrite(13, LOW);

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


Чтобы отключить «автоматическое» управление, например для пина d2, надо в начале кода переправить это:


byte d2 = EEPROM.read(2);

на это:

byte d2 = 0;


В void setup() убрать строки:


...
if(d2) digitalWrite(2, HIGH); else digitalWrite(2, LOW); 
delay(500);
...


И в блоке switch (descript[3]) закомментировать запись в EEPROM, вот так:


...
         ////////////// Кнопки ///////////////////
         case 'A': // d2 вкл
         digitalWrite(2, HIGH); // вкл d2
         d2 = 1; // ставим флаг в единицу (вкл)
         //EEPROM.write(2, d2); // записываем состояние d2 в ячейку №2 EEPROM 
         glavnaia(); // отправка ответа
         break;
         
         case 'a': // d2 откл
         digitalWrite(2, LOW); // откл d2
         d2 = 0; // ставим флаг в ноль (откл)
         //EEPROM.write(2, d2); // записываем состояние d2 в ячейку №2 EEPROM 
         glavnaia(); // отправка ответа
         break; 
...




Диммер:

Умный дом stD

Диапазон значений ШИМ от 0 до 255, ардуина получает (от клиента) значения в диапазоне от 0 до 100, которые внутри программы умножаются на 2.55 и выводятся на «ножку».


         case 'D': // d5 прибавляем shim1
         shim1++; // прибавили 
         if(shim1 > 100) shim1 = 100; // если больше ста, то будет сто
         EEPROM.write(5, shim1); // записали значение в память
         analogWrite(5, shim1 * 2.55); // зажгли лампочку
         glavnaia(); // функция отправки ответа
         break;
         
         case 'd': // d5 убавляем shim1
         shim1--;
         if(shim1 < 1) shim1 = 0;
         EEPROM.write(5, shim1);
         analogWrite(5, shim1 * 2.55);
         glavnaia();
         break; 


Когда Вы сдвигаете ползунок в веб-интерфейсе, то в ардуину отсылается команда увеличить/уменьшить ШИМ на единицу (и так далее пока двигаете ползунок). Переменная shim1++; увеличивается, её значение помещается в память, и на пин подаётся shim1 умноженый на 2.55.

После этого значение shim1 отсылается обратно в веб-интерфейс и присваиваются индикатору и ползунку.
То есть, индикатору и ползунку будет присвоено то значение, которое гарантированно выполнено ардуиной.

Если часть данных потеряется, ползунок сам отодвинется.


Если нажать на кнопку внутри индикатора:

Умный дом stD

То в ардуину отправится команда обнуляющая значение shim1


         case 'F': // мгновенное включение ШИМ на D5
         shim1 = EEPROM.read(5); // считываем значение ШИМ из EEPROM
         analogWrite(5, shim1 * 2.55); // включаем ШИМ D5
         glavnaia();
         break;
         
         case 'f': // мгновенное отключение ШИМ на D5
         shim1 = 0;
         analogWrite(5, shim1); // отключаем ШИМ D5, но НЕ записываем в EEPROM
         glavnaia();
         break; 


При этом, в память ничего НЕ записывается, а нажатие на соседнюю кнопку вернёт значение из памяти.
(так удобнее отключать свет, нежели ползунок сдвигать)


Веб...

Скачайте архив и распакуйте его в рабочую папку сервера (по умолчанию это /var/www), как то так – /var/www/knopki_shimpolz (у вас может быть своя папка).

В браузере зайдите по адресу ваш_роутер/knopki_shimpolz/. Должна появиться вот такая картинка:

Умный дом на Arduino


Как это работает

  Для наглядности откройте файл index.html из архива, и почитайте комментарии.

Работа кнопок описана в предыдущей части.



Диммер:

При первой загрузки страницы, срабатывает функция обновления — show(); (в дальнейшем она работает с установленым интервалом) и у ардуины вместе с другими данными запрашиваются значения ШИМ:


/*обновление*/
show();
setInterval(show,2000);  /* частота обновления в милисекундах */
function show(){  /* функция обновления */
if(flagobnov == 1) { /* это флаг нужен для временного отключения обновления */
            $.ajax({ 
                type: "GET",
	        url: "box2.php?df=o", /* отправка символа о */
                timeout:200, /* время (мс), в течении которого функция будет ждать ответа от сервера */          
                cache: false,       
                success: function(data){   
                                          
                           var vars = data.split(","); /* разбор строки принятой от ардуино */
                           if(vars.length == dlina){ /* проверка длины данных (количество блоков разделённых запятой) */
                               
                               /*d2*/
                               if(vars[0] == 1) { $(".d2otkl").show(); $(".d2vkl").hide(); }  /* в зависимости от принятого флага скрывает/показавыет кнопку вкл или откл */
                               else if(vars[0] == 0) { $(".d2otkl").hide(); $(".d2vkl").show(); } 

                               /*d3*/
                               if(vars[1] == 1) { $(".d3otkl").show(); $(".d3vkl").hide(); }
                               else if(vars[1] == 0) { $(".d3otkl").hide(); $(".d3vkl").show(); }

                               ...

			       shim1 = vars[12]; /* получаем значение ШИМ */ 
			       sh1(); /* и выводим его на первый индикатор */ 

			       shim2 = vars[13]; 
			       sh2();

                               ...        


После получения значения shim1, программа переходит в функцию sh1();


function sh1(){ /* рисование первого индикатора */
  var $ppc = $('.progress-pie-chart'),
    percent = shim1,
    deg = 360*percent/100;
  if (percent > 50) {
    $ppc.addClass('gt-50');
  }
  else $ppc.removeClass('gt-50');
  $('.ppc-progress-fill').css('transform','rotate('+ deg +'deg)');
  $('.ppc-percents span').html(percent+' %       D5  '); /* название на кнопке - D5 */
  sl1();
}

Значение shim1 выводится на индикатор (зелёный кружок) и работа передаётся в функцию sl1();


Функция sl1(); устанавливает ползунок в соответствии со значением shim1


function sl1(){ /* первый слайдер */
       $( "#slider" ).slider({
       value : shim1,
       min : 0,
       max : 100,
       step : 1,
       slide: function( event, ui ) {
       
       ...

Теперь функция slide: function( event, ui ) ожидает движения ползунка.


Когда ползунок будет сдвинут в ту или иную сторону на одно деление, сработает следующий алгоритм:

Отключается обновление


flagobnov = 0;


Проверяется в какую сторону сдвинут ползунок (в большую или меньшую)


if( ui.value > shim1 ){


else if( ui.value < shim1 ){


В ардуину отправляется символ указывающий увеличить (уменьшить) ШИМ на единицу


$.ajax({  
    type: "GET",  
    url: "box2.php?df=D", /* говорим ардуине что надо увеличить ШИМ  на единицу */


Получаем новое значение ШИМ от ардуины и вызывает функцию отрисовки индикатора (sh1();) с новым значением


shim1 = vars[12]; /* получаем от ардуины ответ с новым значением ШИМ */
sh1(); /* и выводим значение ШИМа на индикатор */


Включаем обновление

flagobnov = 1; 


Функция (sh1();) в свою очередь отрисовывает индикатор и передаёт управление в функцию (sl1();).

Функция (sl1();) устанавливает ползунок в соответствии с новым значением ШИМ и ожидает очередного движение ползунка.

Код целиком:


...
function sh1(){ /* рисование первого индикатора */
  var $ppc = $('.progress-pie-chart'),
    percent = shim1,
    deg = 360*percent/100;
  if (percent > 50) {
    $ppc.addClass('gt-50');
  }
  else $ppc.removeClass('gt-50');
  $('.ppc-progress-fill').css('transform','rotate('+ deg +'deg)');
  $('.ppc-percents span').html(percent+' %       D5  '); /* название на кнопке - D5 */
  sl1();
}

function sl1(){ /* первый слайдер */
       $( "#slider" ).slider({
       value : shim1,
       min : 0,
       max : 100,
       step : 1,
       slide: function( event, ui ) {  /* отправили новое значение в арду, получили его обратно, отправили на индикатор и отдуда вернули сюда чтоб установить слайдер */
       flagobnov = 0; /* пока таскаем ползунок отключаем обновление, чтоб не засорять "эфир" */
           if( ui.value > shim1 ){ /* если потащили ползунок в большую сторону, то увеличиваем ШИМ */
		$.ajax({  
		    type: "GET",  
		    url: "box2.php?df=D", /* говорим ардуине что надо увеличить ШИМ  на единицу */
                    timeout:200,
                    cache: false,  
                    success: function(data){                       
                         var vars = data.split(",");
                         if(vars.length == dlina) 
                             { 
			       shim1 = vars[12]; /* получаем от ардуины ответ с новым значением ШИМ */
			       sh1(); /* и выводим значение ШИМа на индикатор */
			     }  
                    }   
 	        });
           }

           else if( ui.value < shim1 ){ /* если потащили ползунок в меньшую сторону, то уменьшаем ШИМ */
		$.ajax({  
		    type: "GET",  
		    url: "box2.php?df=d", /* говорим ардуине что надо уменьшить ШИМ  на единицу */
                    timeout:200,
                    cache: false,  
                    success: function(data){                       
                         var vars = data.split(",");
                         if(vars.length == dlina) 
                             { 
			       shim1 = vars[12]; /* получаем от ардуины ответ с новым значением ШИМ */
			       sh1(); /* и выводим значение ШИМа на индикатор */
			     }  
                    }   
 	        });
           }

        flagobnov = 1; /* включаем обновление */
       }
    });
}
...

Значение индикатора и позиция ползунка, гарантированно соответствуют значению в ардуине.


Нажатие на кнопку «Мгновенное отключение ШИМ» отправляет в ардуину команду обнулить ШИМ, а кнопка «Мгновенное включение ШИМ» запросит у ардуины значение ШИМ, которое было до обнуления.


/* d5 ШИМ */
/*мгновенное включение ШИМ на D5*/
$(".d5shimvkl").click(function(){
                    $.ajax({  
		             type: "GET",  
		             url: "box2.php?df=F",
                             timeout:200,
                             cache: false,  
                             success: function(data)
                                {                       
                                  var vars = data.split(",");
                                    if(vars.length == dlina) 
                                       { 
                                          shim1 = vars[12]; /* получаем от ардуины ответ с новым значением ШИМ */
					  sh1(); /* и выводим значение ШИМа на индикатор */
                                       }  
                                }   
 	                   }); 
                     return false;
                  
	});

/*мгновенное отключение ШИМ на D5*/
$(".d5shimotkl").click(function(){
                    $.ajax({  
		             type: "GET",  
		             url: "box2.php?df=f",
                             timeout:200,
                             cache: false,  
                             success: function(data)
                                {                       
                                  var vars = data.split(",");
                                    if(vars.length == dlina) 
                                       { 
                                          shim1 = vars[12]; /* получаем от ардуины ответ с новым значением ШИМ */
					  sh1(); /* и выводим значение ШИМа на индикатор */
                                       }  
                                }   
 	                   }); 
                     return false;
                  
	});





Дизайн


Позиция индикаторов, их цвет и шрифт меняется в файле shim.css


/* первый кружок */
.progress-pie-chart {
  width: 200px;
  height: 200px;
  top: 90px; /* позиция */
  left: 80px; /* позиция */
  border-radius: 50%;
  background-color: #E5E5E5;
  position: absolute;
}


.ppc-percents span {
  display: block;
  font-size: 26px; /*размер текста на кружках*/
  font-weight: 600; /*ширина текста на кружках*/
  font-family: Arial, Helvetica, sans-serif; /*шрифт*/
  color: #161616; /*цвет текста на кружках*/
  text-shadow: 0px 1px 2px #7c7c7c; /*цвет и размер тени текста*/
}


Размер и позицию ползунков можно менять в файле slai.css


.ui-slider { 
position: relative; 
width: 200px; /* ширина ползунка */
text-align: left; 
outline: none; 
}
...
/* кнопка ползунка */
.ui-slider-horizontal .ui-slider-handle { 
width: 50px; /*размер кнопки ползунка*/
height: 50px;
margin-left: -25px; 
outline: none;
box-shadow: 0 0 10px 3px rgba(0,0,0,0.3);
border-radius: 4px;
border: 1px solid #2b2c2b;
cursor: pointer;
}
...
/*первый ползунок*/
s1 { 
position: absolute; 
top: 360px; 
left: 80px;
font-size: 26px; /*размер текста на кнопках*/
font-weight: 600; /*ширина текста на кнопках*/
font-family: Arial, Helvetica, sans-serif; /*шрифт*/
color: #161616; /*цвет текста на кнопках*/
text-shadow: 0px 1px 2px #7c7c7c; /*цвет и размер тени текста*/
}

/*второй ползунок*/
s2 { 
position: absolute; 
top: 360px; 
left: 420px;
font-size: 26px; /*размер текста на кнопках*/
font-weight: 600; /*ширина текста на кнопках*/
font-family: Arial, Helvetica, sans-serif; /*шрифт*/
color: #161616; /*цвет текста на кнопках*/
text-shadow: 0px 1px 2px #7c7c7c; /*цвет и размер тени текста*/
}




На этом вторая часть закончена, в следующей части рассмотренно подключение температурных датчиков и включение/отключение различных устройств по температуре, а так же добавлен спящий режим для веб-интерфейса.


Вот тут можно скачать библиотеку для разгона Arduino.


Телеграм-чат istarik


  • +761
  • 18913
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






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

0
Добрый день.

Вопрос, отключили вечером эл-во, все погасло, прошло 4-5 часов, все легли спать и тут загорается свет, все проснулись.
Или свет дали на следующий день, когда все разошлись и он будет гореть до вечера.
0
Здравствуйте. Да, будет гореть пока не выключите. Функция автоматического включения реализована для удалённых объектов, например это дача и нужно чтоб что-то работало самостоятельно. В следующей части к «автоматическим» пинам можно подключить обогреватель.
Чтобы отключить «автоматическое» управление, например пина d2 надо:
В начале кода, переправить это:
byte d2 = EEPROM.read(2);

на это:
byte d2 = 0;


В void setup() убрать строки:

if(d2) digitalWrite(2, HIGH); else digitalWrite(2, LOW); 
delay(500);


И в блоке switch (descript[3]) закомментировать запись в EEPROM, вот так:

         ////////////// Кнопки ///////////////////
         case 'A': // d2 вкл
         digitalWrite(2, HIGH); // вкл d2
         d2 = 1; // ставим флаг в единицу (вкл)
         //EEPROM.write(2, d2); // записываем состояние d2 в ячейку №2 EEPROM 
         glavnaia(); // отправка ответа
         break;
         
         case 'a': // d2 откл
         digitalWrite(2, LOW); // откл d2
         d2 = 0; // ставим флаг в ноль (откл)
         //EEPROM.write(2, d2); // записываем состояние d2 в ячейку №2 EEPROM 
         glavnaia(); // отправка ответа
         break; 
Поскольку это шаблон, я решил добавлять функционал поэтапно, чтоб код с самого начала не выглядел громоздким. Позже, включение/отключение "автоматики" можно будет делать из интерфейса.
0
Приветствую!

Делаю все по инструкции, и столкнулся с такой проблемой: при вызове любой функции с ШИМ, вешается почти наглухо роутер.
Вводу через SSH команду «top» и вижу 100% загрузку процессора. При этом появляется множество соединений к Lighttpd.
Подскажите, куда копать?
0
Увы, ничего не поделаешь. Дело в том, что (это выяснилось относительно недавно) на роутере не срабатывает функция stream_set_timeout($fp, 0, 150000); (в файле box2.php), может в OpenWrt пхп не полноценный, может я чего-то недопонимаю.

Получается вот что, когда Вы двигаете ползунок, в роутер очень часто летят пакеты (прибавление/убавление на единицу — это очередной пакет) и если ардуина не успела обработать один пакет и отдать ответ файлу box2.php, то он ждёт ответа (таймаут то в 150мс не сработал), а следующий пакет открывает ещё одно соединение, которое упирается в то, что открыто предыдущим и т.д. Количество соединений начинает расти как снежный ком и всё виснет.

/etc/php.ini у Вас отредактирован как здесь описано?
Минимальный таймаут 1 сек. — меньше не получится.

На полноценном компе такое не наблюдается.

В общем, «ШИМ» надо переделывать. Как только всё исправлю, так сразу выложу.
0
Доброго вечера!
Спасибо за столь подробные и нужные инструкции!

Пытался забороть веб сервер и что-то никак( Не могу найти причину по которой веб сервер отказывается отображать кнопки.

вводная
open wrt — CHAOS CALMER (15.05, r46767)
root@OpenWrt:~# opkg list-installed
base-files - 157-r46767
block-mount - 2015-05-24-09027fc86babc3986027a0e677aca1b6999a9e14
busybox - 1.23.2-1
coreutils - 8.23-1
coreutils-stty - 8.23-1
dnsmasq - 2.73-1
dropbear - 2015.67-1
e2fsprogs - 1.42.12-1
fdisk - 2.25.2-4
firewall - 2015-07-27
fstools - 2015-05-24-09027fc86babc3986027a0e677aca1b6999a9e14
glib2 - 2.43.4-1
hostapd-common - 2015-03-25-1
ip6tables - 1.4.21-1
iptables - 1.4.21-1
iw - 3.17-1
iwinfo - 2015-06-01-ade8b1b299cbd5748db1acf80dd3e9f567938371
jshn - 2015-06-14-d1c66ef1131d14f0ed197b368d03f71b964e45f8
jsonfilter - 2014-06-19-cdc760c58077f44fc40adbbe41e1556a67c1b9a9
kernel - 3.18.20-1-148542ca7db41f593b0a41c28927139c
kmod-b43 - 3.18.20+2015-03-09-3
kmod-b43legacy - 3.18.20+2015-03-09-3
kmod-b44 - 3.18.20-1
kmod-bgmac - 3.18.20-1
kmod-cfg80211 - 3.18.20+2015-03-09-3
kmod-crypto-aes - 3.18.20-1
kmod-crypto-arc4 - 3.18.20-1
kmod-crypto-core - 3.18.20-1
kmod-crypto-hash - 3.18.20-1
kmod-fs-ext4 - 3.18.20-1
kmod-fs-vfat - 3.18.20-1
kmod-gpio-button-hotplug - 3.18.20-1
kmod-hwmon-core - 3.18.20-1
kmod-ip6tables - 3.18.20-1
kmod-ipt-conntrack - 3.18.20-1
kmod-ipt-core - 3.18.20-1
kmod-ipt-nat - 3.18.20-1
kmod-ipv6 - 3.18.20-1
kmod-leds-gpio - 3.18.20-1
kmod-ledtrig-default-on - 3.18.20-1
kmod-ledtrig-netdev - 3.18.20-1
kmod-ledtrig-timer - 3.18.20-1
kmod-lib-crc-ccitt - 3.18.20-1
kmod-lib-crc16 - 3.18.20-1
kmod-libphy - 3.18.20-1
kmod-mac80211 - 3.18.20+2015-03-09-3
kmod-mii - 3.18.20-1
kmod-nf-conntrack - 3.18.20-1
kmod-nf-conntrack6 - 3.18.20-1
kmod-nf-ipt - 3.18.20-1
kmod-nf-ipt6 - 3.18.20-1
kmod-nf-nat - 3.18.20-1
kmod-nf-nathelper - 3.18.20-1
kmod-nls-base - 3.18.20-1
kmod-nls-cp437 - 3.18.20-1
kmod-nls-iso8859-1 - 3.18.20-1
kmod-ppp - 3.18.20-1
kmod-pppoe - 3.18.20-1
kmod-pppox - 3.18.20-1
kmod-pps - 3.18.20-1
kmod-ptp - 3.18.20-1
kmod-scsi-core - 3.18.20-1
kmod-slhc - 3.18.20-1
kmod-tg3 - 3.18.20-1
kmod-usb-acm - 3.18.20-1
kmod-usb-bcma - 3.18.20-1
kmod-usb-core - 3.18.20-1
kmod-usb-ssb - 3.18.20-1
kmod-usb-storage - 3.18.20-1
kmod-usb2 - 3.18.20-1
libattr - 20150220-1
libblkid - 2.25.2-4
libblobmsg-json - 2015-06-14-d1c66ef1131d14f0ed197b368d03f71b964e45f8
libc - 0.9.33.2-1
libext2fs - 1.42.12-1
libffi - 3.0.13-1
libftdi - 0.20-3
libgcc - 4.8-linaro-1
libip4tc - 1.4.21-1
libip6tc - 1.4.21-1
libiwinfo - 2015-06-01-ade8b1b299cbd5748db1acf80dd3e9f567938371
libiwinfo-lua - 2015-06-01-ade8b1b299cbd5748db1acf80dd3e9f567938371
libjpeg - 9a-1
libjson-c - 0.12-1
libjson-script - 2015-06-14-d1c66ef1131d14f0ed197b368d03f71b964e45f8
liblua - 5.1.5-1
libmount - 2.25.2-4
libncurses - 5.9-2
libnl-tiny - 0.1-4
libopenssl - 1.0.2e-1
libpcre - 8.37-2
libpng - 1.2.54-1
libpthread - 0.9.33.2-1
librpc - 2015-04-10-308e9964bfb623773dc0dcc99ef9d18d1551d6ae
librt - 0.9.33.2-1
libsmartcols - 2.25.2-4
libsqlite3 - 3081101-1
libubox - 2015-06-14-d1c66ef1131d14f0ed197b368d03f71b964e45f8
libubus - 2015-05-25-f361bfa5fcb2daadf3b160583ce665024f8d108e
libubus-lua - 2015-05-25-f361bfa5fcb2daadf3b160583ce665024f8d108e
libuci - 2015-04-09.1-1
libuci-lua - 2015-04-09.1-1
libusb-1.0 - 1.0.19-1
libusb-compat - 0.1.4-1
libuuid - 2.25.2-4
libxml2 - 2.9.2-3
libxtables - 1.4.21-1
lighttpd - 1.4.36-1
lighttpd-mod-access - 1.4.36-1
lighttpd-mod-auth - 1.4.36-1
lighttpd-mod-cgi - 1.4.36-1
lighttpd-mod-redirect - 1.4.36-1
lua - 5.1.5-1
luci - git-15.248.30277-3836b45-1
luci-app-firewall - git-15.245.46763-b179283-1
luci-base - git-15.245.46763-b179283-1
luci-lib-ip - git-15.245.46763-b179283-1
luci-lib-nixio - git-15.245.46763-b179283-1
luci-mod-admin-full - git-15.245.46763-b179283-1
luci-proto-ipv6 - git-15.245.46763-b179283-1
luci-proto-ppp - git-15.245.46763-b179283-1
luci-theme-bootstrap - git-15.245.46763-b179283-1
mc - 4.8.14-1.3
mtd - 21
nano - 2.4.1-1
netifd - 2015-06-08-8795f9ef89626cd658f615c78c6a17e990c0dcaa
nvram - 9
odhcp6c - 2015-07-13-024525798c5f6aba3af9b2ef7b3af2f3c14f1db8
odhcpd - 2015-05-21-2ebf6c8216287983779c8ec6597d30893b914a7c
opkg - 9c97d5ecd795709c8584e972bfdf3aee3a5b846d-7
otrx - 1
php5 - 5.6.8-1
php5-cgi - 5.6.8-1
php5-mod-gd - 5.6.8-1
php5-mod-pdo - 5.6.8-1
php5-mod-session - 5.6.8-1
php5-mod-sqlite3 - 5.6.8-1
ppp - 2.4.7-6
ppp-mod-pppoe - 2.4.7-6
procd - 2015-08-16-0da5bf2ff222d1a499172a6e09507388676b5a08
rpcd - 2015-05-17-3d655417ab44d93aad56a6d4a668daf24b127b84
ser2net - 2.10.0-2
swconfig - 10
terminfo - 5.9-2
ubox - 2015-07-14-907d046c8929fb74e5a3502a9498198695e62ad8
ubus - 2015-05-25-f361bfa5fcb2daadf3b160583ce665024f8d108e
ubusd - 2015-05-25-f361bfa5fcb2daadf3b160583ce665024f8d108e
uci - 2015-04-09.1-1
uhttpd - 2015-08-17-f91788b809d9726126e9cf4384fedbbb0c5b8a73
uhttpd-mod-ubus - 2015-08-17-f91788b809d9726126e9cf4384fedbbb0c5b8a73
usign - 2015-05-08-cf8dcdb8a4e874c77f3e9a8e9b643e8c17b19131
wpad-mini - 2015-03-25-1
zlib - 1.2.8-1
zoneinfo-core - 2015d-1
zoneinfo-europe - 2015d-1


Вот так это выглядит
0
В файле index.html увеличьте таймаут с 200 на 500. (timeout:200)


...
show();
setInterval(show,2000);  
function show(){  
if(flagobnov == 1) { 
            $.ajax({ 
                type: "GET",
	        url: "box2.php?df=o", 
                timeout:200, /* время (мс), в течении которого функция будет ждать ответа от сервера */          
                cache: false,       
                success: function(data)
...   



Рекомендую Вам обратить внимание на эту статью.
0
Спасибо за ответ. Завтра попробую.
Статью я видел, но у меня не устанавливаются пакеты arduread и arduserver. Ругается на несоответствие архитектуры (роутер Asus RT-N16). Так как возможностей железа хватает чтобы развернуть lighhtpd c плюшками не стал особо упираться.
комментарий был удален
комментарий был удален
0
Собрал arduread и arduserver для Асуса, в архиве бинарники (устанавливать не нужно), распакуйте архив и скопируйте файлы в корень, всё остальное как в статье.
0
Изменение таймаута ни к чему не привело. активные элементы так и не появились. Но иногда появляется красная надпись stD.

Зато на uhttpd все заработало)))
единственное… подскажите как работать с файлами arduserver? чем их редактировать и обирать?

И еще раз спасибо за проделанную работу!
0
Изменение таймаута...
Каким браузером пользовались?


подскажите как работать с файлами arduserver?
arduserver и arduread — это бинарники, исходники выложены в статье. Редактировать в любом текстовом редакторе, собирать компилятором.


Пожалуйста.
0
Каким браузером пользовались?

firefox — Ie — lunascape
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.