M5stack AtomS3 Animated Gifs Loop

Here’s a fun proof of concept config for the M5Stack Atom S3, showing off some animated gifs. You can use any 128x128 pixel gifs but keep in mind that they take up a ton of space in the firmware image. The code simply loops through the list of gifs, changing every 6 seconds.

This method should work for other esp32s3 devices with displays.

esphome:
  name: atoms3
  friendly_name: AtomS3
  platformio_options:
    board_upload.maximum_ram_size: 327680 
    board_upload.maximum_size: 8388608
  on_boot:
    - priority: 800
      then:
        - lambda: |-
            id(disp).enable();
            id(disp).transfer_byte(0x11);
            id(disp).disable();
esp32:
  board: m5stack-atoms3
  variant: esp32s3
  flash_size: 8MB
  framework:
    type: esp-idf
    version: 5.1.1
    platform_version: 6.4.0

# Enable logging
logger:
  level: ERROR

# Enable Home Assistant API
api:
  encryption:
    key: "<YOURKEYHERE>"

ota:
  password: "<YOUROTAPASSWORD>"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
    
substitutions:
  name: "atoms3"
  device_name: "AtomS3"

# esp32_ble_tracker:

# bluetooth_proxy:
#   active: true

#G4=IR
# remote_transmitter:
#   pin: GPIO4
#   carrier_duty_percent: 50%

i2c:
  - id: bus_a
    sda: GPIO38
    scl: GPIO39

sensor:
  - platform: mpu6886
    address: 0x68
    accel_x:
      name: "$device_name MPU6886 Accel X"
    accel_y:
      name: "$device_name MPU6886 Accel Y"
    accel_z:
      name: "$device_name MPU6886 Accel z"
    gyro_x:
      name: "$device_name MPU6886 Gyro X"
    gyro_y:
      name: "$device_name MPU6886 Gyro Y"
    gyro_z:
      name: "$device_name MPU6886 Gyro z"
    temperature:
      name: "$device_name MPU6886 Temperature"

spi:
  clk_pin: GPIO17
  mosi_pin: GPIO21

# color:
#   - id: my_red
#     red: 100%
#     green: 0%
#     blue: 0%
#   - id: my_yellow
#     red: 100%
#     green: 100%
#     blue: 0%
#   - id: my_green
#     red: 0%
#     green: 100%
#     blue: 0%
#   - id: my_blue
#     red: 0%
#     green: 0%
#     blue: 100%
#   - id: my_gray
#     red: 50%
#     green: 50%
#     blue: 50%

font:
  - file: "gfonts://Roboto"
    id: roboto_32
#     size: 32
#   - file: "gfonts://Roboto"
#     id: roboto_24
#     size: 24
#   - file: "gfonts://Roboto"
#     id: roboto_12
#     size: 12

time:
  - platform: homeassistant
    id: esptime

globals:
  - id: current
    type: int
    restore_value: no
    initial_value: '0'
  - id: last_loop_time
    type: uint32_t
    restore_value: no
    initial_value: '0'
  - id: gifs
    type: std::vector<esphome::animation::Animation*>
    restore_value: no

animation:
  - file: "_gifs_128x128/mariokart.gif"
    id: mariokart
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/blinky.gif"
    id: blinky
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/bmo.gif"
    id: bmo
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/clyde.gif"
    id: clyde
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/peach.gif"
    id: peach
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/megaman.gif"
    id: megaman
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/kirby.gif"
    id: kirby
    type: RGB565
    resize: 128x128

  - file: "_gifs_128x128/galaga.gif"
    id: galaga
    type: RGB565
    resize: 128x128

interval:
  - interval: 0.2s
    then:
      lambda: |-
        id(gifs) = {
          id(mariokart),
          id(blinky),
          id(bmo),
          id(clyde),
          id(peach),
          id(megaman),
          id(kirby),
          id(galaga)
        };
        id(gifs)[id(current)]->next_frame();
display:
  - platform: st7789v # https://esphome.io/components/display/st7789v.html
    id: disp
    model: Custom
    rotation: 180
    backlight_pin: GPIO16
    cs_pin: GPIO15
    dc_pin: GPIO33
    reset_pin: GPIO34
    height: 128
    width: 128
    offset_height: 2
    offset_width: 1
    eightbitcolor: true
    update_interval: 0.2s
    lambda: |-
      uint32_t current_time = id(esptime).now().timestamp;
      uint32_t elapsed_time = current_time - id(last_loop_time);
      if (elapsed_time >= 6) {
        id(current) = (id(current) + 1) % id(gifs).size();
        id(last_loop_time) = current_time;
      }
      it.image(0, 0, id(gifs)[id(current)], COLOR_ON, COLOR_OFF);
#G41=Button
binary_sensor:
  - platform: status
    name: "Node Status"
    id: system_status
  - platform: gpio
    name: Button
    pin:
      number: GPIO41
      inverted: true
      mode:
        input: true
        pullup: true
    filters:
      - delayed_off: 10ms
    on_press:
      then:
        - logger.log: Button Pressed
2 Likes

i have a questrion i use the “SH1106 128x64” display and the “ssd1306_i2c” platform, an my esp32 wroom 32 but my problem is the Gif is to slow, i must be played much faster.

i use

the display

display:
  - platform: ssd1306_i2c
    model: "SH1106 128x64"
    update_interval: 0.2s
    address: "0x3C"
    id: my_display
 it.image(64, 8, id(loading_gif), ImageAlign::TOP_CENTER, COLOR_ON, COLOR_OFF);

and

interval:
  - interval: 0.2s
    then:
      lambda: |-
        id(loading_gif).next_frame(); 

and the gif

animation:
  - file: "_gifs/loading_2.gif"
    id: loading_gif
    resize: 100x50
    use_transparency: true
    #type: GRAYSCALE

the animation

loading_3

have you a hint for me ?