ESP32: отправка данных на Telegram, Народный мониторинг и MQTT брокер, сигнализация.

Тема в разделе "Глядите, что я сделал", создана пользователем ИгорьК, 4 дек 2017.

  1. IvanUA

    IvanUA Гуру

    И все же не дают покоя мне эти восклицательные знаки. (знаю что можно проще, но все же почему?).
    Безымянный.jpg
     
  2. ИгорьК

    ИгорьК Гуру

    Ну здесь же прямо написано.
    Переменная v где-то раньше определена - уберите var перед ней или переименуйте, если она с чем-то конфликтует.
    Для сравнения с нулем используйте оператор точного сравнения "!==".
     
  3. IvanUA

    IvanUA Гуру

    Да я прочитал что написано. Убирал var - естественно пишет что переменная не определена.
    Пробовал "!==" - но тогда результат всегда равен "1"...
     
  4. ИгорьК

    ИгорьК Гуру

    Pub.message - это стринг. Ноль - это цифра. Интерпретатор ожидает сравнения цифры с цифрой - их и надо сравнивать точным сравнением. Дальше все ясно.

    Что касается первой части, то Вы там тоже сравниваете стринг с цифрой. Полагаю, заключение сравнения в скобки решит вопрос с var а нуля в кавычки - в обоих случаях упростит ситуацию в целом.
     
    IvanUA нравится это.
  5. IvanUA

    IvanUA Гуру

    Ожидает - это да, по этому и висит знак вопроса. Но по факту все одно операция логическая, по этому он все аргументы приводит к цифрам. Сделал как Вы посоветовали "0" и знак пропал.
    Ну тут немного сложнее оказалось. При оглашении переменной внутри функции - она и будет доступна только там. А вот оглашение переменной внутри вложенной функции приводило вот к таким последствиям. При повторном оглашении переменной во второй вложенной функции он ругается что переменная уже была оглашена, А если ее не оглашать - то ругается на то что переменной нет.... Могу ошибаться но это называется "Variable hoisting". Короче перенес оглашение (создание) переменной "v" - в начало функции. И все ОК.)))
    Код (Javascript):
       
       mqtt.on('publish', function (sub) {
            var v;
            console.log("\nMQTT=> ",sub.topic,sub.message);
              if (sub.topic==topikSub+"1/set") {
                  v = sub.message != "0";
                  digitalWrite(D4, v);
                  mqtt.publish(topikSub+"1/status", v?1:0);
              }
              if (sub.topic==topikSub+"2/set") {
                  v = sub.message != "0";
                  digitalWrite(D2, v);
                  mqtt.publish(topikSub+"2/status", v?1:0);
              }
        });
     
    Мозги работают(кипят) как у студента. Много интересных вещей начинают складываться по полочкам мозга)))). Единственное что немного смущает, так это то, что информации не так уж и много в интернете, в отличии от Ардуинки с ее С++
     
    Последнее редактирование: 10 дек 2017
  6. ИгорьК

    ИгорьК Гуру

    learn.javascript.ru - ИМХО вполне достаточно
     
    IvanUA нравится это.
  7. petr0vsk

    petr0vsk Нерд

    Надо понимать ждать аналога nodemcu для ESP32 - бесполезно? :(
     
  8. ИгорьК

    ИгорьК Гуру

    http://nodemcu.readthedocs.io/en/dev-esp32/en/build/

    Правда там модулей маловато.
    Для тех кто освоился с Lua - JavaScript от Espruino не так уж сложно подхватить.
     
    Последнее редактирование: 13 дек 2017
  9. ИгорьК

    ИгорьК Гуру

    Продолжение.

    Сила ESP32 (среди прочего) во много аналоговых ног, читающих сигнал до 3.3 вольта, а не как у ESP-8266 - до одного.

    Добавил датчик влажности HIH5030 и ИК сенсор движения, увязал работу через промисы.

    HIH5030 - аналоговый датчик, на его месте может быть любой другой аналоговый (всего чего угодно), соответственно со своим обсчетом.

    ИК-сенсор движения сообщит о перемещении в пространстве как своих, так и чужих.
    Теперь устройство не только публикует данные на брокер, но и подписывается на топик, с которого получает информацию о необходимости публикации данных сенсора движения (то есть, стоит дом на охране или нет).

    Выглядит это так:
    upload_2017-12-13_14-0-35.png

    Скрипт:
    Код (Javascript):
    //   ---- Setup ----//
    var ssid = 'ВАША_ТОЧКА_ДОСТУПА';
    var password = 'ВАШ_СУПЕРПАРОЛЬ';
    var topicc = "test/esp32/"; // Придумать что-то свое
    var myhost = "iot.eclipse.org";
    var myport = "1883";
    var mynarod = "#01:23:45:67:89:AB\n"; // Придумать свое в части цифр
    var pinDS = "D32"; // Нога DS18b20
    var pinHIH = "D33"; // Нога HIH5030
    var pinAlarm = "D21"; // Нога ИК-сенсора
    var HIHDSNumber = 0; // Цифра - порядковый номер датчика, температура с которого
    // учитывается для определения влажности. (Не больше чем количество датчиков минус 1)
    // здесь у меня всего один датчик
    var cl = console.log;
    var wifi = require('Wifi');

    var mod = {
        broker : false,
        alarm : "ON",
        wifi : false,
        narodPermit : true,
        oldalarm : 0
    };

    var dattable = {};

    var mqtt;
    var doAll;
    var tick;
    var nextCheck;

    /*---- Set One Wire and Search DS18b20 ---- */
    var ow = new OneWire(pinDS); /////////
    var sensors = ow.search().map(function (device) {
        return require("DS18B20").connect(ow, device);
    });
    sensors.forEach(function (sensor, index) {
        cl(sensor, index);
    });
    mod.HIHDSNumber = sensors[HIHDSNumber].sCode;

    /*---- Set and Support WiFi & MQTT Broker ---- */
    function repeat(call, timeSec) {
        setTimeout(call, timeSec * 1000);
    }

    function mqttnow() {
        cl('Start MQTT');
        mqtt = require("MQTT").connect({
            host: myhost,
            port: myport
        });
        mqtt.on('connected', function() {
            cl('Connected!');
            mqtt.publish(topicc, "ON");
            mqtt.subscribe(topicc + "command/#");
            mod.broker = true;
            cl('Subscribed!');
            doAll();
        });

        mqtt.on('publish', function (pub) {
            cl("topic: "+pub.topic);
            cl("message: "+pub.message);
            if(pub.topic === "test/esp32/command/alarm") mod.alarm = pub.message;
        });

        mqtt.on('disconnected', function() {
            mod.broker = false;
            mod.wifi = false;
            cl("MQTT disconnected... reconnecting.");
            tick();
        });
    }

    function getwifi(){
      wifi.connect(ssid, {password: password}, function(er) {
        if(er) {
          cl('Error Wifi connect:', er);
          return;
        }
        cl('Connected to Wifi.  IP address is:', wifi.getIP().ip);
        //wifi.save();
        mod.wifi = true;
        mqttnow();
      });
    }

    tick = function() {
        cl("Check WiFi!");
        wifi.getDetails(cl);
        wifi.getIP(function(tb){
            cl(tb.ip);
            if(tb.ip !=="0.0.0.0") {
                mod.wifi = true;
                try {
                    if (mqtt == "undefined"){
                        mqttnow();
                    }
                    else {
                        if (mqtt.connected) return;
                        mqtt.connect();
                    }
                } catch(e){
                    repeat(tick, 15);
                }
            }
            else {
                repeat(tick, 15);
                getwifi();
            }
        });
    };

    /*---- Set Alarm to MQTT Broker ---- */
    function checkalarm(){
      let alarmnow = digitalRead(pinAlarm);
      if(alarmnow !== mod.oldalarm) {
        mod.oldalarm = alarmnow;
        cl("alarmnow = ", alarmnow);
        if((mod.broker === false) || mod.alarm == "OFF") return;
        if(alarmnow) {
          mqtt.publish(topicc + "alarm", "1");
          cl('published ON');
        }
        else {
          mqtt.publish(topicc + "alarm", "0");
          cl('published OFF');
        }
      }
    }

    /*---- Ask Sensors & Send INFO By Promise  ---- */
    function askhumi(resolve, reject){
        let GetHue = function (pin, temp) {
            let RH =  (analogRead(pin) - 0.1515)/ 0.00636;
            let TrueRH = ((RH)/(1.0546 - 0.00216 * temp)).toFixed(1);
            cl("Hum is " + TrueRH+" %");
            return parseFloat(TrueRH);
        };
        let hum = GetHue(pinHIH, dattable[mod.HIHDSNumber]);
        dattable.hum = hum;
        resolve('Got Humidity!');
    }

    function askDS18b20(resolve, reject){
        sensors.forEach(function (sensor, index) {
            cl("\n");
            let dska = 0;
            sensor.getTemp(function (temp) {
                var tt = temp.toFixed(2);
                dska = sensors[index].sCode;
                dattable[dska] = tt;
                cl(dska + ": " + tt + "°C");
                if((index + 1) == sensors.length) resolve('Got Temperature');
            });
        });
    }

    function sendmqtt(resolve, reject){
        if(mod.broker === false){
            reject("Lost MQTT Broker!");
            return;
        }
        let sm = [];
        let send = function(item){
            let topikk = topicc + item[0];
            if(mod.broker) {
                mqtt.publish(topikk, item[1]);
                cl("Pub: ", topikk, item[1]);
                transfer();
            }
        };

        let transfer = function (){
            let item = sm.pop();
            if(item){
                setTimeout(send, 1000, item);
            }
            else {
                resolve("Sent MQTT Messages!");
            }
        };

        for (var key in dattable) sm.push([key, dattable[key]]);
        transfer();
    }

    function sendnm(resolve, reject) {
        if((mod.wifi === false) || (mod.narodPermit === false) ) {
            reject("Too Early or not WiFi!");
            return;
        }
        mod.narodPermit = false;
        setTimeout(()=> mod.narodPermit = true, 5*60*1000);
        cl("\n\n\nNarodmon Starts!");
        let tomon = mynarod;
        for (var key in dattable) {
            tomon = tomon + "#"+key+"#"+dattable[key]+"\n";
        }
        tomon = tomon + "##\n";
        cl(tomon);

        var client = require("net").connect({host: "narodmon.ru", port: 8283}, function() {
            cl('client connected');
            client.write(tomon);
            client.on('data', function(data) {
                cl(">"+JSON.stringify(data));
            });
            client.on('end', function() {
                cl('client disconnected');
                resolve("Narodmon is OK!");
            });
        });
    }

    function doAll(){
        function makePromice(call){
            return new Promise((resolve, reject) => {
            call(resolve, reject);
            });
        }

        let promise = makePromice(askDS18b20);

        promise
            .then(
                result => {
                  cl("\nFulfilled: " + result);
                  return makePromice(askhumi);
                }
            )
            .then(
                result => {
                  cl("\nFulfilled: " + result);
                  return makePromice(sendmqtt);
                }
            )
            .then(
                result => {
                  cl("\nFulfilled: " + result);
                  return makePromice(sendnm);
                }
            )
            .then(
                result => cl("\nFulfilled: " + result),
                error => cl("Rejected: " + error)
            ).then(
           ()=> setTimeout(doAll, 30000)
         );
    ;
    }

    /*---- Start! ---- */
    setInterval(checkalarm, 100);
    repeat(tick, 15);
    getwifi();
     

    В планах:
    • добавить сюда же (пока у меня этого барахла нет) самый говенный датчик на свете - DHT-11 (настоящий ардуинщих работает только с этим датчиком!);
    • посмотреть, работает ли отправка экстренного сообщения на telegram;
    • рискнуть описать суть работы для начинающих, подставившись под усмешки программеров от JS.
    Она с Telegram только так работает!!!! Значит идем дальше...
     
    Последнее редактирование: 13 дек 2017
    IvanUA нравится это.
  10. ИгорьК

    ИгорьК Гуру

    И еще немного - телеграфируем о зло(добро)умышленниках:
    upload_2017-12-13_17-45-8.png
    Вот таким способом:
    Код (C++):
    var ssid = 'ВАША_ТОЧКА_ДОСТУПА';
    var password = 'ВАШ_ПАРОЛЬ';
    var pinAlarm = "D21"; // Нога датчика
    // Это получить от Телеграма:
    var bot = "bot123456789:AAAAAAAAAAAAAAAA-bbbbbbbbbbbbbbb";
    var id = "1234567890";

    var cl = console.log;
    var wifi = require('Wifi');
    var http = require("http");

    var mod = {
       alarm : "ON",
       wifi : false,
       oldalarm : 0
    };

    function getwifi(){
      wifi.connect(ssid, {password: password}, function(er) {
       cl(wifi.getIP().ip);
       mod.wifi = true;
      });
    }

    wifi.on('disconnected', function(details) {
       cl("Lost WiFi!");
       mod.wifi = false;
       getwifi();
    });

    function telegram(alarm){
       let al = alarm || 'Alarm Now!';
       let mes = "https://api.telegram.org/" + bot + "/sendMessage?chat_id=" + id + "&text=" + al;
       http.get(mes, function(res) {
         res.on('data', function(data) {
           cl("process.memory().free = ", process.memory().free);
           console.log(data);
           cl("process.memory().free = ", process.memory().free);
         });
       });
    }

    function checkalarm(){
      let alarmnow = digitalRead(pinAlarm);
      if(alarmnow !== mod.oldalarm) {
      mod.oldalarm = alarmnow;
      cl("alarmnow = ", alarmnow);
      if((mod.wifi === false) || mod.alarm == "OFF") return;
      if(alarmnow) {
        telegram("Alarm IR Sensor!");
      }
      }
    }

    getwifi();
    setInterval(checkalarm, 100);
    setInterval(()=>cl(process.memory().free), 15000);

    Профит:
    upload_2017-12-13_17-53-17.png

    Теперь о грустном. Не смог вкрячить Телеграм в предыдущий код - пишет "мало памяти".
    Возможно, дело в промисах плюс мое незнание языка, однако универсальное оповещающее устройство, полагаю, сделать удастся: температура + проникновение.

    Но... Сыровато пока :-( Вот простейший код:

    upload_2017-12-13_18-32-38.png

    Каков вывод? Учиться, учиться, учиться :)
    По ощущениям, ESP32 не допилена под Espruino, но сдаваться пока рано :)
     
    Последнее редактирование: 14 дек 2017
  11. IvanUA

    IvanUA Гуру

    Игорь, не совсем понял что у Вас не получается...
    По Вашему примеру подключил датчик движения и прописал отправку сообщений в телеграм.
    Единственное не понял зачем вы вызываете process.memory(). По этому я эту часть кода убрал.

    ПС. Ах да, единственное что, в get запросе мне пришлось добавить слово "bot" перед ид моего бота. Тогда и сообщения полетели в телеграм.
     
  12. ИгорьК

    ИгорьК Гуру

    У меня там в примере видно что оно нужно.

    Проблема - не получается добавить функционала - отправка сообщения на api телеграм съедает всю память. Не удается даже Ds18b20 опросить.
    Максимум что сделал - связал с брокером и можно разрешать/запрещать отправку сообщений боту - т.е. снимать и ставить на сигнализацию.

    process.memory() нужен для наблюдения за утечкой памяти. А она течет, когда происходит пересоединение с Wi-Fi, если он пропадает. Дома это не большая проблема, а на даче интернет пропадает по пять раз в день. Память будет съедаться, плата в конце концов зависнет.

    С учетом того, что полная перезагрузка Espruino программным путем не возможна( а только кнопочкрй), утечка памяти есть тоже проблема.

    В общем, изучение Espruino для ESP32 пока выявляет определенные проблемы и сравнение в пользу Lua от NodeMCU. К сожалению, их работа идет медленно.
     
    Последнее редактирование: 15 дек 2017
  13. IvanUA

    IvanUA Гуру

    Игорь, а вы не пробовали тот же скрипт на другом экземпляре ЕСП?
    Дело в том что у меня фактически ваш скрипт с моими хотелками делает без проблем:
    - опрашивает два датчика Ds18b20 и публикует их на брокер;
    - два порта заняты под светодиоды и управляются через брокер;
    - еще один порт со светодиодом отображает состояние датчика движения;
    - ну собственно сам порт под датчик движения;
    - вот теперь и вывод аларма в телеграм;
    - сейчас дописываю вывод в телеграм температуры с датчиков...
    пока все работает. Поставлю на тесты посмотрим когда память кончится, но насколько я успел почитать по поводу JS то в нем реализована функция сборщика мусора. Чем собственно и должна решаться проблема утечки памяти.

    ПС.
    Сразу в голове промелькнула мысль, добавить ардуинку, и подавать на нее с какой то частотой импульсы от ЕСП. Как только ЕСП зависла, импульсов нет, ну и ардуинка ресетит ЕСП)))))))))
     
    Последнее редактирование: 15 дек 2017
    ИгорьК нравится это.
  14. ИгорьК

    ИгорьК Гуру

    Хм... неожиданно.

    Попробовал другой модуль - тоже не очень.
    Пожалуйста, проверьте вот такой простой код:

    Код (Javascript):

    setWatch(function(e) {
      console.log("Button pressed");
    }, D0, { repeat: true, edge: 'rising' });
    Понажимайте кнопку на модуле - что получится?
    Вот мой вариант:
    upload_2017-12-15_10-47-55.png
     
  15. SergeiL

    SergeiL Оракул Модератор

    В свое время, для работающей на даче Leonardo ETH, делал аппаратный WatchDog на ATtiny13.
    Искал WatchDog с таймаутом на 20-30 секунд, но не нашел, поэтому сделал на ATtiny.
    Так, на всякий случай, потому, что на даче.

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

    Честно говоря, не ожидал, на Leonardo ETH ни одного незапланированного рестарта за все время не было (скоро уже год).
    Да и LTE роутер, к которому она подключена, ни разу не ресетился в принципе.
     
    Последнее редактирование: 15 дек 2017
    IvanUA нравится это.
  16. ИгорьК

    ИгорьК Гуру

    Вот это сказка... :)
     
  17. IvanUA

    IvanUA Гуру

    Таже фигня
    Безымянный.jpg
     
  18. IvanUA

    IvanUA Гуру

    Думаю что проблема таки не в модуле, надо думать что там с кодом такое. Кстати если чего, могу вам скинуть весть свой код. Сравните со своим и будет видно что к чему.
     
  19. ИгорьК

    ИгорьК Гуру

    Не в модуле. Прошивка все таки под ESP32 не точится, так, побочный продукт.
    Код прямо из примера - ссылку я дал.
    Lua мне как-то ближе. И возможность исполнять файлы из памяти доставляет. Ну ничего, уже кое что можно делать.
     
  20. IvanUA

    IvanUA Гуру

    Вот вот. И я вот хотел обновить модуль управления коридором на ESP32. Думал "быстренько" соберу на JS... Ан нет. Сейчас видимо быстренько, так как Ардуино ИДЕ (С++) мне как-то ближе, соберу на том что знаю и запущу в эксплуатацию(тестирование).... Ну а JS - буду бороздить в свободное время....

    ПС... Кстати за два дня теста, постоянно отваливается публикация в телеграм, при чем, то вообще ничего не приходит (аларм и температура), то только алармы идут.... Но что самое интересное, модуль то не виснет. Завел эти данные на маджордом, и вижу что ESP32 таки публикует данные в брокер - значит не висит, а работает. Вывод - ЕСП не виснет, каким то макаром отваливаются библиотеки ( в данном случае pub.http).
    И еще что замечал. Если много много раз прошивать модуль, типа отладка, то со временем при прошивке в ком порт лезет всякий мусор, и вплоть до того что при прошивке, экран ноута начинает жить своей жизнью. Не знаю как это точно объяснить, но все становится на свои места когда прошивка заканчивается. И еще Когда много много раз прошиваешь, то он почему то не полностью переписывает прошивку, и начинается вылезание тех функций, которых уже быть не должно... Помогает только полная перепрошивка модуля, вернее новая заливка JS.(((( За эти дни, было два раза..
     
    ИгорьК нравится это.