#!/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)
#<Plugin exec>
# 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"
#</Plugin>
# See also: https://github.com/zefie/CGP (modified with rtlamr plugin)
Comments