How to send a BMP file to the ESP32 file system(SPIFFS) via websocket

Issue #268 resolved
Wenjie Wu created an issue

No description provided.

Comments (16)

  1. John Maloney repo owner

    Is the sending code sending the BMP file as binary data? What language/system is sending the data? Can you post the code that is sending it?

  2. Wenjie Wu reporter

    hi John,

    here is the sending code(Python)

    # pip install pillow websocket-client
    from PIL import Image
    from websocket import create_connection
    
    # create a test  bmp file
    size = (16, 16)
    img = Image.new('RGB', size, "black")
    pixels = img.load()
    for i in range(img.size[0]):
        for j in range(img.size[1]):
            if i == j:
                pixels[i,j] = (255, 0, 0)
            else:
                pixels[i,j] = (0, 255, 0)
    img.save("image.bmp")
    
    # send the file
    ws = create_connection("ws://172.20.10.2:81")
    with open('image.bmp', 'rb') as f: # opening a binary file
        content = f.read()
    ws.send_binary(bytearray(content))
    

  3. John Maloney repo owner

    Thanks! It looks like the MicroBlocks VM (primWebSocketLastEvent) is not correctly handling binary data. (It it reporting it as a string, which means that the first null byte terminates the string.) Will fix.

  4. Wenjie Wu reporter

    The same problem seems to be present in MQTT library

    import paho.mqtt.client as mqtt
    client = mqtt.Client()
    client.username_pw_set('public', 'public')
    client.connect("public.cloud.shiftr.io", 1883, 60)
    client.loop_start()
    ...
    client.publish('bmp', bytearray(content))
    

  5. John Maloney repo owner

    MQTT can handle binary data but you need to set the MQTT buffer size to 1024 (or higher) in order to receive the 822 byte BMP test file. (The default MQTT buffer size is only 128 bytes.)

  6. Wenjie Wu reporter

    hi John , I set the MQTT buffer size to 1024 and 2048, the problem still seems to be the same

  7. John Maloney repo owner

    Are you sure that paho.mqtt.client can handle binary data?

    When I did a test using MicroBlocks to publish the five bytes: 65, 65, 0, 65, 65 I got the expected result. That is, when receiving it as a string I got "AA" because the 0 is the string terminator:

    Screen Shot 2022-05-21 at 7.35.08 AM.png

    When I received in binary, I got five bytes:

    Screen Shot 2022-05-21 at 7.35.19 AM.png

    Based on this test, I think MicroBlocks MQTT is handling binary data as expected.

  8. John Maloney repo owner

    If your goal is simply to save images or other files to the file system of the ESP32/ESP8266, there's an easy way to do that. Using the stand-alone MicroBlocks app (not the webapp), select "show advanced blocks". Then, select "put file on board" from the File menu and select the file you want to save to the board. You can retrieve files from the board using "get file from board".

  9. Wenjie Wu reporter

    Are you sure that paho.mqtt.client can handle binary data?

    I think your test is convincing, the problem may be in paho.mqtt.client, but I didn't find it for now. It's okay, I don't need it for now, just a test.

    If I find the cause afterwards, I'll update here.

  10. John Maloney repo owner

    FYI, I've pushed a fixed version of netPrims.cpp to Bitbucket, in case you want to compile your own VM.

    I'll do a pilot release later today.

  11. Wenjie Wu reporter

    If your goal is simply to save images or other files to the file system of the ESP32/ESP8266, there's an easy way to do that. Using the stand-alone MicroBlocks app (not the webapp), select "show advanced blocks". Then, select "put file on board" from the File menu and select the file you want to save to the board. You can retrieve files from the board using "get file from board".

    It sounds great ! I want to use it to upload some pictures.

    But I also want to transfer images dynamically, about this, I will try in using websocket, I noticed that you have fixed it.

    Thanks!

  12. John Maloney repo owner

    Note that the current WebSocket buffer size is only 1024 bytes. That means that you'll need to split large files into chunks of that size or smaller. That's not too complicated. You'll probably want to implement messages to indicate the start of a file transfer (including the file name) and the end of the file transfer. Those could be text messages (JSON, perhaps). While the file transfer is in progress, each incoming binary message would just be appended to the file. Make sure that the sending side includes a "sleep" to allow time for each binary chunk to be written to the Flash file system. The time for that can vary as the file grows and, because writing to Flash memory is slow (especially if Flash file system blocks need to be erased), the write times can be surprisingly long.

    Actually, now that I think about it, it would be much more robust for the sender waits for an acknowledgement from the sender before sending the next chunk. That way it will adapt to the varying file write speeds.

  13. John Maloney repo owner

    Note that the current WebSocket buffer size is only 1024 bytes. That means that you'll need to split large files into chunks of that size or smaller. That's not too complicated. You'll probably want to implement messages to indicate the start of a file transfer (including the file name) and the end of the file transfer. Those could be text messages (JSON, perhaps). While the file transfer is in progress, each incoming binary message would just be appended to the file. Make sure that the sending side includes a "sleep" to allow time for each binary chunk to be written to the Flash file system. The time for that can vary as the file grows and, because writing to Flash memory is slow (especially if Flash file system blocks need to be erased), the write times can be surprisingly long.

    Actually, now that I think about it, it would be much more robust for the sender to wait for an acknowledgement from the reciver before sending the next chunk. That way it will adapt to the varying file write speeds.

  14. Wenjie Wu reporter

    Actually, now that I think about it, it would be much more robust for the sender to wait for an acknowledgement from the reciver before sending the next chunk. That way it will adapt to the varying file write speeds.

    That's exactly what I did, and it worked fine !

    Thank you for your detailed guidance!

  15. Log in to comment