#!/usr/bin/perl -w
# Mark Kamichoff <prox@prolixium.com>
# Listens on a TCP port for connections from nc/MRTG
# Provides data for:
#	NVMe Temperature sensors 1 & 2 via S.M.A.R.T.: "nt,$dev"
#	Disk Temperature via S.M.A.R.T.: "ht,$devIN,$devOUT"
#	Disk Power Cycle Count via S.M.A.R.T.: "pc,$devIN,$devOUT"
# 	Linux lm-sensors: "ls,$chipIN,$sensorIN,$chipOUT,$sensorOUT"
#	APC UPS Statistics: apcpercent, apcvoltage, apcfreq, or apctemp
#	Disk Sectors R/W: "ds,$node"
#	FreeBSD coretemp: "ct,$cpuidIN,$cpuidOUT"
#	OS X Hardware Monitor: "hm,$sensorIN,$sensorOUT"
#	Linux battery voltage: "bv,$batname"
#	Linux battery charge: "bc,$batname"
#	Linux battery energy: "be,$batname"
#	USB Tenki: "ut,$serial,$channelIN,$channelOUT"
#	Linux / FreeBSD uptime: "up"
#	Linux CPU frequency: "cf,$id"
#	Linux nVidia GPU Temp.: "nv,$gpu,$user,$display"
#	VideoCore IV VPU temperature (multipled by 100) in the Raspberry Pi: "vc"
#	iStats: "is,$sensorIN,$sensorOUT"
#	apple_sensors: "as,$sensorIN,$sensorOUT"
#	Linux BT LE scan rate: "le,$interval"
#	Avahi mDNS "ab"
# Version 1.42 [20250708]

use POSIX qw(setsid);
use POSIX qw(signal);
use IO::Socket;
use Getopt::Std;

# For iStat on macOS, need a ~/.iStats/sensors.conf so specify user that has this in the home dir
$iStatuser="prox";

# Probably don't need to change these
$sensors="/usr/bin/sensors";	# GNU/Linux
$smartctl="/usr/sbin/smartctl";
$apcaccess="/usr/sbin/apcaccess";
$nv="/usr/bin/nvidia-settings";	# GNU/Linux
$sysctl="/usr/sbin/sysctl";
$hwmonitor="/Applications/HardwareMonitor.app/Contents/MacOS/hwmonitor";	# macOS
$usbtenkiget="/usr/local/sbin/usbtenkiget";
$vcgencmd="/usr/bin/vcgencmd";
$istats="env HOME=/Users/$iStatuser /usr/local/bin/istats";	# macOS
$apple_sensors="/Users/prox/src/apple_sensors/temp_sensor";	# macOS
$avahi_browse="/usr/bin/avahi-browse";	# GNU/Linux

# Ignore SIGPIPE, for broken TCP connections (so we don't die completely)
$SIG{PIPE} = 'IGNORE';

# set some vars, based on OS
$un = `uname`;
chomp $un;

if($un eq 'Linux') {
	$hn = `hostname -f`;
} elsif($un eq 'FreeBSD' || $un eq 'Darwin') {
	$hn = `hostname`;
}

# Displays syntax and exists
sub syntax {
	print "Syntax: mrtg-rmt [-dhp port]\n";
	exit(1);
}

# Daemonize subroutine
sub daemonize {
	# Taken from http://www.webreference.com/perl/tutorial/9/2.html
	# (I'm lazy)

	chdir '/'                 or die "Can't chdir to /: $!";
	umask 0;
	open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
	open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
	open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
	defined(my $pid = fork)   or die "Can't fork: $!";
	exit if $pid;
	setsid                    or die "Can't start a new session: $!";
}

# Detault values
$daemon=0;
$port=249;

# Check arguments
%options=();
if(!getopts("p:d",\%options)) {
	syntax();
}
syntax() if defined $options{'h'};
$daemon=1 if defined $options{'d'};
if(defined $options{'p'}) {
	if($options{'p'} gt 0 && $options{'p'} lt 65536) {
		$port = $options{'p'};
	} else {
		print "Error: Port number $options{'p'} is out of range.\n";
		syntax();
	}
}

# Now, daemonize, if we should
if($daemon) {
	daemonize();
}

# Create socket
my $sock = new IO::Socket::INET (
		LocalHost => '0.0.0.0',
		LocalPort => $port,
		Proto => 'tcp',
		Listen => 1,
		Reuse => 1,
		);
die "Could not create socket: $!\n" unless $sock;

