Newer
Older
piValues2MQTT / piValues2MQTT.py
#!/usr/bin/python3

# \file piValues2MQTT.py
# \brief piValues2MQTT
# \author Pascal Gollor
# \copyright cc 2020 by-sa


import optparse, logging, signal, time, re, argparse, platform
from btlewrap.bluepy import BluepyBackend
import paho.mqtt.client as mqtt
from gpiozero import CPUTemperature


DEFAULT_MQTT_SERVER = "127.0.0.1"
DEFAULT_MQTT_PORT = 1883
DEFAULT_BASETOPIC = "pis" # without leading /


## detecting kill signal
# source:	http://stackoverflow.com/questions/18499497/how-to-process-sigterm-signal-gracefully
class GracefulKiller:
	def __init__(self):
		self.kill_now = False
		
		signal.signal(signal.SIGINT, self.exit_gracefully)
		signal.signal(signal.SIGTERM, self.exit_gracefully)
	# end __init__

	def exit_gracefully(self, signum, frame):
		self.kill_now = True
	# end exit_gracefully
# end class GracefulKiller


def on_connect(client, userdata, flags, rc):
	userdata['logger'].info("Connected with result code: %i", rc)
# end on_connect


def on_disconnect(client, userdata, rc):
	msg = "Disconnected with result code: %i"
	if (rc):
		userdata['logger'].error(msg, rc)
	else:
		userdata['logger'].info(msg, rc)
	# end if
# end on_disconnect


def main():
	parser = optparse.OptionParser(
		usage = "%prog [options]",
		description = "piValues2MQTT Grab Measurement data from RaspberryPi an post as MQTT topic",
		version="%prog 0.1a"
	)

	group = optparse.OptionGroup(parser, "MQTT settings")
	group.add_option("-s", "--server",
		dest = "server",
		help = "mqtt server, default %default",
		default = DEFAULT_MQTT_SERVER
	)
	group.add_option("--port",
		dest = "port",
		action = "store",
		type = 'int',
		help = "mqtt server port, default %default",
		default = DEFAULT_MQTT_PORT
	)
	group.add_option("-k", "--keepalive",
		dest = "keepalive",
		action = "store",
		type = 'int',
		help = "keepalive option for mqtt server, default %default",
		default = 60
	)
	group.add_option("-t", "--topic",
		dest = "basetopic",
		help = "basetopic to publish to without leading /, default %default",
		default = DEFAULT_BASETOPIC
	)
	group.add_option("-u", "--username",
		dest = "username",
		help = "connection username",
		default = ""
	)
	group.add_option("-p", "--password",
		dest = "password",
		help = "connection password",
		default = ""
	)
	parser.add_option_group(group)

	group = optparse.OptionGroup(parser, "Basic settings")
	group.add_option('-i', '--interval',
		dest = 'interval',
		help = 'polling interval in seconds, default %default',
		type = 'int',
		default = 60
	)
	group.add_option("-l", "--loglevel",
		dest = "loglevel",
		action = "store",
		type = 'int',
		help = str(logging.CRITICAL) + ": critical  " + str(logging.ERROR) + ": error  " + str(logging.WARNING) + ": warning  " + str(logging.INFO) + ":info  " + str(logging.DEBUG) + ":debug",
		default = logging.ERROR
	)
	group.add_option("-v", "--verbose",
		dest = "verbose",
		action = "store_true",
		help = "show debug messages (overrites loglevel to debug)",
		default = False
	)
	parser.add_option_group(group)

	# parse options
	(options, _) = parser.parse_args()
	
	# init logging
	loglevel = int(options.loglevel)
	if (options.verbose):
		loglevel = logging.DEBUG
	# end if
	logger = logging.getLogger("piValues2MQTT")
	logger.setLevel(loglevel)
	ch = logging.StreamHandler()
	ch.setLevel(loglevel)
	formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
	formatter.datefmt = '%Y-%m-%d %H:%M:%S'
	ch.setFormatter(formatter)
	logger.addHandler(ch)

	# add logger to userdata
	userdata = dict()
	userdata['logger'] = logger

	# add killer
	killer = GracefulKiller()

	# add mqtt client
	client = mqtt.Client()
	
	# set user data for MQTT callbacks
	client.user_data_set(userdata)

	# register MQTT callbacks
	client.on_connect = on_connect
	client.on_disconnect = on_disconnect

	# check username and password
	if (len(options.username) > 0):
		if (len(options.password) == 0):
			raise ValueError("please do not use username without password")
		# end if
		
		client.username_pw_set(options.username, options.password)
	# end if

	# debug output
	logger.debug("server: %s" ,options.server)
	logger.debug("port: %i", options.port)
	logger.debug("basetopic: %s", options.basetopic)
	logger.debug('polling interval: %i seconds', options.interval)

	# connect to MQTT server
	logger.debug("connect to mqtt client")
	client.connect(options.server, options.port, options.keepalive)

	# start client loop
	client.loop_start()

	# forever loop
	hostName = platform.node()
	mqttTopic = options.basetopic + '/' + hostName
	logger.debug("mqtt topic: %s", mqttTopic)
	mqttTopic = mqttTopic.replace(':', '-')
	lastPoll = 0
	try:
		logger.debug("start program loop")
		
		while (1):
			currentTime = time.time()
			if (lastPoll == 0 or currentTime - lastPoll >= options.interval):
				lastPoll = currentTime
				
				# get data
				jsonStr = '{"cpuTemperature":' + str(CPUTemperature().temperature) + '}'
				logger.debug(jsonStr)

				client.publish(mqttTopic, jsonStr)
			# end if

			time.sleep(0.1)
		
			if (killer.kill_now):
				raise KeyboardInterrupt
			# end if
		# end while
	except KeyboardInterrupt:
		logger.debug("exit program loop")
	# end try
	
	# disconnecting
	logger.debug("disconnecting from MQTT server")
	client.loop_stop()
	client.disconnect()
# end main



if __name__ == "__main__":
	try:
		main()
	except Exception as e:
		logging.error(str(e))
	# end try
# end if