
Привет всем!
В своем «умном доме» я решил, что все устройства должны быть завязаны на локальном сервере, чтобы без интернета он не превратился в тыкву.
Но почти всё так или иначе привязано к облаку. Этот пост о том, как отвязать устройства Sonoff от облаков.
Да, я знаю, что таких постов очень много и уже все рассказали, как прошить Sonoff. Но я хочу показать как можно отвязать от облака Sonoff DW2, не прошивая его. Прошить его в любом случае не получится, ведь там не ESP8266, а другая микросхема.
Что понадобится для освобождения от облаков:
- Sonoff Basic, Sonoff 4CH — понадобится паяльник и USB-TTL преобразователь;
- Sonoff DW2 — собственный сервер.
В посте я использую ESPHome + Home Assistant + Docker + PHP, вы можете использовать любое другое ПО, тут главное принцип работы.
Начнем с простого.
Sonoff Basic R2

Хорошая игрушка для умного дома, если вам требуется поуправлять отдельным светильником и не хочется менять всю проводку
Первым делом подготавливаем конфиг нужной нам прошивки (актуальная версия находится тут):
Конфиг ESPHome
Copy # Basic Config esphome: name: sonoff_basic_r2 platform: ESP8266 board: esp8285 wifi: ssid: !secret wifi_ssid password: !secret wifi_password logger: api: ota: # Device Specific Config binary_sensor: - platform: gpio id: push_button pin: number: GPIO0 mode: INPUT_PULLUP inverted: True internal: true on_press: # Prevents unintended LED lit states. if: condition: - switch.is_off: relay then: - switch.turn_on: blue_led - switch.turn_on: relay else: - switch.turn_off: relay switch: # The relay switches on the red side of the LED when active. - platform: gpio name: "Sonoff Basic Relay" pin: GPIO12 id: relay on_turn_off: if: condition: - switch.is_on: blue_led then: - switch.turn_off: blue_led # With this we can control the blue side of the LED. - platform: gpio id: blue_led pin: number: GPIO13 inverted: True
Теперь переходим к железу.
Для удобства припаиваем гребенку с шагом 2.54 на плату и подключаемся USB-TTL преобразователем, например CH340G, соблюдая пины:
- GND — GND
- TX — TX (возможно RX, зависит от преобразователя)
- RX — RX (возможно TX, зависит от преобразователя)
- 3.3V — 3.3V
Перед подключением Sonoff к ПК зажмите кнопку на плате, это необходимо для перехода в режим прошивки. Бывает такое, что устройство не определяется, поэтому я рекомендую поменять местами TX и RX пины, возможно, ваш программатор не учитывает такие моменты.

Сама инструкция по прошивке, скорее всего, вам уже известна, но для тех, кто делает это впервые, рекомендую ознакомиться с сайтом esphome.io
На этом наша работа с R2 окончена, теперь это ESPHome Sonoff R2.
Переходим к следующему пациенту.
Sonoff 4CH (Pro)

Цифра 5 означает, что это пятый контроллер в моем доме.
Приставка PRO означает, что вам доступны 433 МГц выключатели, но сама микросхема, отвечающая за 433 МГц протокол, распаяна отдельно, и ей управлять не получится, но после прошивки она продолжает работать как раньше.
По моим ощущениям 433 МГц протокол стал работать даже быстрее, чем до прошивки, но это может быть плацебо.
Отлично подходит для управления светом в комнатах. Я использую 3 таких на управлении светом во всем доме и 1 для управления насосами котла отопления.
Принцип прошивки аналогичен Basic R2, отличается лишь конфиг (актуальная версия находится тут):
Конфиг ESPHome
Copy # Basic Config esphome: name: sonoff_4chpror2 platform: ESP8266 board: esp01_1m wifi: ssid: !secret wifi_ssid password: !secret wifi_password logger: api: ota: # Device Specific Config binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT_PULLUP inverted: True on_press: - switch.toggle: "relay_1" - platform: gpio pin: number: GPIO9 mode: INPUT_PULLUP inverted: True on_press: - switch.toggle: "relay_2" - platform: gpio pin: number: GPIO10 mode: INPUT_PULLUP inverted: True on_press: - switch.toggle: "relay_3" - platform: gpio pin: number: GPIO14 mode: INPUT_PULLUP inverted: True on_press: - switch.toggle: "relay_4" - platform: gpio pin: number: GPIO0 mode: INPUT_PULLUP inverted: True name: "Sonoff 4CH Pro Button 1" - platform: gpio pin: number: GPIO9 mode: INPUT_PULLUP inverted: True name: "Sonoff 4CH Pro Button 2" - platform: gpio pin: number: GPIO10 mode: INPUT_PULLUP inverted: True name: "Sonoff 4CH Pro Button 3" - platform: gpio pin: number: GPIO14 mode: INPUT_PULLUP inverted: True name: "Sonoff 4CH Pro Button 4" - platform: status name: "Sonoff 4CH Pro Status" switch: - platform: gpio name: "Relay 1" pin: GPIO12 id: "relay_1" - platform: gpio name: "Relay 2" pin: GPIO5 id: "relay_2" - platform: gpio name: "Relay 3" pin: GPIO4 id: "relay_3" - platform: gpio name: "Relay 4" pin: GPIO15 id: "relay_4"
Заливаем прошивку и радуемся отвязанному ESPHome Sonoff 4CH (Pro)
Настало время самого сложного для меня пациента.
Sonoff DW2

