Search models, users, collections, and posts

HABB - Home Assistant Button Box - ESPHome

Print Profile(2)

All
A1 mini
X1 Carbon
P1S
X1
A1
H2D
P1P
X1E
H2D Pro
H2S
P2S
H2C
X2D
A2L

10x2 Magnets - Settings by Part
10x2 Magnets - Settings by Part
Designer
2.5 h
3 plates
5.0(6)

Desktop Housing - 0.16mm layer, 2 walls, 15% infill
Desktop Housing - 0.16mm layer, 2 walls, 15% infill
4.2 h
1 plate

Open in Bambu Studio
Boost
942
2780
38
56
355
103
Released 

Bill of Materials

Maker's Supply Kits and Parts
Select all
M2x8 BHCS Machine Screw (20PCS) - AA044
M2x14 SHCS Machine Screw (20PCS) - AA152
M2x18 SHCS Machine Screw (10PCS) - AA153
M3x5 FHCS Machine Screw (20PCS) - AA187
M3x6 SHCS Machine Screw (20PCS) - AA036
M2x3.5x6 Round Threaded Brass Heat-Insert Nut (20PCS) - AB010
Bambu Filaments
Select all
Cyan (10603) / Refill / 1kg
Jade White (10100) / Refill / 1kg
Black (10101) / Refill / 1kg
List other parts
  • ESP32 - DEVKIT V1 x 1: 30 Pin Model
  • 1.3" OLED Graphic Display x 1: 128x64 with mounting holes
  • 1x4 Membrane Keypad x 1: 5 Wire Connection

Description

H.A.B.B – Home Assistant Button Box 

A customizable 4-button smart control panel case for ESP32 + OLED display

I designed this for a simple, reliable smart home control interface using an ESP32 DevKit V1, a 1.3” 128x64 OLED Screen, and a 1x4 Membrane Keypad. It connects to Home Assistant via ESPHome and can trigger any scene, script, or automation with the push of a button.

 

This button box is perfect for controlling zones in a workshop, studio, or bedroom—turn on printers, ventilation, lights, or even run automations. I built this mainly for my own workspace to quickly trigger automations without having to pull out my phone or open the HA dashboard. It’s compact, clean, and sticks right to any metal surface with magnets.

 

YAML:  I've included a source code file, but wanted to include the basics here - Full YAML is at the bottom of this post!

Specs: 

Size: 115mm x 67mm x 22mm

 

Designed for:

  • ESP32 DevKit V1 (30-pin)

  • SH1106 1.3" 128x64 OLED Display (SPI)

  • Adafruit-style 1x4 membrane keypad

 

Power: USB-powered through a passthrough cutout

 

Mounting: Fits 4x 10x2mm magnets in the back (optional but recommended)

 

 

Assembly: 

ESP32 clearance: The case is just 22mm thick, so either use an ESP32 without headers or bend the pins you need and snip the rest

I highly recommend assembling and testing the electronics before fully assembling this model! 

Step 1: 

Once you have printed the model, start by installing the ESP32. You can use (2x) or (4x) M3x6mm Screws to secure the ESP32.

 

 

Step 2:

If your screen is equipped with headers, remove them. 

 

 

Step 3:

Take 7 jumper wires and cut off one side of the connectors - I recommend leaving ~ 6 inches of wire to work with; Longer wire is not better in this case 

Strip and Tin the ends of the wires and solder them into place, making sure all contacts are clean and well placed

 

The wires should be pointing away from the solder pads

 

 

 

Step 4: 

Install the M2x6 heat inserts in the Keypad Mount

 

Step 5: 

You'll either need to drill a small hole in the 1x4 membrane keypad, or cut off ~6mm of material from the side of the keypad to clear the screw. 

 

 

With that done, you can install the 1x4 Membrane Keypad using (3x) M2x8mm Button Cap Screws. These only need to be finger-tight; be careful not to overtighten. 

 

 

 

 

Step 6: 

You can now install the OLED Screen using (4x) M3x6mm Hex Cap Screws. I recommend pre-threading these screws before final installation. 

 

SCREEN ORIENTATION MATTERS! Make sure the screen is installed the right way. 

 

 

 

 

Step 7: 

Time to wire this thing up! To help with this, I've included a link to an online interactive wiring diagram! Link HERE

 

Some Wiring Notes: 

 

  • Depending on your specific 1x4 Membrane Keypad, the common ground may be pin 1 or pin 5. Verify the pinout of your model
  • Some hot glue can really help hold down the wires and prevent them from coming loose

 

Step 8: 

Almost Done!

 

Now that the wiring is complete, you can shut the case and install the (2x) countersunk M3x5mm Screws on the sides of the case; Because these thread directly into the plastic, be careful not to overtighten. 

 

 

 

Step 9: 

There are 2 small support surfaces on the backside of the case - remove these ( Circled in Red)

 

