MQTT with 2 subscribes



  • Hi,
    I'm new to micropython. I've taken several examples on this forum, assemble them and succeed to subscribe to 2 differents mqtt topics. But how can I put the differnts message in 2 variables like sensor21 and sensor31 ?

    from mqtt import MQTTClient
    import machine
    import time
    import pycom
    
    def sub_cb(topic, msg):
       print(msg)
    
    wlan = WLAN(mode=WLAN.STA)
    wlan.connect("wifi", auth=(WLAN.WPA2, "pass"), timeout=5000)
    
    while not wlan.isconnected():
        machine.idle()
    print("Connected to Wifi\n")
    
    client = MQTTClient("device_id", "192.168.0.20",user="pi", password="raspberry", port=1883)
    
    client.set_callback(sub_cb)
    client.connect()
    
    wifiaddress = ((str(wlan.ifconfig()[:1]))[2:])[:-3]
    client.publish(topic="lopy/ip", msg=wifiaddress)
    
    client.subscribe(topic="pi/sensor21/temperature")
    client.subscribe(topic="pi/sensor31/temperature")
    
    def t3_publication(topic, msg):
        print (topic, ':', msg)
        #pycom.rgbled(0xff00)
    
    client.set_callback(t3_publication)
    
    while True:
        client.check_msg()
    

    Thanks



  • @luc-hanneuse
    first you can try to test if it is None

    if v==None:
    

    and also you can test for type by:

    type(v)
    


  • @livius

    The "topic" and "message" variables are created by the mqtt library.
    And yes, those variables don't react like string, byte,... most of the variables conversion don't work. That's why I called them "unknown".

    I've already print them, but that doesn't help to clarify the type of variable.



  • @luc-hanneuse said in MQTT with 2 subscribes:

    unknown. Is it a string, a byte,... ?

    unknown = None?
    if yes than it mean no value at all.

    And before send put print command to see what you tried to send

    print(str(val))
    s.send(bytes(val))
    

    and if you still have problem show what was printed



  • Finally some improvements, thanks for your help.
    I succeed to subscribe to several topics and get some results.

    topic_sub=["pi/sensor21/temperature","pi/sensor40/temperature","pi/sensor02/temperature","pi/sensor12/in_01","pi/sensor12/out_01"]
    topic_length=len(topic_sub)
    val= [0,0,0,0,0] #should be a better way to create this array from topic_length
    update = None # used if you want to send a signal without waiting the 800s cycle
    
    for i in range(0, topic_length):
        client.subscribe(topic=topic_sub[i])
    
    def mytopic(topic, msg):
        global update
        global topic_length
        global topic_sub
        global val
    
        if ubinascii.hexlify(topic) == ubinascii.hexlify(topic_sub[0]):
            val[0] = (msg[0]-48)*10+(msg[1]-48) #ascii-to-int, to be improved
            val[0] = val[0] % 255 #sure to be a byte
    
        if ubinascii.hexlify(topic) == ubinascii.hexlify(topic_sub[1]):
            val[1] = (msg[0]-48)*10+(msg[1]-48) #ascii-to-int, to be improved
            val[1] = val[1] % 255 #sure to be a byte
    
        if ubinascii.hexlify(topic) == ubinascii.hexlify(topic_sub[2]):
            val[2] = (msg[0]-48)*10+(msg[1]-48) #ascii-to-int, to be improved
            val[2] = val[2] % 255 #sure to be a byte
    
        if ubinascii.hexlify(topic) == ubinascii.hexlify(topic_sub[3]):
            val[3] = (msg[0]-48) #ascii-to-int, to be improved
            update = 1
    
        if ubinascii.hexlify(topic) == ubinascii.hexlify(topic_sub[4]):
            val[4] = (msg[0]-48) #ascii-to-int, to be improved
            update = 1
    
    client.set_callback(mytopic)
    
    chrono = Timer.Chrono()
    chrono.start()
    
    while True:
        client.check_msg()
        if chrono.read()%60 < 5 and blink == 0:#just a blinking
            pycom.rgbled(0x0064)
            blink = 1
            print(".")
    
        if chrono.read()%60 > 5 and blink == 1:#just a blinking
            pycom.rgbled(0x0000)
            blink = 0
            print("-")
    
        if chrono.read() > 800:#wait 800s to avoid the sigfox message limit per day
            pycom.rgbled(0x007f00)
            s.send(bytes(val))
            print("Sigfox sent\n")
            chrono.reset()
            pycom.rgbled(0x0000)
    
        if update == 1:#send immediately if update is triger
            pycom.rgbled(0x007f00)
            s.send(bytes(val))
            print("Sigfox sent\n")
            chrono.reset()
            update = 0
            pycom.rgbled(0x0000)
    

    But the exact nature of the result of topic and message are unknown. Is it a string, a byte,... ?
    Most conversions don't works. I've tried float() or int() and get errors

    I still have errors, certainly related to that problem :
    And I've got the following message error when

    s.send(bytes(val))
    #val is filled with the several message of the topics
    

    The packet is correctly sent, but the program quit with the following error message OSError: [Errno 100] ENETDOWN

    When I send the following code, I've no error

    val = [1,2,3,4,5]
    s.send(bytes(val))
    


  • @luc-hanneuse said in MQTT with 2 subscribes:

    How can I get those variable out of "def"?

    msg_b= None
    msg_c= None
    
    def mytopic(topic, msg):
      global msg_b
      global msg_c
      ...
    


  • @livius said in MQTT with 2 subscribes:

    you must put b and c outside of procedure

    How can I get those variable out of "def"?



  • @luc-hanneuse said in MQTT with 2 subscribes:

    For the previous code, the error is
    NameError: local variable referenced before assignment

    You got this error because you do this

    s.send(bytes([b,c]))
    

    but in the code you have if variants and one of two "b" or "c" is unassigned
    because you got 2 events - look how your code work by changing it to:

    def mytopic(topic, msg):
        print("---start---")
        print (topic, ':', msg)
    

    is your output now like this?

    "---start---"
    b'pi/sensor21/temperature' : b'21.00'
    "---start---"
    b'pi/sensor31/temperature' : b'25'
    

    you must put b and c outside of procedure
    and inside test if both "b" and "c" have values and only then send it
    but this can also cause minssing values if you got only "b" and once again "b" and next "c"
    PS> about simple conversion i am writing about string, if it is a bytes then
    you must catch it e.g. v2=float(str(v))
    but your way should work also byte-48{0ascii} *10...



  • @chumelnicu

    It comes from different devices publishing each one their temperatures.



  • @luc-hanneuse Try to pack that two data (temperatures ) in to json format and publising after to MQTT broker



  • @livius
    For the conversion, It doesn't work :

    v2=float(v)
    

    I've got an error
    can't convert bytes to float

    v2=int(v)
    

    I've got an error
    ValueError: invalid syntax for integer with base 10

    For the previous code, the error is
    NameError: local variable referenced before assignment



  • @luc-hanneuse
    what is the error message?
    and to convert from text to number simply do

    v2=float(v)
    

    or if you need only integer part

    v2=int(float(v))
    


  • @luc-hanneuse

    I've tried this, but I got an error message.

    one="pi/sensor21/temperature"
    two="pi/sensor31/temperature"
    
    client.subscribe(topic=one)
    client.subscribe(topic=two)
    
    def mytopic(topic, msg):
        print (topic, ':', msg)
    
        if topic == one:
            b = (msg[0]-48)*10+(msg[1]-48)
    
        if topic == two:
            c = (msg[0]-48)*10+(msg[1]-48)
        s.send(bytes([b,c]))
        #print("Sigfox sent\n")
    


  • @livius
    So it subscribes correctly to the 2 topics. But I can't succeed in putting each message in a different variable.

    Here is my output :
    b'pi/sensor21/temperature' : b'21.00'
    b'pi/sensor31/temperature' : b'25'



  • @luc-hanneuse
    what is your output from
    print (topic, ':', msg)?



  • @luc-hanneuse
    anyone ?


Log in to reply
 

Pycom on Twitter