#!/bin/bash ## WIP - Check back to this pastebin often (like once a day or so) for updates while this string is here. ## METER_ID="${1}" # first arg required RTL_PPM="${2:-0}" # send arg, optional, rtl ppm data INTERVAL="${3:-${COLLECTD_INTERVAL}}" # third arg, interval. fall back to default collectd value if blank INTERVAL="${INTERVAL:-60}" # third arg second fallback, set to 60 if all else fails MAX_WAIT="${3:-10}" # forth arg, optional, how long to run radio waiting for a packet per instance RTL_WAIT=3 # How long to give rtl_tcp to fire up HOSTNAME="${COLLECTD_HOSTNAME:-`hostname -f`}" function zdbg() { if [ ! -z "${DEBUG_TEST}" ]; then echo "${@}"; fi }; if [ $(echo "${INTERVAL}" | grep -c "\.") -gt 0 ]; then # don't want your float value, collectd INTERVAL=$(printf -v int %.0f "${INTERVAL}") fi while [ "${METER_ID}" != "" ]; do TIME="$(date +%s)" METER_READING="" while [ "${METER_READING}" == "" ]; do # start radio zdbg "Starting Radio with ppm offset ${RTL_PPM}" rtl_tcp -P ${RTL_PPM} 2>/dev/null >/dev/null & RTLERR="$?"; RTLPID="$!"; if [ ${RTLERR} -ne 0 ]; then # TODO: human intervention is probably required but try some sys hacks to power cycle dongle # TODO NOTE: this will require the collectd user to have sudo NOPASSWD priv # for now, sleep and restart the loop zdbg "rtl_tcp failed to start" sleep ${RTL_WAIT} continue; fi zdbg "rtl_tcp started with PID ${RTLPID}, waiting ${RTL_WAIT} seconds to settle..."; sleep ${RTL_WAIT} # time for radio to start zdbg "Attempting Meter ${METER_ID} Read (Max wait time: $((MAX_WAIT - RTL_WAIT))s)..." METER_READING=$(stdbuf -i0 -o0 -e0 rtlamr -freqcorrection=${RTL_PPM} -filterid=${METER_ID} -single=true -duration=$((MAX_WAIT - RTL_WAIT))s -format=json 2>/dev/null) if [ "${METER_READING}" != "" ]; then zdbg "Read meter... parsing..." METER_READING=$(echo "${METER_READING}" | jq -Mrc .Message.Consumption | tail -n1) zdbg "Result: ${METER_READING}" fi # stop radio .. we do it this way to stop kill from echoing to collectd zdbg "Stopping Radio..." kill -9 "${RTLPID}" wait $! &>/dev/null if [ "${METER_READING}" == "" ]; then # Meters beacon often, but this code might still get hit if we don't get a beacon within our timeframe # Broken radio will no longer reach here since we handle rtl_tcp ourselves zdbg "Could not read meter. Check meter ID (${METER_ID}) and antenna." sleep ${RTL_WAIT} fi done echo "PUTVAL ${HOSTNAME}/rtlamr-${METER_ID}/kwh_usage interval=${INTERVAL} N:${METER_READING}" echo "PUTVAL ${HOSTNAME}/rtlamr-${METER_ID}/kwh_reading interval=${INTERVAL} N:${METER_READING}" TIMEEND="$(date +%s)" TIMERUN=$((TIMEEND - TIME)) CALC_INTERVAL=$((INTERVAL - TIME_RUN)) if [ ${CALC_INTERVAL} -gt 0 ]; then sleep ${CALC_INTERVAL}; fi done # types.db addition #kwh_usage usage:DERIVE:0:U #kwh_reading reading:GAUGE:0:U # collectd.conf.d/rtlamr.conf (replace Exec line as needed) # # Exec "user" "path-to-this-script" "your-scm-meter-id" "rtlsdr-ppm-offset" "update-interval" ## Example: Exec "zefie" "/usr/local/sbin/collectd_rtlamr" "39244000 "22" "60" # # See also: https://github.com/zefie/CGP (modified with rtlamr plugin)