but is there something about arduino that requires using latin-1?
No, not really.
What it comes down to is that
Serial.read() reads bytes, irrespective of whatever encoding they may be being used with. ISO-8859 only encodes character code points in the 0-255 range, so when you choose a 0-255 code point and send it as ISO-8859, it gets sent as 1 byte, which is how you're code has been written to receive it.
A 255 code point as utf-8 would require multiple bytes to encode and so would result in multiple
Serial.read() calls for a given value.
If you open a python3 REPL and put
chr(255).encode() or more explicitly
chr(255).encode('utf-8') you will see it results in
b'\xc3\xbf'. So on the Arduino side you will see this as two separate
When you're just taking in strings and UTF-8 and splatting them out via
Serial.println(), the Arduino is blissfully unaware of that they're UTF-8 and not ISO-8859. Really you could use any encoding you wanted, the the caveat being that if you're using c-strings to store them, the encoding would need to be one that doens't allow for a single null byte to be in the middle of the string.
You may want to look into using struct.pack rather than cobbling together python bytestrings with sequences of
struct.pack will also result in a bytestring, but it's more purpose built for doing this.
import struct and then
struct.pack('B', 255) will result in
b'\xff same as
chr(255).encode('iso8859-1'), but at least expresses intent.
'B' here signifies an
unsigned char range, you'll find the format specifiers in the documentation. You'll get a greater benefit when you begin using multiple fields where
struct.pack will be a lot less unwieldy than the
encode and string concatenation.