Скрыть объявление
На нашем форуме недоступен просмотр изображений для неавторизованных пользователей. Если Вы уже зарегистрированы на нашем форуме, то можете войти. Если у Вас еще нет аккаунта, мы будем рады, если Вы к нам присоединитесь. Зарегистрироваться Вы можете здесь.

Еще раз о выключателе

Тема в разделе "Раздел для начинающих", создана пользователем anthony3d, 8 дек 2019.

  1. anthony3d

    anthony3d Новичок

    Сообщения:
    16
    Симпатии:
    0
    Прошу прощения за ламерский вопрос, который уже, наверное, все давно решили… Но
    Делаю по сути первый приличный проект на ESP8266.
    Настенный выключатель с Веб-функцией.
    Т.е. он должен и аппаратно включаться-выключаться, и через веб.
    Взял за основу ESP8266-01 Relay module, к которому повесил кнопку на GPIO2.
    И затормозил на софте.
    Задача стоит так:
    1. ESP должен стать сервером со своим IP и крошечной веб-страничкой, на которой всего один орган управления — чекбокс, управляющий реле.
    (Я потом сделаю супер-сервер, в котором будет нарисован план дома и все эти ESP-чекбоксы будут выведены «быстро-грязно» в iframe.)
    Эта задача решается готовым примером. Правда, хочу этот чекбокс обновлять AJAX'ом, без перезагрузки страницы.
    2. Реле должно переключаться также и от нажатия кнопки на GPIO2. При этом веб-чекбокс тоже должен перевестись в другое положение. (То же должно происходить когда веб-чекбокс переключили с другого браузера.)

    Нет никаких проблем сделать просто аппаратную кнопку — переключатель реле, без веб.
    Также нормально получается включать-выключать реле веб-чекбоксом. И АЯКС там тоже нормально работает.
    Но вот объединить эти две функции не получается.
    Самое главное — я не знаю как обычно делается передача значения переменной из скетча на веб-страничку. Я видел программу, где по таймеру javascript считывает XML, а сервер ему этот XML передает. Скажем так, не самая красивая конструкция. Хотя бы потому, что есть задержка пока передастся блок, да и я вообще против постоянно исполняющейся процедуры на довольно слабеньком устройстве. И еще это не решает синхронизацию чекбокса с разных браузеров.

    Не сталкивался ли кто-нибудь с этой проблемой? Не изобретаю ли я давно придуманный велосипед?
     
  2. svs2007m

    svs2007m Читатель

    Сообщения:
    148
    Симпатии:
    11
    Может готовые решения подойдут типа Blynk:)
     
  3. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.745
    Симпатии:
    186
    имхо запрос данных идет от браузера к есп,
    т.е если есп и имеет новые данные, то сама (есп) не сможет их обновить на открытой странице, без запроса со стороны браузера.
     
  4. lookingooder

    lookingooder Читатель

    Сообщения:
    66
    Симпатии:
    10
     
  5. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.745
    Симпатии:
    186
    И при помощи какой технологии это делать выбор автора.
    Есп может посылать данные в сеть, через отрытый канал, а программа на принимающей стороне может постоянно его слушать и оперативно выводить на экран.
    Может ли это все делать веб страница я не в курсе.
     
  6. lookingooder

    lookingooder Читатель

    Сообщения:
    66
    Симпатии:
    10
    Именно так:
    автообновление HTML страницы каждые 10 сек:
    HTML:
    1. <meta charset="utf-8" http-equiv="refresh" content="10">
    автообновление JS:
    Код (Javascript):
    1. setInterval(getTemp, 10000);
    или еще как-то...
     
  7. CodeNameHawk

    CodeNameHawk Moderator Команда форума

    Сообщения:
    1.745
    Симпатии:
    186
    Так как сделал автор, при помощи XML, намного приятней пользоваться, страница не мелькает, при обновлении.
    Он хочет моментальное обновление данных на страницax. И малую нагрузку на проц.
     
    lookingooder нравится это.
  8. Encrypt

    Encrypt Новичок

    Сообщения:
    48
    Симпатии:
    0
    Нужно использовать вебсокеты.
    Смотрите как реализован этот проект
    evilgeniuslabs/tree-v2
     
  9. anthony3d

    anthony3d Новичок

    Сообщения:
    16
    Симпатии:
    0
    Безобразие с этим XML.
    Круглые сутки выключатель стоит и ждет нажатие кнопки на включение. И происходит это раз 10 в день, если мы дома и не происходит вообще если мы уехали на месяц.
    А каждую секунду исполняется JavaScript процедура, которая считывает XML, который "по свистку" собирает код скетча.
    Я понимаю, что это все происходит внутри одного кристалла, что если этого не делать, то кристалл все равно будет тупить бесконечный цикл ожидания, и еще непонятно что из этого лучше.
    Короче, XML буду делать если другое ничего не получится.

    По Websocket.
    Код, указанный уважаемым Encrypt довольно сложный и делает очень много чего еще. Его явно писал специалист, делающий не первое устройство на ESP. Я попробовал его упростить для понимания, но вызовы серверных функций в нем так раскиданы по тексту, что я бросил это дело.

    И, кажется, я нашел инструмент, которым можно это все сделать. ESPAsyncWebServer

    Постараюсь отписаться по результатам.
     
  10. lookingooder

    lookingooder Читатель

    Сообщения:
    66
    Симпатии:
    10
    JS исполняется только в браузере компьютера, только пока открыта страница вашего выключателя. Вы собираетесь целый день сидеть и смотреть на страничку своего выключателя в браузере?
    Как я понимаю, вы откроете страничку, увидите состояние выключателя, включите или выключите его, если нужно, закроете страничку. Все.
     
  11. Сергей_Ф

    Сергей_Ф Moderator Команда форума

    Сообщения:
    2.280
    Симпатии:
    238
    Не будет ничего исполняться, если сидеть и смотреть на страничку. Js работает по событиям, которые в нем описаны. Если кнопки не нажимать, то ничего и не работает. Если там не втулили отслеживание курсора мыши, конечно. Тогда будет реагировать на мышку.

    Я вам больше скажу, даже если сделать на прерываниях, то процессор тоже будет целые сутки ждать это прерывание. Его конечно, можно загнать в сон, но кроме проблем вы никакого выигрыша не получите, строго говоря. Ну, кроме, морального удовлетворения. Если у вас не батарейное питание, где имеет смысл экономить каждый мВт|ч то не заморачивайтесь. Оно того не стоит.
     
    Последнее редактирование: 9 дек 2019
  12. anthony3d

    anthony3d Новичок

    Сообщения:
    16
    Симпатии:
    0
    В идеале в доме должно быть размещено несколько экранчиков с тачскрином (raspberry pi), на которых будет постоянно транслироваться этот веб-интерфейс с планом дома и выключателями. Поэтому, думаю, Javascript будет действительно выполняться постоянно, более того, еще и не внутри кристалла, а с реально летающими по WiFi пакетами каждую секунду.
    Но, видимо, такова его судьба.
    Напишу что получилось. :)
     
  13. lookingooder

    lookingooder Читатель

    Сообщения:
    66
    Симпатии:
    10
    Не вижу в этом ничего плохого. Посмотрите на свой домашний роутер - лампочки мигают постоянно, даже если вы не ведете никакой активности в сети - значит идет постоянный обмен пакетами. Одним больше, одним меньше :)
     
  14. Сергей_Ф

    Сергей_Ф Moderator Команда форума

    Сообщения:
    2.280
    Симпатии:
    238
    @anthony3d не будет ничего летать, если правильно написать js. Вы наверное, пропустили мой ответ. Js - это один большой callback. Там работа только по событиям. Загрузит один раз страницу и будет ждать события.
    Нажатия кнопки на экране или изменения статуса со стороны esp. Событие отработает и опять будет ждать следующего. Если ничего меняться не будет - то ничего и летать не будет.
     
  15. anthony3d

    anthony3d Новичок

    Сообщения:
    16
    Симпатии:
    0
    Ок!
    Пишу события.
     
  16. lookingooder

    lookingooder Читатель

    Сообщения:
    66
    Симпатии:
    10
    Упс. Как браузер может получить информацию от сервера (ESP), не отослав ему запрос? Серьезно, есть такой способ?
     
  17. Алексей.

    Алексей. Авторитетный участник сообщества

    Сообщения:
    625
    Симпатии:
    73
    Отвечал-же @Encrypt в #8 - смотрите на веб-сокеты.
    Типа они не кошерные и не подходят?
     
  18. Сергей_Ф

    Сергей_Ф Moderator Команда форума

    Сообщения:
    2.280
    Симпатии:
    238
    @lookingooder отошлет запрос и получит ответ. Один раз. Дальше действовать то будет js, а он по событию. Зачем каждую секунду грузить? Даже без веб- сокета можно обойтись.
    Хотя "при умении" можно такого накрутить, что и i7 не справится.
     
  19. Encrypt

    Encrypt Новичок

    Сообщения:
    48
    Симпатии:
    0
    На будущее:
    Еще, я бы порекомендовал вам обратить внимание на MQTT протокол, как альтернативу веб-сокетам.
    В качестве интерфейса и управления -- древний смартфон или планшет и MQTT клиент (например, MQTT Dash, Lazy MQTT...)
    С практической точки зрения немного проще и дешевле построить панель управления с готового устройства.
    Главное чтобы работал экран(тач), фронтальная камера(об этом ниже) , вайфай.

    Но если в планах научится веб-программированию, то лучше начинать с веб-интерфейсов.
    К тому же в обеих выше упомянутых программах используется JavaScript, который очень расширяет функционал.

    Мой базовый пример у входной двери:
    Фото (раскрыть)

    [​IMG]

    Приклеен стационарно на шкафу смартфон на андроиде 4.0 (2012г.) переживший 2-х владельцев.
    Запитан напрямую от БП через dc-dc преобразователь(4.0 вольт) на контакты батареи, то есть батареи там нет.
    Экран включается по движению!

    Из спец софта установлен MQTT Dash, собственно интерфейс и управление.
    Tasker -- автозагрузка всего необходимого и включение экрана по движению.
    Motion Detector -- который фиксирует движение через фронтальную камеру и передает событие в таскер.

    MQTT сервер - Mosquitto крутится на роутере (Xiaomi Router 3G + прошивка от padavan), но для начала можно воспользоваться и облачными сервисами. тотже cloudmqtt.com
    В глубине всей этой автоматизации только ESP8266 12-e 4 mb flash. Мощных железок не использую так как пока не вижу смысла.
     
  20. anthony3d

    anthony3d Новичок

    Сообщения:
    16
    Симпатии:
    0
    Вот, что вышло.
    Я не стал использовать никаких модных библиотек серверов.
    Только подобрал библиотеку для кнопочки, чтобы сама с дребезгом итд. разбиралась.
    Еще пока нет сетевого имени, но это уже просто.
    Что есть:
    1. Стандартная релейная платка для ESP8266 с управлением по GPIO0.
    2. На GPIO2 припаян резистор 3к3 на плюс и кнопочка на землю.
    3. LED на GPIO1.

    Что делает:
    1. Раз в секунду синхронизирует переменную switchState между JS и скетчем.
    2. При нажатии на кнопочку меняет switchState.
    3. При нажатии на чекбокс в веб-интерфейсе меняет switchState.
    4. Синхронный switchState сразу отражается на состоянии реле.
    5. LED показывает сначала процесс подключения, а в дальнейшем сетевую активность ESP.

    Для проверки я подключил все компьютеры и телефоны в доме и наслаждался синхронным переключением движков чекбоксов на них.

    Код (Text):
    1. #include <ESP8266WiFi.h>
    2. const char* ssid = "Home-WiFi";
    3. const char* password = "12345678";
    4. WiFiServer server(80);//Service Port
    5.  
    6. const int __ON = LOW;
    7. const int __OFF = HIGH;
    8. #define LED 1
    9. #define RELAY 0
    10. int switchState = __OFF;
    11. String request;
    12.  
    13. #include <JC_Button.h>
    14. #define BUTTON 2
    15. Button button(BUTTON);
    16. #include "index.h"
    17.  
    18. void setup() {
    19.   pinMode(RELAY, OUTPUT); digitalWrite(RELAY, switchState); // Setup start
    20.   pinMode(LED, OUTPUT); digitalWrite(LED, __ON);
    21.  
    22.   WiFi.begin(ssid, password);
    23.   while (WiFi.status() != WL_CONNECTED) { delay(100); }
    24.   server.begin();
    25.   button.begin();
    26.   digitalWrite(LED, __OFF); // Setup Ok
    27. }
    28.  
    29. void loop() {
    30.   button.read();
    31.   if (button.wasPressed()) { switchState = !switchState; }
    32.   digitalWrite(RELAY, switchState);
    33.   WiFiClient client = server.available(); // Check if a client has connected
    34.   if (client) {
    35.     digitalWrite(LED, __ON); // Client start
    36.     //delay(400);
    37.     request = client.readStringUntil('\r');
    38.     if ( request.indexOf("LEDON") > 0 )  {
    39.       switchState = __ON;  digitalWrite(RELAY, switchState);
    40.       client.print(F("HTTP/1.1 200 OK\r\n"));
    41.     } else if ( request.indexOf("LEDOFF") > 0 ) {
    42.       switchState = __OFF; digitalWrite(RELAY, switchState);
    43.       client.print(F("HTTP/1.1 200 OK\r\n"));
    44.     } else if ( request.indexOf("STATE") > 0 ) {
    45.       client.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/plane\r\n\r\n"));
    46.       client.print((switchState) ? F("LEDOFF") : F("LEDON"));
    47.     } else {
    48.       client.print( header );
    49.       client.print( html );
    50.       delay(5);
    51.     }
    52.     client.flush();
    53.     digitalWrite(LED, __OFF); // Client ok
    54.   }
    55. }
    Код (Text):
    1.  
    2. // -- index.h --
    3. String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
    4. String html = R"=====(
    5. <!DOCTYPE html>
    6. <html>
    7. <head>
    8.   <meta name='viewport' content='width=device-width, initial-scale=1.0'/>
    9.   <meta charset='utf-8'>
    10.   <style>
    11.     #main {display: table; margin: auto;  padding: 0 10px 0 10px; }
    12.  
    13. .checkbox {
    14.   position: absolute;
    15.   z-index: -1;
    16.   opacity: 0;
    17.   margin: 10px 0 0 20px;
    18. }
    19. .checkbox + label {
    20.   position: relative;
    21.   padding: 0 0 0 60px;
    22.   cursor: pointer;
    23. }
    24. .checkbox + label:before {
    25.   content: '';
    26.   position: absolute;
    27.   top: -4px;
    28.   left: 0;
    29.   width: 50px;
    30.   height: 26px;
    31.   border-radius: 13px;
    32.   background: #CDD1DA;
    33.   box-shadow: inset 0 2px 3px rgba(0,0,0,.2);
    34.   transition: .2s;
    35. }
    36. .checkbox + label:after {
    37.   content: '';
    38.   position: absolute;
    39.   top: -2px;
    40.   left: 2px;
    41.   width: 22px;
    42.   height: 22px;
    43.   border-radius: 10px;
    44.   background: #FFF;
    45.   box-shadow: 0 2px 5px rgba(0,0,0,.3);
    46.   transition: .2s;
    47. }
    48. .checkbox:checked + label:before {
    49.   background: #9FD468;
    50. }
    51. .checkbox:checked + label:after {
    52.   left: 26px;
    53. }
    54. .checkbox:focus + label:before {
    55.   box-shadow: inset 0 2px 3px rgba(0,0,0,.2), 0 0 0 3px rgba(255,255,0,.7);
    56. }
    57.  
    58.   </style>
    59.   <script>
    60.     var switchState = false;
    61.     var iCan = true;
    62.     window.setInterval(function(){
    63.       if (iCan) ajaxLoad('STATE');
    64.     }, 1000);
    65.     function switchLED(chk) {
    66.       iCan = false;
    67.       if (chk.checked) {
    68.         ajaxLoad('LEDON');
    69.         switchState = true;
    70.       }
    71.       else {
    72.         ajaxLoad('LEDOFF');
    73.         switchState = false;
    74.       }
    75.       //console.log(switchState);
    76.       iCan = true;
    77.     }
    78.     var ajaxRequest = null;
    79.     if (window.XMLHttpRequest)  { ajaxRequest =new XMLHttpRequest(); }
    80.     else                        { ajaxRequest =new ActiveXObject("Microsoft.XMLHTTP"); }
    81.  
    82.     function ajaxLoad(ajaxURL) {
    83.       if(!ajaxRequest){ alert("AJAX is not supported."); return; }
    84.       //console.log('ajaxLoad');
    85.       ajaxRequest.open("GET",ajaxURL,true);
    86.       ajaxRequest.onreadystatechange = function() {
    87.         if(ajaxRequest.readyState == 4 && ajaxRequest.status==200) {
    88.           var ajaxResult = ajaxRequest.responseText;
    89.           //console.log(ajaxResult);
    90.           if ( ajaxResult.indexOf('LEDON') !== -1 ) {
    91.             //console.log('LEDON received');
    92.             document.getElementById('checkbox').checked = true;
    93.           } else if ( ajaxResult.indexOf('LEDOFF') !== -1 ) {
    94.             //console.log('LEDOFF received');
    95.             document.getElementById('checkbox').checked = false;
    96.           }
    97.         }
    98.       }
    99.       ajaxRequest.send();
    100.     }
    101.   </script>
    102.   <title>Smart Home</title>
    103. </head>
    104. <body>
    105.   <div id='main'>
    106.     <input type="checkbox" class="checkbox" id="checkbox" onclick="switchLED(this)" />
    107.     <label for="checkbox"></label>
    108.   </div>
    109. </body>
    110. </html>)=====";
     

Поделиться этой страницей