Таймер alarm

Тема в разделе "ESP8266, ESP32", создана пользователем Alex.V, 15 окт 2020.

  1. Alex.V

    Alex.V Нуб

    Добрый день. Пытаюсь залить скрипт LUA на прошивку NodeMCU, вылетает ошибка таймера alarm. Погуглив интернеты выяснил что данный параметр был удален в новых версиях nodemcu и заменен на динамический таймер. Своими силами поправить не получилось. Прошу помощи знающих людей.

    В двух словах, скрипт для модуля ,esp8266 и rs485 , для снятия показаний с счетчика энергомера с102, и отправки в MQTT согласно инструкции. Похожий код тут обсуждали.

    Имеется следующий код:

    Код (C++):
    -- Таймеры опроса счётчика
    tmr.alarm(1, CE102M_CyclePeriod, tmr.ALARM_AUTO, function()
        ce102m_step = 1
     
        tmr.alarm(2, CE102M_RequestPeriod, tmr.ALARM_AUTO, function()
            NextRequest(ce102m_step)
            ce102m_step = ce102m_step + 1
            if (ce102m_step > (#ce102m_params + 3)) then
                tmr.unregister(2)
            end
        end)
    end)

    -- Таймер установки соединения по WiFi и MQTT
    tmr.alarm(0, 5000, tmr.ALARM_AUTO, function()
        print("tmr0 "..wifi_status_old.." "..wifi.sta.status())

        if wifi.sta.status() == 5 then -- подключение есть
            if wifi_status_old ~= 5 then -- Произошло подключение к Wifi, IP получен
                print(wifi.sta.getip())
             
                m = mqtt.Client(MQTT_ClientID, 120, MQTT_Client_user, MQTT_Client_password)

                -- Определяем обработчики событий от клиента MQTT
                m:on("connect", function(client)
                    -- Мы подключились к брокеру
                    MQTT_connected = true
                    uart_setup()
                end)
                m:on("offline", function(client)
                    -- Мы отключились от брокера
                    MQTT_connected = false
                end)

                m:connect(MQTT_BrokerIP, MQTT_BrokerPort, 0, 1, nil)
            else
                -- WiFi-подключение есть и не разрывалось
            end
        else
            wifi.sta.connect()
        end

    Ругается на параметр alarm

    Вроде как нужно теперь задавать переменную , но дальше я не осилил.

    Ссылку на файл прилагаю.
    https://bitbucket.org/nadyrshin_ryu/esp8266_ce102m_gate/downloads/

    Если кто может подсказать, направить, буду очень признателен.

    Были уже мысли поставить прошивку старую, но это же не наш метод.
     
  2. b707

    b707 Гуру

    Могу ошибаться. но у вас аларм 2 определен внутри аларма 1. Так нельзя.
    Вынесите аларм2 в основную часть скрипта и посмотрите, не исчезнет ли ошибка.

    Точнее придет ИгорьК и поправит.
     
  3. Alex.V

    Alex.V Нуб

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

    https://stackoverflow.com/questions/59147393/lua-init-lua15-attempt-to-call-method-alarm-a-nil-value
     
  4. b707

    b707 Гуру

    что вам непонятно по ссылке?
    попробуйте переписать
    Код (C++):
    tmr.alarm(2000, tmr.ALARM_AUTO, function ()
    как
    Код (Javascript):
    local tObj = tmr.create()
    -- register an alarm
    tObj:alarm(2000, tmr.ALARM_AUTO, function ()
    Но это не отменяет той ошибки, о которой я писал в первом ответе - вложенные каллбеки это неправильно
     
  5. Alex.V

    Alex.V Нуб

    Так я пробовал поменять, все равно летит ошибка
    я задал локальную переменную в общем списке
    Код (Text):
    local wifi_status_old = 0
    local rx_buff = ""
    local last_param_name
    local MQTT_connected = false
    local m
    local tObj = tmr.create()
    -- Запрашиваемые из счётчика параметры
    local ce102m_params = {"VOLTA","CURRE","POWEP","COS_f","FREQU"}
    local ce102m_step
    далее заменил tmr.alarm на tObj:alarm, так же заменил tmr.unregister на tObj:unregister

    после чего так же летит ошибка

    Код (Text):
    Lua error:     stdin:1: attempt to index global 'tObj' (a nil value)
    stack traceback:
        stdin:1: in main chunk
        [C]: ?
        [C]: ?
     
    я полагаю что глобальная переменная должна быть как то по другому обозначена если он пишет что значение пусто

    И еще вопрос после безошибочного Применения Save to ESP и Send to ESP по идее скрипт должен записаться на ESP, но при нажатии кнопки Reload не загружается список файлов


    Total : 3509482 bytes
    Used : 0 bytes
    Remain: 3509482 bytes

    А после перезагрузки устройства при нажатии Save to ESP


    Код (C++):
    > Lua error:     stdin:1: attempt to call global 'w' (a nil value)
    stack traceback:
        stdin:1: in main chunk
        [C]: ?
        [C]: ?
    > Lua error:     stdin:1: attempt to call global 'w' (a nil value)
    stack traceback:
        stdin:1: in main chunk
        [C]: ?
        [C]: ?
    > > Lua error:     cannot open ce102m_gate.lua:
    stack traceback:
        [C]: in function 'dofile'
        stdin:1: in main chunk
        [C]: ?
        [C]: ?
    >
    И как следствие скрип не загружается в устройство

    Я приложу файл целиком, может кто сможет поправить
     

    Вложения:

    • script2rev.txt
      Размер файла:
      7,4 КБ
      Просмотров:
      39
    Последнее редактирование: 15 окт 2020
  6. serg3295

    serg3295 Гик

    На самом деле один таймер, вложенный в другой, прекрасно работают.
    Код (C++):
    tm1 = tmr.create()
    tm2 = tmr.create()

    tm1:alarm(4000, tmr.ALARM_AUTO, function ()
        print("tmr1")
        tm2:alarm(2000, tmr.ALARM_SINGLE, function ()  print("tmr2")  end)
    end)
     
    Просто второй таймер не стоит делать AUTO. Он же будет запускаться каждый раз от первого таймера, который молотит непрерывно. А если SINGLE, то истечёт и всё.
    Другой вопрос - зачем это надо.
    UPD. Пожалуй, уточню. Второй таймер, конечно, может быть и AUTO, но надо тогда следить, чтобы он успевал истечь stop&unregister внутри периода первого таймера. Иначе с логикой кода будет как-то странно.
     
    Последнее редактирование: 15 окт 2020
  7. ИгорьК

    ИгорьК Оракул Модератор

    В железе не проверял! Исправил только что касается таймеров.


    Код (Lua):
    -- Таймеры опроса счётчика
    tmr.create():alarm(CE102M_CyclePeriod, tmr.ALARM_AUTO, function(pt)
        ce102m_step = 1
        tmr.create():alarm(CE102M_RequestPeriod, tmr.ALARM_AUTO, function(t)
            NextRequest(ce102m_step)
            ce102m_step = ce102m_step + 1
            if (ce102m_step > (#ce102m_params + 3)) then
                t:stop()
                t:unregister()
                t = nil
                ce102m_step = 1
            end
        end)
    end)


    -- Таймер установки соединения по WiFi и MQTT
    tmr.create():alarm(5000, tmr.ALARM_AUTO, function(t)
        print("tmr0 "..wifi_status_old.." "..wifi.sta.status())

        if wifi.sta.status() == 5 then -- подключение есть
            if wifi_status_old ~= 5 then -- Произошло подключение к Wifi, IP получен
                print(wifi.sta.getip())

                m = mqtt.Client(MQTT_ClientID, 120, MQTT_Client_user, MQTT_Client_password)

                -- Определяем обработчики событий от клиента MQTT
                m:on("connect", function(client)
                    -- Мы подключились к брокеру
                    MQTT_connected = true
                    uart_setup()
                end)
                m:on("offline", function(client)
                    -- Мы отключились от брокера
                    MQTT_connected = false
                end)

                m:connect(MQTT_BrokerIP, MQTT_BrokerPort, 0, 1, nil)
            else
                -- WiFi-подключение есть и не разрывалось
            end
        else
            wifi.sta.connect()
        end
    Что-то там тикает из первой части вашего кода как пруф (естественно, необходимые переменные подменены от балды):
    upload_2020-10-15_20-10-41.png

    Весь код... Нет ничего хуже чем копаться в чужом коде, когда тебе это не нужно.
    Вот лишний end:
    upload_2020-10-15_20-16-11.png

    Ну и в целом - его кто-то же писал, ищите там.
     
    Последнее редактирование: 15 окт 2020
  8. Alex.V

    Alex.V Нуб

    Спасибо вам большое, первым делом я написал автору, но в ответ тишина.
     
  9. Alex.V

    Alex.V Нуб

    Решил залить скрипт и в итоге летит ошибка
    Код (Text):
    w([==[  Lua error:     stdin:1: attempt to call global 'w' (a nil value)
    stack traceback:
        stdin:1: in main chunk
        [C]: ?
        [C]: ?
     
    и ее очень много при попытке залить скрипт на ESP
    Я подумал может я где то опечатку совершил, перезалил все заново и все равно тоже самое. Ребята что это может быть? Причем при отправке на ESP ошибок нет, а вот при попытке сохранить на ESP летит ошибка и скрипт не загружается.

    еще нашел вот такую ошибку

    Код (Text):
    Lua error:     stdin:1: unexpected symbol near ']'
     
     
    Последнее редактирование: 17 окт 2020
  10. ИгорьК

    ИгорьК Оракул Модератор

    Такие ошибки лезут когда сильно нарушена структура кода - потеряны пара end или еще что-то такое.

    А это ошибка передачи кода в порту Windows - прилетел какой-то неопознанный знак.
    В таком случае файлы нужно грузить только через

    upload_2020-10-16_23-24-22.png

    Уважаемый, не рабочий это код. Помнится, другой человечек с ним также мучился и ничего не получилось у него.
     
  11. Alex.V

    Alex.V Нуб

    Очень жаль, спасибо за помощь и уделенное время
     
  12. Alex.V

    Alex.V Нуб

    Здравствуйте друзья.
    Я не оставляю надежд на решение своего вопроса любым методом.
    Так как битва с кривым кодом ни к чему не привела, я нашел скетч arduino рабочий под мой счётчик.
    Вопрос в том, мог бы кто то дописать два блока в него. Чтобы он подключался к WiFi и передавал данные на mqtt сервер? Ссылку и код прилагаю

    Понимаю что возможно это не сложная задача, но я с этим ещё не знаком и самому сделать не получилось.

    https://github.com/vgamaev/Energomera-CE102M-Arduino

    Код (C++):
    #include <SoftwareSerial.h>

    #define  ENERGOMERA

    long Previous = 0;
    int Step = 0;
    char x [50];

    // открываем сессию
    byte CmdOpenSesion[] = {0xaF,0x3F,0x21,0x8D,0x0A};
    // читаем тип счетчика
    byte CmdReadType[] = {0x06,0x30,0x35,0xb1,0x8d,0x0a};
    // снимаем показания
    byte CmdEtope[] = {0x81,0xd2,0xb1,0x82,0xc5,0xd4,0x30,0x50,0xc5,0x28,0xa9,0x03,0xb7};
    //напряжение на фазах
    byte CmdVolta[] = {0x81,0xd2,0xb1,0x82,0x56,0xcf,0xcc,0xd4,0x41,0x28,0xa9,0x03,0x5f};
    // мощность
    byte CmdPower[] = {0x81,0xd2,0xb1,0x82,0x50,0xcf,0xd7,0xc5,0x50,0x28,0xa9,0x03,0xe4};
    // частота
    byte CmdFrequ[] = {0x81,0xd2,0xb1,0x82,0xc6,0xd2,0xc5,0xd1,0x55,0x28,0xa9,0x03,0x5c};
    // ток
    byte CmdCurre[] = {0x81,0xd2,0xb1,0x82,0xc3,0x55,0xd2,0xd2,0xc5,0x28,0xa9,0x03,0x5a};
    // cos f
    byte CmdCos_f[] = {0x81,0xd2,0xb1,0x82,0xc3,0x55,0xd2,0xd2,0xc5,0x28,0xa9,0x03,0x5a};


    #define CYCLE_TIME 15
    #define DIR 15  //8
    SoftwareSerial UART(14, 12); //(10, 11); // RX, TX

    struct Energomera{
      String NameParam;
      String StrValue;
      float  FloatValue;
    };


    String ReadStr;
    Energomera Etope;
    Energomera Volta;
    Energomera Power;
    Energomera Curre;
    Energomera Frequ;
    Energomera Cos_f;


    Energomera ValueParser(String inString, String Param)
    {
      String inString2;
      Energomera Buffer;

      Buffer.NameParam = Param;
      Buffer.StrValue = "0";
      Buffer.FloatValue = 0;

      if (inString.lastIndexOf(Param)>0)
          {
              int first = inString.indexOf(Param);
              first = inString.indexOf('(', first + 1 );
              first = first +1;
              //Serial.println(first);
              int first_2 = inString.indexOf(')', first + 1 );
                   
              inString2 = inString.substring(first,first_2);
              inString2.toCharArray(x, sizeof(x));
              float f = atof(x);
           
              Buffer.StrValue = inString2;
              Buffer.FloatValue = f;
           
              inString = "";
          }
          return Buffer;
    }

    void PrintVolume(Energomera Buffer)
    {
       Serial.print(Buffer.NameParam);
       Serial.print("   ");
       Serial.print(Buffer.StrValue);   //формат string
       Serial.print("------>");
       Serial.println(Buffer.FloatValue);           //формат float
    }

    void EnergomeraRead()
    {
      switch (Step) {
            case 1:
               
            break;
            case 2:
               
            break;
            case 3:
                  Etope = ValueParser(ReadStr, "ET0PE");
                  PrintVolume(Etope);
            break;
            case 4:
                  Volta = ValueParser(ReadStr, "VOLTA");
                  PrintVolume(Volta);
            break;
            case 5:
                  Power = ValueParser(ReadStr, "POWEP");
                  PrintVolume(Power);
            break;
            case 6:
                  Frequ = ValueParser(ReadStr, "FREQU");
                  PrintVolume(Frequ);
            break;
            case 7:
                  Curre = ValueParser(ReadStr, "CURRE");
                  PrintVolume(Curre);
            break;
            case 8:
                  Cos_f = ValueParser(ReadStr, "COS_f");
                  PrintVolume(Cos_f);
                  Serial.println();
            break;
            default:

            break;
          }
          ReadStr = "";
    }


    void SendCommand(byte* cmd, int size)
    {
        digitalWrite(DIR, HIGH);
        UART.write (cmd,size);
        digitalWrite(DIR, LOW);
    }

    void EmergomeraWrite()
    {
        switch (Step) {
            case 1:
                 SendCommand(CmdOpenSesion,5);
            break;
            case 2:
                 SendCommand(CmdReadType,6);
            break;
            case 3:
                 SendCommand(CmdEtope,13);
            break;
            case 4:
                 SendCommand(CmdVolta,13);
            break;
            case 5:
                 SendCommand(CmdPower,13);
            break;
            case 6:
                 SendCommand(CmdFrequ,13);
            break;
            case 7:
                 SendCommand(CmdCurre,13);
            break;
            case 8:
                 SendCommand(CmdCos_f,13);
            break;
            case CYCLE_TIME:
                   Step = 0;
            break;
              default:

            break;
          }
     
    }

    void setup()
    {
      Serial.begin(9600);
      UART.begin(9600); //, SWSERIAL_8N1, 14, 12, false, 256);
      pinMode(DIR, OUTPUT);
      digitalWrite(DIR, HIGH);
    }

    void EnergomeraCycle()
    {
      if (UART.available())
        {
          char response = UART.read();
          response &= 0x7F;// convert 8N1 to 7E1
       
          //Serial.print(response);
          char inChar = response;

          ReadStr += inChar;
        }
     
        //ReadStr = "FREQU(50.00)";
        //Serial.println(ReadStr);
       
        if (millis() - Previous > 1000)
        {
         Previous = millis();
         EnergomeraRead();
         Step ++;
         EmergomeraWrite();      
         }
    }

    void loop()
    {
        EnergomeraCycle();
    }
     

    Плата у меня wemos d1 mini
    [​IMG]

    трансивер rs485
    [​IMG]