FiPy: MQTT publishing over CAT-M1



  • So I gave up on Hologram. I do use their SIM card and I was able to send some data to it, but that the only positive I can say... and since they do not have any mean to visualize the data I am trying to use MQTT to send my data elsewhere.
    To get started I decided on free CloudMQTT (also by Amazon but it is not AWS IoT). It also runs Mosquitto. In fact using Python on Raspberry Pi 3B I was able to connect and send data to it both with and without TLS (TLS must be 1.2).

    So now I wrote MycroPython code (that BTW works over LoRa) that reads the data from the sensor and tries to send it to CloudMQTT over CAT-M1. Since I am here it is obvious that I have some problems/questions about it... because I cannot see any data on CloudMQTT as if it never gets it... I already posted a question to its tech support but just want to make sure that I do not do anything stupid with my code:

    HOST = "postman.cloudmqtt.com"
    PORT = 13240
    TOPIC = "dwm/position"
    
    # Connect to CloudMQTT Broker
    mqttClient = MQTTClient(b'FiPy_Node_Client', HOST, port=PORT, user="xxxxxxxx", password="xxxxxxxxxxxxxxx")
    
    #sslParams = {'cert_reqs':ssl.CERT_REQUIRED, 'ca_certs':'/flash/cert/addtrustexternalcaroot.crt'}
    #client = MQTTClient("secureTry1", "postman.cloudmqtt.com", port=23240, ssl=True, user="fxzlcorl", password="Rblo3fKx7G6l", ssl_params=sslParams)
    print("Created mqttClient")
    
    #mqttClient.settimeout(5)
    resp = mqttClient.connect(clean_session=True)
    print("mqttClient connect call returned: {}".format(resp))
    if (resp == 0):
        print("Successfully connected to MQTT Broker")
    
    try:
        #####################################################################################
        # The constructor creates a class with a thread that reads the data from the sensor
        ECG = DFRobotECG('P18', 460)
        #####################################################################################
    
        idx = 1
    
        # Loop for delivery sensor information to CloudMQTT
        while(idx < 5):
    
            # give the sensor a bit time to generate data
            utime.sleep(0.1)
    
            try:
                
                # Get data from the sensor thread
                message = ECG.GetData()
                print("message: {} json string: {}".format(idx, message))
                gc.collect()
     
                # sleep for 1 sec
                utime.sleep(1) 
    
                try:
                    mqttClient.publish(topic=TOPIC, msg=message)
                    print("message {} published".format(idx))
    
                except Exception as ex:
                    print("Exception publishing message {}: {}".format(idx, os.strerror(ex.args[0])))
    
                idx = idx + 1
    
            except Exception as e:
                print("Exception from while loop: {}".format(os.strerror(e.args[0]), e.message))
    
        print("Data-sending loop completed OK. Calling disconnect on MQTT Client...") 
        mqttClient.disconnect()
        gc.collect()
    
    except Exception as e2:
        print("Exception from main code: %s" % os.strerror(e2.args[0]))
        
    finally:
        endLTE()
    

    ...and here is the output:

    Disable MicroPython control and heartbeat of LED
    Instantiated LTE connection.
    Resetting LTE modem ... OK
    Configuring LTE .. OK
    Attaching to LTE network ..... OK
    Connecting on LTE network  OK
    getLTE returned lte: <LTE>
    Created mqttClient
    mqttClient connect call returned: 0
    Successfully connected to MQTT Broker
    
    message: 1 json string: [[0, 0], [1, 1860], [8, 1861], [15, 1862], [22, 1853], [29, 1854], [36, 1852], [43, 1854], [50, 1855], [57, 1862], [64, 1861], [71, 1878], [78, 1848], [85, 1863], [92, 1858]]
    message 1 published
    
    Main.py: Started loop iteration at local time: (1970, 1, 1, 0, 0, 24, 3, 1)
    message: 2 json string: [[145, 1860], [152, 1864], [159, 1852], [166, 1853], [173, 1866], [180, 1852], [187, 1865], [194, 1867], [201, 1854], [208, 1866], [215, 1851], [222, 1852], [229, 1863], [236, 1861], [243, 1854], [250, 1847], [257, 1852], [264, 1863], [271, 1852], [278, 1854], [285, 1853], [292, 1860], [299, 1866], [306, 1846], [313, 1850], [320, 1854], [327, 1859], [334, 1867], [341, 1847], [348, 1851], [355, 1852], [362, 1854], [369, 1859], [376, 1852], [383, 1866], [390, 1862], [397, 1853], [404, 1852], [411, 1853], [418, 1847], [425, 1854], [432, 1853], [439, 1847], [446, 1861], [453, 1853], [460, 1862], [467, 1862], [474, 1851], [481, 1860], [488, 1864], [495, 1854], [502, 1861], [509, 1859], [516, 1851], [523, 1858], [530, 1854], [537, 1860], [544, 1860], [551, 1861], [558, 1851], [565, 1864], [572, 1859], [579, 1852], [586, 1853], [593, 1852], [600, 1854], [607, 1849], [614, 1859], [621, 1852], [628, 1852], [635, 1853], 
    [642, 1849], [649, 1851], [656, 1849], [663, 1854], [670, 1854], [677, 1847], [684, 1852], [691, 1860], [698, 1851], [705, 1862], [712, 1850], [719, 1847], [726, 1853], [733, 1854], [740, 1852], [747, 1861], [754, 1852], [761, 1854], [768, 1854], [775, 1854], [782, 1847], [789, 1854], [796, 1861], [803, 1854], [810, 1860], [817, 1850], [824, 1847], [831, 1850], [838, 1854], [845, 1851], [852, 1847], [859, 1849], [866, 1847], [873, 1854], [880, 1854], [887, 1860], [894, 
    1854], [901, 1849], [908, 1853], [915, 1851], [922, 1852], [929, 1854], [936, 1853], [943, 1845], [950, 1852], [957, 1847], [964, 1852], [971, 1849], [978, 1849], [985, 1847], [992, 1854], [999, 1850], [1006, 1853], [1013, 1854], [1020, 
    1847], [1027, 1847], [1034, 1851], [1041, 1861], [1048, 1847], [1055, 1862], [1062, 1850], [1069, 1850], [1076, 1854], [1083, 1852], [1090, 1852], [1097, 1847], [1104, 1854], [1111, 1861], [1118, 1854], [1125, 1847], [1132, 1860], [1139, 1860], [1146, 1851], [1154, 1853], [1161, 1854], [1168, 1850], [1175, 1851], [1182, 1847], [1189, 1858], [1196, 1852], [1203, 1854], [1210, 1846], [1217, 1847], [1224, 1860], [1231, 1862], [1238, 1854], [1245, 1853], [1252, 1850]]      
    message 2 published
    
    Main.py: Started loop iteration at local time: (1970, 1, 1, 0, 0, 25, 3, 1)
    message: 3 json string: [[1473, 1853], [1480, 1854], [1487, 1849], [1494, 1847], [1501, 1853], [1508, 1854], [1515, 1849], [1522, 1851], [1529, 1851], [1536, 1846], [1543, 1846], [1550, 1850], [1557, 1850], [1564, 1861], [1571, 1842], [1578, 1849], [1585, 1851], [1592, 1847], [1599, 1859], [1606, 1850], [1613, 1859], [1620, 1860], [1627, 1847], [1634, 1847], [1641, 1852], [1648, 1854], [1655, 1853], [1662, 1860], [1669, 1862], [1676, 1853], [1683, 1858], [1690, 1849], [1697, 1852], [1704, 1851], [1711, 1850], [1718, 1854], [1725, 1851], [1732, 1852], [1739, 1854], [1746, 1851], [1753, 1852], [1760, 1861], [1767, 1851], [1774, 1847], [1781, 1852], [1788, 1859], [1795, 1844], [1802, 1854], [1809, 1842], 
    [1816, 1860], [1823, 1851], [1830, 1857], [1837, 1849], [1844, 1849], [1851, 1854], [1858, 1851], [1865, 1853], [1872, 1850], [1879, 1858], [1886, 1861], [1893, 1851], [1900, 1857], [1907, 1852], [1914, 1850], [1921, 1853], [1928, 1850], [1935, 1849], [1942, 1854], [1949, 1852], [1956, 1852], [1963, 1854], [1970, 1850], [1977, 1854], [1984, 1849], [1991, 1853], [1998, 1857], [2005, 1850], [2012, 1854], [2019, 1860], [2026, 1849], [2033, 1853], [2040, 1864], [2047, 1852], [2054, 1850], [2061, 1846], [2068, 1850], [2075, 1853], [2082, 1851], [2089, 1843], [2096, 1859], [2103, 1845], [2110, 1861], [2117, 1851], [2124, 1853], [2131, 1862], [2138, 1852], [2145, 1859], [2152, 1854], [2159, 1851], [2166, 1850], [2173, 1850], [2180, 1854], [2187, 1852], [2194, 1854], [2201, 1852], [2208, 1851], [2215, 1854], [2222, 1847], [2229, 1850], [2236, 1847], [2243, 1859], [2250, 1854], [2257, 1847], [2264, 1853], [2271, 1860], [2278, 1854], [2285, 1860], [2292, 1859], [2299, 1864], [2306, 1854], [2313, 1847], [2320, 1847], [2327, 1852], [2334, 1852], [2341, 1850], [2348, 1847], [2355, 1854], [2362, 1853], [2369, 1854], [2376, 1852], [2383, 1851], [2390, 1860], [2397, 1861], [2404, 1854], [2411, 1861], [2418, 1859], [2425, 1851], [2432, 1849], [2439, 1852], [2446, 1849], [2453, 1860], [2460, 1853], [2467, 1852], [2474, 1852], [2483, 1851], [2490, 1845], [2497, 1851], [2504, 1851], [2511, 1846], [2518, 1847], [2525, 1853], [2532, 1851], [2539, 1854], [2546, 1857], [2553, 1849], [2560, 1852], [2567, 1853], [2574, 1854], [2581, 1849]]
    message 3 published
    
    Main.py: Started loop iteration at local time: (1970, 1, 1, 0, 0, 27, 3, 1)
    message: 4 json string: [[2813, 1845], [2821, 1853], [2828, 1847], [2835, 1847], [2842, 1853], [2849, 1844], [2856, 1847], [2863, 1854], [2870, 1854], [2877, 1849], [2884, 1847], [2891, 1862], [2898, 1845], [2905, 1844], [2912, 1852], [2919, 1854], [2926, 1852], [2933, 1857], [2940, 1853], [2947, 1844], [2954, 1852], [2961, 1862], [2968, 1849], [2975, 1852], [2982, 1850], [2989, 1852], [2996, 1866], [3003, 1853], [3010, 1851], [3017, 1854], [3024, 1852], [3031, 1857], [3038, 1849], [3045, 1851], [3052, 1847], [3059, 1849], [3066, 1847], [3073, 1857], [3080, 1854], [3087, 1847], [3094, 1854], [3101, 1850], [3108, 1851], [3115, 1851], [3122, 1854], [3129, 1850], [3136, 1843], [3143, 1858], [3150, 1859], 
    [3157, 1859], [3164, 1852], [3171, 1859], [3178, 1849], [3185, 1858], [3192, 1843], [3199, 1854], [3206, 1852], [3213, 1847], [3220, 1854], [3227, 1852], [3234, 1858], [3241, 1861], [3248, 1859], [3255, 1847], [3262, 1846], [3269, 1858], [3276, 1847], [3283, 1865], [3290, 1853], [3297, 1859], [3304, 1854], [3311, 1854], [3318, 1844], [3325, 1847], [3332, 1857], [3339, 1847], [3346, 1852], [3353, 1862], [3360, 1852], [3367, 1853], [3374, 1850], [3381, 1850], [3388, 1853], [3395, 1846], [3402, 1854], [3409, 1854], [3416, 1849], [3423, 1852], [3430, 1854], [3437, 1847], [3444, 1854], [3451, 1850], [3458, 1854], [3465, 1846], [3472, 1850], [3479, 1847], [3486, 1849], [3493, 1854], [3500, 1850], [3507, 1852], [3514, 1852], [3521, 1858], [3528, 1849], [3535, 1852], [3542, 1849], [3549, 1852], [3556, 1852], [3563, 1860], [3570, 1854], [3577, 1850], [3584, 1854], [3591, 1850], [3598, 1852], [3605, 1859], [3612, 1861], [3619, 1854], [3626, 1853], [3633, 1852], [3640, 1850], [3647, 1853], [3654, 1854], [3661, 1852], [3668, 1854], [3675, 1859], [3682, 1849], [3689, 1851], [3696, 1850], [3703, 1846], [3710, 1854], [3717, 1854], [3724, 1861], [3731, 1849], [3738, 1861], [3745, 1852], [3752, 1847], [3759, 1846], [3766, 1847], [3773, 1860], [3780, 1854], [3787, 1852], [3794, 1851], [3801, 1851], [3808, 1852], [3815, 1860], [3823, 1852], [3830, 1863], [3837, 1844], [3844, 1853], [3851, 1859], [3858, 1847], [3865, 1859], [3872, 1847], [3879, 1847], [3886, 1851], [3893, 1854], [3900, 1858], [3907, 1854], [3914, 1859], [3921, 1852]]
    
    Disonnecting LTE ... Traceback (most recent call last):
      File "main.py", line 300, in <module>
      File "main.py", line 166, in endLTE
    OSError: the requested operation failed
    Pycom MicroPython 1.20.1.r1 [15b6d69] on 2019-11-02; FiPy with ESP32
    Type "help()" for more information.
    >>> Unhandled exception in thread started by <bound_method>
    IndexError:
    

    I send 4 messages and it is obvious that I do get the 4th print "message 4 published" despite I have exception handling around...and somehow mysteriously the code jumps to endLTE() function which for another mysterious reason throws exception executing lte.disconnect(). Any ideas? Is a payload too big? This is my main question... the next one I may be able to handle by just killing the thread before exiting...

    Then it gets to REPL and sits there for awhile. Then suddenly it throws exception IndexError. So, does it mean that the thread that I sarted with ECG constructor was still looping despite that my main exited??

    EDIT: Dec 16, 2019
    I resolved the problem... It has to do how much data being sent in one chunk and how frequently...The bottom line: send small chunks of data and frequently (for example: you can send 120 bytes every 7 milliseconds and it all goes through without any problems). If you want more details on how to push vast amount of data quickly - ping me...
    And yet, the problem I was having calling lete.disconnect() continues - I constantly get exception on this...

    EDIT: Dec 17, 2019
    Apparently, the data delivery saga continues... My previous joy of resolving it was premature...
    Now that I sent 117 bytes string every 50 msec over mqttClient.publish the call does not return from it when trying to send 43rd message. I tried different combinations of the payload and the transmission frequency and I always get that at some point after 2-2.5 sec of transmitting data (that is 4KB-4.5KB) the call to mqttClient.publish never returns (that is returns after it timed out). And the displays Exception code 118. Initially, I tought that it is multithreading screws things up but now there are no threads left...

    Despite the enormous time and effort I invested in this, the above behavior makes this project (or combination of FiPy + MicroPython not viable). So I definitely will appreciate and open to try any new ideas how to resolve this problem...
    I also wonder if the root of the problem is in the following commands despite that the connection goes through fine and always connects to AT&T.

    print("Configuring LTE ", end='')
        lte.send_at_cmd('AT+CGDCONT=1,"IP","hologram"')  # Changed this from origninal
        print(".", end='')
        lte.send_at_cmd('AT!="RRC::addscanfreq band=4 dl-earfcn=9410"') # no idea what earfcn=9410 is... is it correct??
        print(".", end='')
        lte.send_at_cmd('AT+CFUN=1')
        print(" OK")
    

    Here is the latest code:

        idx = 1
        attempt = 0
    
    
        # Loop for delivery sensor information over CAT-M1
        while(idx < 1000):
    
            print("Main.py: Started loop iteration at local time: {}".format(utime.localtime()))
        
            try:
    
                diff = 0
                message = ""
    
                start = time.ticks_ms()
    
                #print("Start Ticks: {}".format(start))
                while (diff < 50):
                        
                    # get the voltage value
                    v = adc_channel.voltage()
                    
                    diff = utime.ticks_diff(time.ticks_ms(), start)
    
                    message += "{},{} ".format(diff, v)
    
                    gc.collect()
    
                try:
                    mqttClient.publish(topic=TOPIC, msg=message)
                    print("Num: {}  Len: {}  Msg: {}".format(idx, len(message), message))
                    gc.collect()
    
                except Exception as ex:
                    print("Exception publishing {}".format(ex.args[0]))
                    attempt += 1
                    if (attempt > 3):
                        break
                    gc.collect()
    
               idx = idx + 1
    
            except Exception as e:
                print("Exception from while loop: {}".format(e.args[0]))
    
        print("Data-sending loop exited. Calling disconnect on MQTT Client...") 
        mqttClient.disconnect()
        gc.collect()
    
     
    except Exception as e2:
        print("Exception from main code: %s" % e2.args[0])
        
    finally:
        print("Enable MicroPython control and heartbeat of LED")
        pycom.heartbeat(True)
    
        endLTE()
    

Log in to reply
 

Pycom on Twitter