2017-01-07 16 views
0

Мое приложение включает в себя ESP8266 с питанием от батареи, работающий с NodeMCU, с целью периодического обновления значений датчиков над MQTT.С Lua/NodeMCU, как я могу дождаться, пока> 1 mqtt публичные вызовы были сделаны до запуска блока кода?

Чтобы сэкономить время работы от батарей, я хочу позвонить dsleep(), как только закончите с моей работой. Эта работа может включать более 1 вызова mqqt.Client.publish(). Это подводит нас к проблеме, с которой я сталкиваюсь.

Я новичок Lua, но, как я понимаю, правильный способ запустить код после того, как publish() закончил, чтобы дать ему PUBACK обратного вызова:

m = mqtt.Client(...) 
m.publish("/my/topic", "some message", 1, 0, callback_func) 

И в простом случае, как и выше, это отлично работает, даже если фактическая отправка сообщения MQTT является асинхронной по отношению к вызову publish() (см. хорошее обсуждение этого here), callback_func() в приведенном выше примере вызывается только тогда, когда сделано publish().

Но когда у меня есть более одного звонка на publish() и хочу, чтобы мой обратный вызов был a) вызван после того, как все они завершены, и b) только вызывается один раз, я застрял.

Наивный подход к этому было бы поставить обратный вызов (который является необязательным) только на N-м publish() вызова:

m = mqtt.Client(...) 
m.publish("/my/topic", "some message", 1, 0) 
m.publish("/another/topic", "unrelated message", 1, 0, callback_func) 

Но это не будет делать то, что ожидалось. Как documented:

ПРИМЕЧАНИЕ: При вызове publish() более одного раза будет определена последняя функция обратного вызова для ВСЕХ команд публикации.

Таким образом, в приведенном выше примере, callback_func() заканчивает тем, что называется дважды (один раз для каждого успешного publish().

Я мог бы объединить несколько таких publish() вызовов в один вызов, но чувствует, как уродливые взломать, и будет иметь другие неблагоприятные последствия.Если мои два сообщения концептуально различны, этот подход заставит логику отделить их от подписчика - yuck. И если им нужно идти по разным темам, это будет еще хуже. Должен быть лучший способ .

Я думал, возможно mqqt.Client.close() wo uld ждет моих разных publish() звонков, чтобы закончить, но это не так.

У меня нет идей, и я надеюсь, что кто-то, у кого больше опыта Lua и/или NodeMCU + mqqt, может дать мне толчок в правильном направлении.

Вот мой реальный код, если это помогает:

-- prior to this, we've gotten on the wifi network and acquired an IP 
dofile("temp.lua") -- provides get_temp() 

m = mqtt.Client("clientid", 120, "8266test", "password") 

function mainloop(client) 
    print("connected - at top of loop") 
    m:publish("uptime",tmr.time(),1,0, function(client) print("sent uptime") end) 
    temp, humi = get_temp() 
    if (temp ~= nil) then 
     print(string.format("temp: %d", temp)) 
     print(string.format("humi: %d", humi)) 
     m:publish("temp",temp,1,0) 
     m:publish("humi",humi,1,0, function(client) -- note: this callback will be used for all publish() calls 
      rtctime.dsleep(SLEEP_USEC) 
      end) 
    end 
end 

m:on("connect", mainloop) 
m:on("offline", function(client) is_connected = false print ("offline") end) 
m:connect(MQQT_SVR, 1883, 0, mainloop, 
    function(client, reason) print("failed reason: "..reason) end) 

ответ

1

Вариант 1: публиковать все данные сразу, а затем пойти спать.

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

Конечно, есть больше вариантов, но они просты и достаточны.

Edit: пример по запросу

local totalItemCount = 5 

function publishCallback() 
    itemsPublished = (itemsPublished or 0) + 1 
    print("item published") 
    if itemsPublished == totalItemCount then 
    print("I'm done, good night!") 
    end 
end 

for i = 1, totalItemCount do 
    publishCallback() 
end 

опубликованного

опубликованного

опубликованного

опубликованной

артикул

Я закончил, спокойной ночи!

+0

Спасибо! Я думаю, что ни один из этих вариантов действительно не удовлетворяет мои потребности. Вариант 1 заставляет меня искажать поведение системы по ограничениям клиента. В частности, если мои сообщения отличаются по своей природе (они есть) и, следовательно, требуют отдельной обработки (возможно, даже разных подписчиков), я оставил повторную реализацию логики темы (эффективно) внутри абонента. (Например, скажем, я публикую временные данные и данные о присутствии в комнате, и я хочу, чтобы совершенно другая логика на стороне абонента справлялась с этими двумя вещами.) – jrheling

+0

Вариант 2 звучит неплохо, но я не вижу, как его реализовать как обратный вызов ведет себя на 'publish()'. Буквально точно такая же логика запускается для каждого вызова, так как я могу проверить, завершен ли первый вызов? Можете ли вы привести пример того, как это может работать, пожалуйста? – jrheling

+1

вы используете ту же логику с помощью инструкции if, чтобы проверить, выполнены ли вы или нет. вы используете его, если я предполагаю, что вы знакомы с условными утверждениями ... вам не нужно знать, выполняется ли первый вызов. все, что вам нужно знать, это то, что все звонки выполняются до того, как вы можете заснуть. – Piglet