Repository
Munin (contrib)
Last change
2018-08-01
Graph Categories
Family
auto
Capabilities
Keywords
Language
Shell
License
GPL-3.0-only
Authors

wireless_signal_ranges_

Example graph: day

Name

wireless_signal_ranges_ - Group and count all connected wifi peers by signal strength ranges

Applicable Systems

Information is parsed from the output of the tool “iwinfo” (OpenWrt) or “iw” (most systems).

This plugin is suitable for wifi interfaces with a variable selection of peers (e.g. mobile clients).

Configuration

Symlink this plugin with the name of the wifi interface added (e.g. “wlan0”).

Root permissions are probably required for accessing “iw”.

[wireless_signal_ranges_*]
user root

Version

1.1

Author

Lars Kruse devel@sumpfralle.de

License

GPLv3 or above

Magic Markers

#%# family=auto
#%# capabilities=autoconf suggest
#!/bin/sh

: << =cut

=head1 NAME

wireless_signal_ranges_ - Group and count all connected wifi peers by signal strength ranges


=head1 APPLICABLE SYSTEMS

Information is parsed from the output of the tool "iwinfo" (OpenWrt) or "iw" (most systems).

This plugin is suitable for wifi interfaces with a variable selection of peers (e.g. mobile
clients).


=head1 CONFIGURATION

Symlink this plugin with the name of the wifi interface added (e.g. "wlan0").

Root permissions are probably required for accessing "iw".

  [wireless_signal_ranges_*]
  user root


=head1 VERSION

  1.1


=head1 AUTHOR

Lars Kruse <devel@sumpfralle.de>


=head1 LICENSE

GPLv3 or above


=head1 MAGIC MARKERS

  #%# family=auto
  #%# capabilities=autoconf suggest

=cut

set -eu


SCRIPT_PREFIX="wireless_signal_ranges_"

# thresholds for signal quality ranges: ascending values
SIGNAL_THRESHOLDS="-88 -80 -60 0"


# prefer "iwinfo" for information retrieval, if it is available
if which iwinfo >/dev/null; then
	# "iwinfo" has a stable output format but is only available on openwrt
	get_wifi_interfaces() { iwinfo | grep "^[a-zA-Z]" | awk '{print $1}'; }
	# return MAC of peer and the signal strength
	get_wifi_peers() { iwinfo "$1" assoclist | grep "^[0-9a-fA-F]" | awk '{print $2}'; }
else
	# "iw" is available everywhere - but its output format is not recommended for non-humans
	get_wifi_interfaces() { iw dev | awk '{ if ($1 == "Interface") print $2; }'; }
	get_wifi_peers() { iw dev wlan0 station dump \
		| awk '{ if (($1 == "signal") && ($2 == "avg:")) print $3}'; }
fi


clean_fieldname() {
	echo "$1" | sed 's/^\([^A-Za-z_]\)/_\1/; s/[^A-Za-z0-9_]/_/g'
}


get_level_fieldname() {
	echo "range_${1#-}"
}


get_wifi_device_from_suffix() {
	local suffix
	local real_dev
	# pick the part after the basename of the real file
	suffix=$(basename "$0" | sed "s/^$SCRIPT_PREFIX//")
	for real_dev in $(get_wifi_interfaces); do
		[ "$suffix" != "$(clean_fieldname "$real_dev")" ] || echo "$real_dev"
	done | head -1
}


do_config() {
	local wifi
	local lower
	wifi=$(get_wifi_device_from_suffix)
	[ -z "$wifi" ] && echo >&2 "Missing wifi: $wifi" && return 1
	echo "graph_title Wireless signal quality ranges - $wifi"
	echo "graph_args --upper-limit 0"
	echo "graph_vlabel Signal ranges"
	echo "graph_category wireless"
	echo "graph_info This graph shows numbers of peers with defined wifi signal ranges"
	lower="noise"
	for level in $SIGNAL_THRESHOLDS; do
		fieldname=$(get_level_fieldname "$level")
		echo "${fieldname}.label $lower...$level"
		echo "${fieldname}.draw AREASTACK"
		lower="$level"
	done
}


do_fetch() {
	local wifi
	local peer_data
	local previous_count
	local current_count
	local fieldname
	wifi=$(get_wifi_device_from_suffix)
	[ -z "$wifi" ] && echo >&2 "Missing wifi: $wifi" && return 1
	peer_data=$(get_wifi_peers "$wifi")
	previous_count=0
	for level in $SIGNAL_THRESHOLDS; do
		current_count=$(echo "$peer_data" | awk '
			BEGIN { count=0; }
			{ if (($1 != "") && ($1 <= '"$level"')) count++; }
			END { print count; }')
		fieldname=$(get_level_fieldname "$level")
		echo "${fieldname}.value $((current_count - previous_count))"
		previous_count="$current_count"
	done
}


ACTION="${1:-}"

case "$ACTION" in
	config)
		do_config || exit 1
		if [ "${MUNIN_CAP_DIRTYCONFIG:-0}" = "1" ]; then do_fetch; fi
		;;
	autoconf)
		[ -z "$(get_wifi_interfaces)" ] && echo "no (no wifi interfaces found)" && exit 1
		echo "yes"
		;;
	suggest)
		get_wifi_interfaces | while read -r ifname; do
			clean_fieldname "$ifname"
		done
		;;
	"")
		do_fetch
		;;
	*)
		echo >&2 "Invalid action (valid: config / autoconf / suggest / <empty>)"
		echo >&2
		exit 2
		;;
esac