minihil is development device which can be used for HWIL.
The README is used to introduce the tool and provide instructions on how to install the tool, any machine dependencies it may have and any other information that should be provided before the tool is installed.
Table of Contents
- About minihild
- SIL (Software-in-the-Loop) Host Build
- minihildesk GUI Client
- Yocto Image Build (Raspberry Pi Target)
- Flashing the Image to SD Card
- Running on Raspberry Pi 3B+
- JSON-RPC 2.0 API Specification
- Docs
- Copyright and licence
The core of the software is minihild — a POSIX C++ daemon running as a server on the Raspberry Pi target. It listens for incoming connections on TCP port 9000 and parses JSON-RPC 2.0 commands. It controls the Waveshare Relay Board (B) (an 8-channel relay board) via standard Linux character device GPIO controls (libgpiod v2).
It is designed with a decoupled architecture to allow easy expansion (e.g. adding WebSockets) and supports Software-in-the-Loop (SIL) simulation so that you can compile and test the server and its API directly on your local developer PC without Raspberry Pi hardware.
To compile and run the daemon locally on your developer PC in SIL mock mode:
Install the required JSON header libraries:
sudo apt-get install nlohmann-json3-dev# Configure and compile using CMake
cmake -B sw/minihil/build -S sw/minihil
cmake --build sw/minihil/build
# Start the mock daemon
./sw/minihil/build/minihildThe daemon will boot in SIL mode and print:
[SilRelayController] Software-in-the-Loop simulation initialized.
minihildesk is a premium GTKmm-based C++ desktop GUI client designed to connect to the minihild server (either running on a Raspberry Pi target or locally in SIL mock mode).
It features:
- A connection bar supporting standard TCP connection, SSL/TLS secure connection, and Mutual TLS (mTLS) client verification.
- A grid of 8 Relay Control Cards displaying status via glowing LED indicators and active green borders.
- Multi-mode relay control per channel: Toggle (manual switch), Timer (seconds spin-input), Pulse (milliseconds spin-input up to 100,000 ms), and Blink (ON/OFF ms inputs and cycle count).
- Automatic hardware safety auto-off logic: switching modes on an active channel immediately turns the relay OFF on the server before entering the new mode.
- A monospace green log terminal at the bottom showcasing outgoing and incoming JSON-RPC traffic.
Install the GTKmm-4.0 development headers, OpenSSL, and JSON library:
sudo apt-get install libgtkmm-4.0-dev libssl-dev nlohmann-json3-dev# Configure and compile using CMake
cmake -B sw/minihildesk/build -S sw/minihildesk
cmake --build sw/minihildesk/build
# Start the desktop GUI app
./sw/minihildesk/build/minihildeskMiniHIL packages minihild into a custom Yocto Linux image (minihil-image) using meta-raspberrypi and Poky.
Ensure your build host has all required packages for Yocto Scarthgap (refer to rpi-base-platform/README.md for the list of packages).
# 1. Initialize environment (sources Poky and sets up configs/layers)
source sw/setup-env.sh
# 2. Trigger the bitbake build
bitbake minihil-imageThis compiles the C++ application, bundles the systemd daemon config (minihil.service) to start automatically on boot, and outputs a flashable image.
The Yocto build generates a flashable .wic.bz2 image in the deployment directory:
sw/build-minihil/tmp/deploy/images/raspberrypi3-64/minihil-image-raspberrypi3-64.rootfs.wic.bz2
Identify your SD card's device name (e.g. /dev/sdX or /dev/mmcblkX) using lsblk or dmesg.
Warning
Double-check the target device name before flashing! Writing to the wrong disk can destroy data on your host system.
Before flashing, ensure that all partitions on the target SD card are unmounted (otherwise you will get a "Device or resource busy" error):
sudo umount /dev/sdX* 2>/dev/null || truebmaptool natively supports compressed images and will automatically decompress the Yocto symlink on-the-fly.
# Flash directly (replace /dev/sdX with your SD card device)
sudo bmaptool copy sw/build-minihil/tmp/deploy/images/raspberrypi3-64/minihil-image-raspberrypi3-64.rootfs.wic.bz2 /dev/sdXTo avoid modifying the Yocto symlink files and save host disk space, decompress the image on-the-fly and pipe it directly to dd:
# Decompress on-the-fly and flash (replace /dev/sdX with your SD card device)
bzcat sw/build-minihil/tmp/deploy/images/raspberrypi3-64/minihil-image-raspberrypi3-64.rootfs.wic.bz2 | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync- Boot the board: Insert the flashed SD card into your Raspberry Pi 3B+ and power it on.
- Access the console:
- Via SSH: Connect as
rootusing the default passwordroot:ssh root@<rpi-ip-address>
- Via Serial UART: Connect a USB-to-UART adapter to the Raspberry Pi GPIO header (TX on pin 8, RX on pin 10, GND on pin 6). Access the serial interface using
picocomorminicom(enabled with115200baud rate byENABLE_UART = "1"inlocal.conf):picocom -b 115200 /dev/ttyUSB0
- Via SSH: Connect as
- Verify the Daemon: Check that the
minihilserver starts automatically on boot:systemctl status minihil
- Test the JSON-RPC interface locally: Send a command to port 9000 to query the relay states:
echo '{"jsonrpc": "2.0", "method": "get_relays", "id": 1}' | nc localhost 9000
You can send JSON-RPC text frames (terminated by \n) to port 9000.
Energize or de-energize a relay channel manually (1 to 8):
- Request:
{"jsonrpc": "2.0", "method": "set_relay", "params": {"relay_id": 3, "state": true}, "id": 1} - Response:
{"jsonrpc": "2.0", "result": {"relay_id": 3, "state": true, "success": true}, "id": 1}
Query immediate physical states of all 8 relay channels:
- Request:
{"jsonrpc": "2.0", "method": "get_relays", "id": 2} - Response:
{"jsonrpc": "2.0", "result": {"1": false, "2": false, "3": true, "4": false, "5": false, "6": false, "7": false, "8": false}, "id": 2}
Keep a relay active for a specific duration in seconds:
- Request:
{"jsonrpc": "2.0", "method": "start_timer", "params": {"relay_id": 2, "seconds": 10}, "id": 3} - Response:
{"jsonrpc": "2.0", "result": {"relay_id": 2, "seconds": 10, "success": true}, "id": 3}
Generate a single momentary pulse in milliseconds (up to 100,000 ms):
- Request:
{"jsonrpc": "2.0", "method": "start_pulse", "params": {"relay_id": 3, "duration_ms": 5000}, "id": 4} - Response:
{"jsonrpc": "2.0", "result": {"relay_id": 3, "duration_ms": 5000, "success": true}, "id": 4}
Repeatedly cycle relay state ON and OFF:
- Request:
{"jsonrpc": "2.0", "method": "start_blink", "params": {"relay_id": 4, "on_ms": 1000, "off_ms": 1000, "count": 5}, "id": 5} - Response:
{"jsonrpc": "2.0", "result": {"relay_id": 4, "on_ms": 1000, "off_ms": 1000, "count": 5, "success": true}, "id": 5}
Query detailed diagnostic status and remaining time for a single channel:
- Request:
{"jsonrpc": "2.0", "method": "get_relay_status", "params": {"relay_id": 2}, "id": 6} - Response:
{"jsonrpc": "2.0", "result": {"relay_id": 2, "status": "Channel 2: ON (Timer, rem: 8s)"}, "id": 6}
More documentation and info at
Copyright (C) 2020 - 2026 by electux.github.io/minihil
minihil is free software; you can redistribute it and/or modify it.
Lets help and support Raspberry PI && GNOME.