while(1) {
	my $new_sock = $sock->accept();
	if(!$daemon) {
		print "Connection from: ".inet_ntoa ((sockaddr_in($new_sock->peername))[1])."\n";
	}
	$recv = <$new_sock>;

	# If nothing
	if(!$recv) {
		next;
	}

	# hdd Power_Cycle_Count (pc,devIN,devOUT)
	if($recv =~ m/^pc,(\/dev\/[^,]+),(\/dev\/.+)$/) {
		$devIN=$1;

		# this is SO STUPID
		$devOUT=$2;
		if($devOUT =~ m/\r$/) {
			chop $devOUT;
		}

		# Input
		@oarrIN = split(/\n/,`$smartctl -a $devIN`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/Power_Cycle_Count\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+(\d+)/) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Output
		@oarrOUT = split(/\n/,`$smartctl -a $devOUT`);
		$found=0;
		foreach $line (@oarrOUT) {
			if($line =~ m/Power_Cycle_Count\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+(\d+)/) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# Linux NVMe Temperature 1 & 2 (nt,devIN,devOUT)
	} elsif($recv =~ m/^nt,(\/dev\/[^,]+)$/) {

		# this is SO STUPID
		$dev=$1;
		if($dev =~ m/\r$/) {
			chop $dev;
		}

		# Input
		@oarr = split(/\n/,`$smartctl -a $dev`);
		$found=0;
		foreach $line (@oarr) {
			if($line =~ m/Temperature Sensor 1:\s+(\d+) Celsius$/) {
				print $new_sock "$1\n";
				$found++;
			}

			if($line =~ m/Temperature Sensor 2:\s+(\d+) Celsius$/) {
				print $new_sock "$1\n";
				$found++;
			}
		}

		if($found != 2) { print $new_sock "NaN\nNaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;
	
	# hdd Temperature_Cel (ht,devIN,devOUT)
	} elsif($recv =~ m/^ht,(\/dev\/[^,]+),(\/dev\/.+)$/) {
		$devIN=$1;

		# this is SO STUPID
		$devOUT=$2;
		if($devOUT =~ m/\r$/) {
			chop $devOUT;
		}

		# Input
		@oarrIN = split(/\n/,`$smartctl -a $devIN`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/Temperature_Cel[s]*[i]*[u]*[s]*\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+(\d+)/) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Output
		@oarrOUT = split(/\n/,`$smartctl -a $devOUT`);
		$found=0;
		foreach $line (@oarrOUT) {
			if($line =~ m/Temperature_Cel[s]*[i]*[u]*[s]*\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+(\d+)/) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;
	
	# macOS hwmonitor (hm,sensorIN,sensorOUT)
	} elsif ($recv =~ m/^[ht]m,([^,]+),(.+)$/) {
		$sensorIN=$1;

		# this is SO STUPID
		$sensorOUT=$2;
		if($sensorOUT =~ m/\r$/) {
			chop $sensorOUT;
		}

		# slurp it
		undef $dataIN unless defined $dataIN;
		undef $dataOUT unless defined $dataOUT;
		@arr = split(/\n/,`$hwmonitor`);
		foreach $line (@arr) {
			if($line =~ m/^$sensorIN\:\s(\d+)/) {
				$dataIN=$1;
			} elsif($line =~ m/^$sensorOUT\:\s(\d+)/) {
				$dataOUT=$1;
			}
		}

		# Normal stuff
		if(defined $dataIN) { print $new_sock "$dataIN\n"; } else { print $new_sock "NaN\n"; }
		if(defined $dataOUT) { print $new_sock "$dataOUT\n"; } else { print $new_sock "NaN\n"; }
		print $new_sock `uptime`;
		print $new_sock $hn;

	# macOS iStats (is,sensorIN,sensorOUT)
	} elsif ($recv =~ m/^is,([^,]+),(.+)$/) {
		$sensorIN=$1;

		# this is SO STUPID
		$sensorOUT=$2;
		if($sensorOUT =~ m/\r$/) {
			chop $sensorOUT;
		}

		# slurp it
		undef $dataIN unless defined $dataIN;
		undef $dataOUT unless defined $dataOUT;
		@arr = split(/\n/,`$istats --no-graphs --no-scale`);
		foreach $line (@arr) {
			if($line =~ m/^$sensorIN\:\s+([^\.]+)/) {
				$dataIN=$1;
			} elsif($line =~ m/^$sensorOUT\:\s+([^\.]+)/) {
				$dataOUT=$1;
			}
		}

		# Normal stuff
		if(defined $dataIN) { print $new_sock "$dataIN\n"; } else { print $new_sock "NaN\n"; }
		if(defined $dataOUT) { print $new_sock "$dataOUT\n"; } else { print $new_sock "NaN\n"; }
		print $new_sock `uptime`;
		print $new_sock $hn;

	# macOS apple_sensors (is,sensorIN,sensorOUT)
	} elsif ($recv =~ m/^as,([^,]+),(.+)$/) {
		$sensorIN=$1;

		# this is SO STUPID
		$sensorOUT=$2;
		if($sensorOUT =~ m/\r$/) {
			chop $sensorOUT;
		}

		# slurp it
		undef $dataIN;
		undef $dataOUT;
		@arr = split(/\n/,`$apple_sensors`);

		@defs = split(/, /, $arr[0]);
		@vals = split(/, /, $arr[1]);
		$defcount = @defs;
		$valcount = @vals;

		if($defcount == $valcount) {

			# try to find what we want
			# note, these sensors may appear twice, we just take the last one
			for($i = 0; $i<$defcount; $i++) {
				if($defs[$i] eq $sensorIN) {
					$dataIN = $vals[$i];
				}
				if($defs[$i] eq $sensorOUT) {
					$dataOUT = $vals[$i];
				}
			}

		} else {
			# oops, don't know what to do
			print $new_sock "NaN\nNaN\n";
		}

		# Normal stuff
		if(defined $dataIN) { print $new_sock "$dataIN\n"; } else { print $new_sock "NaN\n"; }
		if(defined $dataOUT) { print $new_sock "$dataOUT\n"; } else { print $new_sock "NaN\n"; }
		print $new_sock `uptime`;
		print $new_sock $hn;

	# usb tenki (ut,serial,channelIN,channelOUT)
	} elsif ($recv =~ m/^ut,([^,]+),(\d+),(\d+)$/) {
		$serial=$1;
		$channelIN=$2;
		$channelOUT=$3;

		# xargs echo because newer dracal-view adds extra newline
		@arr = split(/, /, `$usbtenkiget -s $serial -i $channelIN,$channelOUT | xargs echo`);
		
		if(@arr == 2) {
			print $new_sock "$arr[0]\n";
			print $new_sock "$arr[1]";
		} else {
			print $new_sock "NaN\nNaN\n";
		}

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# lm sensors (ls,chipIN,sensorIN,chipOUT,sensorOUT)
	} elsif ($recv =~ m/^ls,([^,]+),([^,]+),([^,]+),(.+)$/) {
		$chipIN=$1;
		$sensorIN=$2;
		$chipOUT=$3;

		# this is SO STUPID
		$sensorOUT=$4;
		if($sensorOUT =~ m/\r$/) {
			chop $sensorOUT;
		}

		# Input - since we print that first
		@oarrIN = split(/\n/,`$sensors $chipIN`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/^$sensorIN\:[^\d]+(\d+)/) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Output - since we print that first
		@oarrOUT = split(/\n/,`$sensors $chipOUT`);
		$found=0;
		foreach $line (@oarrOUT) {
			if($line =~ m/^$sensorOUT\:[^\d]+(\d+)/) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# internal temperature
	} elsif ($recv =~ m/^apctemp$/) {

		# internal temperature
		@oarr = split(/\n/, `$apcaccess`);
		$found=0;
		foreach $line (@oarr) {
			if($line =~ m/^ITEMP\s*:\s*(.+)\s*C\s*Internal/) {
				print $new_sock "$1\n0\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\nNaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# apcaccess frequency
	} elsif ($recv =~ m/^apcfreq$/) {

		# line frequency
		@oarr = split(/\n/, `$apcaccess`);
		$found=0;
		foreach $line (@oarr) {
			if($line =~ m/^LINEFREQ\s*:\s*(.+)\s*Hz/) {
				print $new_sock "$1\n0\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\nNaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# apcaccess percentage (in: load, out: batchrg)
	} elsif ($recv =~ m/^apcpercent$/) {

		# input (load percentage)
		@oarrIN = split(/\n/, `$apcaccess`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/^LOADPCT\s*:\s*(\d+)\./) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# output (charge percentage)
		@oarrIN = split(/\n/, `$apcaccess`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/^BCHARGE\s*:\s*(\d+)\./) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# apcaccess voltage (in: bat, out: line)
	} elsif ($recv =~ m/^apcvoltage$/) {

		# input (battery output voltage)
		@oarrIN = split(/\n/, `$apcaccess`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/^BATTV\s*:\s*(\d+)\./) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# output (line voltage)
		@oarrIN = split(/\n/, `$apcaccess`);
		$found=0;
		foreach $line (@oarrIN) {
			if($line =~ m/^LINEV\s*:\s*(\d+)\./) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;
	
	# disk sectors read/written
	# specify block device (ds,hda)
	} elsif($recv =~ m/^ds,([a-z0-9]+)$/) {
		if(-e "/sys/block/$1/stat") {
			$out = `cat /sys/block/$1/stat`;
			chomp $out;
			if($out =~ m/^\s*\d+\s+\d+\s+(\d+)\s+\d+\s+\d+\s+\d+\s+(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+/) {
				print $new_sock "$1\n$2\n";
			} else {
				print $new_sock "NaN\nNaN\n";
			}
		} else {
			print $new_sock "NaN\nNaN\n";
		}

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# coretemp on FreeBSD (needs coretemp.ko)
	# "ct,$cpuidIN,$cpuidOUT"
	} elsif ($un eq 'FreeBSD' && $recv =~ m/^ct,(\d+),(\d+)/) {
		$IN=$1;
		$OUT=$2;
		if($OUT =~ m/\r$/) {
			chop $OUT;
		}

		$got=0;
		if(`$sysctl dev.cpu.$IN.temperature` =~ m/^dev\.cpu\.$IN\.temperature: (\d+)/) {
			print $new_sock "$1\n";
			$got++;
		}
		if(`$sysctl dev.cpu.$OUT.temperature` =~ m/^dev\.cpu\.$OUT\.temperature: (\d+)/) {
			print $new_sock "$1\n";
			$got++;
		}

		if($got == 1) {
			# one error
			print $new_sock "NaN\n";
		} elsif($got == 0) {
			# all errored
			print $new_sock "NaN\nNaN\n";
		}

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# Linux battery voltage: "bv,$batname" (in mV)
	} elsif ($un eq 'Linux' && $recv =~ m/^bv,([a-zA-Z0-9]+)$/) {
		$bat = $1;
		if($bat =~ m/\r$/) {
			chop $bat;
		}

		$got=0;
		# use current voltage for IN
		if(-e "/sys/class/power_supply/$bat/voltage_now") {
			print $new_sock (`cat /sys/class/power_supply/$bat/voltage_now` / 1000) . "\n";
			$got++;
		}

		# use minimum design voltage for OUT
		if(-e "/sys/class/power_supply/$bat/voltage_min_design") {
			print $new_sock (`cat /sys/class/power_supply/$bat/voltage_min_design` / 1000) . "\n";
			$got++;
		}

		if($got == 1) {
			# one error
			print $new_sock "NaN\n";
		} elsif($got == 0) {
			# all errored
			print $new_sock "NaN\nNaN\n";
		}

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# Linux battery charge/energy: "b[ce],$batname" (in mAh or mWh)
	} elsif ($un eq 'Linux' && $recv =~ m/^b([ce]),([a-zA-Z0-9]+)$/) {
		$type = $1;
		$bat = $2;
		if($bat =~ m/\r$/) {
			chop $bat;
		}

		# need voltage for any calculations
		if(-e "/sys/class/power_supply/$bat/voltage_now") {
			$volt = `cat /sys/class/power_supply/$bat/voltage_now`;
	
			# do we have energy (uWh)?
			if(-e "/sys/class/power_supply/$bat/energy_now" &&
					-e "/sys/class/power_supply/$bat/energy_full_design") {

				$enow = `cat /sys/class/power_supply/$bat/energy_now`;
				$edesign = `cat /sys/class/power_supply/$bat/energy_full_design`;

				# what do we want?
				if($type eq 'c') {
					# charge
					printf $new_sock "%.0f\n", (($enow / $volt) * 1000);
					printf $new_sock "%.0f\n", (($edesign / $volt) * 1000);
				} else {
					# energy
					printf $new_sock "%.0f\n", ($enow / 1000);
					printf $new_sock "%.0f\n", ($edesign / 1000);
				}

			# do we have charge (uAh)?
			} elsif(-e "/sys/class/power_supply/$bat/charge_now" &&
					-e "/sys/class/power_supply/$bat/charge_full_design") {

				$cnow = `cat /sys/class/power_supply/$bat/charge_now`;
				$cdesign = `cat /sys/class/power_supply/$bat/charge_full_design`;

				# what do we want?
				if($type eq 'c') {
					# charge
					printf $new_sock "%.0f\n", ($cnow / 1000);
					printf $new_sock "%.0f\n", ($cdesign / 1000);
				} else {
					# energy
					print $new_sock "%.0f\n", (($volt * $cnow) / 1000000);
					print $new_sock "%.0f\n", (($volt * $cdesign) / 1000000);
				}

			} else {
				# we have nothing :-(
				print $new_sock "NaN\nNaN\n";
			}

		} else {
			# we didn't have voltage!
			print $new_sock "NaN\nNaN\n";
		}

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# VideoCore IV VPU temperature (multipled by 100)
	} elsif ($recv =~ m/^vc$/) {
		$vc = `$vcgencmd measure_temp`;
		if($vc =~ m/^temp=([^']+)'C/) {
			$vcdec = $1*10;
			print $new_sock "$vcdec\n0\n";
		} else {
			print $new_sock "NaN\nNaN\n";
		}

		print $new_sock `uptime`;
		print $new_sock $hn;

	# Avahi (ab)
	} elsif ($recv =~ m/^ab$/) {
		if(-e $avahi_browse) {
			$ab = `$avahi_browse -atl|wc -l`;
			if($ab =~ m/^(\d+)$/) {
				print $new_sock "$1\n0\n";
			} else {
				# uh oh
				print $new_sock "NaN\nNaN\n";
			}
		} else {
			print $new_sock "NaN\nNaN\n";
		}

		print $new_sock `uptime`;
		print $new_sock $hn;

	# Uptime (up) on Linux
	} elsif ($un eq 'Linux' && $recv =~ m/^up$/) {
		if(-e "/proc/uptime") {
			$up = `cat /proc/uptime`;
			if($up =~ m/^(\d+)\./) {
				print $new_sock "$1\n0\n";
			} else {
				# uh oh
				print $new_sock "NaN\nNaN\n";
			}
		} else {
			print $new_sock "NaN\nNaN\n";
		}

		print $new_sock `uptime`;
		print $new_sock $hn;

	# Uptime (up) on FreeBSD
	} elsif ($un eq 'FreeBSD' && $recv =~ m/^up$/) {
		$boottime = `sysctl kern.boottime | awk '{ print \$5; }'|sed 's/,//'`;
		$curtime = `date +%s`;
		$uptime = $curtime - $boottime;

		print $new_sock "$uptime\n0\n";
		print $new_sock `uptime`;
		print $new_sock $hn;

	# CPU frequency (cf,\d+)
	} elsif($recv =~ m/^cf,(\d+),(\d+)$/) {
		@ids = ($1, $2);
		foreach(@ids) {
			$id = $_;

			if(-e "/sys/devices/system/cpu/cpu$id/cpufreq/scaling_cur_freq") {
				$out = `cat /sys/devices/system/cpu/cpu$id/cpufreq/scaling_cur_freq`;
				chomp $out;
				if($out =~ m/^(\d+)$/) {
					print $new_sock $1*1000;
					print $new_sock "\n";
				} else {
					print $new_sock "NaN\n";
				}
			} else {
				print $new_sock "NaN\n";
			}
		}

		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# nVidia GPU Temp. (nv,\d+,.+,:\d+\.\d+)
	} elsif($recv =~ m/^nv,(\d+),([^,]+),(:\d+\.\d+)$/) {
		$gpu=$1;
		$xuser=$2;
		$xdisplay=$3;

		@arr = split(/\n/,`sudo -u $xuser env DISPLAY=$xdisplay $nv -q '[gpu:$gpu]/GPUCoreTemp'`);
		$found=0;
		foreach $line (@arr) {
			if($line =~ m/Attribute 'GPUCoreTemp' \(.+\[gpu:$gpu\]\): (\d+)\./) {
				print $new_sock "$1\n";
				$found=1;
				last;
			}
		}
		if(!$found) { print $new_sock "NaN\n"; }

		# noo
		print $new_sock "NaN\n";
		
		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	# Linux BT LE scan rate: "le,$interval"
	} elsif($recv =~ m/^le,(\d+)$/) {
		$interval=$1;

		$countLE=`timeout -k \$(($interval+5)) -s INT ${interval}s hcitool lescan --passive|wc -l`;

		if($countLE =~ m/^(\d+)/) {
			if($countLE == 0) {
				# hack, if we had to kill previously (will see 0 dip in the graph)
				`systemctl restart bluetooth.service`;
				print $new_sock "NaN\n";
			} else {
				# ignore first line
				$lescanresult = $1 - 1;

				print $new_sock "$1\n";
			}
		} else {
			print $new_sock "NaN\n";
		}

		# noo
		print $new_sock "NaN\n";
		
		# Normal stuff
		print $new_sock `uptime`;
		print $new_sock $hn;

	} else {
		# bad function
		print $new_sock "NaN\nNaN\n";
		print $new_sock `uptime`;
		print $new_sock $hn;
	}

	# Print a bye-bye message
	if(!$daemon) {
		print "Connection to ".inet_ntoa ((sockaddr_in($new_sock->peername))[1])." has been terminated.\n";
	}
}

# We'll never get here, since we don't fork!
close($sock);