Это единственное устройство у которого был доступ в интернет до сегодняшнего дня, у всех остальных «умных устройств» интернет отключен для безопасности.
В интернете я не нашел, как локально работать с датчиком двери, поэтому пришлось разбираться самому.
Начнем с принципа работы: DW2 подключается к вашей Wi-Fi сети и ждет прерывания от «открытия» или «закрытия» двери, в этот момент отправляется запрос на сервер eu-api.coolkit.cc, а уже с него вы получаете всю информацию.
Довольно сложная схема для простого датчика, подумал я и полез в Wireshark. Подменив DNS запись для домена eu-api.coolkit.cc на свой IP, я заметил обращение на 8080 порт, ура, они используют HTTP — значит, это победа!
Запустив nginx на своем сервере, я обнаружил странные логи такого вида:
Логи nginx
192.168.65.1 - - [29/Oct/2023:16:36:50 +0000] "\x16\x03\x01\x02\x00\x01\x00\x01\xFC\x03\x03i\xB5\x19G\xB1\xB2X}\xA3L\xCF\x99\x11\x84 \x00\xCE\x88\xB2S\xBC\xFC$\x86bp\xDA\xFA*\xEFl\xC8 \xB5\x12t\xDC\x13\x80W\x8E\xB1\xD5*\x00\x9E\xAF\xABzz\xEFpx\x92\xFCmY0\x03\xB6a\xE9\xF1\xC5\xC5\x00*" 400 157 "-" "-" "-" 192.168.65.1 - - [29/Oct/2023:16:36:53 +0000] "\x16\x03\x01\x02\x00\x01\x00\x01\xFC\x03\x03\x0B;'hR\x90\xAAY\x06Z\x82c6\xEC\x02p1\xF0\xEFF\xF5\xF3j\x99\x08r\xC1\xA2\x0E\xB6n\xD4 \xE5\x90\x1E\xA7N\xDC\xF3\xCA\xEA\x8C\x8Af5\xC4k\x95\x80W\x8A{\x90\x83\xCB\xBDxR\xB5\xF7\xFC\xFF<\x85\x00,\x8A\x8A\x13\x01\x13\x02\x13\x03\xC0,\xC0+\xCC\xA9\xC00\xC0/\xCC\xA8\xC0" 400 157 "-" "-" "-" 192.168.65.1 - - [29/Oct/2023:16:36:53 +0000] "\x16\x03\x01\x00\x97\x01\x00\x00\x93\x03\x01y|q\x17\x1B\xDD\xDB\xC3\xD79\x22\x1C\xA6nf\x0B]\xAC)^5\xFA5p\xF0\x8DS\x93\xF3\xED\x8AJ\x00\x00\x14\xC0" 400 157 "-" "-" "-"
Интересно, но ничего не понятно.
А что если это HTTPS, ведь первые байты у всех запросов одинаковые?
Да, это HTTPS, но на 8080 порту, странно, но ладно.
Конечно, я расстроился, ожидая SSL Pinning или шифрования данных внутри запроса, но нет, никакого шифрова��ия нет и сертификат Sonoff DW2 не проверяет.
Берем любой сертификат, подсовываем его в nginx и запускаем php-fpm для удобства разработки.
И вот мы получаем успешный POST запрос:
Лог nginx
192.168.65.1 - - [29/Oct/2023:19:39:55 +0000] "POST /api/user/device/update HTTP/1.1" 200 5 "-" "-" "-"
Array ( [deviceid] => ********** [d_seq] => 1546272314 [params] => Array ( [switch] => off [battery] => 2.202 [fwVersion] => 1000.2.925 [type] => 3 [chipID] => ********** [mac] => ********** [rssi] => -83 ) )
Отлично, мы получили информацию с датчика. Пишем скрипт-обработчик и добавляем перенаправление DNS запроса на свой сервер. Я использую Adguard Home, тут есть пункт «Перезапись DNS-запросов», в нем добавляем домен eu-api.coolkit.cc с вашим IP. Не забудьте в DHCP указать первым DNS свой Adguard Home.
Далее добавляем в конфиг следующие строки Home Assistant, чтобы появились новые объекты:
configuration.yaml
sensor: - platform: template sensors: entry_door_battery_voltage: unique_id: 5bc4eb632179f65962327215e2acf9e18d5a83f1 device_class: voltage unit_of_measurement: 'V' value_template: '' entry_door_rssi: unique_id: 053082ee1f19d9ca6a58a0cdb9061ffd87de2fc4 device_class: signal_strength unit_of_measurement: 'dBm' value_template: '' binary_sensor: - platform: template sensors: entry_door: unique_id: 130e755dcb5dfa0696f0835fb73f1307c00e6c76 device_class: door value_template: ''
и получаем долгосрочный токен в HA, его можно выпустить в самом низу страницы /profile
Для удобства и быстрого старта я использую Docker.
Конфигурация nginx
upstream php-sonoff-handler { server php:9000; } server { listen 8080 ssl; server_name eu-api.coolkit.cc; ssl_certificate /etc/nginx/ssl/servercert.pem; ssl_certificate_key /etc/nginx/ssl/serverkey.pem; ssl_dhparam /etc/nginx/ssl/dhparams.pem; location / { include fastcgi_params; fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/project/sonoff.php; fastcgi_pass php-sonoff-handler; fastcgi_intercept_errors on; fastcgi_request_buffering off; fastcgi_max_temp_file_size 0; } }
Конфигурация Docker Compose
version: '3' services: php: container_name: php image: "php:8.2-fpm" volumes: - ./php:/usr/share/nginx/html/project restart: unless-stopped nginx: container_name: nginx image: "nginx:latest" volumes: - ./nginx:/etc/nginx:ro restart: unless-stopped ports: - "8080:8080"
Добавляем скрипт в /php/sonoff.php.
Скрипт позволяет добавлять несколько датчиков, достаточно указать каждому свой ID.
Вместо ******* укажите deviceid своего устройства. Его можно узнать в приложении ewelink, пункт «ID устройства».
PHP скрипт
<?php const HA_API_URL = "http://homeassistant:8123/api/states/"; const HA_TOKEN = 'ВАШ ТОКЕН'; $listDevices = [ '**********' => [ 'id' => 'entry_door', 'name' => 'Входная дверь', 'v_name' => 'Входная дверь (Напряжение)', 's_name' => 'Входная дверь (Сигнал)', ], ]; $data = json_decode(file_get_contents('php://input'), true); $currentDevice = $listDevices[$data['deviceid']]; sendData(sprintf('binary_sensor.%s', $currentDevice['id']), [ 'state' => $data['params']['switch'], 'attributes' => [ 'friendly_name' => $currentDevice['name'], 'device_class' => 'door', ], ]); sendData(sprintf('sensor.%s_battery_voltage', $currentDevice['id']), [ 'state' => $data['params']['battery'], 'attributes' => [ 'friendly_name' => $currentDevice['v_name'], 'state_class' => 'measurement', 'unit_of_measurement' => 'V', 'device_class' => 'voltage', ], ]); sendData(sprintf('sensor.%s_rssi', $currentDevice['id']), [ 'state' => $data['params']['rssi'], 'attributes' => [ 'friendly_name' => $currentDevice['s_name'], 'state_class' => 'measurement', 'unit_of_measurement' => 'dBm', 'device_class' => 'signal_strength', ], ]); function sendData($sensor, $postData) { $url = HA_API_URL . $sensor; // for sending data as json type $fields = json_encode($postData); $ch = curl_init($url); curl_setopt( $ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', // if the content type is json 'Authorization: Bearer ' . HA_TOKEN, // if you need token in header ] ); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); $result = curl_exec($ch); curl_close($ch); }
Запускаем docker и проверяем датчик в панели HA, информация отправляется только при открытии/закрытии двери.
Для удобства я создал репозиторий с примерами кода и конфигурации — GitHub