diff --git a/.gitignore b/.gitignore index 7f7cccc..d2c9c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,4 @@ docs/_build/ # PyBuilder target/ +bin diff --git a/Makefile b/Makefile index 49cac1b..31cd429 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,20 @@ -# Makefile for the board +NAME=esp32-20220117-v1.18.bin -NAME=esp32-20180222-v1.9.3-347-g6e675c1b.bin +all: flash upload console -all: flash console +bin/${NAME}: + mkdir -p bin + wget https://micropython.org/resources/firmware/${NAME} -O bin/${NAME} -flash: - esptool.py -p /dev/ttyUSB0 -b 921600 erase_flash +flash: bin/${NAME} esptool.py -p /dev/ttyUSB0 -b 921600 write_flash --flash_mode dio 0x1000 bin/${NAME} sleep 5 ampy -p /dev/ttyUSB0 put ssd1306.py +upload: + ampy -p /dev/ttyUSB0 put boot.py + ampy -p /dev/ttyUSB0 put main.py + console: echo "Ctrl-A + Ctrl-Q to close Picocom" picocom -b115200 /dev/ttyUSB0 diff --git a/README.md b/README.md index 9cb647e..0f3b26b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Getting started -This howto assumes Ubuntu 16.04 is used on the computer and several tools have been installed: +This howto assumes Ubuntu 18.04+ is used on the computer and several tools have been installed: ``` sudo apt install picocom make python3-pip @@ -17,6 +17,36 @@ cd micropython-skeleton make ``` +In order to access the serial port you likely need to add yourself to the +`dialout` group after which you need to +log out from your desktop session and log in again + +``` +sudo gpasswd -a $USER dialout +``` + +**If you're using one of the computers prepared for the workshop all the steps +above have been performed already for you** + + +## Usage + +To open serial to the microcontroller: + +``` +make console +``` + +To upload `main.py`: + +``` +make upload +``` + +**Note that serial connection is used by both so you can't upload scripts while +serial console is open in another window** + + ## Blinking LED-s First let's some LED-s blinking. @@ -59,7 +89,8 @@ Tasks: ## Button presses On the board there is button labelled "Boot", this is hooked up to pin 2. -By default there is a resistor which pulls the voltage on the pin to 3.3v, but when button is pressed the pin is shorted to ground so the voltage goes to 0v. +By default there is a resistor which pulls the voltage on the pin to 3.3v, +but when button is pressed the pin is shorted to ground so the voltage goes to 0v. Most modern solutions use interrupts to detect voltage change on the pin: ``` @@ -90,27 +121,41 @@ Tasks: ## Driving OLED screens -Let's get some pixels on the screen. +Let's get some pixels on the screen! There's 128x64 pixels monochrome OLED screen connected via I2C bus on the pins 4 and 5. ``` -from machine import Pin, I2C +from machine import Pin, SoftI2C from ssd1306 import SSD1306_I2C -i2c = I2C(-1, Pin(4),Pin(5), freq=400000) # Bitbanged I2C bus +i2c = SoftI2C(Pin(4),Pin(5), freq=400000) # Bitbanged I2C bus oled = SSD1306_I2C(128, 64, i2c) oled.invert(0) # White text on black background oled.contrast(255) # Maximum contrast oled.fill(0) -name = "Lauri" -oled.text("Hi %s" % name, 10, 10) +name = "Hello MicroPython!" +oled.text(" %s" % name, 10, 10) oled.show() ``` Tasks: -1. When button is pressed show a corresponding message on the screen - lights turned on/off or the name of the color shown +1. What IP address was assigned to the board by the wireless network? + Hint: Check out `wlan.ifconfig()` +2. Show button press counter on the screen +3. Show on the screen which color is the RGB LED shining + +## Clock synchronization + +Most boards to do not have battery backed time keep track of the time. +Once you have the microcontroller connected to the Internet you can query +time from one of the NTP servers. + +The Internet connectivity is established using `boot.py` script that is +already included in this repo. It by default connects to `k-space.ee legacy` +wireless network. + ## Temperature & humidity @@ -122,7 +167,6 @@ Next let's hook up DHT11 sensor to the board and measure the temperature. Some code to get you going: - ``` from time import sleep from machine import Pin @@ -150,19 +194,21 @@ Tasks: In this case HC-SR04 is hooked up: -* Trigger is connected to pin 25 -* Echo is connected to pin 26 +* Trigger is connected to pin 12 +* Echo is connected to pin 14 * GND pins are connected * Sonar's Vcc is connected to 3.3V on the board +This is exactly the case with the sumorobots. Feel free to try it out! + Code to measure distance: ``` from time import sleep_us, sleep_ms from machine import Pin, time_pulse_us -trigger = Pin(25, Pin.OUT) -echo = Pin(26, Pin.IN) +trigger = Pin(12, Pin.OUT) +echo = Pin(14, Pin.IN) def measure(): trigger.value(0) @@ -183,66 +229,14 @@ while True: Tasks: 1. Get distance shown on OLED display - - -## Connecting to internet - -Exit the serial console by pressing Ctrl-A and then Ctrl-Q. -Upload module to handle WebSockets and return to Python prompt: - -``` -ampy -p /dev/ttyUSB0 put uwebsockets.py -ampy -p /dev/ttyUSB0 put boot.py # Script that connects to itcollege network -make console -``` - -Press EN button on the board to reset the board. - -Paste following: - -``` -import sys -import uwebsockets -from machine import Pin - -Pin(12, Pin.OUT).value(1) -Pin(13, Pin.OUT).value(1) -led_blue = Pin(15, Pin.OUT) - -channel = "living-room-of-lauri" -uri = "ws://iot.koodur.com:80/ws/" + channel -print("Connecting to:", uri) -conn = uwebsockets.connect(uri) -conn.send("alive") - -turned_off = False - -while True: - print("Reading message...") - fin, opcode, data = conn.read_frame() - if data == "toggle": - turned_off = not turned_off - led_blue.value(turned_off) - else: - print("Got unknown command:", data) -``` - -Using web browser navigate [here](http://iot.koodur.com/demo2.html#living-room-of-lauri) - -1. Move to another channel to prevent flipping lights in my living room -2. Improve the code so the "Boot" button and button in the web interface both work simultaneously -3. Download the HTML file and add buttons to select different colors, adjust Python code to handle new commands -4. Add code to send sensor readings to the webserver +2. How were the constants for converting `duration` to `distance` figured out? ## Summary -ESP32 microcontroller with MicroPython is a really cheap way to get started with the IoT stuff. See more detailed information [here](https://lauri.xn--vsandi-pxa.com/2017/06/espressif.html). - -Some more tricks to try: - -* Add dimming of LED-s with PWM -* Add [colorpicker](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color) +ESP32 microcontroller with MicroPython is a really cheap way to get started +with the IoT stuff. See more detailed information +[here](https://lauri.xn--vsandi-pxa.com/2017/06/espressif.html). Other interesting projects with ESP8266 and ESP32 microcontrollers: diff --git a/bin/esp32-20180222-v1.9.3-347-g6e675c1b.bin b/bin/esp32-20180222-v1.9.3-347-g6e675c1b.bin deleted file mode 100644 index 27eba24..0000000 Binary files a/bin/esp32-20180222-v1.9.3-347-g6e675c1b.bin and /dev/null differ diff --git a/boot.py b/boot.py index befffbb..386ad40 100644 --- a/boot.py +++ b/boot.py @@ -1,5 +1,13 @@ +# Give time to cancel this boot script +import time +print("Press Ctrl-C to stop boot script...") +time.sleep(2) + # Connect to wireless network as client import network wlan = network.WLAN(network.STA_IF) wlan.active(True) -wlan.connect("k-space.ee guest") +wlan.connect("k-space.ee legacy") + +while not wlan.isconnected(): + pass diff --git a/main.py b/main.py index fef1115..d931fd8 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,36 @@ -from time import sleep_ms -from machine import Pin, I2C -from ssd1306 import SSD1306_I2C +import ntptime +ntptime.settime() -i2c = I2C(-1, Pin(4),Pin(5),freq=400000) # Bitbanged I2C bus -assert 60 in i2c.scan(), "No OLED display detected!" -oled = SSD1306_I2C(128, 64, i2c) -buf = "wubba lubba dub dub " -oled.invert(0) # White text on black background -oled.contrast(255) # Maximum contrast -j = 0 +from flipdisc import DisplayBuffer, Font +from time import sleep, localtime +from machine import UART +TIMEZONE = 3 +weekdays = "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" + +port = UART(2, baudrate=4800, tx=17, rx=16) +disp = DisplayBuffer(0x06, 128, 16) while True: - oled.fill(0) - oled.text(buf[j%len(buf):]+buf, 10, 10) - oled.show() - sleep_ms(20) - j += 1 + for j in range(0,10): + year, month, day, hour, minute, second, dow, _ = localtime() + hour = (hour + TIMEZONE) % 24 + i = " %02d:%02d:%02d" % (hour, minute, second) + j = " %04d-%02d-%02d %s" % (year, month, day, weekdays[dow]) + disp.put_text(i.encode("ascii"),0, 0, Font.F6) + disp.put_text(j.encode("ascii"),0, 15, Font.F6) + buf = disp.finalize_buffer() + port.write(buf) + sleep(1) + for j in range(0, 2): + disp.put_text(b"MicroPython",0, 0, Font.F13_F) + buf = disp.finalize_buffer() + port.write(buf) + sleep(2) + disp.put_text(b"... is awesome",0, 0, Font.F13_F) + buf = disp.finalize_buffer() + port.write(buf) + sleep(2) + +port.close() + +