Why IPMI?
I have an older Supermicro server and wanted to monitor its hardware sensors (fans, temps, voltages) inside Home Assistant (HA). IPMI provides a standard interface for this kind of hardware monitoring.
Step 1: Installing ipmitool in Home Assistant’s Docker Container
At first, I tried adding ipmitool to the server’s Buildroot OS, but that was complicated.
Instead, I discovered Home Assistant runs inside an Alpine Linux Docker container, so I just installed ipmitool there:
docker exec -it homeassistant bash
apk update
apk add ipmitool
Yes i know, next update kills it. Since the script is inside the docker container, I could just run apk add ipmitool, every time the script runs, too. Not sure how I will handle this, probably depending how often I need to touch it
However, this gave me a ready-to-use IPMI command line environment directly where HA runs its CLI commands (like those used in command_line sensors or shell commands).
Step 2: Testing IPMI Commands
Example command to read sensor data:
ipmitool -I lanplus -H 10.xxx.xxx..81 -U 'USER-MUST-BE-CAPS' -P 'passwd-encapsulated-due-to-special-characters' sdr
(I later declare that its for the .80 Server, .80 is the Server IP, the IMPI is on .81)
Example output snippet:
CPU1 Temp | 0x00 | ok
CPU2 Temp | 0x00 | ok
System Temp | 32 degrees C | ok
CPU1 Vcore | 1.26 Volts | ok
...
FAN 1 | 2809 RPM | ok
FAN 2 | 2500 RPM | ok
...
To extract just FAN1 RPM, I used:
ipmitool -I lanplus -H 10.101.111.81 -U HOMEASSISTANT -P 'passwd12!§' sdr | grep 'FAN 1' | awk -F '|' '{gsub(/ /,"",$2); print $2}' | cut -d'R' -f1
Which outputs just the numeric RPM value.
However, in the end, I just wrote that output into a file, and used a template sensor to read the JSON file and populate the command_line sensors.
Step 3: Avoiding Frequent Queries to Slow IPMI
Polling every sensor individually every few seconds is slow and stressful for the old board. So I wrote a shell script to query all sensors once, output JSON to a file, and then let HA read and parse that file. So here we go with step 4.
Besides that, as a heads up: I use HAs config packages for my script implementations. So I have all at one place. To be frank I run my yaml side hybrid, so bigger stuff like this IPMI, or my pi.hole management interface, I run it under config_packages, other stuff, single entry stuff, is in the configuration.yaml or the included files.
Or to quote GoogleAI: Home Assistant “packages” are a way to bundle configurations for multiple integrations into a single, logical unit, making it easier to organize and manage complex setups. By defining packages in configuration.yaml, you can group related automations, scripts, sensors, and more by theme (e.g., “weather,” “lighting”), even placing them in separate files or subfolders for better scalability.
Step 4: The Shell Script (e.g. read_ipmi.sh)
A script that queries IPMI and writes JSON:
#!/bin/bash
HOST=$1
USER=$2
PASS=$3
OUTPUT_FILE="/config/config_packages/IPMI-Supermicro/ipmi_status.json"
# Get current timestamp in ISO 8601 format
TIMESTAMP=$(date --utc +"%Y-%m-%dT%H:%M:%SZ")
# Run ipmitool ONCE and reuse the output
RAW_OUTPUT=$(ipmitool -I lanplus -H "$HOST" -U "$USER" -P "$PASS" sdr 2>/dev/null)
if [ -z "$RAW_OUTPUT" ]; then
echo "Error: Could not fetch IPMI data." >&2
exit 1
fi
# Helper function to extract numeric value by sensor name
extract_value() {
echo "$RAW_OUTPUT" | grep "$1" | awk -F '|' '{
gsub(/ /, "", $2);
gsub(/[^0-9.\-]/, "", $2);
print "\"" $3 "\":" $2;
}' | sed 's/ok//'
}
# Start JSON
echo "{" > "$OUTPUT_FILE"
echo "\"timestamp\": \"$TIMESTAMP\"," >> "$OUTPUT_FILE"
# List of sensor label and key pairs
declare -a sensors=(
"System Temp:system_temp"
"CPU1 Vcore:cpu1_vcore"
"CPU2 Vcore:cpu2_vcore"
"CPU1 Mem:cpu1_mem"
"CPU2 Mem:cpu2_mem"
"CPU1 Mem VTT:cpu1_mem_vtt"
"CPU2 Mem VTT:cpu2_mem_vtt"
"+1.1 V:volt_1_1"
"+1.8 V:volt_1_8"
"+5 V:volt_5"
"+12 V:volt_12"
"HT Voltage:ht_voltage"
"+3.3 V:volt_3_3"
"+3.3VSB:volt_3_3sb"
"VBAT:vbat"
"FAN 1:fan1_rpm"
"FAN 2:fan2_rpm"
"FAN 3:fan3_rpm"
"FAN 4:fan4_rpm"
"FAN 5:fan5_rpm"
"FAN 6:fan6_rpm"
)
# Build JSON entries
for i in "${!sensors[@]}"; do
sensor_name="${sensors[$i]%%:*}"
json_key="${sensors[$i]##*:}"
value=$(echo "$RAW_OUTPUT" | grep "^$sensor_name[ ]*|" | awk -F '|' '{
gsub(/ /, "", $2);
gsub(/[^0-9.\-]/, "", $2);
print $2;
}')
# Only include if value is non-empty
if [ -n "$value" ]; then
echo -n "\"$json_key\": $value" >> "$OUTPUT_FILE"
# Add comma unless it's the last item
[ $i -lt $((${#sensors[@]} - 1)) ] && echo "," >> "$OUTPUT_FILE"
fi
done
# End JSON
echo "" >> "$OUTPUT_FILE"
echo "}" >> "$OUTPUT_FILE"
Make executable with:
chmod +x read_ipmi.sh
Step 5: Home Assistant Configuration
Shell Command
shell_command:
update_ipmi_json: bash /config/config_packages/IPMI-Supermicro/read_ipmi.sh !secret ipmi_host !secret ipmi_user !secret ipmi_pass
Well, it turned out, the !secret as source for host, user and passwd didn’t work, for what ever reason, I couldn’t find any reference saying it should, nor it shouldn’t. So my final version looks like this:
shell_command:
update_ipmi_json: bash /config/config_packages/IPMI-Supermicro/read_ipmi.sh IP-ADDRESS USER-IN-ALL-CAPS 'encapsulated-password'
Automation to Run Script Every 2 Minutes
automation:
- id: '21364543210520135451'
alias: SYS_Run IPMI update every 2 minutes
description: 'Runs the shell script for the IPMI query'
trigger:
- platform: time_pattern
minutes: '/2'
action:
- service: shell_command.update_ipmi_json
mode: single
Sensors
Raw JSON sensor:
command_line:
- sensor:
name: "IPMI.80 JSON Raw"
unique_id: ipmi_80_json_raw
command: "cat /config/config_packages/IPMI-Supermicro/ipmi_status.json"
scan_interval: 120
value_template: "{{ value_json.system_temp }}"
json_attributes:
- system_temp
- cpu1_vcore
- cpu2_vcore
- cpu1_mem
- cpu2_mem
- cpu1_mem_vtt
- cpu2_mem_vtt
- volt_1_1
- volt_1_8
- volt_5
- volt_12
- ht_voltage
- volt_3_3
- volt_3_3sb
- vbat
- fan1_rpm
- fan2_rpm
- fan3_rpm
- fan4_rpm
- fan5_rpm
- fan6_rpm
device_info:
identifiers: "ipmi_device_80"
name: "IPMI 80 Device"
manufacturer: "Supermicro"
model: "IPMI Sensor Monitoring"
sw_version: "1.0"
I did not find a way to group those sensor entity into one device. If you know how to do this, feel free to offer a suggestion! Hence me naming them all IPMI.80_* (where the .80 is the IP of the server)
Template sensors to extract each value:
template:
- sensor:
- name: "IPMI.80 System Temp"
unit_of_measurement: "°C"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'system_temp') }}"
- name: "IPMI.80 CPU1 Vcore"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'cpu1_vcore') }}"
- name: "IPMI.80 CPU2 Vcore"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'cpu2_vcore') }}"
- name: "IPMI.80 CPU1 Mem"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'cpu1_mem') }}"
- name: "IPMI.80 CPU2 Mem"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'cpu2_mem') }}"
- name: "IPMI.80 CPU1 Mem VTT"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'cpu1_mem_vtt') }}"
- name: "IPMI.80 CPU2 Mem VTT"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'cpu2_mem_vtt') }}"
- name: "IPMI.80 +1.1 V"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'volt_1_1') }}"
- name: "IPMI.80 +1.8 V"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'volt_1_8') }}"
- name: "IPMI.80 +5 V"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'volt_5') }}"
- name: "IPMI.80 +12 V"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'volt_12') }}"
- name: "IPMI.80 HT Voltage"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'ht_voltage') }}"
- name: "IPMI.80 +3.3 V"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'volt_3_3') }}"
- name: "IPMI.80 +3.3VSB"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'volt_3_3sb') }}"
- name: "IPMI.80 VBAT"
unit_of_measurement: "V"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'vbat') }}"
- name: "IPMI.80 FAN 1 RPM"
unit_of_measurement: "RPM"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'fan1_rpm') }}"
- name: "IPMI.80 FAN 2 RPM"
unit_of_measurement: "RPM"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'fan2_rpm') }}"
- name: "IPMI.80 FAN 3 RPM"
unit_of_measurement: "RPM"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'fan3_rpm') }}"
- name: "IPMI.80 FAN 4 RPM"
unit_of_measurement: "RPM"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'fan4_rpm') }}"
- name: "IPMI.80 FAN 5 RPM"
unit_of_measurement: "RPM"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'fan5_rpm') }}"
- name: "IPMI.80 FAN 6 RPM"
unit_of_measurement: "RPM"
state: "{{ state_attr('sensor.ipmi_80_json_raw', 'fan6_rpm') }}"
Step 6: Final Notes
-
Tried to store the IPMI credentials securely in
secrets.yaml, well that didn’t work out. Which actually is a shame, cause at least my old Supermicro IPMI only hands out those health data to the superuser of the IPMI, in my view a grave miss conception by Supermicro. Even a user should see them, not just the highest level user. Cause that opens up all kinds of wormy cans like wide open access doors just for querying health data. -
Restart Home Assistant after changes. For me, a reload didnt do it. Those command_line sensors always need a full reboot on my machine (official Virtualbox image on 2025.1)
-
You can add more sensors by expanding the shell script and the JSON attributes, well who would have guessed, its kind of obvious and the sense of this post. Well to be frank, I got some help with this post from ChatGPT and that tool is VERY good at pointing out the obvious, time and again, filling in outdated syntax, even after it was clear its outdated and does not work and besides this very annoying nuisance, hits happily screwing you over any change it gets.
-
Prefix sensor names like
"IPMI.80 ..."to group logically in HA, caus I could not find any other way to group them, but I’m happy to hear your suggestions.
Summary
Installing ipmitool inside the HA Docker container made IPMI queries straightforward. Using a shell script to dump all sensor data as JSON reduces load and query frequency on the server. Template sensors cleanly expose the data for use in HA dashboards and automations.
While it works now, and ChatGPT obviously was some sorts of help getting there. I also wasted a lot of time fighting the “learned” core data from before the cutoff day in Sep. 2023 of ChatGPT, so keep that in mind, when you use that tool, HA is just developing so fast, any AI tool is basically always outdated.
Now have fun, and I hope my struggles will help someone.
Manny
ps: i just discovered this tool:
bringing IPMI into HA via HACS!