Делаем автономный умный дом на базе ioBroker и контроллеров Sonoff

Цели:

  1. Получить работающий без всяческих облачных технолгий и доступа в Интернет систему умного дома.
  2. Обойтись минимумом денег.
  3. Желательно обойтись минимумом геморроя.

Чем будем управлять:

  1. Светом.
  2. Котлами.
  3. Водонагревателем.

Платформы для клиентского доступа:

  1. IOS
  2. Android

Установка и настройка сервера ioBroker

В качестве аппаратной платформы была выбрана Raspberry Pi 3 model B, так как обладает достаточным количеством ОЗУ, не требует активного охлаждения и весьма распространена в продаже.

Так как исторически сложилось, что почти все инсталляции ioBroker производятся на Debian, то не будем отходить от этого и установим Raspbian. Можно даже не заморачиваться на выпуск, хоть все инструкции написаны для выпуска Jessie, мы можем с тем же успехом использовать и Stretch. Установку дистрибутива я описывать не буду, в интернете и так полно описаний, как это сделать.

ioBroker же устанавливается чуть менее очевидным способом. Для начала, почистим наш Raspbian от ненужного мусора, например, X11:

root@pc2i:# apt-get remove --auto-remove --purge `libx11-.\*`
root@pc2i:# apt-get autoremove –purge

Второй пункт повторять пока apt не скажет что делать нечего. Затем почистим его от системной сборки NodeJS (потому что нам нужна ванильная):

root@pc2i:# apt-get --purge remove node
root@pc2i:# apt-get --purge remove nodejs
root@pc2i:# apt-get autoremove –purge
root@pc2i:# reboot

Повторять пп. 3 пока apt не скажет что делать нечего.

Входим в систему под root и ставим NodeJS:

root@pc2i:# curl -sL [https://deb.nodesource.com/setup\_6.x](https://deb.nodesource.com/setup_6.x) | sudo -E bash -
root@pc2i:# apt-get install -y build-essential python-rpi.gpio python nodejs
root@pc2i:# reboot

Важное замечание: поскольку мы живём в России, то у нас есть буйствующий Роскомнадзор, поэтому, возможно, придётся поправить >конфигурацию cURL, чтобы нам не сыпало 451 ошибкой при попытке что-то скачать.

Создаём ~/.curlrc и прописываем в него proxy = http://username:password@proxy-host:port , меняя параметры на ваши.

Переходим к установке ioBroker:

root@pc2i:# mkdir /opt/iobroker
root@pc2i:# chmod 777 /opt/iobroker
root@pc2i:# cd /opt/iobroker
root@pc2i:/opt/iobroker# npm install iobroker --unsafe-perm

Теперь ioBroker будет доступен на 8081TCP порту. Не забудьте настроить статический IP-адрес на сервере! Либо static DHCP lease, либо в /etc/dhcpcd.conf. Запомните его, он дальше потребуется для настройки.

Также стоит не забыть открыть тройку портов:

iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 8081 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 8082 -j ACCEPT
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 1883 -j ACCEPT

И заодно добавляем эти три строки в /etc/rc.local, чтобы после перезагрузки порты не остались закрытыми.

Разбираемся с Sonoff

Были закуплены Sonoff Basic и Sonoff TH16. Оба этих "Wi-Fi smart switch" выполнены на контроллере ESP8266EX и имеют на борту 8 мегабит флеш-памяти (1 мегабайт). GPIO, которые могут нам потребоваться, распределены следующим образом:

Использование GPIO

