Here we go, easy work-around for the faulty lcd.image():
from m5stack import *
buffer = open("/sd/images/test.jpg").read()
lcd.image_buff(lcd.CENTER, lcd.CENTER, buffer)
Here we go, easy work-around for the faulty lcd.image():
from m5stack import *
buffer = open("/sd/images/test.jpg").read()
lcd.image_buff(lcd.CENTER, lcd.CENTER, buffer)
Adding upip
to the firmware image would make developer's live much easier.
How to manually install the urllib.parse
library.
Create folder /upip
and add files upip.py and upip_utarfile.py manually.
Install the library with upip:
%cd /flash/upip
import upip
upip.install("micropython-urllib.parse", "/flash/lib")
To get it working, remove re.py
and ffilib.py
from lib
. Hat-tip to Andreas.
Finally you can encode URL parameters for GET requests:
%cd /flash/lib
import urllib.parse
urllib.parse.urlencode({"a":1, "b": 2})
=> 'a=1&b=2'
In the forum I read that there is some advanced touch/swipe functionality available for the Arduino language.
Will there be high level touch/swipe functions for UIFlow?
I would like to do some photo swiping/scrolling on my Core2, like on a smart phone.
Cheers
Mike
I create a GUI with Labels and Touch Buttons, then I want to clear the screen and draw a clock. But even though I hide the elements and delete them, they are still shown as white outline.
How to fully hide GUI designer elements to have a blank screen to draw onto?
@kuriko Wow, this is cool! Core2 UIFlow v1 is in WiFi mode, but with "Terminal (Beta)" I can connect over the USB serial console. The play button will upload and run the current script, even with timers.
Would be very cool if the whole UIFlow web IDE had a setting to just connect via cable. Or if the Terminal play button could be placed somewhere in the IDE, without having the terminal window open all the time.
Side note: The regular UIFlow web IDE play button now shows a green success message "Execute code successfully" when clicked, but the code is actually not running on the device. Either it's not uploaded or not restarted.
@kuriko So I have downgraded to UIFlow v1 firmware on the Core2 again. I started the UIFlow web IDE in Chrome, expected it to have some web serial support (like CircuitPython has a web flasher), but I can not find any settings for USB or serial.
The download page (link) states "Desktop IDE MacOS (update is terminated)", so do I need to run "UIFlow Local Server for MacOS"? The regular UIFlow web IDE only supports WiFi connection?
The local m5burner software worked without a problem with USB /tty.usbserial
.
@robski Found and added RTC and Timer. In UIFlow v2 the WiFi connection still works when using the timer and updating a label every second. I can still update and run code.
I started with M5Stack hardware in 2020 and I am a bit surprised that some functions are still not there in 2024 in UIFlow:
It seems UIFlow2 lost the "Touch Button" in the GUI designer using rounded rectangle with text and on_touch event.
It seems there is no way to design multiple screens or views. It's great to have a graphical GUI designer, but how can you only have one single view and not be able to switch between multiple in designer and via code?
It seems there are no graphics functions in UIFlow v2. I want to programmatically draw an analogue clock (circle, 12x dashes, 3x hands), that seems not possible anymore.
When using graphics functions, it would be great to be able to draw on screen or on a virtual screen, then updating the real screen as a whole.
Should I create separate "feature requests" for those things?
@robski The device is still connected when I run a "regular" program. It seems still to be connected when running a program with timer or while true: sleep(1)
, but as soon as I press "Run", the Connected
turns into Disconnected
.
@kuriko Wanted to try serial, but pressed the "Download" button to save the file. Instead it uploaded the program to the device. Funnily it said first "Upload failed", on second try it was successful. So the naming convention (meaning) seems to be different, even within UIFlow ;-) I would have expected for "Download" to save the file to computer, and rather have something like "Upload" to save it as main program on device. MAybe I try this later
@robski Upgraded to UIFlow 2, was surprised to need to register and bind the device. Can't find a button element, cant find a timer, neither software nor hardware.
@ajb2k3 I am aware to be able to reset the device to re-run, but that's not the point. I can edit end re-run a program via WiFi many times. Just the use of timer or while true: sleep(1)
seems to disable the Wifi connection or the internal software to receive updates from UIFlow web IDE.
Will continue to investigate in an hour or so.
I am trying to use a timer in UIFlow to show the current time. When using "Run" in UIFlow web IDE, it will upload and run the program on Core2 once.
But every time I try to "Run" again, when the program is already running, I get an error in UIFlow web IDE: "Upload code failed, maybe your device is offline check it and retry"
I tried with both the hardware timer and the software timer. I also tried a loop with "Wait 1s". But every time I do this, the UIFlow web IDE can't upload anymore, it worked perfectly before.
What should I change in my code to have the device work with UIFlow web IDE and use a timer to update UI every second?
+1 for something like pages / screens / views
Just getting back into M5Stack hardware, got an idea I want to implement, created the first screen with some select buttons, then got stuck as I found no way to create multiple views and switch between them.
Tried to clear the screen, and draw something, but the buttons are still visible as white rectangles, even when set to hidden.
Adding upip
to the firmware image would make developer's live much easier.
How to manually install the urllib.parse
library.
Create folder /upip
and add files upip.py and upip_utarfile.py manually.
Install the library with upip:
%cd /flash/upip
import upip
upip.install("micropython-urllib.parse", "/flash/lib")
To get it working, remove re.py
and ffilib.py
from lib
. Hat-tip to Andreas.
Finally you can encode URL parameters for GET requests:
%cd /flash/lib
import urllib.parse
urllib.parse.urlencode({"a":1, "b": 2})
=> 'a=1&b=2'
I am currently playing around with some web services and libraries, it mostly fails because most of those MicroPython programs require urllib.parse
to be installed, mostly for urlencode()
.
It would be great to get urllib.parse and its dependencies into the base firmware image.
Cheers
Mike
Well, and there is always the option to just strip it down to the basics.
# urlencode.py
_ALWAYS_SAFE = frozenset(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz'
b'0123456789'
b'_.-')
_ALWAYS_SAFE_BYTES = bytes(_ALWAYS_SAFE)
def quote(string, safe='/', encoding=None, errors=None):
"""quote('abc def') -> 'abc%20def'
Each part of a URL, e.g. the path info, the query, etc., has a
different set of reserved characters that must be quoted.
RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
the following reserved characters.
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
"$" | ","
Each of these characters is reserved in some component of a URL,
but not necessarily in all of them.
By default, the quote function is intended for quoting the path
section of a URL. Thus, it will not encode '/'. This character
is reserved, but in typical usage the quote function is being
called on a path where the existing slash characters are used as
reserved characters.
string and safe may be either str or bytes objects. encoding must
not be specified if string is a str.
The optional encoding and errors parameters specify how to deal with
non-ASCII characters, as accepted by the str.encode method.
By default, encoding='utf-8' (characters are encoded with UTF-8), and
errors='strict' (unsupported characters raise a UnicodeEncodeError).
"""
if isinstance(string, str):
if not string:
return string
if encoding is None:
encoding = 'utf-8'
if errors is None:
errors = 'strict'
string = string.encode(encoding, errors)
else:
if encoding is not None:
raise TypeError("quote() doesn't support 'encoding' for bytes")
if errors is not None:
raise TypeError("quote() doesn't support 'errors' for bytes")
return quote_from_bytes(string, safe)
def quote_plus(string, safe='', encoding=None, errors=None):
"""Like quote(), but also replace ' ' with '+', as required for quoting
HTML form values. Plus signs in the original string are escaped unless
they are included in safe. It also does not have safe default to '/'.
"""
# Check if ' ' in string, where string may either be a str or bytes. If
# there are no spaces, the regular quote will produce the right answer.
if ((isinstance(string, str) and ' ' not in string) or
(isinstance(string, bytes) and b' ' not in string)):
return quote(string, safe, encoding, errors)
if isinstance(safe, str):
space = ' '
else:
space = b' '
string = quote(string, safe + space, encoding, errors)
return string.replace(' ', '+')
def quote_from_bytes(bs, safe='/'):
"""Like quote(), but accepts a bytes object rather than a str, and does
not perform string-to-bytes encoding. It always returns an ASCII string.
quote_from_bytes(b'abc def\x3f') -> 'abc%20def%3f'
"""
if not isinstance(bs, (bytes, bytearray)):
raise TypeError("quote_from_bytes() expected bytes")
if not bs:
return ''
if isinstance(safe, str):
# Normalize 'safe' by converting to bytes and removing non-ASCII chars
safe = safe.encode('ascii', 'ignore')
else:
safe = bytes([c for c in safe if c < 128])
if not bs.rstrip(_ALWAYS_SAFE_BYTES + safe):
return bs.decode()
try:
quoter = _safe_quoters[safe]
except KeyError:
_safe_quoters[safe] = quoter = Quoter(safe).__getitem__
return ''.join([quoter(char) for char in bs])
def urlencode(query, doseq=False, safe='', encoding=None, errors=None):
"""Encode a dict or sequence of two-element tuples into a URL query string.
If any values in the query arg are sequences and doseq is true, each
sequence element is converted to a separate parameter.
If the query arg is a sequence of two-element tuples, the order of the
parameters in the output will match the order of parameters in the
input.
The components of a query arg may each be either a string or a bytes type.
When a component is a string, the safe, encoding and error parameters are
sent to the quote_plus function for encoding.
"""
if hasattr(query, "items"):
query = query.items()
else:
# It's a bother at times that strings and string-like objects are
# sequences.
try:
# non-sequence items should not work with len()
# non-empty strings will fail this
if len(query) and not isinstance(query[0], tuple):
raise TypeError
# Zero-length sequences of all types will get here and succeed,
# but that's a minor nit. Since the original implementation
# allowed empty dicts that type of behavior probably should be
# preserved for consistency
except TypeError:
# ty, va, tb = sys.exc_info()
raise TypeError("not a valid non-string sequence "
"or mapping object")#.with_traceback(tb)
l = []
if not doseq:
for k, v in query:
if isinstance(k, bytes):
k = quote_plus(k, safe)
else:
k = quote_plus(str(k), safe, encoding, errors)
if isinstance(v, bytes):
v = quote_plus(v, safe)
else:
v = quote_plus(str(v), safe, encoding, errors)
l.append(k + '=' + v)
else:
for k, v in query:
if isinstance(k, bytes):
k = quote_plus(k, safe)
else:
k = quote_plus(str(k), safe, encoding, errors)
if isinstance(v, bytes):
v = quote_plus(v, safe)
l.append(k + '=' + v)
elif isinstance(v, str):
v = quote_plus(v, safe, encoding, errors)
l.append(k + '=' + v)
else:
try:
# Is this a sufficient test for sequence-ness?
x = len(v)
except TypeError:
# not a sequence
v = quote_plus(str(v), safe, encoding, errors)
l.append(k + '=' + v)
else:
# loop over the sequence
for elt in v:
if isinstance(elt, bytes):
elt = quote_plus(elt, safe)
else:
elt = quote_plus(str(elt), safe, encoding, errors)
l.append(k + '=' + elt)
return '&'.join(l)
Then we can finally do a nicer GET with parameters:
import urequests
from urlencode import urlencode
url = 'http://server.tld/path/to'
params = {'key1': 'value1', 'key2': 'value2'}
if params:
url = url.rstrip('?') + '?' + urlencode(params, doseq=True)
print(url)
response = urequests.get(url)