Mark McBride

Remote Reboot an ODROID H4 Ultra

In 2025 I bought an ODROID H4 Ultra. It was a bit of an experiment. Could this tiny board be a hassle-free replacement for the Supermicro server boards I’ve grown to love? Turns out the answer is absolutely yes for a homelab. With 8-cores and 4 SATA ports, it’s quite capable for NAS duty and the like.

The ODROID H4 Ultra

Problem: No BMC

There was one key component missing that every server board has: a BMC/IPMI device. A BMC is a system on your motherboard that let’s you do things regardless of whether an operating system is actually running. You can load the BMC’s web UI and see the console, you can use something like ipmitool to issue a hard reset from another computer, and on and on. It’s quite handy as you can stick your server in a garage, or attic, or basement, or wherever you want it and control it as if you had physical access.

But the ODROID doesn’t have a BMC. This is no surprise. No boards of this size do (that I’m aware of). But! As I mentioned, a BMC is just a system on your motherboard. So if we have an extra system, then we can replicate a BMC.

The Target: ODROID’s I/O Expansion GPIO Headers

You can find a map of the ODROID’s EXT_HEAD1 pins on their wiki.

The ODROID H4 Ultra’s I/O Expansion GPIO (EXT_HEAD1) Map

In this case, there are 5 pins that will help us to replicate a BMC/IPMI experience. Pins 6, 8, and 10 can connect to any USB-to-TTL cable and allow remote console access. Pins 17 and 19 can be used to wire up an actual physical power button. But we want remote access. So we need something that can simulate a physical button press.

Solution Component 1: An Optocoupler Relay

An optocoupler 3.3V relay is the essential component to this whole solution. It is the thing that effectively “pushes the button.” The term “optocoupler relay” essentially means “a device capable of receiving a digital signal from device A and relaying it to device B in the form of a 3.3V signal.”

Optocoupler 3V/3.3V Relay

If you look at the right side of that device, you’ll see the 3.3V relayed signal side. This is what will connect to pins 17 and 19 on the ODROID.

Solution Component 2: An USB-to-TTL Serial Adapter Cable

The other thing we’ll need to monitor the ODROID during a reboot is a USB-To-TTL Serial Adapter Cable. You’ll find lots of options on sites like Amazon. I’d take the size of the USB casing into consideration. I originally bought a Waveshare cable, which worked, but the casing was so big it blocked the other USB ports. Ensure the cable you get has GND (ground), RXD (receive), and TXD (transmit) wiring. You find cables with more than that, but unless you have a use for them I’d keep it simple.

DTech USB-to-TTL Serial Adapter Cable

Solution Component 3: Jumper Wires

The simplest components needed are jumper wires. Any brand will do. I recommend buying a pack that comes with male-male, female-female, and male-female ends. Aside from this project, these are just handy to have around and frequently useful for a wide variety of things.

Jumper wires

Solution Component 4: A Signal-Sending 2nd Computer

You can use any computer for this step as long as it has 3 pins: a 3.3V header, a ground header, and a programmable header. I happen to have a Raspberry Pi 5 that sits next to the ODROID, so its GPIO absolutely perfect.

Raspberry Pi 5 GPIO

In this case, we’re going to use pin 1 (3.3V), pin 6 (ground), and pin 11 (GPIO 17). You can find the full pinout description at pinout.xyz.

Putting It All Together

So with the components in hand, all we need to do is connect the right pins and headers with jumper wires. Here’s the logical mapping of wiring necessary between devices.

               RPi GPIO       Optocoupler 3.3V Relay
               ========       ======================
           Pin 1 (3.3V) ----- VCC   
         Pin 6 (Ground) ----- GND  
       Pin 11 (GPIO 17) ----- IN 


 Optocoupler 3.3V Relay       ODROID H4 Ultra EXT_HEAD1
 ======================       =========================
           COM (Common) ----- Pin 17 (PWR_BTN)
     NO (Normally Open) ----- Pin 19 (GND)
   NC (Normally Closed) ----- not connected


USB-to-TTL (USB in RPi)       ODROID H4 Ultra EXT_HEAD1
=======================       =========================
                    RXD ----- Pin 10 (UART0_TXD)
                    TXD ----- Pin 8 (UART0_RXD)
                    GND ----- Pin 6 (GND)
Wires into ODROID H4 Ultra EXT_HEAD1
Wires from Rpi5 GPIO to Optocoupler

Power On!

Ok, let’s see it in action. First, we connect to the ODROID’s console courtesy of our newly installed USB-to-TTL cable. I’m using picocom, but any serial application will do. Another common one is cu.

doas picocom -b 115200 /dev/ttyUSB0

Now as we keep an eye on the console, we use a script to power on the ODROID.

Split tmux screen: ODROID console showing BIOS (top) and RPi’s shell (bottom).
A few seconds later we see the OS’s boot loader. Success!

It works! Like this, we can power the ODROID on or off, or hard reset it if it happens to get stuck. We’ve replicated the most important aspects of a BMC/IPMI interface.

The code behind the shell script

I used the “pinctrl” package to talk to the RPi’s GPIO pins. There are other ways, but I found this to be quite simple.

Script to automate button presses.
#!/usr/bin/env zsh # ensuring we're running as root if [[ "$EUID" -ne 0 ]]; then echo "Run this script as root" exit 1 fi # ensure pinctrl is installed if ! command -v pinctrl > /dev/null ; then echo "Install pinctrl to use this script." exit 1 fi # Specify GPIO pin used for signal gpio_signal_pin=17 # Specify which pinctrl options simulate press and release button_press_signal_option="dh" button_release_signal_option="dl" # by default, simulate a 0.5 second button press button_press_duration=0.5 button_press_description="quick" # simulate a long-press/hard-reset if --long arg supplied if [[ ! -z "${1}" ]] && [[ "${1}" == "--long" ]]; then button_press_duration=7.0 button_press_description="long" fi echo "Simulating a ${button_press_duration} second ${button_press_description} button press ..." echo " sending button press" pinctrl set ${gpio_signal_pin} op ${button_press_signal_option} echo " holding" sleep ${button_press_duration} echo " sending button release" pinctrl set ${gpio_signal_pin} op ${button_release_signal_option} echo "Button released. Sequence complete."

Or, if you want to skip the script, the manual equivalent from the command line is …

doas pinctrl set 17 op dh
doas pinctrl set 17 op dl

Note: if you only issued the first command with “dh” it would be the equivalent of pressing and holding the button and never letting go. So don’t forget the second command!

And that’s it. We now have a fully remote-controllable ODROID with a little help from an RPi and an optocoupler.

A Note on What Didn’t Work

In my first attempt, I used a Waveshare USB-to-TTL device and attempted to make use of the RTS, GND, and VCC pins to issue a reset.

Waveshare USB TO TTL Converter

This kind of worked, but there was a big problem. Plugging in the USB, or connecting to the UART console would trigger the RTS pin and that resulted in button presses I didn’t want. It turns out, if you want to do this, you need a device with a DTR pin, which doesn’t trigger when the devices is activated. With these limitations, I opted for the optocoupler approach, which has the added benefit of fully segregating UART/serial from button presses.