Коллеги! Есть код, который получает текущее время с сервера: Код (Lua): do function getTime(tz) tz = tz or 3 conn=net.createConnection(net.TCP, 0) conn:on("connection",function(conn, payload) conn:send("HEAD / HTTP/1.1\r\n".. "Host: google.com\r\n".. "Accept: */*\r\n".. "User-Agent: Mozilla/4.0".. "\r\n\r\n") end) conn:on("receive", function(conn, payload) -- print('\n\n'..payload) time = string.sub(payload,string.find(payload,"Date: ")+23,string.find(payload,"Date: ")+31) hour = string.sub(time, 0, 2) + tz minute = string.sub(time, 4,5) second = string.sub(time, 7,9) print("\n\n"..hour.."-"..minute.."-"..second) conn:close() end) conn:connect(80,'ya.ru') end getTime() end Задача - превратить его в модуль, который можно загружать и выгружать из памяти. Делаю так: Код (Lua): M={} M.hour = 99 M.minute = 99 M.second = 99 function M.getTime(timeZone) local tz = timeZone or 3 local time conn=net.createConnection(net.TCP, 0) conn:on("connection",function(conn, payload) conn:send("HEAD / HTTP/1.1\r\n".. "Host: google.com\r\n".. "Accept: */*\r\n".. "User-Agent: Mozilla/4.0".. "\r\n\r\n") end) conn:on("receive", function(conn, payload) time = string.sub(payload,string.find(payload,"Date: ")+23,string.find(payload,"Date: ")+31) M.hour = string.sub(time, 0, 2) + tz M.minute = string.sub(time, 4,5) M.second = string.sub(time, 7,9) print("\n\n"..M.hour.."-"..M.minute.."-"..M.second) conn:close() end) conn:connect(80,'ya.ru') return now end function M.retTime(timeZone) M.getTime(timeZone) print(M.hour, M.minute, M.second) return M.hour, M.minute, M.second end return M Обзываем модуль time.lua, загружаем и делаем вызов из другого скрипта: Код (Lua): do local time = require'time' h,m,s = time.retTime(4) print(h,m,s) -- time = nil -- collectgarbage() end Проблема в том, что функция "conn: on" возвращает время когда оно получено (callback), а модуль в целом возвращает немедленные значения. Таким образом: - если его выгружать, он возвращает все время 99 - если не выгружать (а выгружать нужно, иначе зачем вся свистопляска), то он возвращает прошлые значения, при этом сам печатает (print("\n\n"..M.hour.."-"..M.minute.."-"..M.second)) только что полученные.
Немножко не понял вот это " если не выгружать (а выгружать нужно, иначе зачем вся свистопляска), то он возвращает прошлые значения, при этом сам печатает (print("\n\n"..M.hour.."-"..M.minute.."-"..M.second)) только полученные" - что это значит? Давайте начнём с малого, потом продолжим. Если я правильно понял, то если модуль не выгружать, то после срабатывания коллбэка события "receive" он печатает только что полученные значения. При этом если обратится к M.minute и т.п. после срабатывания события - то там будут старые значения, так? Емнип, по умолчанию переменные в Lua декларируются глобальными, если только не указать квантификатор local, по коду вижу, что идёт обращение к глобальной таблице M, т.е. тут всё вроде нормально. Т.е. я не вижу проблемы в том, что вызов retTime возвращает старые значения, поскольку работа по получению новых наверняка асинхронная. По поводу выгрузки, есть только одна идея: юзать отдельную глобальную таблицу только для значений: сделайте отдельный файлик, где пропишите что-то вроде (за синтаксис не ручаюсь, давно было): Код (C++): TimeStruct = {} TimeStruct.hour = 99 ... И подключать этот файл вызовом require("timestruct.lua"), подключенный файл - не выгружать. Из оверхэда - лишняя таблица и метатаблица для объекта в памяти, копейки. Ну и юзать TimeStruct как держатель времени для вашего объекта M.
Не по-русски я объяснил. Чуть исправил пост выше. Модули можно загружать и выгружать из памяти. Если модуль нужен не часто - зачем ему там висеть? Если внутри модуля асинхронная функция, то она возвращает значение через некоторое время. Но сам модуль отвечает "немедленно". Вы попробуйте как это работает - весь код рабочий.
Значит, надо смотреть, возможен ли синхронный режим работы. Если невозможен, есть выход: не читать напрямую сразу, а передавать в функцию retTime свой коллбэк, который дёрнется по прибытию данных. Конечно, в этом случае может понадобиться пересмотр логики работы, т.к. асинхронная логика - это несколько другой коленкор. Кстати, я предпочитаю именно асинхрон в таких вещах - не тормозится ничего. С удовольствием бы, да не на чем. Что код рабочий - верю, просто не очень понимаю, что именно вас смущает? Асинхронность как таковая? Или проблема с выгрузкой? С выгрузкой вы всё равно ничего не сделаете: чтобы иметь старые значения, надо где-то в памяти их держать. Где это будет - уже другой вопрос, но естественно, что при выгрузке скрипта память под все его таблицы уничтожается. Выход - держать необходимый минимум невыгружаемых данных, если уж вопрос памяти стоит так остро.
Дык точно так же, как вы передаёте Код (C++): conn:on("receive", function(conn, payload) Делаете примерно так (навскидку пишу): Код (C++): function M.retTime(timeZone,callback) M.getTime(timeZone,callback) ... end В getTime по приходу данных дёргаете callback: Код (C++): function M.getTime(timeZone, funcToCall) local fc = funcToCall conn:on("receive", function(conn, payload) time = string.sub(payload,string.find(payload,"Date: ")+23,string.find(payload,"Date: ")+31) M.hour = string.sub(time, 0, 2) + tz M.minute = string.sub(time, 4,5) M.second = string.sub(time, 7,9) fc(M) -- дёргаем каллбэк print("\n\n"..M.hour.."-"..M.minute.."-"..M.second) conn:close() end) Ну и где нужно, объявляем саму функцию и передаём её при вызове retTime: Код (C++): function OnDataReceived(m) print(m.hour) ... end M.retTime(timeZone,OnDataReceived) Естественно, это только иллюстрация подхода. Там вообще можно всё что угодно делать: можете тупо в таблицу M поместить указатель на функцию, которая будет дёргаться каждый раз по приходу данных. Делается это точно так же, как вы инициализируете M.hour = 99 и т.п. Lua без разницы, какие данные в таблице - там и ключом, и значением может являться всё что угодно.
вот это... это где? Почему m - маленькая? ... мое линейное Си(шное) мышление с трудом переваривает ...
Код (C++): do local time = require'time' function OnDataReceived(m) print(m.hour) end h,m,s = time.retTime(4, OnDataReceived) print(h,m,s) end Так? ДДДДДДДДДДДДДДДДДДДДДДААААААААААААААААААААААААААААА!!!!!! Еще не понял до конца, но все, буду экспериментировать и въеду окончательно!!!! Спасибо! Трижды спасибо! Эту нитку я размотаю обязательно
Таким образом, исключительно благодаря чуткому руководству DIYMan, модуль time.lua проверки времени выглядит так: Код (Lua): M={} M.hour = 0 M.minute = 0 M.second = 0 function M.getTime(timeZone, funcToCall) local tz = timeZone or 3 local time local fc = funcToCall conn=net.createConnection(net.TCP, 0) conn:on("connection",function(conn, payload) conn:send("HEAD / HTTP/1.1\r\n".. "Host: google.com\r\n".. "Accept: */*\r\n".. "User-Agent: Mozilla/4.0".. "\r\n\r\n") connection = conn end) conn:on("receive", function(conn, payload) time = string.sub(payload,string.find(payload,"Date: ")+23,string.find(payload,"Date: ")+31) M.hour = string.sub(time, 0, 2) + tz M.minute = string.sub(time, 4,5) M.second = string.sub(time, 7,9) fc(M) conn:close() end) conn:connect(80,'ya.ru') return now end return M А получать данные из него надо так: Код (Lua): do local time = require'time' print("time is ", time) -- модуль загружен, ссылка function OnDataReceived(m) print(m.hour, m.minute, m.second) time = nil -- только после возврата удаляем модуль time collectgarbage() -- чистимся end time.getTime(4, OnDataReceived) -- 4 временная зона, и callback print("time at end of code is ", time) -- проверяем, что код исполнен, а модуль еще не выгружен tmr.alarm(1,3000, 0, function() -- проверяем что модуль выгружен callback(ом) print("time NOW is ", time) end) end
Мы же переменную туда передаём, в нашем случае - ссылку на таблицу М. Строго говоря, можно было назвать параметр функции как хочешь - хоть m, хоть incomingParameter, хучь как.
Разобрался. Мне вот как раз этого немножко не хватало. В книге Иерусалимски как-то не очень понятно все это описано. Читал-читал... Но сейчас, полагаю, все понял.
Да какое там руководство - так, мутота одна (с) "Ширли-Мырли". Игорь, вы на досуге почитайте про сами таблицы и метатаблицы в Lua - въехать сложно поначалу, но такие чудеса потом можно творить, аж жуть С помощью метатаблиц можно делать цепочки вызовов методов, динамически назначать свойства по переданным извне строкам, короче - разгуляй полный. Если честно - то я не знаю задачи, которая Lua с её концепцией метатаблиц не по зубам. Плюс - Lua быстр, как Брюс Ли И это является одной из причин, почему его довольно часто используют в геймдеве в качестве скриптового языка.
Для меня callback очень важный шаг. Все операторы Lua я выучил и даже тем тут нагородил, вполне работают все. Но стиль программирования - Сишный Ардуиновский. Я же самоделкин, а не программист. Заметил, кстати, что ардуиноводы очень агрессивны ко всему неардуиновскому А мне и Lua и JS нравится изучать. Я даже между ними пока разницу не вижу. Синтаксис не в счет. Но на JS хотя бы литературы много. Это хорошо.
JS да, за последние годы сильно ушёл вперёд - те же анонимные функции и пр. Когда-то он таким не был. И что-то мне подсказывает, что многие концепции в своё время были содраны, угадайте, с чего? Впрочем, это к делу не пришьёшь. А вот то, что Lua по-любому легче, чем JS - это только в плюс Lua. Я, правда, не знаю, как там ребята сделали порт для ESP, но подозреваю, что должно быть всё грамотно. Меня, правда, пока что-то останавливает юзать NodeMCU, но тому есть одно личное предубеждение - считаю, что пока всё это находится на этапе внедренческих экспериментов. Вот и наблюдаю тихонько со стороны. А вообще говоря, есть у меня мнение, что скриптовые языки таки скоро обоснуются в IoT плотно - намного удобней, с прикладной точки зрения, вести разработку на них. Впрочем, вскрытие покажет. З.Ы. Разница между Lua и JS - огромная: в JS нет метатаблиц. И это - огромный минус JS. Ещё в плюс к Lua - он реально очень легко встраивается, позволяя из нативного кода получать доступ к любым внутренним данным и передавая вовне шо хошь. Никаких плясок с бубном, как было в своё время с JS - COM-объект создай, интерфейсы запроси, всё это жрёт кучу памяти, работает по сравнению с Lua как черепаха, половину того, что хочется, надо через жопу в гланды лезть Короче, вы поняли - я за Lua Хотя на JS код пишу практически каждый день. Для меня Lua - это академический подход, а JS - заслуженный работяга. З.Ы. И почему всегда тянет к красивому и утончённому, хотя повседневно пользуешься топором?
Это не так. Не утверждаю, что умею писать что-то сложное, но все что сделал на ESP8266 - все на Lua и ничто не виснет. Кроме того, посмотрите эту тему: http://forum.amperka.ru/threads/Монитор-co2-в-помещении.8436/ NodeNCU не менее стабилен чем Arduino IDE для ESP8266, без сомнения.