Monitor arbitrary MQTT topics via KDE's ksysguard system monitor.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

149 Zeilen
4.3KB

  1. #!/usr/bin/python3
  2. import os
  3. import sys
  4. import yaml
  5. import paho.mqtt.client as mqtt
  6. from random import random
  7. global config
  8. config_file_path = os.path.dirname(os.path.abspath(__file__))+"/ksysguard-sensor-mqtt.yaml"
  9. # Get and parse command line arguments
  10. if __name__ == '__main__':
  11. import argparse
  12. ap = argparse.ArgumentParser()
  13. ap.add_argument("-c", "--config", required=False, default=None, help="path to the configuration file")
  14. args = vars(ap.parse_args())
  15. if args["config"]:
  16. config_file_path = args["config"]
  17. # Read configuration
  18. with open(config_file_path, "r") as config_file:
  19. try:
  20. config = yaml.safe_load(config_file)
  21. except yaml.YAMLError as err:
  22. print("Could not load configuration file")
  23. print(err)
  24. # We cache the values received via MQTT, so that they are available whenever
  25. # requested by the ksysguard client.
  26. global values
  27. values = dict()
  28. for subscription in config['mqtt']['subscriptions']:
  29. values[subscription['topic']] = None
  30. # Given a monitor name, returns its data if the name matches the list
  31. # of monitors in the configuration. If not, returns None.
  32. def have_monitor(monitor):
  33. return next(iter([subscription for subscription in config['mqtt']['subscriptions'] if subscription['monitor'] == monitor]), None)
  34. # Given a monitor name, returns its most recent value. If the monitor
  35. # does not exist, returns UNKNOWN COMMAND.
  36. def monitor_value(monitor):
  37. subscription = have_monitor(monitor)
  38. if subscription:
  39. return values[subscription['topic']]
  40. else:
  41. return "UNKNOWN COMMAND"
  42. # Given a monitor name, returns its info string. If the monitor does
  43. # not exist, returns UNKNOWN COMMAND.
  44. def monitor_info(monitor):
  45. subscription = have_monitor(monitor)
  46. #print("# Monitor info for "+monitor)
  47. #print(subscription)
  48. if subscription:
  49. descr = subscription['description'] # Shorter to type
  50. return (descr['name'] + "\t" +
  51. (descr['min'] if 'min' in descr else "") + "\t" +
  52. (descr['max'] if 'max' in descr else "") + "\t" +
  53. descr['units'])
  54. else:
  55. return "UNKNOWN COMMAND"
  56. # MQTT logic
  57. # The on_connect handler subscribes to all configured topics
  58. # and issues the ksysguard prompt when finished. From that point,
  59. # the client can start requesting data (although none may be available
  60. # depending on the relative refresh rates of MQTT publishers and the
  61. # ksysguard client.
  62. def on_connect(client, userdata, flags, rc):
  63. print("# Connected with result code "+str(rc))
  64. for subscription in config['mqtt']['subscriptions']:
  65. print("# Subscribing to " + subscription['topic'])
  66. client.subscribe(subscription['topic'])
  67. print("ksysguardd> ", end="", flush=True)
  68. # The callback for when a PUBLISH message is received from the server.
  69. # It stores the received value under the relevant topic key in the
  70. # values dictionary, from where it will be retrieved when requested
  71. # by the ksysguard client.
  72. def on_message(client, userdata, msg):
  73. global values
  74. values[msg.topic] = msg.payload.decode("utf8").strip()
  75. # Create the MQTT client and assign event handlers
  76. client = mqtt.Client(client_id="ksysguardd-"+str(random())[2:])
  77. client.on_connect = on_connect
  78. client.on_message = on_message
  79. if 'username' in config['mqtt'] and 'password' in config['mqtt']:
  80. client.username_pw_set(config['mqtt']['username'], config['mqtt']['password'])
  81. client.connect_async(config['mqtt']['host'], config['mqtt']['port'] if 'port' in config['mqtt'] else 1883, 60)
  82. # Ksysguard logic
  83. # Start by introducing ourselves. The protocol has been mostly deduced
  84. # from this link https://techbase.kde.org/Development/Tutorials/Sensors
  85. # and from the ksysguardd source code.
  86. print("ksysguardd 4")
  87. client.loop_start() # Asynchronously start the MQTT client
  88. # Process lines of input from the ksysguard client
  89. for line in sys.stdin:
  90. line = line.strip()
  91. if line == "monitors": # List available sensors
  92. for subscription in config['mqtt']['subscriptions']:
  93. print(subscription['monitor']+"\t"+subscription['type'])
  94. elif line == "quit": # Shut down this process
  95. print("# Quitting")
  96. client.loop_stop()
  97. exit()
  98. elif len(line) and line[-1] == "?": # This is a query for the monitor's information
  99. print(monitor_info(line[0:-1]))
  100. else: # Assume that this is a query for the monitor's value
  101. print("NaN" if monitor_value(line) == None else monitor_value(line))
  102. print("ksysguardd> ", end="", flush=True)