Monitor arbitrary MQTT topics via KDE's ksysguard system monitor.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

149 rindas
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)