Система Умного дома в первом приближении
Создано: 19-10-2019 14:28:55 изменено: 25-04-2022 12:22:54  Метки: умный дом
Систему умного дома я задумывал много лет назад. Отталкивала высокая стоимость и необходимость перепрокладывать кучу проводов. Я даже собрал года 3-4 назад контроллер MegaD-328 [1]. Но до установки его и настройки дошли руки только сейчас.

Тут применены пару модулей из китая, это модуль сети и блок с реле для ардуино на 5 вольт. На монтажке смонтирован микроконтроллер mega328 и опторазвязки на входы, для того чтоб не попалить ничего. В итоге получилось устройство на 7 входов и 7 выходов. По себестоимости рублей 600-700.

Очень много времени заняло написание и отладка веб-интерфейса. Давно этим не занимался, пришлось очень многое вспоминать. Сначала хотел приспособить базу на sqlite для того чтоб можно было использовать двойные и тройные нажатия на выключатели, однако возникли сложности, все это плохо работало, и в итоге все сократилось до одного скрипта, пары файлов на html и javascript. Вот как это выглядит:

Здесь картинка с видеонаблюдения перед входом, для ее встраивания на компе поток rtsp с регистратора преобразуется с помощью ffmpeg по статье с хабра [2]. Под ней расположены кнопки управления светом, пока только в проходной комнате, где я делаю ремонт, и на улице. Кнопки на css я взял на просторах интернета [3]. Далее я расположил погодный информер с гисметео [4].

Выключатели применил Этюд от Шнайдер Электрик [5], можно применять и обычные переключатели Этюд, только надо вставлять возвратную пружинку под рычажок. Мне выключателей не хватило, пришлось один переделать - подошла половинка пружинки от старой зажигалки.

В планах прикрутить графики температуры, датчики на ESP-01 заказаны и ползут на оленях из китая. Так что возможно будет продолжение...


Список того что использовано:

[1] Умный дом своими руками. Там схема и прошивка устройства.

[2] Видео с камеры наблюдения на сайте бесплатно и без смс

[3] Кнопки-слайдеры на CSS

[4] Конструктор погодных информеров

[5] Кнопка-выключатель Этюд

Если кому интересно, куски кода:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/res/slider.css">
<link rel="stylesheet" type="text/css" href="https://ost1.gismeteo.ru/assets/flat-ui/legacy/css/informer.min.css">
<script type="text/javascript" src="/res/a.js"></script>
<script type="text/javascript" src="/res/hls.min.js"></script>
<script langauge="javascript">
        window.setInterval("refreshDiv()", 15000);
        function refreshDiv(){
                ajaxLoad('/atm.tcl?now=0','perekl');

        }
</script>

<title>Home, sweet home</title>
</head>
<body>
<video id="video"></video>
<script>
  if(Hls.isSupported()) {
    var video = document.getElementById('video');
    var hls = new Hls();
    hls.loadSource('/index.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
  });
 }
</script>
<div id="perekl"></div>
<input type="button" onclick="ajaxLoad('/atm.tcl?now=1','perekl');" value="Выключить все" style="margin-bottom: 15px; font-size: large;" >
<script langauge="javascript">
ajaxLoad('/atm.tcl?now=0','perekl');
</script>

<!-- Gismeteo informer START -->
... здесь информер от гисметео ...
<!-- Gismeteo informer END -->

</body></html>
a.js кусок для ajax запросов:
// here we define global variable
var ajaxdestination="";
function ajaxLoad(what,where) { // get data from source (what)
 try {
   xmlhttp = window.XMLHttpRequest?new XMLHttpRequest():
      new ActiveXObject("Microsoft.XMLHTTP");
 }
 catch (e) { /* do nothing */ }
// document.getElementById(where).innerHTML ="";
// we are defining the destination DIV id, must be stored in global variable (ajaxdestination)
 ajaxdestination=where;
 xmlhttp.onreadystatechange = triggered; // when request finished, call the function to put result to destination DIV
 xmlhttp.open("GET", what);
 xmlhttp.send(null);
 return false;
}

function triggered() { // put data returned by requested URL to selected DIV
 if (xmlhttp.readyState == 4) if (xmlhttp.status == 200)
  document.getElementById(ajaxdestination).innerHTML =xmlhttp.responseText;
  else document.getElementById(ajaxdestination).innerHTML = xmlhttp.status+' '+xmlhttp.statusText;
}
Скрипт atm.tcl на TCL:
#! /usr/bin/tclsh
#source res/config.inc
set ip 192.168.0.14
set pass sec
# названия входных портов
set portin {"Вход" "Комната" "" "" "" "" "Выключить все" }
# команды при нажатии кнопок
set cmd {"8:2" "9:2" "8:2" "" "" "" "a:0"}
# названия выходных портов, вначале пусто для входов, чтоб не править нумерацию портов
set portout {"" "" "" "" "" "" "" "" "Улица свет" "Комната свет" "" "" "" ""}

lappend auto_path [pwd]/lib/
package require html2
package require ncgi
namespace import ::html2::*
set qer [ncgi::parse]
ncgi::importAll

close stderr
set stderr [open /home/tcl_error.log a]

# Послать команду атмеге
proc sendcmd c {
#puts stderr "http://$::ip/$::pass/?cmd=$c"
    set res [catch {set a [exec wget -q -O - http://$::ip/$::pass/?cmd=$c]}]
    if {$res != 0} {
      puts stderr "Нет связи"
      exit
    }
    return $a
}

# пингаем атмегу
proc ping {} {
  set res [catch {exec ping -c1 $::ip}]
  if {$res != 0} {
    ncgi::header
    puts "No ping $::ip"
    puts stderr "Нет пинга"
    exit
  }
}
#ping

#puts stderr $qer
ncgi::header

switch -glob $qer {
  "pt cnt*" {
# обработка нажатий кнопок
    puts [lindex $cmd $pt]
  }
  "all" {
# команда на все выходы 0 1 или 2
    sendcmd "a:$all"
  }
  "toggle" {
# переключение выхода
    sendcmd "$toggle:2"
  }
  "now" {
# ajax вывод переключателей
    if {$now == 1} {sendcmd "a:0"}
    set i -1
    foreach po $portout {
      incr i
      if {$po ne ""} {
        p {
          label -class "b-mail-switch" {
            set st ""
            if {[sendcmd get&pt=$i] eq "OFF"} {set st "checked"}
            puts "<input name='port$i' type='checkbox' onchange=\"ajaxLoad('/atm.tcl?toggle=$i','pust');\" class='b-mail-switch__checkbox' $st>"
            span -class "b-mail-switch__input" {
              span -class "b-mail-switch__inner" {
                span -class "b-mail-switch__state b-mail-switch__state_left"
                span -class "b-mail-switch__state b-mail-switch__state_right"
              }
            }
          }
          span -style "margin-left: 15px; font-size: large;" {puts [lindex $portout $i]}
        }
      }
    }
  }
}
close stderr
1427 просмотров комментировать