Добрый день. Пытаюсь залить скрипт 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 определен внутри аларма 1. Так нельзя. Вынесите аларм2 в основную часть скрипта и посмотрите, не исчезнет ли ошибка. Точнее придет ИгорьК и поправит.
В англоязычных просторах я нашел схожую проблему, там коллега поделился как это исправить, но я не в силах это интерпретировать на мой код, так как он немного сложнее представленного в их случае. Может кто то сможет адаптировать данное решение к моему коду. https://stackoverflow.com/questions/59147393/lua-init-lua15-attempt-to-call-method-alarm-a-nil-value
что вам непонятно по ссылке? попробуйте переписать Код (C++): tmr.alarm(2000, tmr.ALARM_AUTO, function () как Код (Javascript): local tObj = tmr.create() -- register an alarm tObj:alarm(2000, tmr.ALARM_AUTO, function () Но это не отменяет той ошибки, о которой я писал в первом ответе - вложенные каллбеки это неправильно
Так я пробовал поменять, все равно летит ошибка я задал локальную переменную в общем списке Код (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]: ? > И как следствие скрип не загружается в устройство Я приложу файл целиком, может кто сможет поправить
На самом деле один таймер, вложенный в другой, прекрасно работают. Код (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 внутри периода первого таймера. Иначе с логикой кода будет как-то странно.
В железе не проверял! Исправил только что касается таймеров. Код (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 Что-то там тикает из первой части вашего кода как пруф (естественно, необходимые переменные подменены от балды): Весь код... Нет ничего хуже чем копаться в чужом коде, когда тебе это не нужно. Вот лишний end: Ну и в целом - его кто-то же писал, ищите там.
Решил залить скрипт и в итоге летит ошибка Код (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 ']'
Такие ошибки лезут когда сильно нарушена структура кода - потеряны пара end или еще что-то такое. А это ошибка передачи кода в порту Windows - прилетел какой-то неопознанный знак. В таком случае файлы нужно грузить только через Уважаемый, не рабочий это код. Помнится, другой человечек с ним также мучился и ничего не получилось у него.
Здравствуйте друзья. Я не оставляю надежд на решение своего вопроса любым методом. Так как битва с кривым кодом ни к чему не привела, я нашел скетч 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 трансивер rs485