This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

MQTT subscribe
#1
Hello,

I'm trying to subscribe to a MQTT topic ("arqueta/humedad") and asign his value to an object of logic machine.

I'm using de test Mosquitto broker and I publish previously a value to the topic "arqueta/humedad".

I'm using this code (extracted from here) as a resident script but It seems doesn't works and I don't know what I'm doing wrong...

Code:
12345678910111213141516171819202122232425262728293031323334
-- Define a function which is called by mqtt_client:handler(), -- whenever messages are received on the subscribed topics     function callback(topic, message)     print("Received: " .. topic .. ": " .. message)     if (message == "quit") then running = false end   end -- Create an MQTT client instance, connect to the MQTT server and -- subscribe to the topic called "arqueta/humedad"     MQTT = require("mosquitto")   MQTT.Utility.set_debug(true)     mqtt_client = MQTT.client.create("https://test.mosquitto.org", 1883, callback)     mqtt_client:connect("logicmachine")     local humedad = mqtt_client:subscribe("arqueta/humedad")     grp.update('1/1/27', humedad) -- Continously invoke mqtt_client:handler() to process the MQTT protocol and -- handle any received messages.  Also, publish a message on topic "test/1"   running = true   while (running) do     mqtt_client:handler()     mqtt_client:publish("test/1", "test message")     socket.sleep(1.0-- seconds   end -- Clean-up by unsubscribing from the topic and closing the MQTT connection   mqtt_client:unsubscribe({"arqueta/humedad"})   mqtt_client:destroy()
Reply
#2
Upgrade firmware to 2018 RC1. It has built-in MQTT library support and some other features required for this script.

Create resident script with 0 sleep interval. Change broker IP address and mapping tables as needed.
mqtt_to_object maps topic to a group address, object_to_mqtt maps group address to atopic.

Do full script restart via disable/enable when changing any mapping tables and/or broker address.

Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
if not broker then   broker = '192.168.1.101'   function multiply(mult)     return function(value)       local num = tonumber(value)       if num then         return num * mult       else         return value       end     end   end   -- topic to object map   mqtt_to_object = {     ['in/topic1'] = '32/1/1',     ['in/topic2'] = '32/1/2',   }   -- optional topic value conversion function   mqtt_to_object_conv = {     ['in/topic1'] = multiply(100),     ['in/topic2'] = multiply(0.01),   }   -- object to topic map   object_to_mqtt = {     ['1/1/1'] = 'out/topic1',     ['1/1/2'] = 'out/topic2',   }   datatypes = {}   grp.sender = 'mq'   require('socket')   for addr, _ in pairs(object_to_mqtt) do     local obj = grp.find(addr)     if obj then       datatypes[ addr ] = obj.datatype     end   end   mclient = require('mosquitto').new()   mclient.ON_CONNECT = function(res, ...)     log('mqtt connect status', res, ...)     if res then       for topic, _ in pairs(mqtt_to_object) do         mclient:subscribe(topic)       end     else       mclient:disconnect()     end   end   mclient.ON_MESSAGE = function(mid, topic, payload)     local addr = mqtt_to_object[ topic ]     if addr then       local fn = mqtt_to_object_conv[ topic ]       if fn then         payload = fn(payload)       end       grp.write(addr, payload)     end   end   mclient.ON_DISCONNECT = function(...)     log('mqtt disconnect', ...)     mclientfd = nil   end   function mconnect()     local fd     mclient:connect(broker)     fd = mclient:socket()     -- fd ref is valid     if fd then       mclientfd = fd     end   end   mconnect()   function publishvalue(event)     -- message from us or client is not connected     if event.sender == 'mq' or not mclientfd then       return     end     local addr = event.dst     local dpt = datatypes[ addr ]     local topic = object_to_mqtt[ addr ]     -- unknown object     if not dpt or not topic then       return     end     local value = busdatatype.decode(event.datahex, dpt)     if value ~= nil then       if type(value) == 'boolean' then         value = value and 1 or 0       end       mclient:publish(topic, tostring(value))     end   end   lbclient = require('localbus').new(1)   lbclient:sethandler('groupwrite', publishvalue)   lbclientfd = socket.fdmaskset(lbclient:getfd(), 'r')   -- run timer every 5 seconds   timer = require('timerfd').new(5)   timerfd = socket.fdmaskset(timer:getfd(), 'r') end -- mqtt connected if mclientfd then   mclientfdset = socket.fdmaskset(mclientfd, mclient:want_write() and 'rw' or 'r')   res, lbclientstat, timerstat, mclientstat =       socket.selectfds(10, lbclientfd, timerfd, mclientfdset) -- mqtt not connected else   res, lbclientstat, timerstat =     socket.selectfds(10, lbclientfd, timerfd) end if mclientfd and mclientstat then   if socket.fdmaskread(mclientstat) then     mclient:loop_read()   end   if socket.fdmaskwrite(mclientstat) then     mclient:loop_write()   end end if lbclientstat then   lbclient:step() end if timerstat then   -- clear armed timer   timer:read()   if mclientfd then     mclient:loop_misc()   else     mconnect()   end end
Reply
#3
(03.12.2018, 08:43)admin Wrote: Upgrade firmware to 2018 RC1. It has built-in MQTT library support and some other features required for this script.

Create resident script with 0 sleep interval. Change broker IP address and mapping tables as needed.
mqtt_to_object maps topic to a group address, object_to_mqtt maps group address to atopic.

Do full script restart via disable/enable when changing any mapping tables and/or broker address.

I'm trying to do this but it doesn't works. I supose that when I send a value to the broker, automatically the script must receive the value? 

I've just upgrade the firmware. Here's the actual version:

[Image: firmware.png]

Here's my code where I put the mosquitto test broker and the topic "arqueta/humedad" I'm testing. the object 32/1/1 is a "05. 1 byte unsigned integer".

As I say, it doesn't works and I don't know what I'm doing wroing.

The correct line to broker is without "http://"

broker = 'test.mosquitto.org'

Now it works the suscribe.
Reply
#4
Hi!

I have problem with object_to_mqtt this topic will change on MQTT when I write new value? Is it necessary event script? Now I don't see change this value on client.
Reply
#5
No event script is needed. Value is published to selected topic when value changes. Have you checked that MQTT client is connected? Does the reverse (mqtt_to_object) work? Does the client have access to the select topic?
You can log the publish result like this (line 83):
Code:
12
local r, e, c = mclient:publish(topic, tostring(value)) log('publish', r, e, c)
Reply
#6
Solved! the problem was client software that I used, MQTT_to_object worked but no the reverse.
Reply
#7
Admin thank you for this code!, it works great.

But how can i apply a scale factor to one of the "mqtt_to_object"?
Reply
#8
I've updated example post. Edit mqtt_to_object_conv table as needed, custom conversion functions can be added as well.
Reply
#9
(09.03.2020, 08:46)admin Wrote: I've updated example post. Edit mqtt_to_object_conv table as needed, custom conversion functions can be added as well.

Hi,
in my case am using LM as broker and i need to Publish/subscribe single topic Message payloads to different group address?


how to achieve below criteria in LM5

ex: for  relay-1 is 0/0/1 as group address  
topic=100
Payload on=C,1,1,\r\n
Payload off =C,1,0,\r\n

for relay-2 is 0/0/2 as group address 
topic=100
Payload on=C,2,1,\r\n
Payload off=C,2,0,\r\n
Reply
#10
Add custom logic to the MQTT callbacks:
Code:
1234567891011121314151617181920212223
mclient.ON_CONNECT = function(res, ...)   log('mqtt connect status', res, ...)   if res then     mclient:subscribe('100')   else     mclient:disconnect()   end end mclient.ON_MESSAGE = function(mid, topic, payload)   if topic == '100' then     if payload == "C,1,1,\r\n" then       grp.write('0/0/1', true)     elseif payload == "C,1,0,\r\n" then       grp.write('0/0/1', false)     elseif payload == "C,2,1,\r\n" then       grp.write('0/0/2', true)     elseif payload == "C,2,0,\r\n" then       grp.write('0/0/2', false)     end   end end

Using one topic for controlling multiple entities is bad system design. Each relay should have it's own topic for control if possible.
Reply
#11
Hi,
please elaborate this custom Logic in Mqtt callbacks where we can i find
actually am adding this logic in main residence script please find it in attached file(how we have done)
am doing it in correct way...?

Attached Files
.txt   Mqtt res-code_LM5.txt (Size: 3.53 KB / Downloads: 120)
Reply
#12
Looks correct, add logging for each received message in case it does not work:
Code:
1234
mclient.ON_MESSAGE = function(mid, topic, payload)   log(topic, payload)   ... end
Reply
#13
(22.02.2021, 07:24)admin Wrote: Looks correct, add logging for each received message in case it does not work:
Code:
1234
mclient.ON_MESSAGE = function(mid, topic, payload)   log(topic, payload)   ... end

Hi,

Please find attached snap shots of Logs

Attached Files Thumbnail(s)
       
Reply
#14
Check the latest log entry, it shows what data was published to the topic named "100". Modify the ON_MESSAGE callback function to execute actions based on the received payload:
Code:
12345678910
mclient.ON_MESSAGE = function(mid, topic, payload)   log('ON_MESSAGE ', topic, payload)   if topic == '100' then     if payload == "11" then       grp.write('0/0/1', true)     elseif payload == "10" then       grp.write('0/0/1', false)    end   end end

You can use MQTT explorer (http://mqtt-explorer.com/) to connect to LM and send any data to any topics to test your scripts.
Reply
#15
alternatively you can use my declarative binding for mqtt2knx integration, although it was created for zigbee2mqtt topics
https://forum.logicmachine.net/showthread.php?tid=2671
Reply
#16
Hi,
in this case the publishing topic=100, and Payload=C,1,1,1,\r\n like this format while subscribing topic=100 and msg Payload=$FD;2;4;0;0;0;0;0;0;@ while watching from LM log  we found this.

Attached Files Thumbnail(s)
   
Reply
#17
Modify the example in my previous post and implement your custom actions based on the received payload value.
Reply
#18
(26.02.2021, 11:59)admin Wrote: Modify the example in my previous post and implement your custom actions based on the received payload value.

Hi, 
modification according to the log it is working fine... for Boolean objects but when it comes to light Dimming and Fan regulator the commands are different for each value can you please update that conversation according to the following parameters..

group address to MqttSadpublish)
fan speed1_very low----->C,5,1,\r\n
fanspped-low         ------>C,5,2,\r\n
fanspeed_medium  ------>C,5,3,\r\n
fanspeed_High        ----->C,5,4,\r\n
fan_off                    ----->C,5,0\r\n

mqtt to group addressSadSubscribe)
fan speed1_very low----->C,5,1
fanspped-low         ------>C,5,2
fanspeed_medium  ------>C,5,3
fanspeed_High        ----->C,5,4
fan_off                    ----->C,5,0
Reply
#19
You can use 1-byte object with custom values to control values as is (0=off, 4=highest).
Then to convert object value to payload use this:
Code:
1
payload = 'C,5,' .. value .. '\r\n'

To convert payload back to the value use this:
Code:
1
value = payload:match('C,%d,(%d)')
Reply
#20
Hello,

I use the thread to ask:
I need to introduce MQTT actuators of damphos in many rooms. How can I scan the broker for devices and automatically create objects with their names? For example, my punishments will have a topic:
Danfos /room_001...
Danfos /room_200....
How to get the names directly from the broker and create the objects I need - I will need several objects with different types of variables?
Reply


Forum Jump: