#!/usr/bin/python3

import signal, json, time, argparse, sys, systemd.daemon
import paho.mqtt.client as mqtt
from datetime import datetime

run_flag = True

class MemInfo():
	def __init__(self):
		self.total = 0
		self.free = 0
		self.used = 0
		self.available = 0
		self.active = 0
		self.swapfree = 0
		self.swaptotal = 0
		self.swapused = 0

	def update(self):
		with open('/proc/meminfo', 'r') as f:
			data = f.read().split('\n')
			for d in data:
				if 'MemTotal' in d:
					self.total = int(d.split()[1], 10) * 1024
				if 'MemFree' in d:
					self.free = int(d.split()[1], 10) * 1024
				if 'MemAvailable' in d:
					self.available = int(d.split()[1], 10) * 1024
				if 'SwapTotal' in d:
					self.swaptotal = int(d.split()[1], 10) * 1024
				if 'SwapFree' in d:
					self.swapfree = int(d.split()[1], 10) * 1024
			self.swapused = self.swaptotal - self.swapfree
			self.used = self.total - self.free
			self.active = self.total - self.available

class UpTime:
	def __init__(self):
		self.seconds = 0.0

	def update(self):
		with open('/proc/uptime', 'r') as f:
			data = f.read().split()
			self.seconds = float(data[0])

class LoadAverage:
	def __init__(self):
		self.avg1 = 0.0
		self.avg5 = 0.0
		self.avg15 = 0.0

	def update(self):
		with open('/proc/loadavg', 'r') as f:
			data = f.read().split()
			self.avg1 = float(data[0])
			self.avg5 = float(data[1])
			self.avg15 = float(data[2])

class Temperature:
	def __init__(self):
		self.temp0 = 0.0

	def update(self):
		with open('/sys/devices/virtual/thermal/thermal_zone0/temp', 'r') as f:
			data = f.read()
			self.temp0 = float(data) / 1000.0

def signal_handler(signal, frame):
    global run_flag
    print('Exit now')
    run_flag = False

def system_id(ethdev):
	with open('/sys/class/net/{}/address'.format(ethdev), 'r') as f:
		data = f.read().split(':')
		return ''.join(data[:3] + ['ff', 'fe'] + data[3:]).strip()

def tokenize_args():
	args = []
	for a in sys.argv[1:]:
		if ' ' in a:
			n = a.split(' ')
			for x in n:
				args.append(x)
		else:
			args.append(a)
	return args

if __name__ == '__main__':
	parser = argparse.ArgumentParser(description='Publish periodic sysinfo via mqtt', epilog='exit program by crtl-c')
	parser.add_argument('mqttbroker', help='hostname or IP address of MQTT broker to report to')
	parser.add_argument('period', help='reporting period in seconds', type=int)
	parser.add_argument('netdevice', help='netdevice name used for generating unique system ID')
	args = parser.parse_args(tokenize_args())

	if args.period < 1:
		print('period must be 1s or longer')
		sys.exit(1)

	signal.signal(signal.SIGINT, signal_handler)
	m = MemInfo()
	u = UpTime()
	l = LoadAverage()
	t = Temperature()

	sys_id = system_id(args.netdevice)
	client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
	client.connect(args.mqttbroker)
	print('connected to {} using id={}'.format(args.mqttbroker, sys_id))
	timeout = time.time() - args.period
	systemd.daemon.notify('READY=1')

	while run_flag:
		client.loop(timeout=1.0)
		if time.time() - timeout < args.period:
			time.sleep(1)
			systemd.daemon.notify('WATCHDOG=1')
		else:
			timeout = time.time()
			m.update()
			u.update()
			l.update()
			t.update()
			client.publish('/sysinfo/{}/status'.format(sys_id), '{}'.format(json.dumps(
				{
					"id": sys_id,
					"time": datetime.utcnow().replace().isoformat(),
					"loadavg": l.avg1,
					"uptime": u.seconds,
					"temperature": t.temp0,
					"memory_used": m.used,
					"memory_free": m.free,
					"memory_active": m.active,
					"memory_swap_used": m.swapused,
					"memory_swap_free": m.swapfree
				}
			)))

	client.disconnect()