Прошивка, путём страдания и проб, была выбрана ESPEasy mega-20180505 ( https://github.com/letscontrolit/ESPEasy/releases/tag/mega-20180505), как наиболее стабильная и предсказуемая. Прошивать мы её будем через UART (на самом деле USART, но кого это волнует?). В качестве прошивальщика я использовал esptool.py, так как на моём хосте с Arch Linux он прекрасно и без помех установился с помощью yaourt из AUR.

Расположение пинов для прошивки дислоцируется на глаз, но опишу для не очень прозорливых:

Sonoff TH16 - в дальнем от питания углу платы прямо подписаны VCC, Tx, Rx и GND.

Sonoff Basic - пять пятаков с отверстиями между конденсатором, кнопкой и флеш-памятью. Печатью на текстолите они обведены в прямоугольник, ближайший к кнопке обведён в квадрат. Начиная с квадрата: VCC, Tx, Rx, GND, GPIO14.

VCC что для того, что для другого - 3.3 вольта. Важно: питание из розетки вытаскиваем, прежде чем подключить VCC от USB-to-UART, потому что гальванической развязки на плате нет и вы сожгёте к херям свой Sonoff, USB-to-UART, а если не повезёт, то и порты на материнке компьютера.

В качестве USB-to-UART я предпочитаю PL2303HX, так как он зарекомендовал себя за 15 лет его использования мной.

Процесс прошивки очень прост, но перед выполнением каждой команды необходимо руками произвести следующие действия:

А теперь команды:

  1. Читаем, что мы вообще подключили (мало ли чего китайцы могли насовать):
sudo esptool --port /dev/ttyUSB0 --baud 115200 chip\_id
sudo esptool --port /dev/ttyUSB0 --baud 115200 --chip esp8266 flash\_id
sudo esptool --port /dev/ttyUSB0 --baud 115200 --chip esp8266 read\_mac

sudo esptool –port /dev/ttyUSB0 –baud 115200 –chip esp8266 read_flash 0 0x100000 Sonoff_TH1016-2.1.bin

sudo esptool --port /dev/ttyUSB0 --baud 115200 --chip esp8266 erase\_flash
sudo esptool --port /dev/ttyUSB0 --baud 115200 --chip esp8266 write\_flash 0 ~/Downloads/ESPEasy\_mega-20180505/ESP\_Easy\_mega-20180505\_normal\_ESP8266\_1024.bin

Затем можно отключить Sonoff от UART, собрать и запитать вилкой от розетки.

После включения у нас в эфире Wi-Fi 2.4 ГГц появится точка доступа с SSID ESP_Easy_0, подключаемся к ней с паролем configesp и DHCP параметрами авторизации. В силу каких-то странностей, лично у меня нормальная авторизация на этой точке доступа проходила только со смартфона на Android 7.1. После подключения переходим в браузере на http://192.168.4.1/ и выбираем SSID точки доступа, которую мы планируем использовать для умного дома. Там же вводим пароль, сохраняемся, ждём 20 секунд, перезагружаем Sonoff по питанию и переходим на IP-адрес Sonoff, который у нас отобразился на маршрутизаторе (или же вы сделали static lease у DHCP заранее, верно?).

Совет: можно подключить Rx, Tx и GND USB-to-UART к Sonoff (главное VCC не подключать) и смотреть из консоли ПК, что он нам >говорит, например, IP-адрес после подключения к точке. Я лично смотрел это при помощи sudo minicom -D /dev/ttyUSB0.

Приступаем к настройке нашего Sonoff.

-

  1. Настроим немного встроенных функций. Точнее, я их отключаю: Hardware -> GPIO LED -> None (не люблю, чтобы что-то светило постоянно). Там же, ниже GPIO Switch -> None.
  2. Затем настраиваем наши устройства. Переходим на вкладку Devices, дальше по номерам в столбце Task нажимаем Edit.

1.

  1. Настроим реле. - Device ➖ Switch input – Switch - Name ➖ Relay_sonoff1 - Ставим галочку на Enabled - 1st GPIO ➖ GPIO12 - Ставим галочку на Send to controller - Жмём кнопочку Submit
  2. Настроим светодиод. Кстати, не смотрите что на Sonoff TH16 два светодиода, из ESPEasy они будут работать как один. - Device ➖ Switch input – Switch - Name ➖ Led_sonoff1 - Ставим галочку на Enabled - 1st GPIO ➖ GPIO13 - Ставим галочку на Send to controller - Жмём кнопочку Submit
  3. Настроим кнопку. Ну, мало ли захотите что-то на эту кнопку потом повесить. - Device ➖ Switch input – Switch - Name ➖ Button_sonoff1 - Ставим галочку на Enabled - 1st GPIO ➖ GPIO0 - Ставим галочку на Send to controller - Жмём кнопочку Submit
  4. Настроим импорт наших девайсов в дерево драйвера MQTT (читай: чтобы сервер MQTT, прикрученный к ioBroker, разглядел эти девайсы): - Device ➖ Generic – MQTT Import - Name ➖ mqtt_import - Ставим галочку на Enabled - MQTT Topic 1 ➖ /Sonoff1/Relay_sonoff1/Switch (это часть мероприятий по обучению Sonoff восприимчивости к сигналам из ioBroker) - Values ➖ Name ➖ 1 ➖ value1 (чувствительно к регистру!) - Жмём кнопочку Submit
  5. Пункт для Sonoff TH16: прикручиваем AL2301 - датчик температуры и влажности: - Device ➖ Environment - DHT11/12/22 SONOFF2301/7021 - Name -➖ Dht_sonoff1 - Ставим галочку на Enabled - 1st GPIO ➖ GPIO14 - DHT Type ➖ Sonoff am2301 - Ставим галочку на Send to controller - Interval ➖ какой хотим, у меня 30 секунд - Жмём кнопочку Submit

  6. Теперь нам необходимо немножко заскриптовать Sonoff, чтобы он щёлкал реле по команде из ioBroker.
    • Переходим на вкладку Tools
    • В разделе System нажимаем кнопку Advanced
    • Ставим галочку Rules
    • Листаем в самый низ и жмём кнопочку Submit
    • Переходим на вкладку Main и видим, что появилась вкладка Rules
    • Переходим на вкладку Rules
    • Копируем туда следующий код:
on mqtt\_import#value1 do

  if [mqtt\_import#value1] = 1
    gpio,13,0
    gpio,12,1

  else
    gpio,13,1
    gpio,12,0
  endif

endon

-

Поздравляю, Sonoff настроен! Tools ➖ Reboot и по питанию для надёжности. Так же настраиваем и другие датчики, не забывая менять порядковый номер устройства во всех параметрах, чтобы потом самому не запутаться и не дать запутаться ioBroker.

Допиливаем ioBroker

Как ни странно, протокол MQTT хоть и достаточно стандартизированный, но в нём есть расхождения. Например, 0 и 1 относительно false и true совсем не одно и то же, что потребует приколачивания отдельного костыля. Впрочем, увидите далее всё сами. Совет: сначала настраиваем все ваши устройства Sonoff по предыдущей главе, а затем настраиваем ioBroker. Иначе возможны глюки.

Первым делом надо докачать кучу драйверов в ioBroker. Драйвер в понимании ioBroker это модуль, плагин, другими словами, который позволяет что-то с чем-то делать. Открываем админку ioBroker, введя в браузере

http://ip-сервера-ioBroker:8081/ и переходим на вкладку Драйверы. Затем убеждаемся, что наша Raspberry выпущена в большие интернеты, нажимаем кнопочку со стрелочками по кругу в верхнем левом углу вкладки Драйверы (запомните, кстати, эту кнопку на каждой вкладке, где она есть, она ещё пригодится не раз), ждём пока он обновит список доступных драйверов, затем в строке поиска по очереди вбиваем, устанавливаем и настраиваем следующие драйвера:

  1. javascript - драйвер для поддержки пользовательских скриптов. Настройки оставляем без изменений.
  2. mqtt - сервер/брокер для подключения наших Sonoff. Настройки следующие:
  3. Открываем вкладку Соединение (открывается по умолчанию).
  4. Тип ➖ MQTT сервер/брокер
  5. Имя пользователя ➖ mqtt
  6. Пароль ➖ mqtt
  7. Остальное без изменений
  8. Жмём наверху кнопочку Сохранить и выйти
  9. web - базовый веб-интерфейс, предоставляющий доступ к mobile. Настройки можно оставить по умолчанию, потом разберётесь, если потребуется.
  10. mobile - веб-интерфейс для мобильников с адаптивной вёрсткой. Настроек не имеет.

Можно и больше драйверов, но это уже если сами захотите.

Переходим на вкладку Объекты. И тут у нас вдруг появится группа mqtt.0, в которой будут все настроенные наши Sonoff! Если не появилась, то перезапустите драйвер кнопочкой Обновить напротив имени драйвера mqtt на вкладке Настройки драйверов.

Проверим, как настроили Sonoff:

  1. Вкладка Объекты.
  2. Открывая папочки, следуем по пути mqtt.0 -> Sonoff1 -> Relay_sonoff1 -> Switch.
  3. В строке Switch в столбце Значение меняем 0 на 1. Реле должно щёлкнуть! Если не щёлкнуло, проверяйте как настроили Sonoff.

Теперь начинаем ворочать костылями:

  1. Жмём на кнопку с карандашиком напротив Switch, который мы только что проверяли.
  2. Открываем вкладку Raw (Эксперт) в появившемся окне настроек.
  3. Ищем строку "common".
  4. В этой группе ищем строку "type" и меняем её значение на "number", чтобы в итоге получилось "type": "number".
  5. Жмём кнопку "Сохранить".

Повторяем это для каждого Sonoff, что у вас есть в списке объектов.

Ворочаем костылями дальше:

  1. Вкладка Объекты.
  2. Открывая папочки, следуем по пути mqtt.0 ➖ Sonoff1 ➖ Relay_sonoff1
  3. В верхнем левом углу вкладки ищем кнопочку с плюсом. Жмём.
  4. В появившемся окне в поле Имя пишем Relay
  5. Жмём Сохранить.
  6. Теперь жмём карандашик напротив только что созданного Relay
  7. Открываем вкладку Raw (Эксперт) в появившемся окне настроек.
  8. Записываем на бумажку значения "ts", "state" и "object".
  9. Удаляем всё написанное и вставляем следующий код, не забыв заменить в нём значения ts, object и state на записанные вами на бумажку:
{
  "common": {
    "name": "/Sonoff1/Relay_sonoff1/Relay",
    "role": "variable",
    "desc": "mqtt server variable",
    "type": "boolean",
    "write": true,
    "read": true,
    "mobile": {
      "admin": {
        "visible": true,
        "type": "light",
        "name": "Реле Sonoff1"
      }
    }
  },
  "native": {
    "topic": "Sonoff1/Relay_sonoff1/Relay"
  },
  "type": "state",
  "from": "system.adapter.mqtt.0",
  "ts": 1666666666666,
  "_id": "mqtt.0.Sonoff1.Relay_sonoff1.Relay",
  "acl": {
    "object": 1666,
    "owner": "system.user.admin",
    "ownerGroup": "system.group.administrator",
    "state": 1666
  }
}
  1. Пробегаемся по коду ещё раз глазами - не забыли ли ничего?
  2. Жмём кнопку Сохранить.
  3. В столбце Значение напротив появившегося Relay необходимо щелкнуть и снять галочку. Затем нажать ещё ма-аленькую галочку в уголке этого поля.

Проделываем редактуру Switch и Relay со всеми вашими Sonoff, не забывая менять номера устройств во всех кодах, которые вы вставляете.

Переходим к костылям посложнее:

  1. Жмём карандашик в верхнем правом углу вкладки с админкой.
  2. Нажимаем появившуюся кнопку Показать и выбираем там Скрипты.
  3. Снова жмём на карандашик.
  4. Теперь переходим на вкладку Скрипты.
  5. В панели слева выбираем common, затем в верхнем левом углу кнопки нажимаем самую крайнюю слева кнопку с загнутым листочком.
  6. В появившемся окне выбираем тип скрипта - JS.
  7. Теперь новый скрипт откроется для редактирования. Прописываем название: sonoff1_switch и вставляем следующий код:
on('mqtt.0.Sonoff1.Relay_sonoff1.Relay', function (obj) {
    if(getState('mqtt.0.Sonoff1.Relay_sonoff1.Relay').val) {
        log('Включаем реле Sonoff1...');
        setState("mqtt.0.Sonoff1.Relay_sonoff1.Switch", 1);
    } else {
        log('Выключаем реле Sonoff1...');
        setState("mqtt.0.Sonoff1.Relay_sonoff1.Switch", 0);
    }
});
  1. Жмём кнопку Сохранить. Всё, скрипт запущен.

Соответственно, меняя номера Sonoff в скрипте, повторить для всех Sonoff, что есть.

На костылях закончили, переходим к допиливанию драйвера mobile.

Настроек у него нет, но это не должно вас обманывать.

Настроим категории. Категории это то, на основе чего будет сгенерирован интерфейс mobile.

  1. Жмём карандашик в верхнем правом углу вкладки с админкой.
  2. Нажимаем появившуюся кнопку Показать и выбираем там Категории.
  3. Снова жмём на карандашик.
  4. Переходим на вкладку Категории.
  5. Жмём на плюсик в верхнем левом углу вкладки.
  6. Имя пишем functions, затем кнопку сохранить.
  7. Ещё раз жмём на плюсик в верхнем левом углу вкладки.
  8. На этот раз имя пишем rooms, опять же сохраняем.
  9. Теперь выделяем functions и в конце этой строки видим плюсик. Жмём.
  10. В появившемся окне указываем имя light и жмём Сохранить.
  11. Снова плюсик, теперь имя temperature.
  12. И ещё раз, на этот раз имя humidity.
  13. Выделяем rooms и в конце этой строки жмём плюсик.
  14. Пишем название какой-нибудь комнаты, где будет наше управляемое реле, например, terrace.
  15. Снова плюсик, ещё комнату, например, boiler.
  16. Щёлкаем на надпись boiler в столбце Имя и редактируем на что-то более удобочитабельное: Бойлерная.
  17. Так можно проделать со всеми комнатами.
  18. Теперь раскидаем наши свитчи и датчики по категориям. Выделяем light и в конце строки будет этакая прошитая пружиной с левой стороны книжка. Жмём на эту кнопку.
  19. В появившемся окне в его нижнем левом угле давим плюсик и в появившемся окне ищем каталог mqtt.0
  20. Выбираем все созданные нами Relay, которые будут управлять светом.
  21. Жмём Выбрать, затем Ок.
  22. Теперь выбираем temperature и аналогичным образом добавляем туда все объекты, которые показывают температуру. Например, mqtt.0 -> Sonoff1 -> Dht_sonoff1 -> Temperature.
  23. То же самое проделываем с humidity (влажность).
  24. Теперь переходим к комнатам. Так же добавляем в категорию каждой комнаты все датчики, которые там будут находиться.
  25. Обновляем структуру кнопочкой вверху.
  26. Теперь переходим на вкладку Объекты и все объекты, которые вы в пп. 24 добавили в комнаты, должны получить от вас указание, в какой комнате они находятся. Ищем необходимый Relay и в этой строке кликаем по столбцу с заголовком Комната, выбираем комнату.

Ну, теперь мы можем пощёлкать из веб-интерфейса, поздравляю! Открывайте в браузере http://ip_адрес_raspberry:8082/mobile/ и тыкайте сколько влезет! Только не очень быстро 🙂

Возможно, у вас появится желание изменить надписи в веб-интерфейсе mobile. Нажимаем в верхнем правом углу страницы кнопочку i и в появившейся слева панели выбираем Реж. изменений. Дальше всё интуитивно понятно.

Бонус: работа чего-то по расписанию

Тут всё не слишком сложно, если вы умеете читать код на JS.

ioBroker.javascript умеет в cron, за сим рассказываю, как, например, решить одну задачу.

Задача: дома есть газовый котёл, электрический котёл и электрический водонагреватель. Газовый котёл отлично справляется и с отоплением, и с нагревом воды, но нам страшно спать со включенным газом. Поэтому надо сделать, чтобы с 22 до 6 часов дом отапливался электрическим котлом, а вода нагревалась электрическим водонагревателем, но в остальное время вместо них работал газовый котёл, благо у него топливо подешевле.

Определимся, что мы имеем:

Подключим Sonoff1 к реле управления газового котла, Sonoff2 - к реле управления электрокотла, а Sonoff3 к реле управления водонагревателя. Датчик температуры и влажности прикрутим по ГОСТу - полтора метра от пола и не менее метра от наружной стены дома.

Теперь скриптуем. Открываем вкладку Скрипты в ioBroker и создаём новый скрипт. Назовём его, например, gasheater_autostart. Дальше код, затем я его немного прокомментирую:

schedule("* 6-21 * * *", function () {
    var State_relay1 = getState("mqtt.0.Sonoff1.Relay_sonoff1.Relay").val;
    var State_relay3 = getState("mqtt.0.Sonoff3.Relay_sonoff3.Relay").val;
    var temp = getState("mqtt.0.Sonoff3.Dht_sonoff3.Temperature").val;
    var maxTemp = 23;
    var minTemp = 22;
    if(temp > maxTemp && State_relay1 === true) {
        log('Выключаем газовый котёл...');
        setState("mqtt.0.Sonoff1.Relay_sonoff1.Relay", false);
    } else if(temp < minTemp && State_relay1 === false) {
        log('Включаем газовый котёл...');
        setState("mqtt.0.Sonoff1.Relay_sonoff1.Relay", true);
    }
    if(State_relay3 === true) {
        log('Выключаем водонагреватель...');
        setState("mqtt.0.Sonoff3.Relay_sonoff3.Relay", false);
    }
});

Код у нас начинается с функции schedule. Это встроенная в драйвер javascript функция, позволяющая использовать cron для запуска некоторого кода. То, что у нас написано, позволяет запускать каждую минуту в седьмом, восьмом, девятом и так далее часу. Дальше в обёртке идёт код, при помощи включения и выключения газового котла поддерживающего температуру между 22 и 23 градусами по шкале Цельсия. Также код выключает электроводонагреватель на время работы газового котла.

Чтобы изменить время запуска, необходимо выделить первый параметр функции schedule вместе с кавычками и нажать кнопку Cron в верхнем правом углу вкладки.

Теперь сделаем так, чтобы ночью работал электрокотёл и включался электроводонагреватель. Создаём ещё один скрипт, называем его electroheater_autostart и копируем следующий код:

schedule("* 0-5,22,23 * * *", function () {
    var State_relay2 = getState("mqtt.0.Sonoff2.Relay_sonoff2.Relay").val;
    var State_relay3 = getState("mqtt.0.Sonoff3.Relay_sonoff3.Relay").val;
    var temp = getState("mqtt.0.Sonoff3.Dht_sonoff3.Temperature").val;
    var maxTemp = 23;
    var minTemp = 22;
    if(temp > maxTemp && State_relay === true) {
        log('Выключаем электрокотёл...');
        setState("mqtt.0.Sonoff2.Relay_sonoff2.Relay", false);
    } else if(temp < minTemp && State_relay === false) {
        log('Включаем электрокотёл...');
        setState("mqtt.0.Sonoff2.Relay_sonoff2.Relay", true);
    }
    if(State_relay3 === false) {
        log('Включаем водонагреватель...');
        setState("mqtt.0.Sonoff3.Relay_sonoff3.Relay", true);
    }
});

Здесь у нас всё аналогично, с разницей в том, что мы включаем и выключаем другой Sonoff и указано другое время для работы.

Приятного использования!