EV3 Mailboxes in Python

Recently I wanted to enter the Alexa / LEGO MINDSTORMS challenge:

https://www.hackster.io/contests/alexa-lego-voice-challenge

My idea required being able to send EV3 Mailbox messages via Bluetooth between ev3dev and a stock EV3 running the EV3g language – from Python. I’m new to Python, I’m a Perl programmer at heart, so this was somewhat of a learning curve moment. I had to get to grips with Bluetooth (not that difficult as I’m used the IP networking) and Python at the same time.

I figured that one of the major selling points of Python was its extensive library of support functions, so set to looking for something providing EV3 Mailbox handling. My research wasn’t as fruitful as I’d hoped for. I could find various chunks of code but either they were flawed in their behaviour, or much more heavyweight than I wanted. So I decided to jump in feet first and write my own library.

I’d written a library for App Inventor 2 [0] [1] [2] [3] [4] that would encode & decode EV3 Mailbox payloads before, so this wasn’t too daunting a task. One aspect of Mailbox messages is that there isn’t an identifier within the payload that identifies the content: String, Float (IEE754 32 bit), Boolean. Normally this is handled in EV3g by expecting a specific type relating to the message name – i.e. a message called “status” would be defined to always be a Boolean, but “command” would always be a String – the code forces the type to remain constant. However, the type of the payload can be deduced to some extent, so I decide that I’d implement that within the Python class:

  • Payload length = 1 byte => Boolean
  • Payload length = 4 bytes
    • Last byte != NULL or NULL in the other bytes => Float
    • Otherwise => String
  • All other payloads => String

The only issue with the logic above is that really, really, small numbers may get decoded as strings, e.g. “@@@\x00” would get seen as a string, not 5.90052e-39 which is also a valid decode of it. As such I also implemented a .force_float() method which will re-decode the payload.

The git repo for this library can be found at:

https://gitlab.com/Jander/ev3-mailbox-python

To use it do something like:

from ev3mailbox import EV3Mailbox as Mailbox

message = EV3Mailbox.encode("Name", "Message value", Mailbox.Type.TEXT)
print(message)

# Data from Bluetooth
 mailbox = EV3Mailbox.decode(payload)
 print(mailbox)

Hopefully this will prove useful to others. The code has been released under the GPLv3: https://www.gnu.org/licenses/gpl-3.0.txt

4 thoughts on “EV3 Mailboxes in Python”

  1. Why not just pass Mailbox.Type.TEXT to EV3Mailbox.decode() instead of trying to automatically figure out the data type?

    1. The issue is that you can’t tell what to decode a message as until you know its name. The name and the contents are in the same payload. For example: I send two messages from the EV3g, one called “Fred” and is a String, the other called “Bert” which is a Float. I couldn’t call .decode() on the message with a type – until I knew what the message name was I couldn’t provide a type. You’d have to partially decode the message to get its name, and hence its related type. Once you knew its type, you would then have to call a second decode method.

      I did do this in an earlier version of the class:

      if __name__ == '__main__':
          tests = [
              ["string","mortimer",Mailbox.Type.TEXT],
              ["true",True,Mailbox.Type.BOOL],
              ["T",True,Mailbox.Type.BOOL],
              ["false",False,Mailbox.Type.BOOL],
              ["F",False,Mailbox.Type.BOOL],
              ["number",3.141,Mailbox.Type.NUMBER],
          ]
      
          for test in tests:
              message = Mailbox.encode(test[0], test[1], test[2])
              print(message)
              print(Mailbox.raw_bytes(message))
              name, content = Mailbox.unpack(message)
              print(name, content)
              value = Mailbox.decode(content, test[2])
              print(value)

      However, I figured that it was possible to deduce the content of the message in the vast majority of cases so have gone for that as it’s far simpler to use.

      1. For clarity, see the code below. It sends, at different times, three different messages (names and types):

        Sending Different Mailbox Types

        At the ev3dev/Python end I could have a thread that is simply receiving these message payloads, but cannot know beforehand what they are, so cannot assume the type. With the auto-decode functionality it would be possible for the thread to maintain a dict of messages, by name, and what their value & type is which could be used by another thread – similar to the way that a thread in EV3g can wait on an update to a message name.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.