├── nqueens.py ├── DHT11_Sensor_SSD1306.py ├── LICENSE ├── SimpleWebClockWithTimer.py ├── WebJSONQuery_Template.py ├── ConwayGameOfLife_SSD1306.py ├── SimpleWebClockWithTimerUsingWebAPI.py ├── DeepSleep_Cloud_Update.py ├── Simple_WebServer_AP.py ├── WS2812_NeoPixelRainbow.py ├── Simple_WebServer.py └── README.md /nqueens.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | maxQueens = 8 4 | 5 | def verifyPos(newColPos, rowPos): 6 | for colPos in range(newColPos): 7 | if queens[colPos] == rowPos or abs(colPos - newColPos) == abs(queens[colPos] - rowPos): 8 | return False 9 | return True 10 | 11 | def placeQueen(maxQ, colPos=0): 12 | global counter 13 | if colPos == maxQ: 14 | counter += 1 15 | print(counter, queens) 16 | else: 17 | for rowPos in range(1, maxQ + 1): 18 | if verifyPos(colPos, rowPos): 19 | queens[colPos] = rowPos 20 | placeQueen(maxQ, colPos + 1) 21 | 22 | counter = 0 23 | queens = [0] * maxQueens 24 | 25 | start = time.ticks_us() 26 | placeQueen(maxQueens) 27 | end = time.ticks_us() 28 | 29 | print('{} results in {} ms'.format(counter, (end - start) / 1000)) 30 | -------------------------------------------------------------------------------- /DHT11_Sensor_SSD1306.py: -------------------------------------------------------------------------------- 1 | # Display DHT11 sensor readings on SSD1306 2 | 3 | from machine import Pin, I2C 4 | import time, dht, ssd1306 5 | 6 | # DHT11 sensor (Pin D5) 7 | dht = dht.DHT11(Pin(14)) 8 | 9 | # SSD1306 OLED display (SCL: D1, SDA: D2) 10 | display = ssd1306.SSD1306_I2C(128, 64, I2C(scl=Pin(5), sda=Pin(4))) 11 | 12 | # template string for formatting 13 | template_str = '\nTemperature:\n {} *C \n\nHumidity:\n {} % ' 14 | 15 | while True: 16 | 17 | # get readings from DHT11 18 | dht.measure() 19 | 20 | # generate formatted string 21 | output_str = template_str.format(dht.temperature(), dht.humidity()) 22 | 23 | # print output without \n (new line) character 24 | print(output_str.replace('\n', '')) 25 | 26 | # print output on oled 27 | display.fill(0) 28 | for index, line in enumerate(output_str.split('\n')): 29 | display.text(line, 8, index * 8) 30 | display.show() 31 | 32 | # wait for 2 seconds 33 | time.sleep(2) 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alan Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SimpleWebClockWithTimer.py: -------------------------------------------------------------------------------- 1 | # Timer-based simple clock with SSD1306 oled display (by Alan Wang) 2 | 3 | SSID = '' # WiFi ssid 4 | PW = '' # WiFi password 5 | TMZ_HOUR_OFFSET = 8 # timezone hour offset 6 | SCL = 5 7 | SDA = 4 8 | 9 | import network, ntptime, time, ssd1306, gc 10 | from machine import Pin, SoftI2C, Timer 11 | 12 | gc.enable() 13 | 14 | # weekday names 15 | weekday = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday') 16 | 17 | # setup oled display (SCL -> D1, SDA -> D2) 18 | display = ssd1306.SSD1306_I2C(128, 64, SoftI2C(scl=Pin(SCL), sda=Pin(SDA))) 19 | 20 | # setup and connect WiFi 21 | wifi = network.WLAN(network.STA_IF) 22 | wifi.active(True) 23 | wifi.connect(SSID, PW) 24 | while not wifi.isconnected(): 25 | pass 26 | 27 | sec_prev = 0 28 | 29 | # time update function 30 | def ntpUpdate(timer): 31 | while True: 32 | try: 33 | ntptime.settime() # query NTP server and update system time 34 | break 35 | except: 36 | time.sleep(5) # try again if failed 37 | 38 | # display update function 39 | def clockUpdate(timer): 40 | global sec_prev 41 | lt = time.localtime(time.time() + TMZ_HOUR_OFFSET * 3600) 42 | if lt[5] != sec_prev: 43 | display.fill(0) 44 | display.text(weekday[lt[6]], 8, 8) 45 | display.text('{0:04d}-{1:02d}-{2:02d}'.format(*lt), 8, 24) 46 | display.text('{3:02d}:{4:02d}:{5:02d}'.format(*lt), 8, 40) 47 | display.show() # display clock 48 | sec_prev = lt[5] 49 | 50 | # update time for the first time 51 | ntpUpdate(None) 52 | 53 | # start timers (coroutines) 54 | timer_ntp, timer_display = Timer(-1), Timer(-1) 55 | timer_ntp.init(mode=Timer.PERIODIC, period=900000, callback=ntpUpdate) 56 | timer_display.init(mode=Timer.PERIODIC, period=100, callback=clockUpdate) 57 | -------------------------------------------------------------------------------- /WebJSONQuery_Template.py: -------------------------------------------------------------------------------- 1 | # ESP8266 Web JSON Query Template 2 | 3 | import network, requests, time, sys 4 | 5 | # user info 6 | ssid = '' # change this to your WiFi AP name 7 | pw = '' # change this to your WiFi AP password 8 | 9 | # API url 10 | api_url = 'http://api.open-notify.org/iss-now.json' 11 | 12 | 13 | # wifi error descriptions 14 | wifi_error = { 15 | network.STAT_WRONG_PASSWORD: 'wrong password', 16 | network.STAT_NO_AP_FOUND: 'wifi AP not found', 17 | -1: 'due to other problems', 18 | } 19 | 20 | # connecting to WiFi 21 | wifi = network.WLAN(network.STA_IF) 22 | wifi.active(True) 23 | wifi.connect(ssid, pw) 24 | 25 | print('ESP8266 connecting to', ssid, '...') 26 | while wifi.status() == network.STAT_CONNECTING: 27 | pass 28 | 29 | if wifi.status() != network.STAT_GOT_IP: 30 | print('Failed to connect:', wifi_error.get(wifi.status(), wifi_error[-1])) 31 | sys.exit() 32 | 33 | print('Connected.') 34 | print('IP:', wifi.ifconfig()[0], '\n') 35 | time.sleep(1) 36 | 37 | 38 | while True: 39 | 40 | try: 41 | # send HTTP GET request to the API 42 | print('Querying API:', api_url) 43 | response = requests.get(api_url) 44 | 45 | if response.status_code == 200: 46 | print('Query successful. JSON response:') 47 | # return a dict object containing the JSON data 48 | parsed = response.json() 49 | print(parsed) # you can access data by using parsed[key] 50 | 51 | else: 52 | print('Query failed. ' + \ 53 | 'Status code:', response.status_code) 54 | 55 | response.close() 56 | 57 | except Exception as e: 58 | print('Error occurred:', e) 59 | print('If you see a SSL error above, ' + \ 60 | 'either you have unstable Wifi or ' + \ 61 | 'the API is not supported by MicroPython.') 62 | 63 | print('') 64 | time.sleep(30) 65 | -------------------------------------------------------------------------------- /ConwayGameOfLife_SSD1306.py: -------------------------------------------------------------------------------- 1 | # Conway's Game of Life on 128x64 SSD1306 OLED and ESP8266 (by Alan Wang) 2 | 3 | 4 | BIRTH = (3, ) # number of nearby cells for a new cell to be born 5 | SURVIVAL = (2, 3) # number of nearby cells for an existing cell to survive 6 | WIDTH = 128 7 | HEIGHT = 64 8 | DOT_SIZE = 3 # draw 3x3 dots -> board size 128/3 x 64/3 9 | RAND_BIT = 2 # cell randomize factor (2 = 2^2 (1/4 chance)) 10 | 11 | 12 | from machine import Pin, ADC, SoftI2C, freq 13 | from micropython import const 14 | from ssd1306 import SSD1306_I2C 15 | import random, time, gc 16 | 17 | 18 | freq(160000000) 19 | gc.enable() 20 | random.seed(sum([ADC(0).read() for _ in range(1000)])) # generate randomize seed from floating analog pin 21 | 22 | 23 | X = WIDTH // DOT_SIZE 24 | Y = HEIGHT // DOT_SIZE 25 | TOTAL = X * Y 26 | board = [0 if random.getrandbits(RAND_BIT) else 1 27 | for _ in range(TOTAL)] 28 | gen = 0 29 | 30 | 31 | display = SSD1306_I2C(WIDTH, HEIGHT, 32 | SoftI2C(scl=Pin(5), sda=Pin(4), freq=400000)) 33 | display.fill(0) 34 | display.show() 35 | 36 | 37 | print('Conway\'s Game of Life: matrix size {} x {}'.format(X, Y)) 38 | 39 | 40 | def calculate_next_gen(): # calculate next generation of cells 41 | global board 42 | buffer = [0] * TOTAL 43 | for i in range(TOTAL): 44 | group = board[i-1:i+2] + \ 45 | board[(i-1-X)%TOTAL:(i+2-X)%TOTAL] + \ 46 | board[(i-1+X)%TOTAL:(i+2+X)%TOTAL] 47 | cells = sum(group) 48 | if not board[i]: 49 | if cells in BIRTH: 50 | buffer[i] = 1 51 | else: 52 | if (cells - 1) in SURVIVAL: 53 | buffer[i] = 1 54 | board = buffer 55 | 56 | 57 | def display_board(): # draw cells on OLED 58 | display.fill(0) 59 | for i in range(TOTAL): 60 | if board[i]: 61 | display.fill_rect((i % X) * DOT_SIZE, 62 | (i // X) * DOT_SIZE, 63 | DOT_SIZE, DOT_SIZE, 1) 64 | display.show() 65 | 66 | 67 | gen, t_start, t_dur = 0, 0, 0 68 | 69 | while True: 70 | gen += 1 71 | print('Gen {}: {} cell(s) ({} ms)'.format(gen, sum(board), t_dur)) 72 | display_board() 73 | t_start = time.ticks_ms() 74 | calculate_next_gen() 75 | t_dur = time.ticks_diff(time.ticks_ms(), t_start) 76 | -------------------------------------------------------------------------------- /SimpleWebClockWithTimerUsingWebAPI.py: -------------------------------------------------------------------------------- 1 | # Timer-based clock with SSD1306 oled display (by Alan Wang), 2 | # RTC and World Time API version (automatic timezone) 3 | 4 | SSID = '' # WiFi ssid 5 | PW = '' # WiFi password 6 | SCL = 5 7 | SDA = 4 8 | 9 | import network, requests, time, ssd1306, gc 10 | from machine import Pin, SoftI2C, Timer, RTC 11 | 12 | gc.enable() 13 | 14 | # weekday names 15 | weekday = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday') 16 | 17 | # setup oled display (SCL -> D1, SDA -> D2) 18 | display = ssd1306.SSD1306_I2C(128, 64, SoftI2C(scl=Pin(SCL), sda=Pin(SDA))) 19 | 20 | # inernal RTC 21 | rtc = RTC() 22 | 23 | # setup and connect WiFi 24 | wifi = network.WLAN(network.STA_IF) 25 | wifi.active(True) 26 | wifi.connect(SSID, PW) 27 | while not wifi.isconnected(): 28 | pass 29 | 30 | sec_prev = 0 31 | 32 | # time update function 33 | def rtcUpdate(timer): 34 | while True: 35 | try: 36 | response = requests.get('http://worldtimeapi.org/api/ip') 37 | if response.status_code == 200: 38 | parsed = response.json() 39 | # parsed['unixtime']: local unixtime since 1970/01/01 00:00:00) 40 | # parsed['raw_offset']: timezone hour offset 41 | # 946684800: unixtime of 2020/01/01 00:00:00 (system start time on MicroPython) 42 | # generate datetime tuple based on these information 43 | dt = time.localtime(parsed['unixtime'] + parsed['raw_offset'] - 946684800) 44 | # rtc.datetime((year, month, day, weekday, hour, minute, second, microsecond)) 45 | rtc.datetime((dt[0], dt[1], dt[2], dt[6], dt[3], dt[4], dt[5], 0)) 46 | break 47 | except: 48 | time.sleep(10) # try again if failed 49 | 50 | # display update function 51 | def clockUpdate(timer): 52 | global sec_prev 53 | dt = rtc.datetime() 54 | if dt[6] != sec_prev: 55 | display.fill(0) 56 | display.text(weekday[dt[3]], 8, 8) 57 | display.text('{0:04d}-{1:02d}-{2:02d}'.format(*dt), 8, 24) 58 | display.text('{4:02d}:{5:02d}:{6:02d}'.format(*dt), 8, 40) 59 | display.show() # display clock 60 | sec_prev = dt[6] 61 | 62 | # update time for the first time 63 | rtcUpdate(None) 64 | 65 | # start timers 66 | timer_ntp, timer_display = Timer(-1), Timer(-1) 67 | timer_ntp.init(mode=Timer.PERIODIC, period=900000, callback=rtcUpdate) 68 | timer_display.init(mode=Timer.PERIODIC, period=100, callback=clockUpdate) 69 | -------------------------------------------------------------------------------- /DeepSleep_Cloud_Update.py: -------------------------------------------------------------------------------- 1 | # ESP8266 Deep Sleep/Cloud Data Update 2 | 3 | # Upload this script onto the board as main.py, then remember to 4 | # connect D0 (GPIO 16) and RST with a jumper wire in order to 5 | # wake the board from deep sleep. 6 | 7 | # You can also maunally wake it up by pressing the RST button or 8 | # pull RST low with an external switch. 9 | 10 | # Afterwards, you may need to re-flash the firmware to reset ESP8266. 11 | 12 | import network, requests, machine, time, dht 13 | 14 | # user info 15 | wifi_ssid = 'your_wifi_ssid' # change this to your WiFi AP name 16 | wifi_pw = 'your_wifi_password' # change this to your WiFi AP password 17 | 18 | # IFTTT Webhook key/event name 19 | # see: https://ifttt.com/maker_webhooks 20 | webhook_key = 'your_ifttt_webhook_key' 21 | webhook_event_name = 'your_ifttt_webhook_event_name' 22 | 23 | webhook_url = 'https://maker.ifttt.com/trigger/' + \ 24 | webhook_event_name + '/with/key/' + webhook_key 25 | 26 | 27 | if machine.reset_cause() == machine.DEEPSLEEP_RESET: 28 | print('ESP8266 woken from a deep sleep...') 29 | 30 | 31 | # light up onboard LED 32 | led = machine.Pin(2, machine.Pin.OUT, value=0) 33 | 34 | 35 | # connecting to WiFi 36 | wifi = network.WLAN(network.STA_IF) 37 | wifi.active(True) 38 | 39 | wifi.connect(wifi_ssid, wifi_pw) 40 | while not wifi.isconnected(): 41 | pass 42 | 43 | 44 | # get readings from DHT11 (connected to D5) 45 | dht = dht.DHT11(machine.Pin(14)) 46 | dht.measure() 47 | 48 | 49 | # Upload data via IFTTT 50 | query_url = '{}?value1={}&value2={}&value3={}'.format( 51 | webhook_url, 'Temp(*C)/Humid(%)', 52 | dht.temperature(), dht.humidity()) 53 | 54 | response = None 55 | 56 | try: 57 | print('Upload data...') 58 | response = requests.get(query_url) 59 | except: 60 | pass 61 | 62 | if not response == None and response.status_code == 200: 63 | print('Upload successful') 64 | # led flashing quickly 65 | for _ in range(10): 66 | led.value(1) 67 | time.sleep_ms(25) 68 | led.value(0) 69 | time.sleep_ms(25) 70 | else: 71 | print('Upload failed') 72 | # led flashing slowly 73 | led.value(1) 74 | time.sleep_ms(250) 75 | led.value(0) 76 | time.sleep_ms(250) 77 | 78 | # led off 79 | led.value(1) 80 | 81 | 82 | # Go to deep sleep and wake up after a period of time 83 | print('Go to deep sleep...') 84 | rtc = machine.RTC() 85 | rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) 86 | rtc.alarm(rtc.ALARM0, 30000) 87 | machine.deepsleep() 88 | -------------------------------------------------------------------------------- /Simple_WebServer_AP.py: -------------------------------------------------------------------------------- 1 | ssid = 'ESP8266' # AP name 2 | pw = '12345678' # AP password 3 | port = 80 # server port 4 | conns = 1 # number of channels 5 | 6 | 7 | from machine import Pin 8 | import network, socket 9 | 10 | led = Pin(2, Pin.OUT, value=1) 11 | 12 | 13 | # webpage template 14 | html = """ 15 | 16 | 17 | 18 | ESP8266 Web Server 19 | 20 | 21 | 32 | 33 | 34 |
35 |

