feat: add MQTT sensor publishing for Home Assistant
Adds a new s6 service (svc-foldingathome-mqtt) that polls the FAH 8 API on port 7396 every 30 seconds and publishes 4 sensors to HA via MQTT autodiscovery: Status, PPD, Work Unit Progress, and Credit estimate. Requires the Mosquitto broker add-on; declared as mqtt:want so the add-on remains functional without it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ RUN \
|
|||||||
curl \
|
curl \
|
||||||
jq \
|
jq \
|
||||||
libexpat1 \
|
libexpat1 \
|
||||||
|
mosquitto-clients \
|
||||||
netcat-openbsd && \
|
netcat-openbsd && \
|
||||||
echo "**** install foldingathome ****" && \
|
echo "**** install foldingathome ****" && \
|
||||||
if [ "${BUILD_ARCH}" = "aarch64" ]; then \
|
if [ "${BUILD_ARCH}" = "aarch64" ]; then \
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ ports_description:
|
|||||||
7396/tcp: Folding@home Web Interface
|
7396/tcp: Folding@home Web Interface
|
||||||
map:
|
map:
|
||||||
- config:rw
|
- config:rw
|
||||||
|
services:
|
||||||
|
- mqtt:want
|
||||||
options:
|
options:
|
||||||
user: ""
|
user: ""
|
||||||
team: "247478"
|
team: "247478"
|
||||||
|
|||||||
99
root/etc/s6-overlay/s6-rc.d/svc-foldingathome-mqtt/run
Executable file
99
root/etc/s6-overlay/s6-rc.d/svc-foldingathome-mqtt/run
Executable file
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/with-contenv bashio
|
||||||
|
# shellcheck shell=bash
|
||||||
|
|
||||||
|
FAH_API="http://localhost:7396/api"
|
||||||
|
POLL_INTERVAL=30
|
||||||
|
STATE_TOPIC="foldingathome/state"
|
||||||
|
DISCOVERY_PREFIX="homeassistant"
|
||||||
|
|
||||||
|
# Abort cleanly if MQTT service is not available
|
||||||
|
if ! bashio::services.mqtt; then
|
||||||
|
bashio::log.info "MQTT not available — skipping sensor publishing. Install the Mosquitto broker add-on to enable HA sensors."
|
||||||
|
exec sleep infinity
|
||||||
|
fi
|
||||||
|
|
||||||
|
MQTT_HOST=$(bashio::services.mqtt 'host')
|
||||||
|
MQTT_PORT=$(bashio::services.mqtt 'port')
|
||||||
|
MQTT_USER=$(bashio::services.mqtt 'username')
|
||||||
|
MQTT_PASS=$(bashio::services.mqtt 'password')
|
||||||
|
UNIQUE_ID="foldingathome_$(hostname | tr -cd '[:alnum:]_')"
|
||||||
|
|
||||||
|
mqtt_publish() {
|
||||||
|
mosquitto_pub \
|
||||||
|
-h "$MQTT_HOST" -p "$MQTT_PORT" \
|
||||||
|
-u "$MQTT_USER" -P "$MQTT_PASS" \
|
||||||
|
-t "$1" -m "$2" -r -q 1
|
||||||
|
}
|
||||||
|
|
||||||
|
publish_discovery() {
|
||||||
|
local device
|
||||||
|
device=$(jq -n \
|
||||||
|
--arg id "$UNIQUE_ID" \
|
||||||
|
'{identifiers: [$id], name: "Folding@home", model: "FAH 8", manufacturer: "foldingathome.org"}')
|
||||||
|
|
||||||
|
declare -A sensors
|
||||||
|
sensors=(
|
||||||
|
["status"]='{"name":"Folding@home Status","value_template":"{{ value_json.status }}","icon":"mdi:dna"}'
|
||||||
|
["ppd"]='{"name":"Folding@home PPD","value_template":"{{ value_json.ppd }}","unit_of_measurement":"PPD","icon":"mdi:speedometer","state_class":"measurement"}'
|
||||||
|
["progress"]='{"name":"Folding@home Progress","value_template":"{{ value_json.progress }}","unit_of_measurement":"%","icon":"mdi:progress-clock","state_class":"measurement"}'
|
||||||
|
["credit"]='{"name":"Folding@home Credit","value_template":"{{ value_json.credit }}","unit_of_measurement":"points","icon":"mdi:star","state_class":"total_increasing"}'
|
||||||
|
)
|
||||||
|
|
||||||
|
for key in "${!sensors[@]}"; do
|
||||||
|
local config
|
||||||
|
config=$(echo "${sensors[$key]}" | jq \
|
||||||
|
--arg uid "${UNIQUE_ID}_${key}" \
|
||||||
|
--arg topic "$STATE_TOPIC" \
|
||||||
|
--argjson device "$device" \
|
||||||
|
'. + {unique_id: $uid, state_topic: $topic, device: $device}')
|
||||||
|
mqtt_publish "${DISCOVERY_PREFIX}/sensor/${UNIQUE_ID}_${key}/config" "$config"
|
||||||
|
done
|
||||||
|
|
||||||
|
bashio::log.info "HA sensor discovery published (${#sensors[@]} sensors)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wait for FAH API to become ready
|
||||||
|
bashio::log.info "Waiting for Folding@home API on port 7396..."
|
||||||
|
until curl -sf "${FAH_API}/info" > /dev/null 2>&1; do
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
bashio::log.info "Folding@home API ready — starting MQTT sensor publisher"
|
||||||
|
|
||||||
|
publish_discovery
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
UNITS=$(curl -sf "${FAH_API}/units" 2>/dev/null || echo "[]")
|
||||||
|
UNIT_COUNT=$(echo "$UNITS" | jq 'length')
|
||||||
|
|
||||||
|
if [ "$UNIT_COUNT" -gt 0 ]; then
|
||||||
|
RAW_STATE=$(echo "$UNITS" | jq -r '.[0].state // "unknown"')
|
||||||
|
case "$RAW_STATE" in
|
||||||
|
RUN) STATUS="Running" ;;
|
||||||
|
PAUSE) STATUS="Paused" ;;
|
||||||
|
FINISH) STATUS="Finishing" ;;
|
||||||
|
ASSIGN) STATUS="Assigning" ;;
|
||||||
|
DOWNLOAD) STATUS="Downloading" ;;
|
||||||
|
SEND) STATUS="Sending" ;;
|
||||||
|
*) STATUS="Idle" ;;
|
||||||
|
esac
|
||||||
|
PPD=$(echo "$UNITS" | jq '[.[].ppd // 0] | add // 0 | round')
|
||||||
|
PROGRESS=$(echo "$UNITS" | jq '.[0].progress // 0 | . * 100 | round')
|
||||||
|
CREDIT=$(echo "$UNITS" | jq '[.[].credit // 0] | add // 0 | round')
|
||||||
|
else
|
||||||
|
STATUS="Idle"
|
||||||
|
PPD=0
|
||||||
|
PROGRESS=0
|
||||||
|
CREDIT=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
PAYLOAD=$(jq -n \
|
||||||
|
--arg status "$STATUS" \
|
||||||
|
--argjson ppd "$PPD" \
|
||||||
|
--argjson progress "$PROGRESS" \
|
||||||
|
--argjson credit "$CREDIT" \
|
||||||
|
'{status: $status, ppd: $ppd, progress: $progress, credit: $credit}')
|
||||||
|
|
||||||
|
mqtt_publish "$STATE_TOPIC" "$PAYLOAD"
|
||||||
|
|
||||||
|
sleep "$POLL_INTERVAL"
|
||||||
|
done
|
||||||
1
root/etc/s6-overlay/s6-rc.d/svc-foldingathome-mqtt/type
Normal file
1
root/etc/s6-overlay/s6-rc.d/svc-foldingathome-mqtt/type
Normal file
@@ -0,0 +1 @@
|
|||||||
|
longrun
|
||||||
Reference in New Issue
Block a user