├── .vscode └── settings.json ├── Micropython.md ├── README.md ├── bme280.py ├── boot.py ├── copy-python-app-to-esp32.sh ├── flash-micropython-firmware.sh └── main.py /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": false 3 | } -------------------------------------------------------------------------------- /Micropython.md: -------------------------------------------------------------------------------- 1 | Obsolete 2 | Test 3 | test 4 | 5 | https://stackoverflow.com/questions/34400272/visual-studio-code-always-asking-for-git-credentials 6 | 7 | # Streaming Data from ESP32 using MicroPython and MQTT 8 | 9 | ## Resources 10 | 11 | * [MicroPython and ESP32](https://github.com/micropython/micropython-esp32) 12 | * [MicroPython](https://micropython.org/) 13 | * [MicroPython libraries](https://github.com/micropython/micropython-lib) 14 | * [MicroPython PiP Package Index](https://pypi.python.org/pypi?%3Aaction=search&term=micropython) 15 | * [ESP8266 Documentation (ESP32 not documeneted yet)](http://docs.micropython.org/en/latest/esp8266/) 16 | * [ESP32 Firmware](http://micropython.org/download/#esp32) 17 | * [Adafruit MicroPython Resources](https://www.google.com.au/search?client=ubuntu&hs=h2P&channel=fs&q=adafruit+micropython&spell=1&sa=X&ved=0ahUKEwii1ITmhpDVAhUEXrwKHY3YDoUQvwUIIygA&biw=1221&bih=626) 18 | 19 | ### uMqtt PiP Packages 20 | 21 | * [umqtt.simple](https://github.com/micropython/micropython-lib/tree/master/umqtt.simple) 22 | * [umqtt.robust](https://github.com/micropython/micropython-lib/tree/master/umqtt.robust) 23 | 24 | ### Other 25 | 26 | * [MicroPython BME280 Sensor Driver](https://github.com/catdog2/mpy_bme280_esp8266/blob/master/bme280.py) 27 | * [NTP Library](https://stackoverflow.com/questions/12664295/ntp-client-in-python) 28 | * [Hackster MicroPython Mqtt Project](https://www.hackster.io/bucknalla/mqtt-micropython-044e77) 29 | * [Espressif esptool](https://github.com/espressif/esptool) 30 | * [Mosquitto Broker](https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-ubuntu-16-04) 31 | 32 | ## ESP32 MicroPython Firmware Flashing Process 33 | 34 | See [Adafruit MicroPython Flasing How-to Tutorial](https://learn.adafruit.com/micropython-basics-how-to-load-micropython-on-a-board/esp8266) 35 | 36 | 37 | ### Overview of ESP32 flashing process 38 | 39 | 1. Install esptool 40 | 2. Erase Flash 41 | 3. Deploy MicroPython Firmware 42 | 43 | 44 | ### Install esptool.py firmware flash tool 45 | 46 | On Windows 47 | ```bash 48 | pip install esptool 49 | ``` 50 | 51 | On Mac and Linux 52 | ```bash 53 | sudo pip install esptool 54 | ``` 55 | 56 | 57 | ### Erasing ESP32 flash 58 | 59 | ```bash 60 | esptool.py --port /dev/ttyUSB0 erase_flash 61 | ``` 62 | 63 | ### Flashing ESP32 MicroPython firmware 64 | 65 | Download [ESP32 Firmware](http://micropython.org/download/#esp32) and deploy to ESP32. 66 | 67 | ```bash 68 | esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash 0x0000 firmware.bin 69 | ``` 70 | 71 | 72 | ## Installing Required MicroPython PIP Packages 73 | 74 | Install the following uPip packages. You need to estabish a network connection on the ESP32 board then upip.install the umqtt packages. 75 | 76 | ```python 77 | import network 78 | import upip 79 | 80 | sta_if = network.WLAN(network.STA_IF) 81 | sta_if.active(True) 82 | sta_if.connect("Wifi SSID", "Wifi password") 83 | 84 | upip.install('micropython-umqtt.simple') 85 | upip.install('micropython-umqtt.robust') 86 | 87 | ``` 88 | 89 | 90 | 91 | ## MicroPython and Publish over MQTT 92 | 93 | Deploy the boot.py and main.py files using the Adafruit ampy package. 94 | 95 | See [Adafruit MicroPython Tool (ampy)](https://learn.adafruit.com/micropython-basics-load-files-and-run-code/install-ampy) for information on copying files to the ESP32. 96 | 97 | ```bash 98 | pip install adafruit-ampy 99 | 100 | ampy --port /dev/ttyUSB0 put boot.py 101 | ampy --port /dev/ttyUSB0 put main.py 102 | ``` 103 | 104 | ```python 105 | # boot.py 106 | 107 | import network 108 | sta_if = network.WLAN(network.STA_IF) 109 | sta_if.active(True) 110 | sta_if.connect("Wifi SSID", "Wifi password") 111 | ``` 112 | 113 | 114 | 115 | ```python 116 | # main.py 117 | 118 | from umqtt.robust import MQTTClient 119 | import machine 120 | import utime as time 121 | import gc 122 | import bme280 123 | 124 | 125 | # Wifi connect established in the boot.py file. Uncomment if needed 126 | # import network 127 | # sta_if = network.WLAN(network.STA_IF) 128 | # sta_if.active(True) 129 | # sta_if.connect("NCW", "malolos5459") 130 | 131 | client = MQTTClient("esp32-01", "192.168.1.122") 132 | pin5 = machine.Pin(5, machine.Pin.OUT) 133 | 134 | i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21)) 135 | bme = bme280.BME280(i2c=i2c) 136 | 137 | def checkwifi(): 138 | while not sta_if.isconnected(): 139 | time.sleep_ms(500) 140 | print(".") 141 | sta_if.connect() 142 | 143 | def publish(): 144 | count = 1 145 | while True: 146 | pin5.value(0) 147 | checkwifi() 148 | v = bme.values 149 | msg = b'{"MsgId":%u,"Mem":%u,"Celsius":%s,"Pressure":%s,"Humidity":%s}' % (count, gc.mem_free(), v[0][:-1], v[1][:-3], v[2][:-1]) 150 | client.publish(b"home/weather", msg) 151 | pin5.value(1) 152 | count = count + 1 153 | time.sleep(20) 154 | 155 | client.reconnect() 156 | 157 | publish() 158 | ``` 159 | 160 | ## Connecting to ESP32 with Putty 161 | 162 | Install Putty for your platform. Connect at 115200 baud rate 163 | 164 | See [Adafruit Serial REPL Tutorial](https://learn.adafruit.com/micropython-basics-how-to-load-micropython-on-a-board/serial-terminal). -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Streaming Data from ESP32 using MicroPython and MQTT 2 | 3 | ## Resources 4 | 5 | * [MicroPython and ESP32](https://github.com/micropython/micropython-esp32) 6 | * [MicroPython](https://micropython.org/) 7 | * [MicroPython libraries](https://github.com/micropython/micropython-lib) 8 | * [MicroPython PiP Package Index](https://pypi.python.org/pypi?%3Aaction=search&term=micropython) 9 | * [ESP8266 Documentation (ESP32 not documeneted yet)](http://docs.micropython.org/en/latest/esp8266/) 10 | * [ESP32 Firmware](http://micropython.org/download/#esp32) 11 | * [Adafruit MicroPython Resources](https://www.google.com.au/search?client=ubuntu&hs=h2P&channel=fs&q=adafruit+micropython&spell=1&sa=X&ved=0ahUKEwii1ITmhpDVAhUEXrwKHY3YDoUQvwUIIygA&biw=1221&bih=626) 12 | 13 | ### uMqtt PiP Packages 14 | 15 | * [umqtt.simple](https://github.com/micropython/micropython-lib/tree/master/umqtt.simple) 16 | * [umqtt.robust](https://github.com/micropython/micropython-lib/tree/master/umqtt.robust) 17 | 18 | ### Other 19 | 20 | * [MicroPython BME280 Sensor Driver](https://github.com/catdog2/mpy_bme280_esp8266/blob/master/bme280.py) 21 | * [NTP Library](https://stackoverflow.com/questions/12664295/ntp-client-in-python) 22 | * [Hackster MicroPython Mqtt Project](https://www.hackster.io/bucknalla/mqtt-micropython-044e77) 23 | * [Espressif esptool](https://github.com/espressif/esptool) 24 | * [Mosquitto Broker](https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-ubuntu-16-04) 25 | * [PuTTY](http://www.putty.org/) 26 | * [Serial Support on the Windows Subsystem for Linux](https://blogs.msdn.microsoft.com/wsl/2017/04/14/serial-support-on-the-windows-subsystem-for-linux/?WT.mc_id=iot-0000-dglover) 27 | 28 | ## ESP32 MicroPython Firmware Flashing Process 29 | 30 | See [Adafruit MicroPython Flasing How-to Tutorial](https://learn.adafruit.com/micropython-basics-how-to-load-micropython-on-a-board/esp8266) 31 | 32 | 33 | ### Overview of ESP32 flashing process 34 | 35 | 1. Install esptool 36 | 2. Erase Flash 37 | 3. Deploy MicroPython Firmware 38 | 39 | 40 | ### Install esptool.py firmware flash tool 41 | 42 | On Windows 43 | ```bash 44 | pip install esptool 45 | ``` 46 | 47 | On Mac and Linux 48 | ```bash 49 | sudo pip install esptool 50 | ``` 51 | 52 | 53 | ### Erasing ESP32 flash 54 | 55 | ```bash 56 | esptool.py --port /dev/ttyUSB0 erase_flash 57 | ``` 58 | 59 | ### Flashing ESP32 MicroPython firmware 60 | 61 | Download [ESP32 Firmware](http://micropython.org/download/#esp32) and deploy to ESP32. 62 | 63 | ```bash 64 | esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash 0x0000 firmware.bin 65 | ``` 66 | 67 | 68 | ## Installing Required MicroPython PIP Packages 69 | 70 | Install the following uPip packages. You need to estabish a network connection on the ESP32 board then upip.install the umqtt packages. 71 | 72 | ```python 73 | import network 74 | import upip 75 | 76 | sta_if = network.WLAN(network.STA_IF) 77 | sta_if.active(True) 78 | sta_if.connect("Wifi SSID", "Wifi password") 79 | 80 | upip.install('micropython-umqtt.simple') 81 | upip.install('micropython-umqtt.robust') 82 | 83 | ``` 84 | 85 | 86 | 87 | ## MicroPython and Publish over MQTT 88 | 89 | Deploy the boot.py and main.py files using the Adafruit ampy package. 90 | 91 | See [Adafruit MicroPython Tool (ampy)](https://learn.adafruit.com/micropython-basics-load-files-and-run-code/install-ampy) for information on copying files to the ESP32. 92 | 93 | ```bash 94 | pip install adafruit-ampy 95 | 96 | ampy --port /dev/ttyUSB0 put boot.py 97 | ampy --port /dev/ttyUSB0 put main.py 98 | ``` 99 | 100 | ```python 101 | # boot.py 102 | 103 | import network 104 | sta_if = network.WLAN(network.STA_IF) 105 | sta_if.active(True) 106 | sta_if.connect("Wifi SSID", "Wifi password") 107 | ``` 108 | 109 | 110 | 111 | ```python 112 | # main.py 113 | 114 | from umqtt.robust import MQTTClient 115 | import machine 116 | import utime as time 117 | import gc 118 | import bme280 119 | 120 | 121 | # Wifi connect established in the boot.py file. Uncomment if needed 122 | # import network 123 | # sta_if = network.WLAN(network.STA_IF) 124 | # sta_if.active(True) 125 | # sta_if.connect("NCW", "malolos5459") 126 | 127 | client = MQTTClient("esp32-01", "192.168.1.122") 128 | pin5 = machine.Pin(5, machine.Pin.OUT) 129 | 130 | i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21)) 131 | bme = bme280.BME280(i2c=i2c) 132 | 133 | def checkwifi(): 134 | while not sta_if.isconnected(): 135 | time.sleep_ms(500) 136 | print(".") 137 | sta_if.connect() 138 | 139 | def publish(): 140 | count = 1 141 | while True: 142 | pin5.value(0) 143 | checkwifi() 144 | v = bme.values 145 | msg = b'{"MsgId":%u,"Mem":%u,"Celsius":%s,"Pressure":%s,"Humidity":%s}' % (count, gc.mem_free(), v[0][:-1], v[1][:-3], v[2][:-1]) 146 | client.publish(b"home/weather", msg) 147 | pin5.value(1) 148 | count = count + 1 149 | time.sleep(20) 150 | 151 | client.reconnect() 152 | 153 | publish() 154 | ``` 155 | 156 | ## Connecting to ESP32 with Putty 157 | 158 | Install Putty for your platform. Connect at 115200 baud rate 159 | 160 | See [Adafruit Serial REPL Tutorial](https://learn.adafruit.com/micropython-basics-how-to-load-micropython-on-a-board/serial-terminal). 161 | -------------------------------------------------------------------------------- /bme280.py: -------------------------------------------------------------------------------- 1 | # Authors: Paul Cunnane 2016, Peter Dahlebrg 2016 2 | # 3 | # This module borrows from the Adafruit BME280 Python library. Original 4 | # Copyright notices are reproduced below. 5 | # 6 | # Those libraries were written for the Raspberry Pi. This modification is 7 | # intended for the MicroPython and esp8266 boards. 8 | # 9 | # Copyright (c) 2014 Adafruit Industries 10 | # Author: Tony DiCola 11 | # 12 | # Based on the BMP280 driver with BME280 changes provided by 13 | # David J Taylor, Edinburgh (www.satsignal.eu) 14 | # 15 | # Based on Adafruit_I2C.py created by Kevin Townsend. 16 | # 17 | # Permission is hereby granted, free of charge, to any person obtaining a copy 18 | # of this software and associated documentation files (the "Software"), to deal 19 | # in the Software without restriction, including without limitation the rights 20 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | # copies of the Software, and to permit persons to whom the Software is 22 | # furnished to do so, subject to the following conditions: 23 | # 24 | # The above copyright notice and this permission notice shall be included in 25 | # all copies or substantial portions of the Software. 26 | # 27 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | # THE SOFTWARE. 34 | 35 | import time 36 | from ustruct import unpack, unpack_from 37 | from array import array 38 | 39 | # BME280 default address. 40 | BME280_I2CADDR = 0x76 41 | 42 | # Operating Modes 43 | BME280_OSAMPLE_1 = 1 44 | BME280_OSAMPLE_2 = 2 45 | BME280_OSAMPLE_4 = 3 46 | BME280_OSAMPLE_8 = 4 47 | BME280_OSAMPLE_16 = 5 48 | 49 | BME280_REGISTER_CONTROL_HUM = 0xF2 50 | BME280_REGISTER_CONTROL = 0xF4 51 | 52 | 53 | class BME280: 54 | 55 | def __init__(self, 56 | mode=BME280_OSAMPLE_1, 57 | address=BME280_I2CADDR, 58 | i2c=None, 59 | **kwargs): 60 | # Check that mode is valid. 61 | if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4, 62 | BME280_OSAMPLE_8, BME280_OSAMPLE_16]: 63 | raise ValueError( 64 | 'Unexpected mode value {0}. Set mode to one of ' 65 | 'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or ' 66 | 'BME280_ULTRAHIGHRES'.format(mode)) 67 | self._mode = mode 68 | self.address = address 69 | if i2c is None: 70 | raise ValueError('An I2C object is required.') 71 | self.i2c = i2c 72 | 73 | # load calibration data 74 | dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26) 75 | dig_e1_e7 = self.i2c.readfrom_mem(self.address, 0xE1, 7) 76 | self.dig_T1, self.dig_T2, self.dig_T3, self.dig_P1, \ 77 | self.dig_P2, self.dig_P3, self.dig_P4, self.dig_P5, \ 78 | self.dig_P6, self.dig_P7, self.dig_P8, self.dig_P9, \ 79 | _, self.dig_H1 = unpack("> 4) 87 | 88 | self.dig_H6 = unpack_from("> 4 125 | raw_press = ((readout[0] << 16) | (readout[1] << 8) | readout[2]) >> 4 126 | # temperature(0xFA): ((msb << 16) | (lsb << 8) | xlsb) >> 4 127 | raw_temp = ((readout[3] << 16) | (readout[4] << 8) | readout[5]) >> 4 128 | # humidity(0xFD): (msb << 8) | lsb 129 | raw_hum = (readout[6] << 8) | readout[7] 130 | 131 | result[0] = raw_temp 132 | result[1] = raw_press 133 | result[2] = raw_hum 134 | 135 | def read_compensated_data(self, result=None): 136 | """ Reads the data from the sensor and returns the compensated data. 137 | 138 | Args: 139 | result: array of length 3 or alike where the result will be 140 | stored, in temperature, pressure, humidity order. You may use 141 | this to read out the sensor without allocating heap memory 142 | 143 | Returns: 144 | array with temperature, pressure, humidity. Will be the one from 145 | the result parameter if not None 146 | """ 147 | self.read_raw_data(self._l3_resultarray) 148 | raw_temp, raw_press, raw_hum = self._l3_resultarray 149 | # temperature 150 | var1 = ((raw_temp >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11) 151 | var2 = (((((raw_temp >> 4) - self.dig_T1) * 152 | ((raw_temp >> 4) - self.dig_T1)) >> 12) * self.dig_T3) >> 14 153 | self.t_fine = var1 + var2 154 | temp = (self.t_fine * 5 + 128) >> 8 155 | 156 | # pressure 157 | var1 = self.t_fine - 128000 158 | var2 = var1 * var1 * self.dig_P6 159 | var2 = var2 + ((var1 * self.dig_P5) << 17) 160 | var2 = var2 + (self.dig_P4 << 35) 161 | var1 = (((var1 * var1 * self.dig_P3) >> 8) + 162 | ((var1 * self.dig_P2) << 12)) 163 | var1 = (((1 << 47) + var1) * self.dig_P1) >> 33 164 | if var1 == 0: 165 | pressure = 0 166 | else: 167 | p = 1048576 - raw_press 168 | p = (((p << 31) - var2) * 3125) // var1 169 | var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25 170 | var2 = (self.dig_P8 * p) >> 19 171 | pressure = ((p + var1 + var2) >> 8) + (self.dig_P7 << 4) 172 | 173 | # humidity 174 | h = self.t_fine - 76800 175 | h = (((((raw_hum << 14) - (self.dig_H4 << 20) - 176 | (self.dig_H5 * h)) + 16384) 177 | >> 15) * (((((((h * self.dig_H6) >> 10) * 178 | (((h * self.dig_H3) >> 11) + 32768)) >> 10) + 179 | 2097152) * self.dig_H2 + 8192) >> 14)) 180 | h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4) 181 | h = 0 if h < 0 else h 182 | h = 419430400 if h > 419430400 else h 183 | humidity = h >> 12 184 | 185 | if result: 186 | result[0] = temp 187 | result[1] = pressure 188 | result[2] = humidity 189 | return result 190 | 191 | return array("i", (temp, pressure, humidity)) 192 | 193 | @property 194 | def values(self): 195 | """ human readable values """ 196 | 197 | t, p, h = self.read_compensated_data() 198 | 199 | p = p // 256 200 | pi = p // 100 201 | pd = p - pi * 100 202 | 203 | hi = h // 1024 204 | hd = h * 100 // 1024 - hi * 100 205 | return ("{}C".format(t / 100), "{}.{:02d}hPa".format(pi, pd), 206 | "{}.{:02d}%".format(hi, hd)) 207 | -------------------------------------------------------------------------------- /boot.py: -------------------------------------------------------------------------------- 1 | import network 2 | sta_if = network.WLAN(network.STA_IF) 3 | sta_if.active(True) 4 | sta_if.connect("NCW", "malolos5459") 5 | -------------------------------------------------------------------------------- /copy-python-app-to-esp32.sh: -------------------------------------------------------------------------------- 1 | ampy --port /dev/ttyUSB0 put boot.py 2 | ampy --port /dev/ttyUSB0 put main.py 3 | ampy --port /dev/ttyUSB0 put bme280.py -------------------------------------------------------------------------------- /flash-micropython-firmware.sh: -------------------------------------------------------------------------------- 1 | esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash 0x0000 esp32-20170716-v1.9.1-219-g3580284e.bin 2 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from umqtt.robust import MQTTClient 2 | import machine 3 | import utime as time 4 | import gc 5 | import bme280 6 | 7 | 8 | # Wifi connect established in the boot.py file. Uncomment if needed 9 | # import network 10 | # sta_if = network.WLAN(network.STA_IF) 11 | # sta_if.active(True) 12 | # sta_if.connect("NCW", "malolos5459") 13 | 14 | #upip packages - see README.md 15 | # upip.install('micropython-umqtt.simple') 16 | # upip.install('micropython-umqtt.robust') 17 | 18 | client = MQTTClient("esp32-01", "192.168.1.122") 19 | pin5 = machine.Pin(5, machine.Pin.OUT) 20 | 21 | i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21)) 22 | bme = bme280.BME280(i2c=i2c) 23 | 24 | def initialise(): 25 | blinkcnt = 0 26 | checkwifi() 27 | while blinkcnt < 50: 28 | pin5.value(blinkcnt % 2) 29 | blinkcnt = blinkcnt + 1 30 | time.sleep_ms(100) 31 | 32 | def checkwifi(): 33 | blinkcnt = 0 34 | while not sta_if.isconnected(): 35 | time.sleep_ms(500) 36 | pin5.value(blinkcnt % 2) 37 | blinkcnt = blinkcnt + 1 38 | 39 | def publish(): 40 | count = 1 41 | while True: 42 | pin5.value(0) 43 | checkwifi() 44 | v = bme.values 45 | msg = b'{"MsgId":%u,"Mem":%u,"Celsius":%s,"Pressure":%s,"Humidity":%s}' % (count, gc.mem_free(), v[0][:-1], v[1][:-3], v[2][:-1]) 46 | client.publish(b"home/weather", msg) 47 | pin5.value(1) 48 | count = count + 1 49 | time.sleep(5) 50 | 51 | initialise() 52 | 53 | client.reconnect() 54 | 55 | publish() 56 | --------------------------------------------------------------------------------