369 lines
11 KiB
Bash
Executable File
369 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
: << =cut
|
|
|
|
=head1 NAME
|
|
|
|
tasmota_ - logs voltage, energy usage, power, power factor and current logged from tasmota power switches
|
|
|
|
To install the plugin, copy or move the plugin to /usr/share/munin/plugins/ set
|
|
the chmod to 755 and create a symbolic link:
|
|
ln -s /usr/share/munin/plugins/tasmota_ /etc/munin/plugins/tasmota_hostname_voltage
|
|
ln -s /usr/share/munin/plugins/tasmota_ /etc/munin/plugins/tasmota_hostname_energy
|
|
ln -s /usr/share/munin/plugins/tasmota_ /etc/munin/plugins/tasmota_hostname_power
|
|
ln -s /usr/share/munin/plugins/tasmota_ /etc/munin/plugins/tasmota_hostname_powerfactor
|
|
ln -s /usr/share/munin/plugins/tasmota_ /etc/munin/plugins/tasmota_hostname_current
|
|
|
|
Plugin also implements suggests, so if you have nodeattr installed and
|
|
/etc/genders populated with "tasmota" as well as "powermon",
|
|
"DS18B20","SCD40", "PMS5003" or "millivolts" flags for those tasmota
|
|
devices that implement energy or temperature monitoring, you can run
|
|
an ansible play like this to set up your links:
|
|
https://github.com/spacelama/ansible-initial-server-setup/tree/master/roles/monitoring/tasks
|
|
|
|
=head1 APPLICABLE SYSTEMS
|
|
|
|
Any host that can access tasmota systems and has "jq" installed. Can
|
|
auto suggest values if nodeattr genders (debian: apt install genders)
|
|
installed and configured with tasmota, powermon, DS18B20, SCD40,
|
|
PMS5003, millivolts flags.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Tim Connors <tconnors@rather.puzzling.org>
|
|
|
|
=head1 LICENSE
|
|
|
|
GPLv2 or later
|
|
|
|
=head1 MAGICK MARKERS
|
|
|
|
#%# family=auto
|
|
#%# capabilities=autoconf
|
|
|
|
=cut
|
|
|
|
cached_curl=none
|
|
# runs curl on "Status $1", and parses through jq -c "$2", setting the value in "$res"
|
|
# Caches the curl results for when we're plotting multiple (power) values
|
|
# -- don't forget to make sure we're not being called in a subshell!
|
|
get_status() {
|
|
if [ "$cached_curl" = none ] ; then
|
|
# run curl, cache the result, and if there was an error, set value to "U"
|
|
if ! cached_curl=$( curl --max-time 5 -fsS --data-urlencode "cmnd=Status $1" "http://$DEVICE/cm" ) ; then
|
|
cached_curl='{}'
|
|
fi
|
|
fi
|
|
res=$( echo "$cached_curl" | jq -c -r "$2" )
|
|
if [ "$res" = null ] ; then
|
|
res=U
|
|
fi
|
|
}
|
|
|
|
DEVICE=$(basename "$0" | cut -d_ -f2)
|
|
FUNCTION=$(basename "$0" | cut -d_ -f3)
|
|
|
|
. "$MUNIN_LIBDIR/plugins/plugin.sh"
|
|
|
|
if [ "$1" = "autoconf" ]; then
|
|
if ! which curl > /dev/null 2>&1 ; then
|
|
echo "no (no curl)"
|
|
exit 0
|
|
fi
|
|
if ! which jq > /dev/null 2>&1 ; then
|
|
echo "no (no jq)"
|
|
exit 0
|
|
fi
|
|
|
|
echo yes && exit 0
|
|
fi
|
|
|
|
if [ "$1" = "suggest" ]; then
|
|
nodeattr -n '(tasmota || beken) && powermon' | while read -r device ; do
|
|
for i in voltage power powerfactor current energy ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
nodeattr -n '(tasmota || beken) && DS18B20' | while read -r device ; do
|
|
for i in DS18B20 ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
nodeattr -n '(tasmota || beken) && SCD40' | while read -r device ; do
|
|
for i in SCD40 ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
nodeattr -n '(tasmota || beken) && PMS5003' | while read -r device ; do
|
|
for i in PMS5003 ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
nodeattr -n '(tasmota || beken) && millivolts' | while read -r device ; do
|
|
for i in millivolts ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
nodeattr -n '(tasmota || beken) && switch' | while read -r device ; do
|
|
for i in switch ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
nodeattr -n '(tasmota || beken) && dimmer' | while read -r device ; do
|
|
for i in dimmer ; do
|
|
echo "${device}_${i}"
|
|
done
|
|
done
|
|
exit
|
|
fi
|
|
|
|
voltage() {
|
|
axis=Volts
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Voltage: $DEVICE"
|
|
echo "graph_vlabel Volts"
|
|
echo "graph_args --base 1000 -l 0"
|
|
|
|
echo "$axis.label Voltage"
|
|
else
|
|
get_status 8 ".StatusSNS.ENERGY.Voltage"
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
current() {
|
|
axis=Current
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Current: $DEVICE"
|
|
echo "graph_vlabel Amps"
|
|
echo "graph_args --base 1000 -l 0"
|
|
|
|
echo "$axis.label Current"
|
|
else
|
|
get_status 8 ".StatusSNS.ENERGY.Current"
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
power() {
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Power: $DEVICE"
|
|
echo "graph_vlabel Watts"
|
|
echo "graph_args --base 1000 -l 0"
|
|
|
|
for axis in ApparentPower ReactivePower Power ; do
|
|
echo "$axis.label $axis"
|
|
echo "$axis.type GAUGE"
|
|
echo "$axis.min 0"
|
|
|
|
print_thresholds "$axis"
|
|
done
|
|
else
|
|
for axis in ApparentPower ReactivePower Power ; do
|
|
get_status 8 ".StatusSNS.ENERGY.$axis"
|
|
echo "$axis.value $res"
|
|
done
|
|
fi
|
|
}
|
|
|
|
powerfactor() {
|
|
axis=PowerFactor
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Power factor: $DEVICE"
|
|
echo "graph_vlabel Power Factor"
|
|
echo "graph_args --base 1000 -l 0"
|
|
|
|
echo "$axis.min 0"
|
|
echo "$axis.max 1"
|
|
echo "$axis.label Power Factor"
|
|
else
|
|
get_status 8 ".StatusSNS.ENERGY.Factor"
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
energy() {
|
|
axis=Energy
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Energy: $DEVICE"
|
|
echo "graph_args --base 1000"
|
|
|
|
echo "graph_vlabel kWh"
|
|
echo "$axis.label Energy"
|
|
echo "$axis.draw AREA"
|
|
else
|
|
get_status 8 ".StatusSNS.ENERGY.Total"
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
DS18B20() {
|
|
axis=Temperature
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Temperature: $DEVICE"
|
|
echo "graph_args --base 1000"
|
|
|
|
echo "graph_vlabel °C"
|
|
echo "$axis.label Temperature"
|
|
echo "$axis.type GAUGE"
|
|
#echo "$axis.min 0"
|
|
else
|
|
get_status 10 ".StatusSNS.DS18B20.Temperature"
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
SCD40() {
|
|
axis=CO2
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Carbon Dioxide: $DEVICE"
|
|
echo "graph_args --base 1000"
|
|
|
|
echo "graph_vlabel PPM"
|
|
echo "$axis.label Carbon Dioxide"
|
|
echo "$axis.type GAUGE"
|
|
else
|
|
get_status 8 ".StatusSNS.SCD40.CarbonDioxide"
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
PMS5003() {
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Particulate Pollution: $DEVICE"
|
|
echo "graph_args --base 1000"
|
|
|
|
for v in 'PB1=<1μm PPD' 'PB2_5=<2.5μm PPD' 'PB10=<10μm PPD' ; do
|
|
axis=$( echo "$v" | cut -d= -f 1 )
|
|
lab=$( echo "$v" | cut -d= -f 2 )
|
|
|
|
echo "$axis.label $lab"
|
|
echo "$axis.type GAUGE"
|
|
echo "$axis.min 0"
|
|
done
|
|
else
|
|
for v in 'PB1="PB1"' 'PB2_5="PB2.5"' 'PB10="PB10"' ; do
|
|
axis=$( echo "$v" | cut -d= -f 1 )
|
|
field=$( echo "$v" | cut -d= -f 2 )
|
|
get_status 8 ".StatusSNS.PMS5003.$field"
|
|
echo "$axis.value $res"
|
|
done
|
|
fi
|
|
}
|
|
|
|
millivolts() {
|
|
axis=Volts
|
|
if [ "$1" = "config" ]; then
|
|
limits=
|
|
# # man rrdgraph for relevant --limit args
|
|
# if [ -n "$lower" ] ; then
|
|
# limits="$limits --lower-limit $lower --rigid --allow-shrink"
|
|
# limits="$limits --lower-limit $lower --rigid --alt-autoscale"
|
|
# fi
|
|
# if [ -n "$upper" ] ; then
|
|
# limits="$limits --upper-limit $upper --rigid"
|
|
# fi
|
|
echo "graph_title Tasmota Volts: $DEVICE"
|
|
# echo "graph_args --base 1000$limits"
|
|
echo "graph_args --base 1000 --alt-autoscale --alt-y-grid"
|
|
|
|
echo "graph_vlabel Volts"
|
|
echo "$axis.label V"
|
|
echo "$axis.type GAUGE"
|
|
else
|
|
get_status 8 ".StatusSNS.ANALOG.Range"
|
|
if [ "$res" != U ] ; then
|
|
res=$( echo "$res" | awk '{printf "%0.3f", $1/1000}' )
|
|
fi
|
|
echo "$axis.value $res"
|
|
fi
|
|
}
|
|
|
|
switch() {
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Switch: $DEVICE"
|
|
echo "graph_args --base 1000 -l 0"
|
|
fi
|
|
|
|
for v in POWER POWER{1,2,3,4,5,6,7,8,9} ; do
|
|
axis=$( echo "$v" | cut -d= -f 1 )
|
|
lab=$( echo "$v" | cut -d= -f 2 )
|
|
get_status 11 ".StatusSTS.$v"
|
|
|
|
if [ "$res" != U ] || [ -e $MUNIN_PLUGSTATE/tasmota/$DEVICE.$FUNCTION.$v.seen ] ; then
|
|
# if we've ever seen an axis, then we want to keep
|
|
# telling munin we are capable of reading that axis,
|
|
# even if the device is currently unpowered
|
|
mkdir -p $MUNIN_PLUGSTATE/tasmota
|
|
touch $MUNIN_PLUGSTATE/tasmota/$DEVICE.$FUNCTION.$v.seen
|
|
|
|
if [ "$1" = "config" ]; then
|
|
echo "$axis.label $lab"
|
|
echo "$axis.type GAUGE"
|
|
echo "$axis.min 0"
|
|
else
|
|
case "$res" in
|
|
ON)
|
|
res=1
|
|
;;
|
|
OFF)
|
|
res=0
|
|
;;
|
|
U) # assume off, since if it doesn't have power to get wifi, then it's not going to have power output
|
|
res=0
|
|
;;
|
|
esac
|
|
|
|
echo "$axis.value $res"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
dimmer() {
|
|
if [ "$1" = "config" ]; then
|
|
echo "graph_title Tasmota Dimmer: $DEVICE"
|
|
echo "graph_args --base 1000 -l 0"
|
|
fi
|
|
|
|
for v in Channel{1,2,3,4} ; do
|
|
axis=$( echo "$v" | cut -d= -f 1 )
|
|
lab=$( echo "$v" | cut -d= -f 2 )
|
|
get_status 11 ".StatusSTS.$v"
|
|
|
|
if [ "$res" != U ] || [ -e $MUNIN_PLUGSTATE/tasmota/$DEVICE.$FUNCTION.$v.seen ] ; then
|
|
# if we've ever seen an axis, then we want to keep
|
|
# telling munin we are capable of reading that axis,
|
|
# even if the device is currently unpowered
|
|
mkdir -p $MUNIN_PLUGSTATE/tasmota
|
|
touch $MUNIN_PLUGSTATE/tasmota/$DEVICE.$FUNCTION.$v.seen
|
|
|
|
if [ "$1" = "config" ]; then
|
|
echo "$axis.label $lab"
|
|
echo "$axis.type GAUGE"
|
|
echo "$axis.min 0"
|
|
else
|
|
if [ "$res" = U ] ; then
|
|
res=0 # assume 0 power, since if it doesn't have power to get wifi, then it's not going to have power output
|
|
fi
|
|
|
|
echo "$axis.value $res"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
case "$FUNCTION" in
|
|
voltage|power|powerfactor|current|energy|DS18B20|SCD40|PMS5003|millivolts|switch|dimmer)
|
|
$FUNCTION "$1"
|
|
;;
|
|
*)
|
|
echo "Unknown Function"
|
|
;;
|
|
esac
|
|
|
|
if [ "$1" = "config" ] ; then
|
|
echo "graph_category sensors"
|
|
print_thresholds "$axis"
|
|
fi
|