├── .gitattributes ├── .gitignore ├── README.md ├── publishThingspeak.py └── subscribeThingspeak.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## MQTT protocol with Thingspeak using Micropython 2 | Example code showing how to use the MQTT protocol with the Thingspeak cloud service [https://thingspeak.com] 3 | 4 | * Publish data 5 | * Subscribe to data 6 | 7 | ## Thingspeak configuration 8 | 1. Create a Thingspeak account https://thingspeak.com 9 | 1. Create a new Thingspeak Channel (select New Channel on the My Channels page) 10 | * the `Channel ID` is required for configuration (found at the top of every channel page) 11 | 1. Create a new MQTT Device by following instructions in https://www.mathworks.com/help/thingspeak/mqtt-basics.html 12 | * when you create a new MQTT device it is important to record the three configuration parameters: 13 | * `MQTT Client ID` 14 | * `MQTT Username` 15 | * `MQTT Password` (careful - you can only copy the password during the MQTT device creation step) 16 | 17 | ## Example code configuration 18 | * The code includes variables with the form **"ENTER_"** indicating places where WiFi and Thingspeak configuration 19 | parameters are needed 20 | 21 | ## Tested with Hardware 22 | * Adafruit Feather HUZZAH ESP8266 23 | * Adafruit Feather HUZZAH ESP32 24 | * WeMos D1 Mini 25 | * Lolin D32 26 | * Lolin D32 Pro 27 | * Pyboard D (note: requires UMQTT library to be installed) 28 | 29 | ## Tested with Micropython Versions 30 | * Micropython v1.19.1 31 | 32 | ### Recommended Tools for Windows 33 | * Adafruit Ampy to copy files to the filesystem 34 | * install version 1.0.3 or newer which has the -d option (use **-d1** to avoid USB connection issues in Windows) 35 | * Putty to interact with the REPL 36 | * set Serial speed to 115200 and Flow control to None 37 | 38 | ## Publishing data to ThingSpeak channels 39 | 40 | #### Usage 41 | 1. Configure code file _publishThingspeak.py_ with WiFi and ThingSpeak configuration parameters 42 | 1. Copy the file _publishThingspeak.py_ to your device, using [ampy](https://github.com/scientifichackers/ampy), [rshell](https://github.com/dhylands/rshell), or [webrepl](http://micropython.org/webrepl/) 43 | ``` 44 | $ ampy -pCOMx -d1 put publishThingspeak.py main.py 45 | ``` 46 | 1. Reset the board 47 | 1. Observe that data is being Published to the ThingSpeak channel at Thingspeak.com 48 | 49 | ## Subscribing to ThingSpeak channels (still to be updated) 50 | 51 | #### Usage 52 | 1. Configure code file _subscribeThingspeak.py_ with ThingSpeak parameters 53 | 1. Copy the file _subscribeThingspeak.py_ to your device, using [ampy](https://github.com/scientifichackers/ampy), [rshell](https://github.com/dhylands/rshell), [webrepl](http://micropython.org/webrepl/) 54 | ``` 55 | $ ampy -pCOMx -d1 put subscribeThingspeak.py main.py 56 | ``` 57 | 4. Configure a 2nd device to publish the freeHeap data (see above) 58 | 1. Reset the board 59 | 1. Connect to the REPL with Putty (or simlar) to observe subscribed channel data being received (every 30s in the example code) 60 | 61 | ## Installing UMQTT Package for Pyboard D 62 | The example code requires the MicroPython MQTT (UMQTT) Package. Pyboard D firmware does not have this package built-in 63 | 64 | ##### How to install the UMQTT package 65 | 1. Navigate to [Micropython lib](https://github.com/micropython/micropython-lib 66 | 1. Select the "Clone or download" button 67 | 1. Select "Download ZIP" 68 | 1. Extract the ZIP. Should see folder called "micropython-lib-master" 69 | 1. Two files need to be copied to the MicroPython filesystem 70 | * micropython-lib\micropython\umqtt.simple\umqtt\simple.py 71 | * micropython-lib\micropython\umqtt.robust\umqtt\robust.py 72 | 73 | Copy these two files to the MicroPython filesystem with the directory structure shown below. 74 | 75 | ``` 76 | boot.py 77 | lib 78 | | 79 | umqtt 80 | simple.py 81 | robust.py 82 | ``` 83 | 84 | Example with Ampy: 85 | ``` 86 | >ampy -pCOM27 -d1 ls 87 | boot.py 88 | >ampy -pCOM27 -d1 mkdir lib 89 | >ampy -pCOM27 -d1 mkdir lib/umqtt 90 | >ampy -pCOM27 -d1 put simple.py lib/umqtt/simple.py 91 | >ampy -pCOM27 -d1 put robust.py lib/umqtt/robust.py 92 | >ampy -pCOM27 -d1 ls 93 | boot.py 94 | lib 95 | >ampy -pCOM27 -d1 ls lib 96 | umqtt 97 | >ampy -pCOM27 -d1 ls lib/umqtt 98 | simple.py 99 | robust.py 100 | ``` 101 | ##### Validating the UMQTT package install 102 | From the REPL (using Putty, etc) execute the following commands and observe similar output 103 | ``` 104 | >>> from umqtt.robust import MQTTClient 105 | 106 | >>> dir(MQTTClient) 107 | ['__class__', '__init__', '__module__', '__name__', '__qualname__', '__bases__', '__dict__', 'connect', 'delay', 'disconnect', 'log', 'DEBUG', 'DELAY', 'reconnect', 'publish', 'wait_msg', '_send_str', '_recv_len', 'set_callback', 'set_last_will', 'ping', 'subscribe', 'check_msg'] 108 | ``` 109 | 110 | If you see this result you have successfully installed the umqtt package. :tada: :relieved: -------------------------------------------------------------------------------- /publishThingspeak.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2019 Mike Teachman 3 | # https://opensource.org/licenses/MIT 4 | # 5 | # Example MicroPython code showing how to use the MQTT protocol to 6 | # publish data to a Thingspeak channel 7 | # 8 | # User configuration parameters are indicated with "ENTER_". 9 | 10 | import network 11 | from umqtt.robust import MQTTClient 12 | import time 13 | import gc 14 | import sys 15 | 16 | # Configuration parameters 17 | #======================================================= 18 | WIFI_SSID = 'ENTER_WIFI_SSID' 19 | WIFI_PASSWORD = 'ENTER_WIFI_PASSWORD' 20 | THINGSPEAK_MQTT_CLIENT_ID = b"ENTER_THINGSPEAK_MQTT_CLIENT_ID" 21 | THINGSPEAK_MQTT_USERNAME = b"ENTER_THINGSPEAK_MQTT_USERNAME" 22 | THINGSPEAK_MQTT_PASSWORD = b"ENTER_THINGSPEAK_MQTT_PASSWORD" 23 | THINGSPEAK_CHANNEL_ID = b'ENTER_THINGSPEAK_CHANNEL_ID' 24 | #======================================================= 25 | 26 | # turn off the WiFi Access Point 27 | ap_if = network.WLAN(network.AP_IF) 28 | ap_if.active(False) 29 | 30 | # connect the device to the WiFi network 31 | wifi = network.WLAN(network.STA_IF) 32 | wifi.active(True) 33 | wifi.connect(WIFI_SSID, WIFI_PASSWORD) 34 | 35 | # wait until the device is connected to the WiFi network 36 | MAX_ATTEMPTS = 20 37 | attempt_count = 0 38 | while not wifi.isconnected() and attempt_count < MAX_ATTEMPTS: 39 | attempt_count += 1 40 | time.sleep(1) 41 | 42 | if attempt_count == MAX_ATTEMPTS: 43 | print('could not connect to the WiFi network') 44 | sys.exit() 45 | 46 | # connect to Thingspeak MQTT broker 47 | # connection uses unsecure TCP (port 1883) 48 | # 49 | # To use a secure connection (encrypted) with TLS: 50 | # set MQTTClient initializer parameter to "ssl=True" 51 | # Caveat: a secure connection uses more heap space 52 | THINGSPEAK_MQTT_USERNAME = THINGSPEAK_MQTT_CLIENT_ID 53 | 54 | client = MQTTClient(server=b"mqtt3.thingspeak.com", 55 | client_id=THINGSPEAK_MQTT_CLIENT_ID, 56 | user=THINGSPEAK_MQTT_USERNAME, 57 | password=THINGSPEAK_MQTT_PASSWORD, 58 | ssl=False) 59 | 60 | try: 61 | client.connect() 62 | except Exception as e: 63 | print('could not connect to MQTT server {}{}'.format(type(e).__name__, e)) 64 | sys.exit() 65 | 66 | # continually publish two fields to a Thingspeak channel using MQTT 67 | PUBLISH_PERIOD_IN_SEC = 20 68 | while True: 69 | try: 70 | freeHeapInBytes = gc.mem_free() 71 | credentials = bytes("channels/{:s}/publish".format(THINGSPEAK_CHANNEL_ID), 'utf-8') 72 | payload = bytes("field1={:.1f}&field2={:.1f}\n".format(freeHeapInBytes, 10.2), 'utf-8') 73 | client.publish(credentials, payload) 74 | time.sleep(PUBLISH_PERIOD_IN_SEC) 75 | except KeyboardInterrupt: 76 | print('Ctrl-C pressed...exiting') 77 | client.disconnect() 78 | wifi.disconnect() 79 | break -------------------------------------------------------------------------------- /subscribeThingspeak.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # Copyright (c) 2019 Mike Teachman 3 | # https://opensource.org/licenses/MIT 4 | # 5 | # Subscribe to data from a Thingspeak channel using the MQTT protocol 6 | # 7 | # Tested using the releases: 8 | # ESP8266 9 | # MicroPython 1.9.3 10 | # MicroPython 1.9.4 11 | # MicroPython 1.10 12 | # ESP32 13 | # MicroPython 1.9.4 (needs addition of MicroPython umqtt module) 14 | # MicroPython 1.10 15 | # 16 | # Tested using the following boards: 17 | # Adafruit Feather HUZZAH ESP8266 18 | # Adafruit Feather HUZZAH ESP32 19 | # WeMos D1 Mini 20 | # 21 | # prerequisites: 22 | # - Thingspeak account 23 | # - Thingspeak channel with published data 24 | # - Thingspeak Read API Key for the channel 25 | # - Thingspeak MQTT API Key for the account 26 | # 27 | # User configuration parameters are indicated with "ENTER_". 28 | # User configuration parameters are indicated with "ENTER_". 29 | 30 | import network 31 | from umqtt.robust import MQTTClient 32 | import time 33 | import os 34 | import sys 35 | 36 | def cb(topic, msg): 37 | print((topic, msg)) 38 | freeHeap = float(str(msg,'utf-8')) 39 | print("free heap size = {} bytes".format(freeHeap)) 40 | 41 | # WiFi connection information 42 | wifiSSID = '' 43 | wifiPassword = '' 44 | 45 | # turn off the WiFi Access Point 46 | ap_if = network.WLAN(network.AP_IF) 47 | ap_if.active(False) 48 | 49 | # connect the ESP8266 device to the WiFi network 50 | wifi = network.WLAN(network.STA_IF) 51 | wifi.active(True) 52 | wifi.connect(wifiSSID, wifiPassword) 53 | 54 | # wait until the device is connected to the WiFi network 55 | MAX_ATTEMPTS = 20 56 | attempt_count = 0 57 | while not wifi.isconnected() and attempt_count < MAX_ATTEMPTS: 58 | attempt_count += 1 59 | time.sleep(1) 60 | 61 | if attempt_count == MAX_ATTEMPTS: 62 | print('could not connect to the WiFi network') 63 | sys.exit() 64 | 65 | # create a random clientID 66 | randomNum = int.from_bytes(os.urandom(3), 'little') 67 | myMqttClient = bytes("client"+str(randomNum), 'utf-8') 68 | 69 | # connect to Thingspeak MQTT broker 70 | # connection uses unsecure TCP (port 1883) 71 | # 72 | # To use a secure connection (encrypted) with TLS: 73 | # set MQTTClient initializer parameter to "ssl=True" 74 | # Caveat: a secure connection uses about 9k bytes of the heap 75 | # (about 1/4 of the micropython heap on the ESP8266 platform) 76 | THINGSPEAK_URL = b"mqtt.thingspeak.com" 77 | THINGSPEAK_USER_ID = b'' 78 | THINGSPEAK_MQTT_API_KEY = b'' 79 | client = MQTTClient(client_id=myMqttClient, 80 | server=THINGSPEAK_URL, 81 | user=THINGSPEAK_USER_ID, 82 | password=THINGSPEAK_MQTT_API_KEY, 83 | ssl=False) 84 | 85 | # callback to handle data when MQTT channel updates 86 | client.set_callback(cb) 87 | try: 88 | client.connect() 89 | except Exception as e: 90 | print('could not connect to MQTT server {}{}'.format(type(e).__name__, e)) 91 | sys.exit() 92 | 93 | # subscribe a Thingspeak channel field using MQTT 94 | THINGSPEAK_CHANNEL_ID = b'' 95 | THINGSPEAK_CHANNEL_READ_API_KEY = b'' 96 | subscribeTopic = bytes("channels/{:s}/subscribe/fields/field1/{:s}".format(THINGSPEAK_CHANNEL_ID, THINGSPEAK_CHANNEL_READ_API_KEY), 'utf-8') 97 | client.subscribe(subscribeTopic) 98 | 99 | # wait until data has been Published to the Thingspeak channel 100 | while True: 101 | try: 102 | client.wait_msg() 103 | except KeyboardInterrupt: 104 | print('Ctrl-C pressed...exiting') 105 | client.disconnect() 106 | sys.exit() 107 | 108 | --------------------------------------------------------------------------------