ESP8266 Web Server

36 |

LED status:

37 |
38 |

39 |

40 |
41 |
42 | 43 | 44 | """ 45 | 46 | # add HTTP response headers 47 | http_resp = 'HTTP/1.1 200 OK\r\n' + \ 48 | 'Content-Type: text/html\r\n' + \ 49 | 'Connection: close\r\n\r\n' 50 | 51 | # parse html to a single string 52 | html = http_resp + ''.join([line.strip() for line in html.split('\n')]) 53 | 54 | 55 | # generated webpage to be sent to user 56 | def web_page(): 57 | led_status = 'ON' if led.value() == 0 else 'OFF' 58 | return html.replace('', led_status) 59 | 60 | # extract any number of parameter names and values from HTTP response 61 | def get_paras(get_str): 62 | para_dict = {} 63 | q_pos = get_str.find('/?') 64 | if q_pos > 0: 65 | http_pos = get_str.find('HTTP/') 66 | para_list = get_str[q_pos + 2 : http_pos - 1].split('&') 67 | for para in para_list: 68 | para_tmp = para.split('=') 69 | para_dict.update({para_tmp[0] : para_tmp[1]}) 70 | return para_dict 71 | 72 | 73 | # start server 74 | print('Starting server...') 75 | wifi = network.WLAN(network.AP_IF) 76 | wifi.config(essid=ssid, password=pw, channel=conns, 77 | authmode=network.AUTH_WPA_WPA2_PSK) 78 | wifi.active(True) 79 | 80 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 81 | s.bind(('', port)) 82 | s.listen(conns) 83 | print('Web server started on AP', 84 | '<{}> (local ip: http://{}:{})'.format(ssid, wifi.ifconfig()[0], port)) 85 | 86 | 87 | while True: 88 | 89 | # wait for client 90 | client, addr = s.accept() 91 | print('Client connected from', addr[0]) 92 | request = client.recv(1024) 93 | 94 | # extract url parameters 95 | request_text = request.decode('utf-8') 96 | paras = get_paras(request_text) 97 | 98 | # control the led 99 | led_status = paras.get('led', None) 100 | if led_status == 'On': 101 | led.value(0) 102 | else: 103 | led.value(1) 104 | 105 | # send response (web page) to user 106 | response = web_page() 107 | client.send(response) 108 | client.close() 109 | -------------------------------------------------------------------------------- /WS2812_NeoPixelRainbow.py: -------------------------------------------------------------------------------- 1 | # WS2812 NeoPixel LED Rainbow/Rotation Effect (based on Adafruit example) 2 | 3 | neo_pin = 5 # pin for NeoPixel 4 | neo_num = 12 # number of leds 5 | neo_maxlevel = 0.3 # max brightness level (0.0-1.0) 6 | 7 | 8 | from machine import Pin 9 | from neopixel import NeoPixel 10 | import time 11 | 12 | 13 | class NeoPixelRainbow(): 14 | 15 | def __init__(self, pin, num=0, brightness=0.0): 16 | self._np = NeoPixel(Pin(pin, Pin.OUT), num) 17 | self._buffer = [(0, 0, 0)] * num 18 | self._brightness = brightness 19 | 20 | def __getitem__(self, key): 21 | return self._buffer[key] 22 | 23 | def __setitem__(self, key, value): 24 | if isinstance(key, int): 25 | self._buffer[key] = tuple(value) 26 | elif isinstance(key, slice): 27 | self._buffer[key] = [tuple(color) for color in value] 28 | 29 | def __len__(self): 30 | return len(self._buffer) 31 | 32 | @property 33 | def n(self): 34 | return len(self._buffer) 35 | 36 | def _color(self, color): 37 | return tuple([round(c * self._brightness) for c in color]) 38 | 39 | def wheel(self, pos): 40 | r, g, b = 0, 0, 0 41 | if pos < 0 or pos > 255: 42 | pass 43 | elif pos < 85: 44 | r, g, b = 255 - pos * 3, pos * 3, 0 45 | elif pos < 170: 46 | pos -= 85 47 | r, g, b = 0, 255 - pos * 3, pos * 3 48 | else: 49 | pos -= 170 50 | r, g, b = pos * 3, 0, 255 - pos * 3 51 | return (r, g, b) 52 | 53 | def fill(self, color): 54 | self[:] = [color] * self.n 55 | 56 | def clear(self, color): 57 | self.fill((0, 0, 0)) 58 | 59 | def rainbowCycle(self, cycle=0): 60 | for i in range(len(self._buffer)): 61 | self[i] = self.wheel((round(i * 255 / self.n) + cycle) & 255) 62 | 63 | def rotate(self, clockwise=True): 64 | self[:] = (self[-1:] + self[:-1]) if clockwise else (self[1:] + self[:1]) 65 | 66 | def write(self): 67 | for i in range(self.n): 68 | self._np[i] = self._color(self[i]) 69 | self._np.write() 70 | 71 | 72 | np = NeoPixelRainbow(pin=neo_pin, 73 | num=neo_num, 74 | brightness=neo_maxlevel) 75 | 76 | 77 | RED = (255, 0, 0) 78 | YELLOW = (255, 150, 0) 79 | GREEN = (0, 255, 0) 80 | CYAN = (0, 255, 255) 81 | BLUE = (0, 0, 255) 82 | PURPLE = (180, 0, 255) 83 | WHITE = (255, 255, 255) 84 | BLACK = (0, 0, 0) 85 | COLORS = (RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, WHITE, BLACK) 86 | 87 | for color in COLORS: 88 | np.fill(color) 89 | np.write() 90 | time.sleep_ms(200) 91 | 92 | for color in COLORS: 93 | for i in range(np.n): 94 | np[i] = color 95 | np.write() 96 | time.sleep_ms(25) 97 | 98 | np.rainbowCycle() 99 | 100 | for _ in range(np.n * 3): 101 | np.rotate(clockwise=True) 102 | np.write() 103 | time.sleep_ms(25) 104 | 105 | cycle = 0 106 | while True: 107 | np.rainbowCycle(cycle) 108 | np.write() 109 | cycle = (cycle + 1) & 255 110 | -------------------------------------------------------------------------------- /Simple_WebServer.py: -------------------------------------------------------------------------------- 1 | ssid = '' # WiFi name 2 | pw = '' # WiFi password 3 | port = 80 # server port 4 | conns = 1 # number of channels 5 | 6 | 7 | from machine import Pin 8 | import network, socket, sys 9 | 10 | led = Pin(2, Pin.OUT, value=1) 11 | 12 | 13 | # webpage template 14 | html = """ 15 | 16 | 17 | 18 | ESP8266 Web Server 19 | 20 | 21 | 32 | 33 | 34 |
35 |

