From 9307ea1360ff0092132db803a0f5c9a2a8d21fdb Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Wed, 21 Jun 2023 16:24:37 +0100 Subject: [PATCH 01/15] add co2 example --- fonts/3x5.bitmapfont | Bin 0 -> 462 bytes .../examples/stellar_unicorn/README.md | 22 ++-- micropython/examples/stellar_unicorn/co2.py | 104 ++++++++++++++++++ 3 files changed, 115 insertions(+), 11 deletions(-) create mode 100644 fonts/3x5.bitmapfont create mode 100644 micropython/examples/stellar_unicorn/co2.py diff --git a/fonts/3x5.bitmapfont b/fonts/3x5.bitmapfont new file mode 100644 index 0000000000000000000000000000000000000000..ee7e966eff530f0aef9e543418bc19fdea1ae8b5 GIT binary patch literal 462 zcmb_XK@P((2qS?kRSs=Xi_$L2{QqB$uDk8h!z>YG8!VDIL_QJNd%T{H;Oug~?6iL1 z8r=l*gQ*b{qhNy_vdS#y`m8!rk>Zqg5)rDj3qwJmVa*K7^lCO>BLu+E3{;4oBt=W{ z5=$A{klgK1h0gG`6rclg=F|#EhqnlLhyp2RpHJPBgG&`lT`-|bZyOF<3Cgnj6*0tG O>&<`ueJrPZH}efG&J6kh literal 0 HcmV?d00001 diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 1f32f55d..33900798 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -19,10 +19,10 @@ - [Exchange Ticker](#exchange-ticker) - [HTTP Text](#http-text) - [Weather](#weather) -- [NumPy examples](#numpy-examples) +- [NumPy Examples](#numpy-examples) - [Other Examples](#other-examples) + - [CO2](#co2) - [Launch (Demo Reel)](#launch-demo-reel) -- [Other Resources](#other-resources) ## About Stellar Unicorn @@ -155,7 +155,7 @@ Requires `logging.mpy` and `tinyweb` from [micropython/examples/common](../../ex Display current weather data from the [Open-Meteo](https://open-meteo.com/) weather API. -## NumPy examples +## NumPy Examples [numpy](numpy) @@ -163,16 +163,16 @@ The examples in the folder use `numpy`-like array functions contained in the `ul ## Other Examples +### CO2 + +[co2.py](co2.py) + +Add a [SCD41 sensor breakout](https://shop.pimoroni.com/products/scd41-co2-sensor-breakout) to make an carbon dioxide detector. Press A, B and C to switch between modes. + +This examples uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../fonts) and copy it to your Pico W. + ### Launch (Demo Reel) [launch](launch) If you want to get the demo reel that Stellar Unicorn ships with back, copy the contents of this `launch` folder to your Pico W. - -## Other Resources - -Here are some cool Stellar Unicorn community projects and resources that you might find useful / inspirational! Note that code at the links below has not been tested by us and we're not able to offer support with it. - -- :link: [Green Energy Display with Stellar Unicorn](https://www.hackster.io/andreas-motzek/clock-and-green-energy-display-with-stellar-unicorn-641dcb) -- :link: [stellar-emoji-react - paint emojis from a computer, phone or tablet](https://github.com/chriscareycode/stellar-unicorn/tree/main/stellar-emoji-react) -- :link: [stellar-paste - paste images from the clipboard to Stellar Unicorn](https://github.com/chriscareycode/stellar-unicorn/tree/main/stellar-paste) diff --git a/micropython/examples/stellar_unicorn/co2.py b/micropython/examples/stellar_unicorn/co2.py new file mode 100644 index 00000000..65e79862 --- /dev/null +++ b/micropython/examples/stellar_unicorn/co2.py @@ -0,0 +1,104 @@ +# Add a SCD41 sensor breakout to your Stellar Unicorn to make a handy CO2 detector! +# https://shop.pimoroni.com/products/scd41-co2-sensor-breakout +# Press A for CO2, B for temperature and C for humidity +# This example uses a custom tiny font - find 3x5.bitmapfont in pimoroni-pico/fonts + +from stellar import StellarUnicorn +from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN as DISPLAY +import breakout_scd41 +from pimoroni_i2c import PimoroniI2C +from pimoroni import BREAKOUT_GARDEN_I2C_PINS + +su = StellarUnicorn() +graphics = PicoGraphics(DISPLAY) +i2c = PimoroniI2C(**BREAKOUT_GARDEN_I2C_PINS) + +# the range of readings to map to colours +# https://www.kane.co.uk/knowledge-centre/what-are-safe-levels-of-co-and-co2-in-rooms +MIN = 400 +MAX = 2000 + +# pick what bits of the colour wheel to use (from 0-360°) +# https://www.cssscript.com/demo/hsv-hsl-color-wheel-picker-reinvented/ +HUE_START = 100 # green +HUE_END = 0 # red + +# some pen colours to use +BLACK = graphics.create_pen(0, 0, 0) +WHITE = graphics.create_pen(255, 255, 255) + +# some other variables to keep track of stuff +mode = "co2" +flashy_light = False + + +# sets up a handy function we can call to clear the screen +def clear(): + graphics.set_pen(BLACK) + graphics.clear() + + +# set up +breakout_scd41.init(i2c) +breakout_scd41.start() + +graphics.set_font(open("3x5.bitmapfont", "rb").read()) +graphics.set_pen(WHITE) +graphics.text("WAIT", 0, 0, scale=1) +su.update(graphics) + +while True: + + if su.is_pressed(StellarUnicorn.SWITCH_A): + mode = "co2" + if su.is_pressed(StellarUnicorn.SWITCH_B): + mode = "temp" + if su.is_pressed(StellarUnicorn.SWITCH_C): + mode = "humidity" + + if breakout_scd41.ready(): + clear() + + # read the sensor + co2, temperature, humidity = breakout_scd41.measure() + + # calculate a colour from the co2 reading + hue = max(0, HUE_START + ((co2 - MIN) * (HUE_END - HUE_START) / (MAX - MIN))) + + # draw the border and background + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, 0.8)) + graphics.clear() + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, 0.2)) + graphics.rectangle(1, 1, 14, 14) + + graphics.set_pen(WHITE) + if mode == "co2": + # draw the co2 level + co2_string = str(co2) + if co2 < 999: + graphics.text(f"{co2:.0f}", 2, 2, scale=1, fixed_width=True) + else: + graphics.text(f"{co2_string[0]}", 1, 2, scale=1, fixed_width=True) + graphics.text(f"{co2_string[1]}K", 7, 2, scale=1, fixed_width=True) + graphics.pixel(5, 6) + + graphics.text("PPM", 3, 9, scale=1) + + if mode == "temp": + # draw the temperature + graphics.text("T:", 2, 2, scale=1) + graphics.text(f"{temperature:.0f}°", 2, 8, scale=1, fixed_width=True) + + if mode == "humidity": + # draw the temperature + graphics.text("H:", 2, 2, scale=1) + graphics.text(f"{humidity:.0f}%", 2, 8, scale=1, fixed_width=True) + + # flash the top right pixel to show the sensor's been read + if flashy_light is False: + graphics.pixel(15, 0) + flashy_light = True + else: + flashy_light = False + + su.update(graphics) From d759522b0881237ea5ed17407bfcc40610888d5e Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Wed, 21 Jun 2023 16:49:13 +0100 Subject: [PATCH 02/15] Adjust clock.py Clock now uses smaller font so it fits on the screen --- micropython/examples/stellar_unicorn/README.md | 2 ++ micropython/examples/stellar_unicorn/clock.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 33900798..ec977769 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -50,6 +50,8 @@ The easiest way to start displaying cool stuff on Stellar Unicorn is using our S Clock example with (optional) NTP synchronization. You can adjust the brightness with LUX + and -, and resync the time by pressing A. +This examples uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../fonts) and copy it to your Pico W. + ### Eighties Super Computer [eighties_super_computer.py](eighties_super_computer.py) diff --git a/micropython/examples/stellar_unicorn/clock.py b/micropython/examples/stellar_unicorn/clock.py index 20339f1d..63fa9dd4 100644 --- a/micropython/examples/stellar_unicorn/clock.py +++ b/micropython/examples/stellar_unicorn/clock.py @@ -8,6 +8,8 @@ # WIFI_PASSWORD = "Your WiFi password" # # Clock synchronizes time on start, and resynchronizes if you press the A button +# +# This example uses a custom tiny font - find 3x5.bitmapfont in pimoroni-pico/fonts import time import math @@ -193,7 +195,7 @@ def redraw_display_if_reqd(): gradient_background(hue, sat, val, hue + HUE_OFFSET, sat, val) - clock = "{:02}:{:02}:{:02}".format(hour, minute, second) + clock = "{:02} {:02}".format(hour, minute) # calculate text position so that it is centred w = graphics.measure_text(clock, 1) @@ -206,7 +208,7 @@ def redraw_display_if_reqd(): # set the font -graphics.set_font("bitmap6") +graphics.set_font(open("3x5.bitmapfont", "rb").read()) su.set_brightness(0.5) sync_time() From 16f8f0ab055d00a7f69b28444aba0865d8904d7d Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Wed, 21 Jun 2023 16:50:21 +0100 Subject: [PATCH 03/15] Adjust lava_lamp.py --- micropython/examples/stellar_unicorn/lava_lamp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/stellar_unicorn/lava_lamp.py b/micropython/examples/stellar_unicorn/lava_lamp.py index de8d4454..c7a1d265 100644 --- a/micropython/examples/stellar_unicorn/lava_lamp.py +++ b/micropython/examples/stellar_unicorn/lava_lamp.py @@ -13,7 +13,7 @@ You can adjust the brightness with LUX + and -. su = StellarUnicorn() graphics = PicoGraphics(DISPLAY) -blob_count = 10 +blob_count = 5 class Blob(): From cbaf1fa27d498a72965e2dacd83b10c95728eca8 Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Thu, 22 Jun 2023 12:20:25 +0100 Subject: [PATCH 04/15] fix co2.py formatting --- micropython/examples/stellar_unicorn/co2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/stellar_unicorn/co2.py b/micropython/examples/stellar_unicorn/co2.py index 65e79862..5eaf08e5 100644 --- a/micropython/examples/stellar_unicorn/co2.py +++ b/micropython/examples/stellar_unicorn/co2.py @@ -75,7 +75,7 @@ while True: if mode == "co2": # draw the co2 level co2_string = str(co2) - if co2 < 999: + if co2 < 1000: graphics.text(f"{co2:.0f}", 2, 2, scale=1, fixed_width=True) else: graphics.text(f"{co2_string[0]}", 1, 2, scale=1, fixed_width=True) From 951fe4d8b827fad783f328744170975bfe80152e Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Thu, 22 Jun 2023 17:12:55 +0100 Subject: [PATCH 05/15] SCD41: update example to use default pins --- micropython/examples/breakout_scd41/scd41_demo.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/micropython/examples/breakout_scd41/scd41_demo.py b/micropython/examples/breakout_scd41/scd41_demo.py index 8c2c19df..3020ac76 100644 --- a/micropython/examples/breakout_scd41/scd41_demo.py +++ b/micropython/examples/breakout_scd41/scd41_demo.py @@ -1,12 +1,9 @@ +import breakout_scd41 +from pimoroni_i2c import PimoroniI2C +from pimoroni import BREAKOUT_GARDEN_I2C_PINS # or PICO_EXPLORER_I2C_PINS or HEADER_I2C_PINS import time -import pimoroni_i2c -import breakout_scd41 - -PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5} -PINS_PICO_EXPLORER = {"sda": 20, "scl": 21} - -i2c = pimoroni_i2c.PimoroniI2C(**PINS_PICO_EXPLORER) +i2c = PimoroniI2C(**BREAKOUT_GARDEN_I2C_PINS) # or PICO_EXPLORER_I2C_PINS or HEADER_I2C_PINS breakout_scd41.init(i2c) breakout_scd41.start() From 6afdfef45bb73efb0911df22e1e4ec330c73bf6e Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Tue, 27 Jun 2023 17:36:08 +0100 Subject: [PATCH 06/15] Stellar: update weather example --- .../examples/stellar_unicorn/README.md | 2 +- .../stellar_unicorn/weather/icons/cloud.jpg | Bin 0 -> 776 bytes .../stellar_unicorn/weather/icons/cloud1.jpg | Bin 1151 -> 0 bytes .../stellar_unicorn/weather/icons/cloud2.jpg | Bin 1579 -> 0 bytes .../stellar_unicorn/weather/icons/cloud3.jpg | Bin 1656 -> 0 bytes .../stellar_unicorn/weather/icons/cloud4.jpg | Bin 1656 -> 0 bytes .../stellar_unicorn/weather/icons/rain.jpg | Bin 0 -> 895 bytes .../stellar_unicorn/weather/icons/rain1.jpg | Bin 2053 -> 0 bytes .../stellar_unicorn/weather/icons/rain2.jpg | Bin 2100 -> 0 bytes .../stellar_unicorn/weather/icons/rain3.jpg | Bin 2091 -> 0 bytes .../stellar_unicorn/weather/icons/rain4.jpg | Bin 2053 -> 0 bytes .../stellar_unicorn/weather/icons/snow.jpg | Bin 0 -> 1046 bytes .../stellar_unicorn/weather/icons/snow1.jpg | Bin 2128 -> 0 bytes .../stellar_unicorn/weather/icons/snow2.jpg | Bin 2196 -> 0 bytes .../stellar_unicorn/weather/icons/snow3.jpg | Bin 2223 -> 0 bytes .../stellar_unicorn/weather/icons/snow4.jpg | Bin 2169 -> 0 bytes .../stellar_unicorn/weather/icons/storm.jpg | Bin 0 -> 909 bytes .../stellar_unicorn/weather/icons/storm1.jpg | Bin 1360 -> 0 bytes .../stellar_unicorn/weather/icons/storm2.jpg | Bin 1692 -> 0 bytes .../stellar_unicorn/weather/icons/storm3.jpg | Bin 1835 -> 0 bytes .../stellar_unicorn/weather/icons/storm4.jpg | Bin 1703 -> 0 bytes .../stellar_unicorn/weather/icons/sun.jpg | Bin 0 -> 991 bytes .../stellar_unicorn/weather/icons/sun1.jpg | Bin 2273 -> 0 bytes .../stellar_unicorn/weather/icons/sun2.jpg | Bin 2193 -> 0 bytes .../stellar_unicorn/weather/icons/sun3.jpg | Bin 2269 -> 0 bytes .../stellar_unicorn/weather/icons/sun4.jpg | Bin 2194 -> 0 bytes ...icons_sourcefile(doesn't need copying).svg | 1577 ----------------- .../stellar_unicorn/weather/weather.py | 136 +- 28 files changed, 46 insertions(+), 1669 deletions(-) create mode 100644 micropython/examples/stellar_unicorn/weather/icons/cloud.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/cloud1.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/cloud2.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/cloud3.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/cloud4.jpg create mode 100644 micropython/examples/stellar_unicorn/weather/icons/rain.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/rain1.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/rain2.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/rain3.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/rain4.jpg create mode 100644 micropython/examples/stellar_unicorn/weather/icons/snow.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/snow1.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/snow2.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/snow3.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/snow4.jpg create mode 100644 micropython/examples/stellar_unicorn/weather/icons/storm.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/storm1.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/storm2.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/storm3.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/storm4.jpg create mode 100644 micropython/examples/stellar_unicorn/weather/icons/sun.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/sun1.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/sun2.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/sun3.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons/sun4.jpg delete mode 100644 micropython/examples/stellar_unicorn/weather/icons_sourcefile(doesn't need copying).svg diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index ec977769..231a7481 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -155,7 +155,7 @@ Requires `logging.mpy` and `tinyweb` from [micropython/examples/common](../../ex [weather](weather) -Display current weather data from the [Open-Meteo](https://open-meteo.com/) weather API. +Display current weather data from the [Open-Meteo](https://open-meteo.com/) weather API. Make sure to copy across the `icons` folder to your Unicorn. ## NumPy Examples diff --git a/micropython/examples/stellar_unicorn/weather/icons/cloud.jpg b/micropython/examples/stellar_unicorn/weather/icons/cloud.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba4a6aa6f90bda11f8f174747f66ad9680c3e116 GIT binary patch literal 776 zcmex=``2_j6xdp@o1cgOJMMZh|#U;coyG6VInuyV4pa*FVB^NNrR z{vTivwh= zDOELf4NWZ*Q!{f5ODks=S2uSLPp{yR(6I1`$f)F$)U@=B%&g*)(z5c3%Btp;*0%PJ z&aO$5r%atTea6gLixw|gx@`H1m8&*w-m-Pu_8mKS9XfpE=&|D`PM*4S`O4L6*Kgds z_3+W-Cr_U}fAR9w$4{TXeEs(Q$Io9Ne=#yJL%ap|8JfR3M&~ka)>xhT)6Qdr?PR-2hpUWi(FzVCJ$9Vg1iRy8F3zKBFkrR zk0JbZi-Cuk5g2*Qf(-TyKYxEq``i1+_R)O?*GKxYk@r2zR~TkT%NxEu641ZvxrEC0 zz;g!fB8seatPclXuw aPZ6rqZ>R)XDob-Fh%nz*U&>Jb|0V#hqYVB4 literal 0 HcmV?d00001 diff --git a/micropython/examples/stellar_unicorn/weather/icons/cloud1.jpg b/micropython/examples/stellar_unicorn/weather/icons/cloud1.jpg deleted file mode 100644 index 7c400e81f4e89910c388c9fa5cc751ed95ab3e0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1151 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 literal 0 HcmV?d00001 diff --git a/micropython/examples/stellar_unicorn/weather/icons/rain1.jpg b/micropython/examples/stellar_unicorn/weather/icons/rain1.jpg deleted file mode 100644 index 9e676daf20e4affa57ba670afc9274356ec35947..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2053 zcmbu+c{JPU8VB%SB$g;`V@sQA71h?#+OL^3$(^4|n4eC_g49B|msbeUzS&`8X?|R#5niUQ}H2yy^wBy5?nV z9h=kK(%RPE@usJ@uYZ8|esE}lKl!hzkJB@=bHbI?PiyNN;O5qz3j#p@e6l}a|KmdJ zx+GvQC`@|K1(6`{ZYTmKsctBxV0l@Z5UQwQ6epu}AuX@639f1EEKv5l(JiZT!el~A zxJUc9?Eiz^`Af1tVgGdv0di2t?&m=ffCV7(pWi@=;9+6_Rv}<42958yPiC~qhcu(f z99{hF4UP{&keg8cv}es1Ift^xRaceHW%aGsFzDcoR{nU9+d$nlLsC|HVMx&{5(;0P zqcHbDZ5y$?t_fcGjNi5gvl-g~lo)c8g>*PehAReSOdATL3h2oZW2g^cl1YbY@S+i) z=PF`%FV^c8W66O8GV#pf&d2nJBiVXtXI+1DH3KzH@F&PVu)8Kgng@r z#`dk{+Kxf}n|m5VdCG*91+r}4eS+L8?J}L;x-X0SJ0vn423;6~(*f|-v&|L&F?D}pWo*|Fw3Vr_>jr~;(F^lHL zhkKw_n~_^8g<&DbDxU?T&OSamTB(Pusmn>H2NF#S>)nvIy))Fhlw%9ck}&7;BRQNp zF%VymrCXMQVJ)b$#SBJ z!;VY$aTvUJ>iM^#D!Jd7o;4acmo76W( zZ%a>iR=AGFPzlp6`*&z9ItFc1pf6ERPaPFeY^!`BhXgMnF;NOd^XObE>p5fbx-ez^ z9GG&dIV2wSB>U(<9zEwsa|22!PaVoli1wsy&PE)|Ee~4XxQUFauDf^kT7Gi$_=wlp4Za5ddmU*!!4xz~-R2A0n~y!yk@(PH{=FnXlnm!X!{ z)WVBoIWJ1F)Xy1i`XycTAq+1xsN+@uk1IQTroWcz@FXp2^2FXOpi7IJ=RqvjqX#EL8MbO_a#kX(Fr#~m+mB&L56nBH1 z%(BguuD`^W#aOn8RKN8U0|#yO>2YN_{OkW@uqGz=%$uol;N+eprOTxIts$D6+Kv4DO)FT^yGXVuH(9vo;vpucK;s*c@pzFahiDlaYxcCQ%5S)Lcsin>%0*4;trb>T>)LD#BT z^BFg;vrx6V&aEnle@2>Y;DJ7q-LTvqj6+K*x&>Geofo7UQT zSxjkgO$d{D-D_*gfyo&dMa7`%_Y0Oy8ig4$U?6AnfFhf6(gV|@wCV+Zs5y{&CBK-U zp2Hm;H@w{FzD3bs^;LNOG;9A_&N-#j=NDRXz00KNB-_sjGo4(e$I+(Flz?_vX(x(K i`H{gIbWfx0AU_D>Xz{BHeQ|z*+K;9(I-IcL!QTOuyT7gg diff --git a/micropython/examples/stellar_unicorn/weather/icons/rain2.jpg b/micropython/examples/stellar_unicorn/weather/icons/rain2.jpg deleted file mode 100644 index 5fe470c72d496ef8a7ce8d4dc7537932a3fe3cf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2100 zcmbu-c{H2p9tZF@5=$&K5rlM6RW;U%W%Md?RLj^p)7k|o2DR0ihN)$$n4;yhjjaw^ zu~zN7$xum9rPHyLqL##{itSCSyols-=bpLe+`sO*^Lx(o$8(^9& z#?smnfWctEwSxf&rU8q?)!(YakiQjhcv$cPK#2h-fs=69DL@DXgQH*qCZGfWFyTM5 zfqxfF2#ydI5fwv;BX-XTv!-^IOvW)*ar|OVHstdxd{4-x9F(|S-sm2 zo{FhlXy}oec;MK_J*xT`mcau{r_QD^FAC^8YbGV;AZ+_X@hIV!jT`&Ot*OmPV`!5&j zz$Ju0z!9Q{E|?JcV8T%dVP%|%jQJH&?+ElMz1w247alxq=s~LJUj^lSB8SE0PaCjQ zxrelW$^JK3(*Gs<3-%w^6d(zQ9XuW!1>ga`@5(lYkBkxkhtE+$_``Gh=&f}dSxS+>5Wnq=S1Ytc} z3uQR(m3XL)EfvUV&y!~Z71Z(kQ{%}!c+u!?u{Q!h%&@C0wzMLhG>3f;r5Owu2CwO{ zCmi|o;We6Ol`T2Io9w5(w*MjL(M*BDhE`Z&ol;67((G6q3M3UX1VD-zdX$Eqe{HtT z-yLL3*?Ja85Na;7YBv^dhw0oXy*J}&k}Fg4QbphT^lgimi`_;1LcHB1L^`(7lPJmE z;oGzQ#Pg**_R@9R?NqhoZ7Ke-aZ$00J6^`EXIx({<S=_PD z3Ud-)imm40zRZyq5fgIWpH|7@W0~HPzo^%^H?J&k+wE+7tk4+@`okxmb`6((RaQ0F zPBw2pnvXFC#RWh-kDD+j06uGMY0c!6R4cwOnGEQJTs5k{AY~ zQvf8>Y%9#Gp{QQ0P8Dk=(YixVBGlpH_-eo?$z!k}5D@m8vkZ;A8 zJ-KsnY_+98Y`t`ZH_)7Bu;*#YA3tkm^igH=_aP_?*8>@{*U8K{`(8JG#9a?m?>UYE zZs7Y&f{CX`mgx|`N%FTAw+XtBhF{(*$S#D^AVX(2G}m+KeOVow$>3RJj(0G(U*wwJ zQ1#b?^^UXg6z?U6Bm2}|4c-1li0G%KrHmz2S;<`}3_?B&YQf4>t{4|nx*O}(Lb(}R z=b;QWW>_+|sNnec(~82Q%q}cfiZWH466Z$UStgw*t_|GUzKMx#?YyrOLXy(|ezb+4 zX!35Y?&0|Q?(E8Ttu&-9x~3LU$5R8J>{EE(6sd4A$vO#IG2M1Vnb$^Jb97m7FNQCT zjybY!e`9>ws^j24lBrOxbCHs)DKBYDLcymoHshT~BJQzaP0dzK`J@-e{l@(OQhab2 zsX7?9BC~89N^3f0f2*pWwU2k2_@SZo!pO{-ta2hJRJ^^hxxF3NH=Ccx{!W;a#x-(j z1@Vk5=|p;Hwd*n;4KguvaymMEIk$mY!pi8%?2(T4F_J0Xapc-)^CV5Vs%IgT$oz4E z5Ih)5z1|f{%N-}a_tK3&9(S7Sa5p?(0LVdM*-JY-Jx-oR$7a1^dX2h|X^{g(00h2$ z)n1Uw@y`n>QJ{GRx=1^p8?rZ%cf-1dB)Fu-`e`N3d!X52is7jQg3bU$#pL>p^jgv) z7t`pURBa26-rIeS%XhwBpB>RiwL*&5N2}X(X4TnQrgL>sv6FxK+=%BE)&>t@=spdvYnt#D?8PL*^e7(BR!8RPN;k^I_h3mMZOpEU0$pd7Z(Ae5jL&3OOa@|Q zE$C>dGagQ82l17G^aVE(1{s>izzT7SYN?38Z%w3)d1(%XInxwo7)Bz_+;Q YSxqSm)MYQa8C{=LePx#^00fi&1lYIJH2?qr diff --git a/micropython/examples/stellar_unicorn/weather/icons/rain3.jpg b/micropython/examples/stellar_unicorn/weather/icons/rain3.jpg deleted file mode 100644 index 91be10a9dc810584d65b3f337a5c77a81cd9891b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2091 zcmbu+do-=@r+0VP)Ki>5`?{}@w`$|WpQ^0O_ z7dICG27>|TwiX~A2aax^{!(p+{H1{H%hEOgr2y;&_QGKXfD8%-N5P~#Ko0<5a(`q4 z|1OveTvl#}yaGZ|X=|WjToT!_3#jEajV{Y*|symBLznwEYuBQxh-?k{=y1@{Xdl|C+eQckaUT3h$LzM=6& zQ!|IlYwzfM)zv*PIP`XSWc1w_UoicTnUAw`pM>Db>gO+OU!nDlZ5IrH|M_Hp!2ZjH z+H%Rr%ED#kw_Pw9^45lmJf|pHL$v-u*doC!x}ci(Arz17IwK`QGK5c z-w52M{Y&=0!LI*bvOi(}ag71WaM;%8!BGGXkc7{FMN1HIQb4v^#9Sm!ZTd~;cOqkW z_GGRJKIJPn1SO(TpFJ4(LO=^K?m-Q8mBPZIwMJ$+bh$$?MLav)e91DZFt03z{xS-K zZzxs~zSk3@me&lSGvDxHcc_RdzL1toX5-}JTNQexfPyWnEb(!9CTSA$9?G!kvW;G} z5{&ptIQ@$)CKVp!$WU^`!NtvwdG|gPX)K$@P?&mD3c^u42_+)YxKe=Xs5;o9I`zhJ zNwU$y9rM5!DFrdS_|KMSuEm)B?eXmocx=APqgRI3Zu_nseKpfsA}PjszJo~G%WR4= zxGp&%h)}$b4E~mB@xs%{RNW)@LSj-};>>!8eZzPDuVxEc)J=@(U_lbg*P;L$agh%W zt!hjveWAHd!ozt3ZLuS2p(_hy#i2W)$}hiX1U{di248r3uw7MeaXC2;RyJ%ug&Qsy z3(mN|opT!E_9#k$WHFdBDFs9>I4TawLO?y!kqiBFi0L+zqB%#NFaZgFPx7eJLw&OE zO^x@*tn$zs>Sb{;x;0OtF=qF5CTdL4jm^b*<&hD#Wi4mXDZ%-AZ`3Gdb{W_sj}o}t zW+{-`;!*BY3B|Qz%qsXFC~i$wNwI34N zSazMd6NJSFXFI%>)G7a7A27lRGma?ehCDCj)~IjUHITo@(ETz_!vv}eS%uRo&`8=AAsE|HMdrv~eT zG_j+L%$(t+jfwfMgI-eLdcTMO~xDshOYqmrJK2%bpGXUuJk@SH-Y zTB#x&@8r$={7Ge&X0eM_G($!x5eV1jI|_ALxp*y4=xkw3hWIFjxbqr0c8{(m>&FGN zc=JUHhIL1RPN?7=!Y$BH#ERa1uZW4eC&A>uF0=&-Q8_U{VY0q z5tsr`Z_aS%Nu~6j&>rtBOnn^Y7vsSwHB0}Pai$7|O_EqcSKD-VgC{!MdS$qbgjrsR z$q?3|oWRUv#23-1g{FOTSG*c^pOow^@nBr}*51G}8i-Lbxwyax6D{OaDcfohRaf9^ z9h)tVhb7~Ik{fif&x^iz%1+2FMxKgAOwF6TIl{F+-tj=+W7GRIU5I&B@if}6dOXO< zK~hS8qm4S&Pt0qMN24v?OyM-JghvT4+p8&@{X{yEr6g)h#~z;QRrusLVFc=BhSd%x z;mX)ME3ZD8fM{K;+8U5>YpZcb&#ivoGt!EC3Ov3MkU(*9jn-(XeJS3zVGSMRcbJ<` zJ8FwM5Ac`FaxF)1n_2I!(P$Yl;C!s(*$0s9GGE7G&30L^XA%k`{KaPp-ad>20=_mr z_y>bv@%u;tQzzCz+spMn7-DDD<-;9dINvLCl`lBM?#L-I4(UNs83ZH&?e72DLEF=p PSnlF=+j!6mCw=!%5gW-L diff --git a/micropython/examples/stellar_unicorn/weather/icons/rain4.jpg b/micropython/examples/stellar_unicorn/weather/icons/rain4.jpg deleted file mode 100644 index 9e676daf20e4affa57ba670afc9274356ec35947..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2053 zcmbu+c{JPU8VB%SB$g;`V@sQA71h?#+OL^3$(^4|n4eC_g49B|msbeUzS&`8X?|R#5niUQ}H2yy^wBy5?nV z9h=kK(%RPE@usJ@uYZ8|esE}lKl!hzkJB@=bHbI?PiyNN;O5qz3j#p@e6l}a|KmdJ zx+GvQC`@|K1(6`{ZYTmKsctBxV0l@Z5UQwQ6epu}AuX@639f1EEKv5l(JiZT!el~A zxJUc9?Eiz^`Af1tVgGdv0di2t?&m=ffCV7(pWi@=;9+6_Rv}<42958yPiC~qhcu(f z99{hF4UP{&keg8cv}es1Ift^xRaceHW%aGsFzDcoR{nU9+d$nlLsC|HVMx&{5(;0P zqcHbDZ5y$?t_fcGjNi5gvl-g~lo)c8g>*PehAReSOdATL3h2oZW2g^cl1YbY@S+i) z=PF`%FV^c8W66O8GV#pf&d2nJBiVXtXI+1DH3KzH@F&PVu)8Kgng@r z#`dk{+Kxf}n|m5VdCG*91+r}4eS+L8?J}L;x-X0SJ0vn423;6~(*f|-v&|L&F?D}pWo*|Fw3Vr_>jr~;(F^lHL zhkKw_n~_^8g<&DbDxU?T&OSamTB(Pusmn>H2NF#S>)nvIy))Fhlw%9ck}&7;BRQNp zF%VymrCXMQVJ)b$#SBJ z!;VY$aTvUJ>iM^#D!Jd7o;4acmo76W( zZ%a>iR=AGFPzlp6`*&z9ItFc1pf6ERPaPFeY^!`BhXgMnF;NOd^XObE>p5fbx-ez^ z9GG&dIV2wSB>U(<9zEwsa|22!PaVoli1wsy&PE)|Ee~4XxQUFauDf^kT7Gi$_=wlp4Za5ddmU*!!4xz~-R2A0n~y!yk@(PH{=FnXlnm!X!{ z)WVBoIWJ1F)Xy1i`XycTAq+1xsN+@uk1IQTroWcz@FXp2^2FXOpi7IJ=RqvjqX#EL8MbO_a#kX(Fr#~m+mB&L56nBH1 z%(BguuD`^W#aOn8RKN8U0|#yO>2YN_{OkW@uqGz=%$uol;N+eprOTxIts$D6+Kv4DO)FT^yGXVuH(9vo;vpucK;s*c@pzFahiDlaYxcCQ%5S)Lcsin>%0*4;trb>T>)LD#BT z^BFg;vrx6V&aEnle@2>Y;DJ7q-LTvqj6+K*x&>Geofo7UQT zSxjkgO$d{D-D_*gfyo&dMa7`%_Y0Oy8ig4$U?6AnfFhf6(gV|@wCV+Zs5y{&CBK-U zp2Hm;H@w{FzD3bs^;LNOG;9A_&N-#j=NDRXz00KNB-_sjGo4(e$I+(Flz?_vX(x(K i`H{gIbWfx0AU_D>Xz{BHeQ|z*+K;9(I-IcL!QTOuyT7gg diff --git a/micropython/examples/stellar_unicorn/weather/icons/snow.jpg b/micropython/examples/stellar_unicorn/weather/icons/snow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58fc521d7fe89218706be833159e2f4083528d08 GIT binary patch literal 1046 zcmex=``2_j6xdp@o1cgOJMMZh|#U;coyG6VInuyV4pa*FVB^NNrR z{vTivwh= zDOELf4NWZ*Q!{f5ODks=S2uSLPp{yR(6I1`$f)F$)U@=B%&g*)(z5c3%Btp;*0%PJ z&aO$5r%atTea6gLixw|gx@`H1m8&*w-m-Pu_8mKS9XfpE=&|D`PM*4S`O4L6*Kgds z_3+W-Cr_U}fAR9w$4{TXeEs(Q$Io9Ne=#yJL%ap|8JfR3M&~ka)>xhT)6Qdr?PR-2hpUWi(FzVCJ$9Vg1iRy8F3zKBFkrR zk0JbZi-Cuk5g2*Qf(-TypXzVE|5o>5di$3B3_ljTMDvSOEPHc1J}WG0?-e(1??_S3 zY4=Q3w2vzANqh>~^h7v*(bJu|T!BmD<}No+yPWmXZe^uy_|%Jk<{p!Yo$**JdDEMC zTP}g;J*upFk*9QT8Rx2J9{ZS?F<*P@dx;I`p7o@@q3Z%&cuiHBDbVxzcoAU zxvRsoGFxh=&>goUY?Udhr}>;(VL3 z8N1%0;_D0bJkA9NJ#ATX^)cJzOeeFR;EVgxvrW_fosZul-fH8xyn_GGFXhaCVjoSH z-^?kMej9a5QTOSZtj0x6t_;Sf6+;3lxg8W$0g6kwd{P(aVThuy4qXKWp}42SDJ0fySR78`&+`_nt&nqWxsqyd`vYs zCe?>8x#jsnC!0xg(w?5SbX|Rl)8y8iT#fCEYEFIg`p@wHCIB;mjfnsN literal 0 HcmV?d00001 diff --git a/micropython/examples/stellar_unicorn/weather/icons/snow1.jpg b/micropython/examples/stellar_unicorn/weather/icons/snow1.jpg deleted file mode 100644 index de769f956703ff6b8be4465b1e67b3676373c1c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2128 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 RBfAN6M(dlIxhzpK{Vyb-`Op9W diff --git a/micropython/examples/stellar_unicorn/weather/icons/snow3.jpg b/micropython/examples/stellar_unicorn/weather/icons/snow3.jpg deleted file mode 100644 index b85dc3b2662348326d4ee724492ab1b30e9baf00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2223 zcmbu-do+~m8UXNb3=I)YF5}jWyLPrjE|ECh2uaAEkfuq+j3lDQbrxmDB{@ZeOo^e1 z5ke(TIa8`&VJtY{_(8$d7rg@@AJyXr%p#i5{T#H6E0jNB_>_EoJpZ(W#?QkD7;Zre6ytVZe~&@4>@3p=TNHdUydb^RUgPI0*G${w0B#EO=@47UflL`fYS0d$ z<}jcqdlZLG349=w0~3xi=Z7FUKa?%gY>i|#Z?xK7G%~|YQpyk>GLx_vv3M6@@dlx4 zHL*!?(0a~V4wTu9h4R?4SMCN~XL{19+oiP(a^j?I z1q&tl>8{STxDcV6@l$a5R&iV2>_iIr#2{VvvSlPD{_W1Nv&E7UNJFZF6&ZoQfyJWY z+!U-GiNkJl%AGse@4AD)3+g}Pz}Rxv*NH2bo{TwMwhOW-H@`JgD?YnuTt^TdFY@uA z%nx|U0fZ#&^VEJf<6yr`H1gc(~`i$R`?KYswXKB%v0;^wWev+KEmJg6MNSw&;y`4{f zSkw8WSq@};6}#;W=iPEsqk83Y-l;&o)pYVYQEkNZjvd@#d$Pv6NRIE2gO@#1jTGhi zm?DxS*KV4x%E3JAkv(-MV8qrMvmB>qF*>0s?%*SChaQQ_^UO>Mo5raSWai+$&zbF( zDWk3D#bp1X7VG4I$Gv~2FZOnFkG}L{C**nAMruaWOP=%L zBxOO^%=kXkSiU-`zymTMi1h2ekAMW0Q5brDR!rs=E#R$$ZU)0?y>)_qAAe<0RT2uO=30+CD#F+Y%eB z#Te{#?Jd@zcHt*o4&8-x)xwhGfGWQ$@LBWr`rrq^C-Ip+)iVF0h+ETkV{d4o1-wSh zs)iZWP*v|6%Kb03KI4R=jDXC8gdQTzByT%frwL40keZRfn^BUHbdlfM859d8>jIZq z9m_3zgV>m5>K$T7OGCu$DmBjPzB`rJ-818$yik{>PV%1tOfj#t5uD#RaAPKQCHoO zir>+WRbzsF)OHkq9pVu9p}2t*!84g!`SXnsIk){(btFa|+etG3W3pQE0@(wCrbtu> zz5A-vlNl^ zI?6??W}zLxbnj`ndAcF4e%OIpuI;0l&8`ayS=uz*jW^ADaOJL`r;u@+@1kXhcQv%c zZe@GWELtMAdtQTb!lIJu>C+f0%|e_FZJQ=@=n$Iz{z<|sjDKUQ1{;gIhMQp-6?Bf2 z_GK^iDNf*UUfT2RqSD+DuedjpLX>;tKR3s{+qyDd3O!sS!(lm!n{=3l20xBeB-e}6 zrZ^Wbu*{$KpQ(5Ct9&~i8Wkc8BeXd_F&C9r3tuI~Skw|?v}eYGOZEmeCYaF>gYiC7 zO45T-y?tmB#=jZrx-lIA9ZOHR6GGGcDx-O+5q_gKHPBvt>%wDJL)KfG zCoy{|Q~QP-zI8n9j~7JOZ<)0pkDjYvnE&i~{a3^Lx;a5$A;Smb%DSP(E`CH)U6)RJ znc(WH8xD=nqwC=|Ohb-A{#7fz^aq9bd#A)-c(&r6h8y~0Dy*YN8L!I|U*RjW%MaKu tmp;HEXSaT(JL4OEr0zcvyOl)Lz34$Pp*b=S9Naj_Idr*Dz(dN%{{>EY2KE2| diff --git a/micropython/examples/stellar_unicorn/weather/icons/snow4.jpg b/micropython/examples/stellar_unicorn/weather/icons/snow4.jpg deleted file mode 100644 index 8ae9bd6af3d2affd9c44eb265b5ed77fc179d1f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2169 zcmbu+e>Bto9tZHxY<^psF^uR-S$^eWzA9^ODatM@KSm>3Qi!yWeKkaE61l0!M0fcy znjiW4l^*=Kb%3p@=Q)q}TlrEs z4XpR}-0ulMAQ0fl>H?ILfX7<*r)n+aPX(-9Rz3g_8o)+iBNSo*s30Iv1VkwS%mDzR z`g=C;?}Dg6VXA8C8k$<#s{^g;0Tl=osse+ms={Ea)2XZH01Tn3_mkr;HRM5xx&>9= zDdP%T!*X|1uYuo)Y?JfRGntxNC_^J-^kyr}7Hb=<%g?Ucw(s!Rv)9vW-+piZfIw1E z@F8-`jE;O8%kOUqy7-@dQ8AOQ4_C;J`t zUoOO|O9cjl!qnGX5S8TB4Mo6Ie{xjQ+jUT#LPc6QWoYQ{zQS(m)wFc>lNlU6Gopps zgq3Ut*J!`V{x?|W|0Vka_8*rB(1Ai$KM#rk+<}#obbCp>9&JjH;*fkIdP#IQUe2iH$WzPw}mmla<6bdeH}`8sGR^ySXU zGvOk)X(r=T501tSAMIzyNng3~)3#mZi;-)BQuk@N0ra`B4Ui1~rG4scyO@ekjuGsh#EkS(nq8OP zW6P6rvZANCeB&^Det6aQZINP=BlxcV(8ybFXm(QdOTx$wQc!uo1Igzl1}zruUDB!< z!KRa(3~XQUF-)$(c@D;A@r~Vav(pNO63FB!fnJ=8IYaDzOUiryNp@z|SMHD`(P%Bm zMbMnaeTi_IxsW6(Te|ZGL9BzhyS48%J?O1<=d-E0o-1{ttp&EX-03)tj`;|YaAOD@bt4OKR9PNz&eocpN)18 zsp0xoYtcvV-pd*A^>(TCtB&q5Y2wKWa&bi0OWiJ2Q}W~kvRC=V7h2UvA6`@hp?Z?2 z$u+byZig)vyv{km;ZBC*rKHit+6tc#A2gkuRp?`izZ92HK}%RMxRt4(g0_dj#$KPJ zv-{+1sktiM8dPJej%O#;$5>Y)I^6RIwl|WX(3X-M>w4&SAIb@|v3`+MgPvk#pUwLpdfhxDOXiVwwbcbJ;Qn6qOT}JDU(;->4g-P@JhqS)n_h$AEeKs|nd&agI$=4Vx zN3!Uxn-7j%$MqL?2++ls%AbR(&t?(VJ^bk~O6MdM=Kv7~y$hla&R9~HZ%%e)R=ULf+?%h)3dVl*Ye zrEWoYqVf&SU(#j14#OZn6^hXy1=P*P4(Wwq7*oM#Wv$EXor}&iFM+%0yJsO%(CH`g z!rx{c8pTo#me|dspN#%_cL~kOjsV+p=?R9t4!Vjx;|hob?kq5KY;FVfNh!QsoU81M z7j4sv?p-tEvNzpi`5=uDrmm45M*@5R}iLT!~_3XEJcCjFZ5K!K1NCG8WNq6_8x zIE&PM^17%t58=>JksWH8D|rhVE@#MICu@kVr8vAS_Aeqx+%}wFE>aC+Grzh$J|T~ldGzM vbJ@|vK-JBApK7oyD#P_5&vShlX5|=7zc#~tfq7!R{Lr0lgUz*Mj&kB(gd)(H diff --git a/micropython/examples/stellar_unicorn/weather/icons/storm.jpg b/micropython/examples/stellar_unicorn/weather/icons/storm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..28110bba521c69a9faf3318175022b9cfa973a6a GIT binary patch literal 909 zcmex=``2_j6xdp@o1cgOJMMZh|#U;coyG6VInuyV4pa*FVB^NNrR z{vTivwh= zDOELf4NWZ*Q!{f5ODks=S2uSLPp{yR(6I1`$f)F$)U@=B%&g*)(z5c3%Btp;*0%PJ z&aO$5r%atTea6gLixw|gx@`H1m8&*w-m-Pu_8mKS9XfpE=&|D`PM*4S`O4L6*Kgds z_3+W-Cr_U}fAR9w$4{TXeEs(Q$Io9Ne=#yJL%ap|8JfR3M&~ka)>xhT)6Qdr?PR-2hpUWi(FzVCJ$9Vg1iRy8F3zKBFkrR zk0JbZi-Cuk5g2*Qf(-Ty8$a+r_`Ceze}>kuDBdSw!STCnZp}SX*gJW*kVjJ8hfqbM zYJJB!0qpbtB>bIeBm1%VAk*!GVpj2OTXU@(b<7Q3?sK}cu(xYrg2d^^@T&X=a~2J z6>Hb7QD`l2!!}>3QjY-e+g*-x~fl=lgvD8^_cS+mA+VnI-#q|F_n^N5USaPgvm-wdu$v zm8`B6k~1dv88GNxK2TYfI`zqx4>x<1+4e~swO;ZyFL&FV+2v(hw|xqp5xO*N_f)m} L^M6*#|Gx8LvnOK-vSy@`H|qMvW5}awt1(JSZA;@q>zSQc)8pmzcPOq?D?fx`w8fiK&^ng{76V zi>sTvho@I?NN8AiL}XNQN@`kqMrKxVNoiSmMP*fUOKV$uM`zch$y26In?7UatVN5L zEM2yI#mZHiHgDOwZTpU$yAB;ba`f2o6DLnyx_ss8wd*%--g@}x@sp>|p1*kc>f@)+ zU%r0({^RE_kiQrinBhSN@fe!F1cClyVqsxsVF&q(k*OSrnFU!`6%E;h90S=C3x$=8 z8aYIqCNA7~kW<+>=!0ld(M2vX6_bamA3R_5p0RnOl0{dx5xF!#ai^Ih@0YyPR; zIi339(d*;)__qCMtYr3?e5*pOUNG}w#kyzW+x|0nL?&FA_b=ks{qLt<@Wk)oj(<`7 zVfDd!P8;cmvTE{8|D-;MxBn5YUzWK!Q|OP)ej0dvoj;# zzQ0wy*y^mxp-QRr@*n=or(a6$_`~(!&gQlq`s}kFSnTdE__1|r;Z`k)%%^)Sowbjr zt~Xrn{kp_Zq%iWBIdjK)XMW${o=v|>lV@mJt!mes@7~Y#X}>`6nXt@x*AG4_%9CB~ z`q)VF+^VB#rG^zX;aAh`lY^$bOvp&myu32V&o?QRGjUcxss5jm`h&jz86M1@X20R? z_r{vg2l^7P>x_Ryeq?$dd@)!0XyD7kN8_YEs!h!o{djq+_gSU$K9{~$`$qdu%HC`C z@4VOLl+G`Ioi4pQ=~6a5eE;OH|9baJ+Q@#$KW4{t{p~)h7jn$k_Q^$NR<)knYktJq zSI(E+{qn4vm;N&ZO%A-qbaau8*w4aMx9{A%8@b8dMm*rGNRj@}`xW2hxo%fHKQ`?j z%g$YUKDh4hwsGZe&ewNo`tq=epsebBqyIk<+EZ4?kS_^p1P`*^iZTKHUmcZCTvD*xmBNj!f=*GH=P1 zlJM_`J>N}!y=vdy^UuAvZr-Tut+KJWLO&-3!$@+JT=I~!XY00Myk z=e8HX8v!hLPTy5KA>S3S^O*MxK=K27fxR$@DgZ@7U`Pn>IiL&x5WcV3z~2Rd!r*+n z5c~pyLfZ{ZVgM8ZgF)diK0Y{nyZh?)Jpf1YiL2;Z?2>Rgk5DB@>Lp~~q*HescGpsxq0~o#9M_$_e)C4$}1|Xs!0uvP0hbOZfWi8dQPFzUcBt4 zGX`J38G1X+oSb_9$MnqX-24K2<ur0`VN78`pzsV-_QX;X*GjMb@mSJFWG;CCH^nj zH`qTeCLj!hY=0gM377+1?Bc2;S0JAUz-Jo2v^4cA1{E8#lj|qQN#xyLXvQigR#&>1 zi()IM8opiD)(U^9H0#@N0Spc1aCvNwr z`-nW?s*m>gv!)hlN&i!7@^H z7sjgTh!-&1GpVSdoXC}D$)s>3;>+<3cyW#yBmC$O2v_=4GnE+4Hq-(ZRAX3bou#OQ%MH?I1ooDuX?2SBujnkn6|z{^D>r=cP{&m0&x$qH@Ac&Rswo#D zbfaS3Uk8|Do%80;;e0h2Rn8|JeEkK^7oCdG;e^L`IPidp+Xd#2#?}*JT_<#87vuCn z3>&)aG7!9n;xykyIV;cB$PbZXGn(vsRr^oSS7RK!9CL!&jJW-F48OF`Uyjk2URqry zx|4HPxi`sjW{Rv3>W|Q&kL{*&O0YNWN*Mf=q`o%e=SLls91v(m(J-9{IOjUOfl}_9 zNpBFUM@EOoFeJ2@%&A_9qw$W@seSC39cd8HKVTvKjyLU}i zO^>2edfCx;R+z5p*Gp1L&_{Y$QJzt;-iq3>!LkfmcUYYZQlmXvNyh)I@+@dZQ>nSu z<;SsFbQH>Vsd4kTL#h?b6gR1&xL3JF95yLh4RE`Ww}Cqy+ErOiC@s*wi4Ca^+;l69 ztj6F9S~JVA*szCzzVnS^s^d!w2cw%DEG`Du=@j)iX4*V?BE3B=8~#%1HAXKb5 z3EW@8?IkNYcGL-4#P3fwQ)g{WF3yeXx8i6VE#;3qK!geAdV(2v^)kxq8%1vQQ^7vo zjBt+!OSQg?&o||JY>T2p47P~o3K-02piDu5bSmkLk9S8v@E%(Q)Vhpb>ERN4eVVWx z-LxtPBW{2QYpp!=6XR{umH1Ay+&W z-lLePzeH>Gpr{Jw?kZC#FfVU$<`jiN@so>lG&aoWm@RA%wzk}YiOqssFNG>rmV~|3 z2i%26uT0`FHY%SSr7|)Ku)?%M74{yC&Q`s$LSI7tba;?Ict~NC+=#E_py=JtYHasu hQeE$+n#})Vt8lq;?mqd1tya$2bXxbBwy}QR@Sn}1?dt#l diff --git a/micropython/examples/stellar_unicorn/weather/icons/storm3.jpg b/micropython/examples/stellar_unicorn/weather/icons/storm3.jpg deleted file mode 100644 index 6081f046654ef0891ff4a29e6c9958699875cbd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1835 zcmbu+eKga190%~Bc8 zKp+rc|J(vp{eb&?_d_)w@0V4o_AiiY-e-{J_ zgCo?C>L?A(xq+&M02Bg)LE$h20uG;>J~wv`z%dA&m3Eud76pVOjbj$uCtkUwZnC+& zK{xOfXu3AyWD-h4Pk)I4*38^um8F$~qm#4Cy7lf`wt8&a?&%e@GdLu47k+o-frE#l zqKSu3#gb0Pk>k&tzd)lWGg4ABuU^Z#o}F`pSx{KSF6P|6Q&PdNtg5c5z5k%GsrgAu z>#tASI)z=`J+FKFL=vg&-O%vJ`wye?iOJ7XUw&8oF+J~s0I=^*_6_zg7iP`{g~MTR z>l2PEBW105Uvgk+FTE`r^%3Zk0EnOx6a1x)CQ|Y3P|cNX+E(w7+Ek z4VLu3WZz-`xJ1AL7-a7AU>IN{FdI2G~O1@)5!ixP^7e4>sLCyaI7pc&FBscy-RNBl<95siYm zMEs|5(b+=#=cbME*r+&#KPS60lA+WPzv0ts*C3f9n&@Xj~Cd*d3C)^cF& z&EV8$qY$Y;;8%?r7R zv@K+t30ZK>ef|UffpoI%E#|6sgvm$pk8Zlv@{UV3O4KP*yf`gEkDO|xHV~GA7);3$xNCX zG};K;FB@l&(gr_0-y@EDoWE4L13cd7?R2xMJ|)ad7~9_KPzX0^r;j&To;$u->GIq#5$$!kg-Ix{Wjab!1cPrCdVs)*gQE;ct zpRNKR6xUK}^TtYxPs_6NK_*$&Xy^i>n=XK~?7RtzCD_U!X)gEsDy?UTbKCV}6q!f- z6``|BGZ7Cegu7J$p)Svjt;=qqfp4ia3TmeCGdhWYs6VpNU@wts)J^}5nvQeV8-3>nn5*HbOeC+PM4>*`yGpHnnpIQwpJIUjvJoz2poO-$z;_4To4 T2TP)@9m0bHZdyAnRrUP|Es;5$ diff --git a/micropython/examples/stellar_unicorn/weather/icons/storm4.jpg b/micropython/examples/stellar_unicorn/weather/icons/storm4.jpg deleted file mode 100644 index 98cdc59c01e66aff906414d311da0631845bc5ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1703 zcmbu+cTm%37zglQ7GVe&ro>W|Eee)EKqTrR%HGpBhzx<)T1AKuWgI9Ff`S7?gF+>Q zAS*&xD#{cTWQJu>2#E|q$}b|CB9KDu*}MMLtIvDyAJ4td`@Q?TuXtF@12#I?*xLXQ z2n0C3wgB-6V7=abSFMM9SHSvZaRY#o1hxQMU=U3Jih{sU5OE8j0RRxh*KFYLfjMXEZ0+nFJiWYqd=KFd2L_!84hbcm z438k4i;ND1A{}uuejrU!P|++sp)q!!Ve1{7e9R#{js#}f&j2@Pxck|FBfXf1%<<5aOAoR z0*zeTFcciI)mTEo${pz+rl^UDmsHw+?Ou7Kl$MDHs2p&%S6W5ebX-TcPWwyt-(U&< zOZE-+kBbXzfI-$i4~7Ev0jq(ti>|9unPLDwS-JACs$2c%9CKk(Ij=skUhar3XAvK5 ztdg^8Ak?5>hv$t9BT9dq@~-MPeWE+!QeJW4ji=`m4%SRIyxlEV(h-{+5GL92rxktvQZ@juSi;Va^QGq)HW)tyq z^V|z`Os94e866TSa%E=q1yYu!d9T??wL6hC-mb^#XGB$*VWkF}h!b^|*4x`A(v6vp zvk}HhVfa>a7=>jm@9cTGVu|FR?m_aFJGM9dN9BpwEmOBjID1$ZTi(95^hs?EGP&zb zeK`{VidaQmv8{}4eGNS=o=lJYJG7Q|g=W*=W(cBpVjv+~3^bbWi1U9u4;2+R_!$o_ zhk$H8Vw9Q3HK)=!$<#V5-`QYvyMTEzi*_*QHe==!tvXkG==`aboXmn3itm;Z8E>vr z=8RZzdb2B=V=+;dys^vC2-Zk6sRxHFjmA~Urf&<7E0BU4s# zvu8(bx_mZ&!D6Da$Wh8x-X<+Piw9PMqT1a@MOSYo#`r7+xDTSa3a~=OJHy0@^pM9buTnj z13e;`r;t*|<~on?A{%lyFS~)Kn;gyVR@JBY>2M-ChE3^kt&XJmWc?Vo zuFv4O85*0EOO~MDcMJg+V;a98qK|;N?*+n0{7U{ZUc2Ucv<7ING6kAnGGsB>xqM_x zJ(}nnD+{(ImR)%)l?N`Hp=&5Ocm5u$fznf^W3qJ;mQQTHIB~G@v+}AFEpFgQYDkkw ztC3#XG33>8P)V@Ehe*Q(tNCNlr2O%fTsh6cL2F9aR-eS9H{@>(bWZbs8aU&|autqB zN39D~nTq5Gor(7T-U%8O=$F$u1-m=4XHKu3grf70GEl}!d2MNM`0JNRZd zeGrH3)m$(o@2%RL66^$3wuhHi%Xd;pbEgS8-Oe255H`l~P_}Dt37r#hL5*bjf)&K> ztDLr{Hal07U#gh7E2@_k9fYcvQ=hYXLm#$hT6i(g*b^=a#SSLkS}t^IctMeVqnBGI uzksf+osr>jj$n*cwkUM&lJ;=RPEF15Jc$YW^=O$xXY2gUPmf=VU;PQ#^YlRg diff --git a/micropython/examples/stellar_unicorn/weather/icons/sun.jpg b/micropython/examples/stellar_unicorn/weather/icons/sun.jpg new file mode 100644 index 0000000000000000000000000000000000000000..78bbdc8b5cc0fbf1c4c38b9d4210519ff107c650 GIT binary patch literal 991 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 MFrZ=KSdDV}pF0fxb^rhX diff --git a/micropython/examples/stellar_unicorn/weather/icons_sourcefile(doesn't need copying).svg b/micropython/examples/stellar_unicorn/weather/icons_sourcefile(doesn't need copying).svg deleted file mode 100644 index 8eedbcb0..00000000 --- a/micropython/examples/stellar_unicorn/weather/icons_sourcefile(doesn't need copying).svg +++ /dev/null @@ -1,1577 +0,0 @@ - - - - diff --git a/micropython/examples/stellar_unicorn/weather/weather.py b/micropython/examples/stellar_unicorn/weather/weather.py index 7cc00674..c36a7131 100644 --- a/micropython/examples/stellar_unicorn/weather/weather.py +++ b/micropython/examples/stellar_unicorn/weather/weather.py @@ -3,28 +3,35 @@ from stellar import StellarUnicorn from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN as DISPLAY import WIFI_CONFIG from network_manager import NetworkManager -import uasyncio as asyncio +import uasyncio import urequests import jpegdec +""" +This example connects to Open Meteo to access the current weather conditions. +It then displays an appropriate weather icon on Stellar Unicorn. + +Find out more about the Open Meteo API at https://open-meteo.com +""" + # Set your latitude/longitude here (find yours by right clicking in Google Maps!) LAT = 53.38609085276884 LNG = -1.4239983439328177 TIMEZONE = "auto" # determines time zone from lat/long URL = "http://api.open-meteo.com/v1/forecast?latitude=" + str(LAT) + "&longitude=" + str(LNG) + "¤t_weather=true&timezone=" + TIMEZONE -WEATHER_TEXT = '' -user_icon = None + +# how often to poll the API, in minutes +UPDATE_INTERVAL = 5 def get_data(): - global WEATHER_TEXT, temperature, weathercode + global temperature, weathercode print(f"Requesting URL: {URL}") r = urequests.get(URL) # open the json data j = r.json() print("Data obtained!") - print(j) # parse relevant data from JSON current = j["current_weather"] @@ -33,8 +40,7 @@ def get_data(): winddirection = calculate_bearing(current["winddirection"]) weathercode = current["weathercode"] date, now = current["time"].split("T") - WEATHER_TEXT = f"Temp: {temperature}°C Wind Speed: {windspeed}kmph Wind Direction: {winddirection} As of: {date}, {now}" - print(WEATHER_TEXT) + print(f"Temp: {temperature}°C Wind Speed: {windspeed}kmph Wind Direction: {winddirection} As of: {date}, {now}") r.close() @@ -46,8 +52,14 @@ def calculate_bearing(d): def status_handler(mode, status, ip): - global MESSAGE - print("Network: {}".format(WIFI_CONFIG.SSID)) + # reports wifi connection status + print(mode, status, ip) + print('Connecting to wifi...') + if status is not None: + if status: + print('Wifi connection successful!') + else: + print('Wifi connection failed!') # create galactic object and graphics surface for drawing @@ -57,97 +69,39 @@ display = PicoGraphics(DISPLAY) WIDTH = StellarUnicorn.WIDTH HEIGHT = StellarUnicorn.HEIGHT +RED = display.create_pen(255, 0, 0) + jpeg = jpegdec.JPEG(display) -TEXT_COLOUR = display.create_pen(200, 0, 200) -BLACK = display.create_pen(0, 0, 0) -WHITE = display.create_pen(255, 255, 255) +su.set_brightness(1.0) -def run(): - # Setup wifi +# set up wifi +try: network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler) + uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)) +except Exception as e: + print(f'Wifi connection failed! {e}') - # Connect to Wifi network - asyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)) - while (not network_manager.isconnected()): - time.sleep(0.1) - - -su.set_brightness(1) -run() # Sets up Wifi connection - - -def outline_text(text, x, y): - display.set_pen(BLACK) - display.text(text, x - 1, y - 1, -1, 1) - display.text(text, x, y - 1, -1, 1) - display.text(text, x + 1, y - 1, -1, 1) - display.text(text, x - 1, y, -1, 1) - display.text(text, x + 1, y, -1, 1) - display.text(text, x - 1, y + 1, -1, 1) - display.text(text, x, y + 1, -1, 1) - display.text(text, x + 1, y + 1, -1, 1) - - display.set_pen(WHITE) - display.text(text, x, y, -1, 1) - - -def draw_page(cycle): - global user_icon - text_cycle = cycle % 1000 - cycle = cycle % 4 - # Clear the display - display.set_pen(15) - display.clear() - - # Draw the page header - display.set_font("bitmap6") - - if temperature is not None: +while True: + get_data() + if weathercode is not None: # Choose an appropriate icon based on the weather code # Weather codes from https://open-meteo.com/en/docs - if user_icon is not None: - icons = ["icons/snow{0}.jpg".format(cycle + 1), "icons/rain{0}.jpg".format(cycle + 1), "icons/cloud{0}.jpg".format(cycle + 1), "icons/sun{0}.jpg".format(cycle + 1), "icons/storm{0}.jpg".format(cycle + 1)] - jpeg.open_file(icons[user_icon]) - else: - if weathercode in [71, 73, 75, 77, 85, 86]: # codes for snow - jpeg.open_file("icons/snow{0}.jpg".format(cycle + 1)) - elif weathercode in [51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82]: # codes for rain - jpeg.open_file("icons/rain{0}.jpg".format(cycle + 1)) - elif weathercode in [1, 2, 3, 45, 48]: # codes for cloud - jpeg.open_file("icons/cloud{0}.jpg".format(cycle + 1)) - elif weathercode in [0]: # codes for sun - jpeg.open_file("icons/sun{0}.jpg".format(cycle + 1)) - elif weathercode in [95, 96, 99]: # codes for storm - jpeg.open_file("icons/storm{0}.jpg".format(cycle + 1)) + if weathercode in [71, 73, 75, 77, 85, 86]: # codes for snow + jpeg.open_file("icons/snow.jpg") + elif weathercode in [51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82]: # codes for rain + jpeg.open_file("icons/rain.jpg") + elif weathercode in [1, 2, 3, 45, 48]: # codes for cloud + jpeg.open_file("icons/cloud.jpg") + elif weathercode in [0]: # codes for sun + jpeg.open_file("icons/sun.jpg") + elif weathercode in [95, 96, 99]: # codes for storm + jpeg.open_file("icons/storm.jpg") jpeg.decode(0, 0, jpegdec.JPEG_SCALE_FULL) - display.set_pen(TEXT_COLOUR) - outline_text(WEATHER_TEXT, 16 - text_cycle, 0) else: - display.set_pen(0) - display.set_pen(15) - display.text("Unable to display weather! Check your network settings in WIFI_CONFIG.py", 5, 65, WIDTH, 1) + display.set_pen(RED) + display.text("ERR", 0, 0, WIDTH, 1) su.update(display) - - -while 1: - - get_data() - for count in range(500): - - if su.is_pressed(StellarUnicorn.SWITCH_A): - user_icon = 0 - if su.is_pressed(StellarUnicorn.SWITCH_B): - user_icon = 1 - if su.is_pressed(StellarUnicorn.SWITCH_C): - user_icon = 2 - if su.is_pressed(StellarUnicorn.SWITCH_D): - user_icon = 3 - if su.is_pressed(StellarUnicorn.SWITCH_BRIGHTNESS_UP): - user_icon = 4 - if su.is_pressed(StellarUnicorn.SWITCH_BRIGHTNESS_DOWN): - user_icon = None - draw_page(count) - time.sleep(0.2) + time.sleep(UPDATE_INTERVAL * 60) From 130685eeebce47191fe4ba24c12ef2faa249516a Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Sun, 2 Jul 2023 15:14:25 +0100 Subject: [PATCH 07/15] Stellar: adjust html text example --- micropython/examples/stellar_unicorn/http_text/html_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/stellar_unicorn/http_text/html_text.py b/micropython/examples/stellar_unicorn/http_text/html_text.py index dfd186af..33b08431 100644 --- a/micropython/examples/stellar_unicorn/http_text/html_text.py +++ b/micropython/examples/stellar_unicorn/http_text/html_text.py @@ -173,7 +173,7 @@ async def message_update(): graphics.set_pen(graphics.create_pen(int(BACKGROUND_COLOUR[0]), int(BACKGROUND_COLOUR[1]), int(BACKGROUND_COLOUR[2]))) graphics.clear() - outline_text(MESSAGE, x=PADDING - shift, y=11) + outline_text(MESSAGE, x=PADDING - shift, y=4) # update the display su.update(graphics) From ce24330842d9f1b46cdb1ed896b4baa832c8bd0c Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Sun, 2 Jul 2023 15:19:32 +0100 Subject: [PATCH 08/15] Stellar: move font to common --- {fonts => common/fonts}/3x5.bitmapfont | Bin micropython/examples/stellar_unicorn/README.md | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename {fonts => common/fonts}/3x5.bitmapfont (100%) diff --git a/fonts/3x5.bitmapfont b/common/fonts/3x5.bitmapfont similarity index 100% rename from fonts/3x5.bitmapfont rename to common/fonts/3x5.bitmapfont diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 231a7481..01feacc4 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -50,7 +50,7 @@ The easiest way to start displaying cool stuff on Stellar Unicorn is using our S Clock example with (optional) NTP synchronization. You can adjust the brightness with LUX + and -, and resync the time by pressing A. -This examples uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../fonts) and copy it to your Pico W. +This example uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../common/fonts) and copy it to your Pico W. ### Eighties Super Computer @@ -171,7 +171,7 @@ The examples in the folder use `numpy`-like array functions contained in the `ul Add a [SCD41 sensor breakout](https://shop.pimoroni.com/products/scd41-co2-sensor-breakout) to make an carbon dioxide detector. Press A, B and C to switch between modes. -This examples uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../fonts) and copy it to your Pico W. +This examples uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../common/fonts) and copy it to your Pico W. ### Launch (Demo Reel) From 323650380527f541f4c84b229e10197148d3ce4e Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Sun, 2 Jul 2023 17:48:53 +0100 Subject: [PATCH 09/15] Stellar: add pizazz to weather example --- .../examples/stellar_unicorn/README.md | 9 +- .../stellar_unicorn/weather/weather.py | 100 +++++++++++++++++- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 01feacc4..0bec972a 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -157,6 +157,13 @@ Requires `logging.mpy` and `tinyweb` from [micropython/examples/common](../../ex Display current weather data from the [Open-Meteo](https://open-meteo.com/) weather API. Make sure to copy across the `icons` folder to your Unicorn. +Buttons: +A - show / hide temperature +B - swap between Celsius and Fahrenheit +C - randomly select a weather icon +D - add rainbows +LUX + and - adjust brightness + ## NumPy Examples [numpy](numpy) @@ -171,7 +178,7 @@ The examples in the folder use `numpy`-like array functions contained in the `ul Add a [SCD41 sensor breakout](https://shop.pimoroni.com/products/scd41-co2-sensor-breakout) to make an carbon dioxide detector. Press A, B and C to switch between modes. -This examples uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../common/fonts) and copy it to your Pico W. +This example uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../common/fonts) and copy it to your Pico W. ### Launch (Demo Reel) diff --git a/micropython/examples/stellar_unicorn/weather/weather.py b/micropython/examples/stellar_unicorn/weather/weather.py index c36a7131..2be0355b 100644 --- a/micropython/examples/stellar_unicorn/weather/weather.py +++ b/micropython/examples/stellar_unicorn/weather/weather.py @@ -6,12 +6,20 @@ from network_manager import NetworkManager import uasyncio import urequests import jpegdec +from random import choice """ This example connects to Open Meteo to access the current weather conditions. It then displays an appropriate weather icon on Stellar Unicorn. Find out more about the Open Meteo API at https://open-meteo.com + +Buttons: +A - show / hide temperature +B - swap between Celsius and Fahrenheit +C - randomly select a weather icon +D - add rainbows +LUX + and - adjust brightness """ # Set your latitude/longitude here (find yours by right clicking in Google Maps!) @@ -62,18 +70,34 @@ def status_handler(mode, status, ip): print('Wifi connection failed!') -# create galactic object and graphics surface for drawing +# create objects and picographics surface for drawing su = StellarUnicorn() display = PicoGraphics(DISPLAY) +jpeg = jpegdec.JPEG(display) + +# some useful constants WIDTH = StellarUnicorn.WIDTH HEIGHT = StellarUnicorn.HEIGHT +BLACK = display.create_pen(0, 0, 0) RED = display.create_pen(255, 0, 0) +ORANGE = display.create_pen(246, 138, 30) +YELLOW = display.create_pen(255, 216, 0) +GREEN = display.create_pen(0, 121, 64) +BLUE = display.create_pen(0, 0, 255) +INDIGO = display.create_pen(36, 64, 142) +VIOLET = display.create_pen(115, 41, 130) +WHITE = display.create_pen(255, 255, 255) -jpeg = jpegdec.JPEG(display) +show_temperature = True +show_fahrenheit = False +show_rainbow = False -su.set_brightness(1.0) +# timer variable to keep track of how often to poll the api +timer = UPDATE_INTERVAL * 60.0 + +su.set_brightness(0.8) # set up wifi try: @@ -83,7 +107,45 @@ except Exception as e: print(f'Wifi connection failed! {e}') while True: - get_data() + # adjust brightness with LUX + and - + if su.is_pressed(StellarUnicorn.SWITCH_BRIGHTNESS_UP): + su.adjust_brightness(+0.05) + print(f"Brightness set to {su.get_brightness()}") + if su.is_pressed(StellarUnicorn.SWITCH_BRIGHTNESS_DOWN): + su.adjust_brightness(-0.05) + print(f"Brightness set to {su.get_brightness()}") + + if su.is_pressed(StellarUnicorn.SWITCH_A): + show_temperature = not show_temperature + print(f"Show temperature = {show_temperature}") + # debounce + time.sleep(0.1) + + if su.is_pressed(StellarUnicorn.SWITCH_B): + show_fahrenheit = not show_fahrenheit + print(f"Show fahrenheit = {show_fahrenheit}") + # debounce + time.sleep(0.1) + + # I hate this weather, give me another + if su.is_pressed(StellarUnicorn.SWITCH_C): + weathercode = choice([71, 51, 1, 0, 95]) + print("Weather icon randomised!") + # debounce + time.sleep(0.1) + + # brighten up boring weather with a rainbow + if su.is_pressed(StellarUnicorn.SWITCH_D): + show_rainbow = not show_rainbow + print(f"Show rainbow = {show_rainbow}") + # debounce + time.sleep(0.1) + + # we only need to ping the api for data every UPDATE_INTERVAL + if timer >= UPDATE_INTERVAL * 60: + get_data() + timer = 0.0 + if weathercode is not None: # Choose an appropriate icon based on the weather code # Weather codes from https://open-meteo.com/en/docs @@ -99,9 +161,37 @@ while True: jpeg.open_file("icons/storm.jpg") jpeg.decode(0, 0, jpegdec.JPEG_SCALE_FULL) + if show_rainbow is True: + display.set_pen(VIOLET) + display.circle(WIDTH - 1, HEIGHT - 1, 6) + display.set_pen(BLUE) + display.circle(WIDTH - 1, HEIGHT - 1, 5) + display.set_pen(GREEN) + display.circle(WIDTH - 1, HEIGHT - 1, 4) + display.set_pen(YELLOW) + display.circle(WIDTH - 1, HEIGHT - 1, 3) + display.set_pen(ORANGE) + display.circle(WIDTH - 1, HEIGHT - 1, 2) + display.set_pen(RED) + display.circle(WIDTH - 1, HEIGHT - 1, 1) + + # draw the temperature text + if show_temperature is True: + display.set_pen(RED) + if show_fahrenheit is True: + fahrenheit = (temperature * 9 / 5) + 32 + # measure the text so we can right align it + text_width = display.measure_text(f"{fahrenheit:.0f}°", scale=1) + display.text(f"{fahrenheit:.0f}°", WIDTH - text_width, 4, WIDTH, scale=1) + else: + # measure the text so we can right align it + text_width = display.measure_text(f"{temperature:.0f}°", scale=1) + display.text(f"{temperature:.0f}°", WIDTH - text_width, 4, WIDTH, scale=1) + else: display.set_pen(RED) display.text("ERR", 0, 0, WIDTH, 1) su.update(display) - time.sleep(UPDATE_INTERVAL * 60) + timer += 0.1 + time.sleep(0.1) From 37638172aec24049462cbcf05cbbfee053de1f16 Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Sun, 2 Jul 2023 19:02:08 +0100 Subject: [PATCH 10/15] Stellar: add temperature example --- .../examples/stellar_unicorn/README.md | 7 ++ .../stellar_unicorn/thermometer_pico.py | 103 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 micropython/examples/stellar_unicorn/thermometer_pico.py diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 0bec972a..11e904c8 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -12,6 +12,7 @@ - [Nostalgia Prompt](#nostalgia-prompt) - [Rainbow](#rainbow) - [Scrolling Text](#scrolling-text) + - [Thermometer](#thermometer) - [Today](#today) - [Wireless Examples](#wireless-examples) - [Cheerlights History](#cheerlights-history) @@ -105,6 +106,12 @@ Some good old fashioned rainbows! You can adjust the cycling speed with A and B, Display scrolling wisdom, quotes or greetz. You can adjust the brightness with LUX + and -. + +### Thermometer +[thermometer_pico.py](thermometer_pico.py) + +Shows the temperature (from the Pico W's internal sensor) against an appropriately coloured pulsing blob. + ### Today [today.py](today.py) diff --git a/micropython/examples/stellar_unicorn/thermometer_pico.py b/micropython/examples/stellar_unicorn/thermometer_pico.py new file mode 100644 index 00000000..21524af6 --- /dev/null +++ b/micropython/examples/stellar_unicorn/thermometer_pico.py @@ -0,0 +1,103 @@ +from machine import ADC +import time +from stellar import StellarUnicorn +from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN + +""" +Reads the internal temperature sensor on the Pico W... +... and displays an appropriately coloured pulsing blob. +""" + +# The range of readings that we want to map to colours +MIN = 15 +MAX = 35 + +# pick what bits of the colour wheel to use (from 0-360°) +# https://www.cssscript.com/demo/hsv-hsl-color-wheel-picker-reinvented/ +HUE_START = 230 # blue +HUE_END = 359 # red + +# rainbow party mode +rainbow_orb = False + +# set up the Unicron +su = StellarUnicorn() +graphics = PicoGraphics(DISPLAY_STELLAR_UNICORN) + +# set up the ADC +sensor_temp = ADC(ADC.CORE_TEMP) +conversion_factor = 3.3 / 65535 # used for calculating a temperature from the raw sensor reading + +# set up constants and variables for drawing +WIDTH, HEIGHT = graphics.get_bounds() + +BLACK = graphics.create_pen(0, 0, 0) +WHITE = graphics.create_pen(255, 255, 255) + +forward = True +orb_brightness = 0.5 +hue = 0.0 + +graphics.set_font("bitmap8") + +while True: + + # read the onboard sensor + # the following two lines do some maths to convert the number from the temp sensor into celsius + reading = sensor_temp.read_u16() * conversion_factor + temperature = 27 - (reading - 0.706) / 0.001721 + + print(f""" + Temperature: {temperature:.2f} °C + """) + + # fills the screen with black + graphics.set_pen(BLACK) + graphics.clear() + + # draw a weird orb: + # three overlapping circles with varying saturations + if rainbow_orb is True: + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.5, orb_brightness)) + graphics.circle(8, 8, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.7, orb_brightness)) + graphics.circle(7, 7, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, orb_brightness)) + graphics.circle(7, 7, 5) + hue += 0.01 * 360 + else: + # calculate a colour from the temperature + hue = max(0, HUE_START + ((temperature - MIN) * (HUE_END - HUE_START) / (MAX - MIN))) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.6, orb_brightness)) + graphics.circle(8, 8, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.8, orb_brightness)) + graphics.circle(7, 7, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, orb_brightness)) + graphics.circle(7, 7, 5) + + # pulse the orb! + if forward is True: + orb_brightness += 0.01 + if orb_brightness >= 0.7: + orb_brightness = 0.7 + forward = False + + if forward is False: + orb_brightness -= 0.01 + if orb_brightness <= 0.3: + orb_brightness = 0.3 + forward = True + + # draw the temperature + # try BLACK for a funky negative space effect + graphics.set_pen(WHITE) + graphics.text(f"{temperature:.0f}°", 2, 5, scale=1) + + # or uncomment these lines if you'd prefer it in Freedom Units + # graphics.set_pen(WHITE) + # fahrenheit = (temperature_average * 9 / 5) + 32 + # graphics.text(f"{fahrenheit:.0f}°", 2, 5, scale=1) + + # time to update the display + su.update(graphics) + time.sleep(0.1) From 6b67f652c7f9017928cb4876dc60517e6f4f4f59 Mon Sep 17 00:00:00 2001 From: helgibbons <50950368+helgibbons@users.noreply.github.com> Date: Sun, 2 Jul 2023 19:17:24 +0100 Subject: [PATCH 11/15] Stellar: adjust exchange_ticker.py --- .../stellar_unicorn/exchange_ticker.py | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/micropython/examples/stellar_unicorn/exchange_ticker.py b/micropython/examples/stellar_unicorn/exchange_ticker.py index cccf17d6..eb59332d 100644 --- a/micropython/examples/stellar_unicorn/exchange_ticker.py +++ b/micropython/examples/stellar_unicorn/exchange_ticker.py @@ -25,13 +25,13 @@ currency_rate = "" rate_keys = [] # display options -line_1_line = -2 -line_2_line = 9 -line_3_line = 20 +line_1_line = -1 +line_2_line = 4 +line_3_line = 9 ref_currency_index = 0 -cycles_per_sequence = 120 +cycles_per_sequence = 200 su = StellarUnicorn() graphics = PicoGraphics(DISPLAY) @@ -61,8 +61,8 @@ def get_data(currency_selected): graphics.set_pen(graphics.create_pen(20, 20, 20)) graphics.clear() graphics.set_pen(graphics.create_pen(100, 100, 100)) - graphics.text("Get", 0, 10, scale=1, spacing=1) - graphics.text("data", 8, 16, scale=1, spacing=1) + graphics.text("Get", 0, 0, scale=1) + graphics.text("data", 0, 7, scale=1) su.update(graphics) gc.collect() # open the json file @@ -88,14 +88,11 @@ def update_display(cycle): graphics.set_pen(graphics.create_pen(20, 20, 20)) graphics.clear() graphics.set_pen(graphics.create_pen(100, 0, 0)) - graphics.text(ref_currency_name, calculate_xpos((len(ref_currency_name)), cycle), line_1_line, scale=2, spacing=1) + graphics.text(ref_currency_name, calculate_xpos((len(ref_currency_name)), cycle), line_1_line, scale=1) graphics.set_pen(graphics.create_pen(100, 100, 0)) - if len(currency_symbol) > 3: - graphics.text(currency_symbol, calculate_xpos((len(currency_symbol)), cycle), line_2_line, scale=2, spacing=1) - else: - graphics.text(currency_symbol, 0, line_2_line, scale=2, spacing=1) + graphics.text(currency_symbol, calculate_xpos((len(currency_symbol)), cycle), line_2_line, scale=1) graphics.set_pen(graphics.create_pen(0, 100, 100)) - graphics.text(currency_rate, calculate_xpos((len(currency_rate)), cycle), line_3_line, scale=2, spacing=1) + graphics.text(currency_rate, calculate_xpos((len(currency_rate)), cycle), line_3_line, scale=1) def update_base_currency(index): From 58cdc85b1fd5071c362b9d0835be3e5b4b404ddc Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Mon, 3 Jul 2023 12:15:12 +0100 Subject: [PATCH 12/15] stellar: add encoder wheel demo --- .../examples/stellar_unicorn/README.md | 6 + .../examples/stellar_unicorn/encoder_wheel.py | 168 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 micropython/examples/stellar_unicorn/encoder_wheel.py diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 11e904c8..608803ae 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -23,6 +23,7 @@ - [NumPy Examples](#numpy-examples) - [Other Examples](#other-examples) - [CO2](#co2) + - [Encoder Wheel](#encoder-wheel) - [Launch (Demo Reel)](#launch-demo-reel) ## About Stellar Unicorn @@ -187,6 +188,11 @@ Add a [SCD41 sensor breakout](https://shop.pimoroni.com/products/scd41-co2-senso This example uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../../common/fonts) and copy it to your Pico W. +### Encoder Wheel +[encoder_wheel.py](encoder_wheel.py) + +This example uses [RGB Encoder Wheel breakout](https://shop.pimoroni.com/products/rgb-encoder-wheel-breakout) to make an RGB colour picker. Use the encoder wheel to pick a hue and view the RGB breakdown of that colour on the Unicorn display (you can adjust saturation and brightness using the buttons on the breakout too). + ### Launch (Demo Reel) [launch](launch) diff --git a/micropython/examples/stellar_unicorn/encoder_wheel.py b/micropython/examples/stellar_unicorn/encoder_wheel.py new file mode 100644 index 00000000..7ccd6d1e --- /dev/null +++ b/micropython/examples/stellar_unicorn/encoder_wheel.py @@ -0,0 +1,168 @@ +import time +from pimoroni_i2c import PimoroniI2C +from pimoroni import BREAKOUT_GARDEN_I2C_PINS +from breakout_encoder_wheel import BreakoutEncoderWheel, UP, DOWN, LEFT, RIGHT, CENTRE, NUM_LEDS +from stellar import StellarUnicorn +from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN + +""" +Create a colour wheel on the Encoder Wheel's LED ring, and use all functions of the wheel to interact with it. +Draw bars on the Unicorn to represent the currently selected RGB value + + +Rotate the wheel to select a Hue +Press the up direction to increase Brightness +Press the down direction to decrease Brightness +Press the left direction to decrease Saturation +Press the right direction to increase Saturation +Press the centre to hide the selection marker + +Press Ctrl+C to stop the program. +""" + +# Constants +BRIGHTNESS_STEP = 0.01 # How much to increase or decrease the brightness each update +SATURATION_STEP = 0.01 # How much to increase or decrease the saturation each update +UPDATES = 50 # How many times to update the LEDs per second +UPDATE_RATE_US = 1000000 // UPDATES + +# Create a new BreakoutEncoderWheel +i2c = PimoroniI2C(**BREAKOUT_GARDEN_I2C_PINS) +wheel = BreakoutEncoderWheel(i2c) + +# Set up the Unicron +su = StellarUnicorn() +su.set_brightness(1.0) +graphics = PicoGraphics(DISPLAY_STELLAR_UNICORN) + +# Variables +brightness = 1.0 +saturation = 1.0 +position = 0 +changed = True +last_centre_pressed = False + + +# From CPython Lib/colorsys.py +def hsv_to_rgb(h, s, v): + if s == 0.0: + return v, v, v + i = int(h * 6.0) + f = (h * 6.0) - i + p = v * (1.0 - s) + q = v * (1.0 - s * f) + t = v * (1.0 - s * (1.0 - f)) + i = i % 6 + if i == 0: + return v, t, p + if i == 1: + return q, v, p + if i == 2: + return p, v, t + if i == 3: + return p, q, v + if i == 4: + return t, p, v + if i == 5: + return v, p, q + + +# Simple function to clamp a value between 0.0 and 1.0 +def clamp01(value): + return max(min(value, 1.0), 0.0) + + +# Sleep until a specific time in the future. Use this instead of time.sleep() to correct for +# inconsistent timings when dealing with complex operations or external communication +def sleep_until(end_time): + time_to_sleep = time.ticks_diff(end_time, time.ticks_us()) + if time_to_sleep > 0: + time.sleep_us(time_to_sleep) + + +while True: + # Record the start time of this loop + start_time = time.ticks_us() + + # If up is pressed, increase the brightness + if wheel.pressed(UP): + brightness += BRIGHTNESS_STEP + changed = True # Trigger a change + + # If down is pressed, decrease the brightness + if wheel.pressed(DOWN): + brightness -= BRIGHTNESS_STEP + changed = True # Trigger a change + + # If right is pressed, increase the saturation + if wheel.pressed(RIGHT): + saturation += SATURATION_STEP + changed = True # Trigger a change + + # If left is pressed, decrease the saturation + if wheel.pressed(LEFT): + saturation -= SATURATION_STEP + changed = True # Trigger a change + + # Limit the brightness and saturation between 0.0 and 1.0 + brightness = clamp01(brightness) + saturation = clamp01(saturation) + + # Check if the encoder has been turned + if wheel.delta() != 0: + # Update the position based on the count change + position = wheel.step() + changed = True # Trigger a change + + # If centre is pressed, trigger a change + centre_pressed = wheel.pressed(CENTRE) + if centre_pressed != last_centre_pressed: + changed = True + last_centre_pressed = centre_pressed + + # Was a change triggered? + if changed: + # Print the colour at the current hue, saturation, and brightness + r, g, b = [int(c * 255) for c in hsv_to_rgb(position / NUM_LEDS, saturation, brightness)] + + # Set the LED at the current position to either the actual colour, + # or an inverted version to show a "selection marker" + if centre_pressed: + wheel.set_rgb(position, r, g, b) + else: + wheel.set_rgb(position, 255, 255, 255) + + # Set the LEDs below the current position + for i in range(0, position): + wheel.set_hsv(i, i / NUM_LEDS, saturation, brightness) + + # Set the LEDs after the current position + for i in range(position + 1, NUM_LEDS): + wheel.set_hsv(i, i / NUM_LEDS, saturation, brightness) + wheel.show() + changed = False + + # set unicron + graphics.set_pen(graphics.create_pen(0, 0, 0)) + graphics.clear() + # draw background + graphics.set_pen(graphics.create_pen(30, 30, 30)) + graphics.rectangle(0, 1, 16, 4) + graphics.rectangle(0, 6, 16, 4) + graphics.rectangle(0, 11, 16, 4) + # draw bars + graphics.set_pen(graphics.create_pen(r, g, b)) + graphics.rectangle(0, 1, int(r / 255 * 16), 4) + graphics.rectangle(0, 6, int(g / 255 * 16), 4) + graphics.rectangle(0, 11, int(b / 255 * 16), 4) + # draw labels + graphics.set_pen(graphics.create_pen(255, 0, 0)) + graphics.rectangle(0, 1, 1, 4) + graphics.set_pen(graphics.create_pen(0, 255, 0)) + graphics.rectangle(0, 6, 1, 4) + graphics.set_pen(graphics.create_pen(0, 0, 255)) + graphics.rectangle(0, 11, 1, 4) + su.update(graphics) + + # Sleep until the next update, accounting for how long the above operations took to perform + sleep_until(time.ticks_add(start_time, UPDATE_RATE_US)) From 3786cbdfe6d3299d9b81c2079f4feb54c8646fb7 Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Mon, 3 Jul 2023 13:18:18 +0100 Subject: [PATCH 13/15] Stellar: correct typo --- micropython/examples/stellar_unicorn/thermometer_pico.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micropython/examples/stellar_unicorn/thermometer_pico.py b/micropython/examples/stellar_unicorn/thermometer_pico.py index 21524af6..b1b8d3e7 100644 --- a/micropython/examples/stellar_unicorn/thermometer_pico.py +++ b/micropython/examples/stellar_unicorn/thermometer_pico.py @@ -95,7 +95,7 @@ while True: # or uncomment these lines if you'd prefer it in Freedom Units # graphics.set_pen(WHITE) - # fahrenheit = (temperature_average * 9 / 5) + 32 + # fahrenheit = (temperature * 9 / 5) + 32 # graphics.text(f"{fahrenheit:.0f}°", 2, 5, scale=1) # time to update the display From 1d1b521dfbca6d565d7a661333ad4e59259a5837 Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Mon, 3 Jul 2023 14:29:56 +0100 Subject: [PATCH 14/15] stellar: add BME280 and BME68x examples --- .../examples/stellar_unicorn/README.md | 14 ++ .../stellar_unicorn/thermometer_bme280.py | 134 ++++++++++++++++++ .../stellar_unicorn/thermometer_bme68x.py | 134 ++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 micropython/examples/stellar_unicorn/thermometer_bme280.py create mode 100644 micropython/examples/stellar_unicorn/thermometer_bme68x.py diff --git a/micropython/examples/stellar_unicorn/README.md b/micropython/examples/stellar_unicorn/README.md index 608803ae..d7c1f788 100644 --- a/micropython/examples/stellar_unicorn/README.md +++ b/micropython/examples/stellar_unicorn/README.md @@ -24,6 +24,8 @@ - [Other Examples](#other-examples) - [CO2](#co2) - [Encoder Wheel](#encoder-wheel) + - [Thermometer (BME280)](#thermometer-bme280) + - [Thermometer (BME68x)](#thermometer-bme68x) - [Launch (Demo Reel)](#launch-demo-reel) ## About Stellar Unicorn @@ -180,6 +182,8 @@ The examples in the folder use `numpy`-like array functions contained in the `ul ## Other Examples +These examples use additional hardware. + ### CO2 [co2.py](co2.py) @@ -193,6 +197,16 @@ This example uses a custom tiny bitmap font, find 3x5.bitmapfont in [fonts](../. This example uses [RGB Encoder Wheel breakout](https://shop.pimoroni.com/products/rgb-encoder-wheel-breakout) to make an RGB colour picker. Use the encoder wheel to pick a hue and view the RGB breakdown of that colour on the Unicorn display (you can adjust saturation and brightness using the buttons on the breakout too). +### Thermometer (BME280) +[thermometer_bme280.py](thermometer_bme280.py) + +Shows temperature, humidity and pressure (from a [BME280 sensor breakout](https://shop.pimoroni.com/products/bme280-breakout)) against an appropriately coloured pulsing blob. + +### Thermometer (BME68x) +[thermometer_bme68x.py](thermometer_bme68x.py) + +Shows temperature, humidity and pressure (from a [BME680](https://shop.pimoroni.com/products/bme680-breakout) or [BME688](https://shop.pimoroni.com/products/bme688-breakout) sensor breakout) against an appropriately coloured pulsing blob. + ### Launch (Demo Reel) [launch](launch) diff --git a/micropython/examples/stellar_unicorn/thermometer_bme280.py b/micropython/examples/stellar_unicorn/thermometer_bme280.py new file mode 100644 index 00000000..bcbd22ab --- /dev/null +++ b/micropython/examples/stellar_unicorn/thermometer_bme280.py @@ -0,0 +1,134 @@ +import time +from stellar import StellarUnicorn +from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN +from pimoroni_i2c import PimoroniI2C +from pimoroni import BREAKOUT_GARDEN_I2C_PINS +from breakout_bme280 import BreakoutBME280 + +""" +Reads the temperature from a BME280 +... and displays an appropriately coloured pulsing blob. + +Buttons: +A - Show temperature +B - Show humidity +C - Show pressure +""" + +# The range of readings that we want to map to colours +MIN = 10 +MAX = 30 + +# pick what bits of the colour wheel to use (from 0-360°) +# https://www.cssscript.com/demo/hsv-hsl-color-wheel-picker-reinvented/ +HUE_START = 230 # blue +HUE_END = 359 # red + +# rainbow party mode +rainbow_orb = False + +# set up the Unicron +su = StellarUnicorn() +graphics = PicoGraphics(DISPLAY_STELLAR_UNICORN) + +# set up the sensor +i2c = PimoroniI2C(**BREAKOUT_GARDEN_I2C_PINS) +bme = BreakoutBME280(i2c) + +# set up constants and variables for drawing +WIDTH, HEIGHT = graphics.get_bounds() + +BLACK = graphics.create_pen(0, 0, 0) +WHITE = graphics.create_pen(255, 255, 255) + +forward = True +orb_brightness = 0.5 +hue = 0.0 +mode = "temperature" + +graphics.set_font("bitmap8") + +while True: + + if su.is_pressed(StellarUnicorn.SWITCH_A): + mode = "temperature" + print(f"mode = {mode}") + + elif su.is_pressed(StellarUnicorn.SWITCH_B): + mode = "humidity" + print(f"mode = {mode}") + + elif su.is_pressed(StellarUnicorn.SWITCH_C): + mode = "pressure" + print(f"mode = {mode}") + + # read the onboard sensor + # the following two lines do some maths to convert the number from the temp sensor into celsius + temperature, pressure, humidity = bme.read() + + print(f""" + Temperature: {temperature:.2f} °C + Humidity: {humidity:.2f} % + Pressure: {pressure/100:.2f} hPa + """) + + # fills the screen with black + graphics.set_pen(BLACK) + graphics.clear() + + # draw a weird orb: + # three overlapping circles with varying saturations + if rainbow_orb is True: + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.5, orb_brightness)) + graphics.circle(8, 8, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.7, orb_brightness)) + graphics.circle(7, 7, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, orb_brightness)) + graphics.circle(7, 7, 5) + hue += 0.01 * 360 + else: + # calculate a colour from the temperature + hue = max(0, HUE_START + ((temperature - MIN) * (HUE_END - HUE_START) / (MAX - MIN))) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.6, orb_brightness)) + graphics.circle(8, 8, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.8, orb_brightness)) + graphics.circle(7, 7, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, orb_brightness)) + graphics.circle(7, 7, 5) + + # pulse the orb! + if forward is True: + orb_brightness += 0.01 + if orb_brightness >= 0.7: + orb_brightness = 0.7 + forward = False + + if forward is False: + orb_brightness -= 0.01 + if orb_brightness <= 0.3: + orb_brightness = 0.3 + forward = True + + # select a pen colour for the text + # try BLACK for a funky negative space effect + graphics.set_pen(WHITE) + + if mode == "temperature": + graphics.text(f"{temperature:.0f}°", 2, 5, scale=1) + # or uncomment these lines if you'd prefer it in Freedom Units + # fahrenheit = (temperature * 9 / 5) + 32 + # graphics.text(f"{fahrenheit:.0f}°", 2, 5, scale=1) + + if mode == "humidity": + graphics.text(f"{humidity:.0f}%", 1, 5, scale=1) + + if mode == "pressure": + if pressure/100 < 1000: + graphics.text(f"{pressure/100:.0f} hPa", 1, 0, WIDTH, scale=1) + else: + pressure_string = str(pressure/100) + graphics.text(f"{pressure_string[0]}.{pressure_string[1]}k hPa", 0, 0, WIDTH, scale=1) + + # time to update the display + su.update(graphics) + time.sleep(0.1) diff --git a/micropython/examples/stellar_unicorn/thermometer_bme68x.py b/micropython/examples/stellar_unicorn/thermometer_bme68x.py new file mode 100644 index 00000000..d5f98bf4 --- /dev/null +++ b/micropython/examples/stellar_unicorn/thermometer_bme68x.py @@ -0,0 +1,134 @@ +import time +from stellar import StellarUnicorn +from picographics import PicoGraphics, DISPLAY_STELLAR_UNICORN +from pimoroni_i2c import PimoroniI2C +from pimoroni import BREAKOUT_GARDEN_I2C_PINS +from breakout_bme68x import BreakoutBME68X + +""" +Reads the temperature from a BME680 or BME688 +... and displays an appropriately coloured pulsing blob. + +Buttons: +A - Show temperature +B - Show humidity +C - Show pressure +""" + +# The range of readings that we want to map to colours +MIN = 10 +MAX = 30 + +# pick what bits of the colour wheel to use (from 0-360°) +# https://www.cssscript.com/demo/hsv-hsl-color-wheel-picker-reinvented/ +HUE_START = 230 # blue +HUE_END = 359 # red + +# rainbow party mode +rainbow_orb = False + +# set up the Unicron +su = StellarUnicorn() +graphics = PicoGraphics(DISPLAY_STELLAR_UNICORN) + +# set up the sensor +i2c = PimoroniI2C(**BREAKOUT_GARDEN_I2C_PINS) +bme = BreakoutBME68X(i2c) + +# set up constants and variables for drawing +WIDTH, HEIGHT = graphics.get_bounds() + +BLACK = graphics.create_pen(0, 0, 0) +WHITE = graphics.create_pen(255, 255, 255) + +forward = True +orb_brightness = 0.5 +hue = 0.0 +mode = "temperature" + +graphics.set_font("bitmap8") + +while True: + + if su.is_pressed(StellarUnicorn.SWITCH_A): + mode = "temperature" + print(f"mode = {mode}") + + elif su.is_pressed(StellarUnicorn.SWITCH_B): + mode = "humidity" + print(f"mode = {mode}") + + elif su.is_pressed(StellarUnicorn.SWITCH_C): + mode = "pressure" + print(f"mode = {mode}") + + # read the onboard sensor + # the following two lines do some maths to convert the number from the temp sensor into celsius + temperature, pressure, humidity, gas, status, _, _ = bme.read() + + print(f""" + Temperature: {temperature:.2f} °C + Humidity: {humidity:.2f} % + Pressure: {pressure/100:.2f} hPa + """) + + # fills the screen with black + graphics.set_pen(BLACK) + graphics.clear() + + # draw a weird orb: + # three overlapping circles with varying saturations + if rainbow_orb is True: + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.5, orb_brightness)) + graphics.circle(8, 8, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.7, orb_brightness)) + graphics.circle(7, 7, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, orb_brightness)) + graphics.circle(7, 7, 5) + hue += 0.01 * 360 + else: + # calculate a colour from the temperature + hue = max(0, HUE_START + ((temperature - MIN) * (HUE_END - HUE_START) / (MAX - MIN))) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.6, orb_brightness)) + graphics.circle(8, 8, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 0.8, orb_brightness)) + graphics.circle(7, 7, 7) + graphics.set_pen(graphics.create_pen_hsv((hue / 360), 1.0, orb_brightness)) + graphics.circle(7, 7, 5) + + # pulse the orb! + if forward is True: + orb_brightness += 0.01 + if orb_brightness >= 0.7: + orb_brightness = 0.7 + forward = False + + if forward is False: + orb_brightness -= 0.01 + if orb_brightness <= 0.3: + orb_brightness = 0.3 + forward = True + + # select a pen colour for the text + # try BLACK for a funky negative space effect + graphics.set_pen(WHITE) + + if mode == "temperature": + graphics.text(f"{temperature:.0f}°", 2, 5, scale=1) + # or uncomment these lines if you'd prefer it in Freedom Units + # fahrenheit = (temperature * 9 / 5) + 32 + # graphics.text(f"{fahrenheit:.0f}°", 2, 5, scale=1) + + if mode == "humidity": + graphics.text(f"{humidity:.0f}%", 1, 5, scale=1) + + if mode == "pressure": + if pressure/100 < 1000: + graphics.text(f"{pressure/100:.0f} hPa", 1, 0, WIDTH, scale=1) + else: + pressure_string = str(pressure/100) + graphics.text(f"{pressure_string[0]}.{pressure_string[1]}k hPa", 0, 0, WIDTH, scale=1) + + # time to update the display + su.update(graphics) + time.sleep(0.1) From 52df18e550b3e577aa04fbb3bd661e4dfc9afbf1 Mon Sep 17 00:00:00 2001 From: Hel Gibbons Date: Mon, 3 Jul 2023 14:34:10 +0100 Subject: [PATCH 15/15] stellar: lint BME280/68x examples --- micropython/examples/stellar_unicorn/thermometer_bme280.py | 6 +++--- micropython/examples/stellar_unicorn/thermometer_bme68x.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/micropython/examples/stellar_unicorn/thermometer_bme280.py b/micropython/examples/stellar_unicorn/thermometer_bme280.py index bcbd22ab..f4137c4e 100644 --- a/micropython/examples/stellar_unicorn/thermometer_bme280.py +++ b/micropython/examples/stellar_unicorn/thermometer_bme280.py @@ -123,10 +123,10 @@ while True: graphics.text(f"{humidity:.0f}%", 1, 5, scale=1) if mode == "pressure": - if pressure/100 < 1000: - graphics.text(f"{pressure/100:.0f} hPa", 1, 0, WIDTH, scale=1) + if pressure / 100 < 1000: + graphics.text(f"{pressure / 100:.0f} hPa", 1, 0, WIDTH, scale=1) else: - pressure_string = str(pressure/100) + pressure_string = str(pressure / 100) graphics.text(f"{pressure_string[0]}.{pressure_string[1]}k hPa", 0, 0, WIDTH, scale=1) # time to update the display diff --git a/micropython/examples/stellar_unicorn/thermometer_bme68x.py b/micropython/examples/stellar_unicorn/thermometer_bme68x.py index d5f98bf4..f01045c2 100644 --- a/micropython/examples/stellar_unicorn/thermometer_bme68x.py +++ b/micropython/examples/stellar_unicorn/thermometer_bme68x.py @@ -123,10 +123,10 @@ while True: graphics.text(f"{humidity:.0f}%", 1, 5, scale=1) if mode == "pressure": - if pressure/100 < 1000: - graphics.text(f"{pressure/100:.0f} hPa", 1, 0, WIDTH, scale=1) + if pressure / 100 < 1000: + graphics.text(f"{pressure / 100:.0f} hPa", 1, 0, WIDTH, scale=1) else: - pressure_string = str(pressure/100) + pressure_string = str(pressure / 100) graphics.text(f"{pressure_string[0]}.{pressure_string[1]}k hPa", 0, 0, WIDTH, scale=1) # time to update the display