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>
100 lines
3.6 KiB
Plaintext
Executable File
100 lines
3.6 KiB
Plaintext
Executable File
#!/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
|