diff --git a/micropython/examples/pico_inky/WIFI_CONFIG.py b/micropython/examples/pico_inky/WIFI_CONFIG.py
new file mode 100644
index 00000000..b54d8867
--- /dev/null
+++ b/micropython/examples/pico_inky/WIFI_CONFIG.py
@@ -0,0 +1,2 @@
+SSID = ""
+PSK = ""
diff --git a/micropython/examples/pico_inky/bored_api.py b/micropython/examples/pico_inky/bored_api.py
new file mode 100644
index 00000000..fac9a055
--- /dev/null
+++ b/micropython/examples/pico_inky/bored_api.py
@@ -0,0 +1,75 @@
+import WIFI_CONFIG
+from network_manager import NetworkManager
+import time
+import uasyncio
+import ujson
+from urllib import urequest
+from picographics import PicoGraphics, DISPLAY_INKY_PACK
+from pimoroni import Button
+
+
+"""
+Simple demo to get a random activity from BoredAPI.com
+"""
+
+WIFI_COUNTRY = "GB" # Changeme!
+
+
+button_a = Button(12)
+button_b = Button(13)
+button_c = Button(14)
+
+graphics = PicoGraphics(DISPLAY_INKY_PACK)
+graphics.set_font("bitmap8")
+
+WIDTH, HEIGHT = graphics.get_bounds()
+ENDPOINT = "https://www.boredapi.com/api/activity"
+
+
+def status_handler(mode, status, ip):
+ graphics.set_update_speed(2)
+ graphics.set_pen(15)
+ graphics.clear()
+ graphics.set_pen(0)
+ graphics.text("Network: {}".format(WIFI_CONFIG.SSID), 10, 10, scale=2)
+ status_text = "Connecting..."
+ if status is not None:
+ if status:
+ status_text = "Connection successful!"
+ else:
+ status_text = "Connection failed!"
+
+ graphics.text(status_text, 10, 30, scale=2)
+ graphics.text("IP: {}".format(ip), 10, 60, scale=2)
+ graphics.update()
+
+
+network_manager = NetworkManager(WIFI_COUNTRY, status_handler=status_handler)
+
+
+def update():
+ uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
+
+ url = ENDPOINT
+ print("Requesting URL: {}".format(url))
+ j = ujson.load(urequest.urlopen(url))
+
+ print(j)
+
+ graphics.set_update_speed(1)
+ graphics.set_pen(15)
+ graphics.clear()
+ graphics.set_pen(0)
+ graphics.text(j["activity"], 10, 10, wordwrap=WIDTH - 20, scale=2)
+ graphics.text(j["type"], 10, 108, scale=2)
+
+ graphics.update()
+
+
+# Run continuously.
+# Be friendly to the API you're using!
+while True:
+ update()
+
+ while not button_a.is_pressed:
+ time.sleep(0.1)
diff --git a/micropython/examples/pico_inky/clock.py b/micropython/examples/pico_inky/clock.py
new file mode 100644
index 00000000..46b4ecba
--- /dev/null
+++ b/micropython/examples/pico_inky/clock.py
@@ -0,0 +1,170 @@
+import time
+import machine
+from picographics import PicoGraphics, DISPLAY_INKY_PACK
+
+
+# Buttons
+button_a = machine.Pin(12, machine.Pin.IN, pull=machine.Pin.PULL_UP)
+button_b = machine.Pin(13, machine.Pin.IN, pull=machine.Pin.PULL_UP)
+button_c = machine.Pin(14, machine.Pin.IN, pull=machine.Pin.PULL_UP)
+
+# Display
+graphics = PicoGraphics(DISPLAY_INKY_PACK)
+WIDTH, HEIGHT = graphics.get_bounds()
+graphics.set_update_speed(3)
+graphics.set_font("gothic")
+
+# RTC
+rtc = machine.RTC()
+
+cursors = ["hour", "minute", "year", "month", "day", "finish"]
+set_clock = False
+cursor = 0
+last = 0
+
+
+def days_in_month(month, year):
+ if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0):
+ return 29
+ return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1]
+
+
+# Button handling function
+def button(pin):
+ global last, set_clock, cursor, year, month, day, hour, minute
+
+ adjust = 0
+ changed = False
+
+ time.sleep(0.01)
+ if pin.value():
+ return
+
+ if pin == button_b and not set_clock:
+ cursor = 0
+ set_clock = True
+ draw_clock()
+ return
+
+ if set_clock:
+ if pin == button_b:
+ cursor += 1
+ cursor %= len(cursors)
+ changed = True
+
+ if pin == button_a:
+ adjust = 1
+ changed = True
+
+ if pin == button_c:
+ adjust = -1
+ changed = True
+
+ if cursors[cursor] == "finish":
+ if adjust != 0:
+ set_clock = False
+ changed = True
+ if not set_clock:
+ rtc.datetime((year, month, day, 0, hour, minute, second, 0))
+
+ if cursors[cursor] == "year":
+ year += adjust
+ year = max(year, 2022)
+ day = min(day, days_in_month(month, year))
+
+ if cursors[cursor] == "month":
+ month += adjust
+ month = min(max(month, 1), 12)
+ day = min(day, days_in_month(month, year))
+
+ if cursors[cursor] == "day":
+ day += adjust
+ day = min(max(day, 1), days_in_month(month, year))
+
+ if cursors[cursor] == "hour":
+ hour += adjust
+ hour %= 24
+
+ if cursors[cursor] == "minute":
+ minute += adjust
+ minute %= 60
+
+ if changed:
+ draw_clock()
+
+
+button_a.irq(trigger=machine.Pin.IRQ_FALLING, handler=button)
+button_b.irq(trigger=machine.Pin.IRQ_FALLING, handler=button)
+button_c.irq(trigger=machine.Pin.IRQ_FALLING, handler=button)
+
+
+def draw_clock():
+ hms = "{:02}:{:02}:{:02}".format(hour, minute, second)
+ ymd = "{:04}/{:02}/{:02}".format(year, month, day)
+
+ hms_width = graphics.measure_text(hms, 1.8)
+ hms_offset = int((WIDTH / 2) - (hms_width / 2))
+ h_width = graphics.measure_text(hms[0:2], 1.8)
+ mi_width = graphics.measure_text(hms[3:5], 1.8)
+ mi_offset = graphics.measure_text(hms[0:3], 1.8)
+
+ ymd_width = graphics.measure_text(ymd, 1.0)
+ ymd_offset = int((WIDTH / 2) - (ymd_width / 2))
+ y_width = graphics.measure_text(ymd[0:4], 1.0)
+ m_width = graphics.measure_text(ymd[5:7], 1.0)
+ m_offset = graphics.measure_text(ymd[0:5], 1.0)
+ d_width = graphics.measure_text(ymd[8:10], 1.0)
+ d_offset = graphics.measure_text(ymd[0:8], 1.0)
+
+ graphics.set_pen(15)
+ graphics.clear()
+ graphics.set_pen(0)
+
+ # No "thickness" setting in PG so, uh, fake it!
+ graphics.text(hms, hms_offset, 40, scale=1.8)
+ graphics.text(hms, hms_offset, 41, scale=1.8)
+ graphics.text(hms, hms_offset + 1, 40, scale=1.8)
+ graphics.text(hms, hms_offset - 1, 40, scale=1.8)
+
+ # Double up the text to fill out the lines
+ graphics.text(ymd, ymd_offset, 100, scale=1.0)
+ graphics.text(ymd, ymd_offset, 101, scale=1.0)
+
+ if set_clock:
+ if cursors[cursor] == "year":
+ graphics.line(ymd_offset, 120, ymd_offset + y_width, 120)
+
+ if cursors[cursor] == "month":
+ graphics.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120)
+
+ if cursors[cursor] == "day":
+ graphics.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120)
+
+ if cursors[cursor] == "hour":
+ graphics.line(hms_offset, 70, hms_offset + h_width, 70)
+
+ if cursors[cursor] == "minute":
+ graphics.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70)
+
+ done_width = graphics.measure_text("done", scale=0.5)
+ graphics.text("done", WIDTH - done_width - 5, HEIGHT - 15, scale=0.5)
+ if cursors[cursor] == "finish":
+ graphics.line(WIDTH - done_width - 5, HEIGHT - 5, WIDTH - 5, HEIGHT - 5)
+
+ graphics.update()
+
+
+year, month, day, wd, hour, minute, second, _ = rtc.datetime()
+
+if (year, month, day) == (2021, 1, 1):
+ rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0))
+
+last_second = second
+
+while True:
+ if not set_clock:
+ year, month, day, wd, hour, minute, second, _ = rtc.datetime()
+ if second != last_second:
+ draw_clock()
+ last_second = second
+ time.sleep(0.01)
diff --git a/micropython/examples/pico_inky/network_manager.py b/micropython/examples/pico_inky/network_manager.py
new file mode 100644
index 00000000..74026363
--- /dev/null
+++ b/micropython/examples/pico_inky/network_manager.py
@@ -0,0 +1,85 @@
+import rp2
+import network
+import machine
+import uasyncio
+
+
+class NetworkManager:
+ _ifname = ("Client", "Access Point")
+
+ def __init__(self, country="GB", client_timeout=30, access_point_timeout=5, status_handler=None):
+ rp2.country(country)
+ self._ap_if = network.WLAN(network.AP_IF)
+ self._sta_if = network.WLAN(network.STA_IF)
+
+ self._mode = network.STA_IF
+ self._client_timeout = client_timeout
+ self._access_point_timeout = access_point_timeout
+ self._status_handler = status_handler
+ self.UID = ("{:02X}" * 8).format(*machine.unique_id())
+
+ def isconnected(self):
+ return self._sta_if.isconnected() or self._ap_if.isconnected()
+
+ def ifaddress(self):
+ if self._sta_if.isconnected():
+ return self._sta_if.ifconfig()[0]
+ if self._ap_if.isconnected():
+ return self._ap_if.ifconfig()[0]
+ return '0.0.0.0'
+
+ def disconnect(self):
+ if self._sta_if.isconnected():
+ self._sta_if.disconnect()
+ if self._ap_if.isconnected():
+ self._ap_if.disconnect()
+
+ async def wait(self, mode):
+ while not self.isconnected():
+ self._handle_status(mode, None)
+ await uasyncio.sleep_ms(1000)
+
+ def _handle_status(self, mode, status):
+ if self._status_handler is not None:
+ self._status_handler(self._ifname[mode], status, self.ifaddress())
+
+ async def client(self, ssid, psk):
+ if self._sta_if.isconnected():
+ return
+
+ self._ap_if.disconnect()
+ self._ap_if.active(False)
+ self._ap_if.deinit()
+
+ self._sta_if = network.WLAN(network.STA_IF)
+ self._sta_if.active(True)
+ self._sta_if.connect(ssid, psk)
+
+ try:
+ await uasyncio.wait_for(self.wait(network.STA_IF), self._client_timeout)
+ self._handle_status(network.STA_IF, True)
+
+ except uasyncio.TimeoutError:
+ self._sta_if.active(False)
+ self._handle_status(network.STA_IF, False)
+ raise RuntimeError("WIFI Client Failed")
+
+ async def access_point(self):
+ if self._ap_if.isconnected():
+ return
+
+ self._sta_if.disconnect()
+ self._sta_if.active(False)
+ self._sta_if.deinit()
+
+ self._ap_if = network.WLAN(network.AP_IF)
+ self._ap_if.active(True)
+
+ try:
+ await uasyncio.wait_for(self.wait(network.AP_IF), self._access_point_timeout)
+ self._handle_status(network.AP_IF, True)
+
+ except uasyncio.TimeoutError:
+ self._sta_if.active(False)
+ self._handle_status(network.AP_IF, False)
+ raise RuntimeError("WIFI AP Failed")
diff --git a/micropython/examples/pico_inky/placekitten.py b/micropython/examples/pico_inky/placekitten.py
new file mode 100644
index 00000000..08ddea9f
--- /dev/null
+++ b/micropython/examples/pico_inky/placekitten.py
@@ -0,0 +1,86 @@
+import WIFI_CONFIG
+from network_manager import NetworkManager
+import uasyncio
+from urllib import urequest
+from picographics import PicoGraphics, DISPLAY_INKY_PACK
+import jpegdec
+import random
+
+
+"""
+Grab a random image from PlaceKitten.com
+and display it on Inky Pack.
+
+Optionally cache to flash, if you need the RAM
+for something else.
+"""
+
+WIFI_COUNTRY = "GB" # Changeme!
+
+
+graphics = PicoGraphics(DISPLAY_INKY_PACK)
+
+WIDTH, HEIGHT = graphics.get_bounds()
+FILENAME = "placekitten.jpg"
+ENDPOINT = "http://placekitten.com/{0}/{1}"
+
+
+def status_handler(mode, status, ip):
+ graphics.set_update_speed(3)
+ graphics.set_pen(15)
+ graphics.clear()
+ graphics.set_pen(0)
+ graphics.text("Network: {}".format(WIFI_CONFIG.SSID), 10, 10, scale=2)
+ status_text = "Connecting..."
+ if status is not None:
+ if status:
+ status_text = "Connection successful!"
+ else:
+ status_text = "Connection failed!"
+
+ graphics.text(status_text, 10, 30, scale=2)
+ graphics.text("IP: {}".format(ip), 10, 60, scale=2)
+ graphics.update()
+
+
+graphics.set_font("bitmap8")
+graphics.set_update_speed(1)
+
+network_manager = NetworkManager(WIFI_COUNTRY, status_handler=status_handler)
+uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
+
+
+url = ENDPOINT.format(WIDTH, HEIGHT + random.randint(0, 10))
+print("Requesting URL: {}".format(url))
+socket = urequest.urlopen(url)
+
+# Load the image data into RAM (if you have enough!)
+data = bytearray(1024 * 10)
+socket.readinto(data)
+socket.close()
+
+
+"""
+# Stream the image data from the socket onto disk in 1024 byte chunks
+# if you're doing something else RAM intensive you might want to use this!
+data = bytearray(1024)
+with open(FILENAME, "wb") as f:
+ while True:
+ if socket.readinto(data) == 0:
+ break
+ f.write(data)
+socket.close()
+"""
+
+jpeg = jpegdec.JPEG(graphics)
+jpeg.open_RAM(data)
+jpeg.decode(0, 0)
+
+graphics.set_pen(15)
+graphics.rectangle(0, HEIGHT - 14, WIDTH, 14)
+
+graphics.set_pen(0)
+graphics.text(url, 5, HEIGHT - 9, scale=1)
+
+graphics.set_update_speed(1)
+graphics.update()
diff --git a/micropython/examples/pico_inky/quote_of_the_day.py b/micropython/examples/pico_inky/quote_of_the_day.py
new file mode 100644
index 00000000..579e5daa
--- /dev/null
+++ b/micropython/examples/pico_inky/quote_of_the_day.py
@@ -0,0 +1,88 @@
+import WIFI_CONFIG
+from network_manager import NetworkManager
+import time
+import uasyncio
+import ujson
+from urllib import urequest
+from picographics import PicoGraphics, DISPLAY_INKY_PACK
+
+
+"""
+Grab the quote of the day from Wikipedia.
+"""
+
+WIFI_COUNTRY = "GB" # Changeme!
+
+graphics = PicoGraphics(DISPLAY_INKY_PACK)
+
+WIDTH, HEIGHT = graphics.get_bounds()
+ENDPOINT = "https://en.wikiquote.org/w/api.php?format=json&action=expandtemplates&prop=wikitext&text={{{{Wikiquote:Quote%20of%20the%20day/{3}%20{2},%20{0}}}}}"
+MONTHNAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
+
+
+last_date = ""
+
+
+def parse_qotd(text):
+ text = text.split("\n")
+ return (
+ text[6][2:].replace("[[", "").replace("]]", "").replace("
", '\n').replace("
", '\n'), # Quote
+ text[8].split("|")[2][5:-4] # Author
+ )
+
+
+def status_handler(mode, status, ip):
+ graphics.set_update_speed(2)
+ graphics.set_pen(15)
+ graphics.clear()
+ graphics.set_pen(0)
+ graphics.text("Network: {}".format(WIFI_CONFIG.SSID), 10, 10, scale=2)
+ status_text = "Connecting..."
+ if status is not None:
+ if status:
+ status_text = "Connection successful!"
+ else:
+ status_text = "Connection failed!"
+
+ graphics.text(status_text, 10, 30, scale=2)
+ graphics.text("IP: {}".format(ip), 10, 60, scale=2)
+ graphics.update()
+
+
+network_manager = NetworkManager(WIFI_COUNTRY, status_handler=status_handler)
+
+while True:
+ graphics.set_font("bitmap8")
+ graphics.set_update_speed(1)
+
+ uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
+
+ date = list(time.localtime())[:3]
+ date.append(MONTHNAMES[date[1] - 1])
+
+ if "{3} {2}, {0}".format(*date) == last_date:
+ time.sleep(60)
+ continue
+
+ url = ENDPOINT.format(*date)
+ print("Requesting URL: {}".format(url))
+ j = ujson.load(urequest.urlopen(url))
+
+ text = j['expandtemplates']['wikitext']
+
+ text, author = parse_qotd(text)
+
+ print(text)
+
+ graphics.set_pen(15)
+ graphics.clear()
+ graphics.set_pen(0)
+ graphics.text("QoTD - {2} {3} {0:04d}".format(*date), 10, 10, scale=2)
+ graphics.text(text, 10, 30, wordwrap=WIDTH - 20, scale=1)
+ graphics.text(author, 10, 108, scale=1)
+
+ graphics.update()
+
+ last_date = "{3} {2}, {0}".format(*date)
+
+ time.sleep(60)