You can now install the 10x2 magnets. I've designed these to be push-fit, but feel free to use a little glue if you'd like. 

 

 

 

Step 10 - optional but recommended: 

If you didn't cut your wiring short enough, there's a chance it can push on the front cover, creating a small gap. 

 

The two small screws on the back of the case can help pull the front cover back into alignment, eliminating the gap altogether.

 

The M2x14mm goes towards the top of the case and the M2x18mm screw goes towards the bottom

 

 

 

 

 

All Done! 

Step back and admire your work! 

 

 

YAML:

captive_portal:

 

# SPI bus configuration for the OLED screen

spi:

  clk_pin: GPIO18         # Clock pin for SPI communication

  mosi_pin: GPIO23        # Data pin (Master Out, Slave In)

 

# Loads a font from Google Fonts (Roboto, size 16) to use on the screen

font:

  - file: "gfonts://Roboto"

    id: font1

    size: 16

 

# OLED display setup using SPI connection

display:

  - platform: ssd1306_spi

    model: "SH1106 128x64"        # 1.3" OLED display with SH1106 controller

    cs_pin: GPIO5                 # Chip select pin for SPI

    dc_pin: GPIO16                # Data/Command pin

    reset_pin: GPIO17             # Reset pin for the display

    id: oled_display

    rotation: 180                 # Flips the screen upside down because of how it's mounted

    update_interval: 1s          # Refresh display once per second

 

    # Pages are different views you can show on the screen

    pages:

      - id: page_main

        lambda: |-                # This is the main screen shown by default

          it.print(6, -2, id(font1), "1: Scene 1");

          it.print(6, 12, id(font1), "2: Scene 2");

          it.print(6, 26, id(font1), "3: Scene 3");

          it.print(6, 40, id(font1), "4: Scene 4 ");

 

      # These are the pages shown temporarily after a button press

      - id: page1

        lambda: |-

          it.print(0, 0, id(font1), "Scene 1 triggered");  

 

      - id: page2

        lambda: |-

          it.print(0, 0, id(font1), "Scene 2 triggered");

 

      - id: page3

        lambda: |-

          it.print(0, 0, id(font1), "Scene 3 triggered");

 

      - id: page4

        lambda: |-

          it.print(0, 0, id(font1), "Scene 4 triggered");

 

# Button inputs (binary sensors) from the membrane keypad

binary_sensor:

  # Button 1 triggers Scene 1

  - platform: gpio

    pin:

      number: GPIO12                  #What GPIO Pin the button is assigned to

      mode: INPUT_PULLUP          # Enables internal pull-up resistor

      inverted: true              # Button connects to GND, so logic is flipped

    name: "Keypad Button 1"

    internal: true                # This hides the button from Home Assistant UI

    on_press:

      then:

        - logger.log: "Scene 1 activated"         # Logs to ESPHome console

        - homeassistant.service:

            service: scene.turn_on

            data:

              entity_id: scene.scene_1                    # Triggers Home Assistant scene

        - display.page.show: page1                         # Show confirmation screen

        - delay: 5s                                        # Wait 5 seconds

        - display.page.show: page_main                     # Return to main screen


 

  # Button 2 triggers Scene 2

  - platform: gpio

    pin:

      number: GPIO13

      mode: INPUT_PULLUP

      inverted: true

    name: "Keypad Button 2"

    internal: true

    on_press:

      then:

        - logger.log: "Scene 2 activated"

        - homeassistant.service:

            service: scene.turn_on

            data:

              entity_id: scene.scene_2

        - display.page.show: page2

        - delay: 5s

        - display.page.show: page_main


 

  # Button 3 triggers Scene 3

  - platform: gpio

    pin:

      number: GPIO27

      mode: INPUT_PULLUP

      inverted: true

    name: "Keypad Button 3"

    internal: true

    on_press:

      then:

        - logger.log: "Scene 3 activated"

        - homeassistant.service:

            service: scene.turn_on

            data:

              entity_id: scene.scene_3

        - display.page.show: page3

        - delay: 5s

        - display.page.show: page_main


 

  # Button 4 triggers Scene 4

  - platform: gpio

    pin:

      number: GPIO14

      mode: INPUT_PULLUP

      inverted: true

    name: "Keypad Button 4"

    internal: true

    on_press:

      then:

        - logger.log: "Scene 4 activated"

        - homeassistant.service:

            service: scene.turn_on

            data:

              entity_id: scene.scene_4

        - display.page.show: page4

        - delay: 5s

        - display.page.show: page_main

Comment & Rating (38)

(0/1000)

License

This user content is licensed under a Standard Digital File License.

You shall not share, sub-license, sell, rent, host, transfer, or distribute in any way the digital or 3D printed versions of this object, nor any other derivative work of this object in its digital or physical format (including - but not limited to - remixes of this object, and hosting on other digital platforms). The objects may not be used without permission in any way whatsoever in which you charge money, or collect fees.