ESP8266 Web Server

36 |

LED status:

37 |
38 |

39 |

40 |
41 |
42 | 43 | 44 | """ 45 | 46 | # add HTTP response headers 47 | http_resp = 'HTTP/1.1 200 OK\r\n' + \ 48 | 'Content-Type: text/html\r\n' + \ 49 | 'Connection: close\r\n\r\n' 50 | 51 | # parse html to a single string 52 | html = http_resp + ''.join([line.strip() for line in html.split('\n')]) 53 | 54 | 55 | # generated webpage to be sent to user 56 | def web_page(): 57 | led_status = 'ON' if led.value() == 0 else 'OFF' 58 | return html.replace('', led_status) 59 | 60 | # extract url parameters from HTTP request 61 | def get_paras(get_str): 62 | para_dict = {} 63 | q_pos = get_str.find('/?') 64 | if q_pos > 0: 65 | http_pos = get_str.find('HTTP/') 66 | para_list = get_str[q_pos + 2 : http_pos - 1].split('&') 67 | for para in para_list: 68 | para_tmp = para.split('=') 69 | para_dict.update({para_tmp[0] : para_tmp[1]}) 70 | return para_dict 71 | 72 | 73 | # wifi error descriptions 74 | wifi_error = { 75 | network.STAT_WRONG_PASSWORD: 'wrong password', 76 | network.STAT_NO_AP_FOUND: 'wifi AP not found', 77 | -1: 'due to other problems', 78 | } 79 | 80 | # connect to wifi 81 | print('Connecting to WiFi...') 82 | wifi = network.WLAN(network.STA_IF) 83 | wifi.active(True) 84 | wifi.connect(ssid, pw) 85 | while wifi.status() == network.STAT_CONNECTING: 86 | pass 87 | 88 | if wifi.status() != network.STAT_GOT_IP: 89 | print('Failed to connect:', wifi_error.get(wifi.status(), wifi_error[-1])) 90 | sys.exit() 91 | 92 | print('Connected.') 93 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 94 | s.bind(('', port)) 95 | s.listen(conns) 96 | print('Web server started on', 'http://{}:{}'.format(wifi.ifconfig()[0], port)) 97 | 98 | 99 | while True: 100 | 101 | # wait for client 102 | client, addr = s.accept() 103 | print('Client connected from', addr[0]) 104 | request = client.recv(1024) 105 | 106 | # extract url parameters 107 | request_text = request.decode('utf-8') 108 | paras = get_paras(request_text) 109 | 110 | # control the led 111 | led_status = paras.get('led', None) 112 | if led_status == 'On': 113 | led.value(0) 114 | else: 115 | led.value(1) 116 | 117 | # send response (web page) to user 118 | response = web_page() 119 | client.send(response) 120 | client.close() 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266 MicroPython Cookbook 2 | 3 | ![Micropython-logo svg](https://user-images.githubusercontent.com/44191076/79063718-e5975580-7cd5-11ea-90a2-6f350adfb0cd.png) 4 | 5 | I publish ESP8266/ESP32 MicroPyton projects from time to time on [Hackster.io](https://www.hackster.io/alankrantas). Here I have some smaller project/scripts I wrote forMicroPython, in which I tried to make the code as simple as possible and only use built-in modules. 6 | 7 | Most of the code works for ESp8266, ESP32 and Raspberry Pi Pico W. 8 | 9 | See [ESP8266 Pinout Reference](https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/) for the actual GPIO number for each pins. All ESP8266s (for example, NodeMCU and WeMos D1/D1 mini as well as their clones) are functionally identical. Most of them use either CP2012 or CH340 USB chip which requires driver on Windows. 10 | 11 | ## Hello World (Blinky) 12 | 13 | Controlling the on-board LED on pin D4 (GPIO 2) or an external LED: 14 | 15 | ```python 16 | from machine import Pin 17 | import utime 18 | 19 | led = Pin(2, Pin.OUT) 20 | 21 | while True: 22 | led.value(not led.value()) 23 | utime.sleep_ms(500) 24 | ``` 25 | 26 | or 27 | 28 | ```python 29 | from machine import Pin, Timer 30 | 31 | led = Pin(2, Pin.OUT) 32 | 33 | timer = Timer(-1) 34 | timer.init(mode=Timer.PERIODIC, period=500, 35 | callback=lambda _: led.value(not led.value())) 36 | ``` 37 | 38 | > The onboaard LED in most ESP8266s are reversed so it will light up at low voltage instead. 39 | 40 | ## Pull-Up Button 41 | 42 | Reading a button connecting to pin D1 (GPIO 5) and GND, no resistor required: 43 | 44 | ```python 45 | from machine import Pin, Signal 46 | import utime 47 | 48 | btn = Signal(Pin(5, Pin.IN, Pin.PULL_UP), invert=True) 49 | 50 | while True: 51 | print(f'Button pressed: {'yes' if btn.value() else 'no'}') 52 | utime.sleep_ms(100) 53 | ``` 54 | 55 | > MicroPython now supports f-string but the examples below still use ```format``` for backward compatibility. 56 | 57 | --- 58 | 59 | ## Simple Timer-Based Simple Web Clock on SSD1306 60 | 61 | File: [SimpleWebClockWithTimer.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/SimpleWebClockWithTimer.py) 62 | 63 | A simple web clock that update system RTC time every 15 minutes via NTP server. It uses two machine.timers instead of a while loop, reducing the code down to less than 40 actual lines. Change the SSID and PW to your own WiFi AP. 64 | 65 | The [SimpleWebClockWithTimerUsingWebAPI.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/SimpleWebClockWithTimerUsingWebAPI.py) version works the same but use [World Time API](http://worldtimeapi.org/) to query time instead and update it via the machine.RTC module. Since the API can detect your timezone, you don't need to set it in this version. 66 | 67 | ## Display DHT11 Sensor Readings on SSD1306 68 | 69 | File: [DHT11_Sensor_SSD1306.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/DHT11_Sensor_SSD1306.py) 70 | 71 | A simple example of displaying DHT11's temperature and humidity readings on SSD1306 OLED as well as printing them in REPL. A very basic weather station. 72 | 73 | Change dht.DHT11 to dht.DHT22 if you are using a DHT22 sensor. 74 | 75 | ## Simple Web Server 76 | 77 | File: [Simple_WebServer.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/Simple_WebServer.py) 78 | 79 | A simple web server in STA mode (connect to your WiFi and will return a HTML webpage to your web browser). You'll have to connect the ESP8266 on your computer to read the actual IP it get. This example allows you to turn the onboard LED on or off. 80 | 81 | File: [Simple_WebServer_AP.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/Simple_WebServer_AP.py) 82 | 83 | This is the AP mode version, which will start its own WiFi access point (works without externam WiFi). Connect the AP (default named "ESP8266" with password 12345678, can be changed in the code) from your smartphone and open http://192.168.4.1 in your phone browser. 84 | 85 | ## Web JSON Query Template 86 | 87 | File: [WebJSONQuery_Template.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/WebJSONQuery_Template.py) 88 | 89 | A template for querying a API and get its JSON response. The JSON response would be a dictionary object, in which you can extract any data you need. 90 | 91 | Note: if you get a SSL error (like "TLS buffer overflow" and/or "ssl_handshake_status: -xxx"), either your WiFi is unstable or the API is not fully supported by MicroPython. 92 | 93 | ## Deep Sleep/Cloud Data Update 94 | 95 | File: [DeepSleep_Cloud_Update.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/DeepSleep_Cloud_Update.py) 96 | 97 | This use deep sleep to make the board wake up every 30 seconds and upload readings of a DHT11 via IFTTT's Webhook service (in my case the data would be uploaded to a Google Drive spreadsheet). 98 | 99 | The script must be uploaded onto the board in order to make deep sleep work. Connect D0 (GPIO 16) and RST before you powering it up. Afterwards the board's REPL may not be responsive and you'll have to re-flash the firmware. 100 | 101 | ## WS2812 NeoPixel Rainbow/Rotation Effect 102 | 103 | File: [WS2812_NeoPixelRainbow.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/WS2812_NeoPixelRainbow.py) 104 | 105 | Based on Adafruit's NeoPixel example code, basically a wrapper class with rainbow/rotate methods, slice assignment and brightness control. 106 | 107 | ## Conway's Game of Life on SSD1306 108 | 109 | File: [ConwayGameOfLife_SSD1306.py](https://github.com/alankrantas/esp8266-micropython-cookbook/blob/master/ConwayGameOfLife_SSD1306.py) 110 | 111 | Run the simulation of [Conway's Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) on the SSD1306 OLED display. The rules and the size of cell matrix can both be adjusted. Here I use a single-dimension list to simplify the code. 112 | --------------------------------------------------------------------------------