import gi import tempfile import time import os import signal import paho.mqtt.client as mqtt gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk gi.require_version('AppIndicator3', '0.1') from gi.repository import AppIndicator3 as AppIndicator from PIL import Image, ImageDraw, ImageFont import yaml oldtmpfile = '' oldalertcount = 0 menu = Gtk.Menu() fp = open("mqtt-systray.yaml") conf = yaml.safe_load(fp) fp.close() mqttprefix = conf['config']['mqtt_prefix'] mqtthost = conf['config']['mqtt_host'] appindicator = AppIndicator.Indicator.new( 'mqttalert', '', AppIndicator.IndicatorCategory.APPLICATION_STATUS) def create_image(width, height, count, color_circle): # Generate an image and draw a pattern image = Image.new('RGB', (width, height), 'white') dc = ImageDraw.Draw(image) #dc.circle((width // 2, height // 2), height // 2, fill=color2) radius = height // 2 ellipse_xy = (0, 0, radius*2, radius*2) dc.ellipse(ellipse_xy, color_circle) if count > 0: #font = ImageFont.truetype("OpenSans-Regular.ttf", int(width)) font = ImageFont.load_default(float(width)) dc.text((12, -12),str(count),(0,0,0),font=font) return image def quit(): os.remove(oldtmpfile) Gtk.main_quit() def signal_handler(sig, frame): #print('You pressed Ctrl+C!') quit() def gtkquit(source): quit() def gtkdashboard(source): Gtk.show_uri_on_window(None, conf['config']['dashboard_url'],int(Gdk.CURRENT_TIME)) def get_alert_text_warning(devicea, sensora): alert_text = '' if 'value' in conf['devices'][devicea]['values'][sensora]: if 'max_warning' in conf['devices'][devicea]['values'][sensora] and conf['devices'][devicea]['values'][sensora]['value'] > conf['devices'][devicea]['values'][sensora]['max_warning']: alert_text = '!!high!! ' elif 'min_warning' in conf['devices'][devicea]['values'][sensora] and conf['devices'][devicea]['values'][sensora]['value'] < conf['devices'][devicea]['values'][sensora]['min_warning']: alert_text = '!!low!! ' return alert_text def get_alert_text_critical(devicea, sensora): alert_text = '' if 'value' in conf['devices'][devicea]['values'][sensora]: if 'max_critical' in conf['devices'][devicea]['values'][sensora] and conf['devices'][devicea]['values'][sensora]['value'] > conf['devices'][devicea]['values'][sensora]['max_critical']: alert_text = '!!HIGH!! ' elif 'min_critical' in conf['devices'][devicea]['values'][sensora] and conf['devices'][devicea]['values'][sensora]['value'] < conf['devices'][devicea]['values'][sensora]['min_critical']: alert_text = '!!LOW!! ' return alert_text def get_alert_text(devicea, sensora): alert_text = '' if get_alert_text_critical(devicea, sensora) != '': alert_text = get_alert_text_critical(devicea, sensora) elif get_alert_text_warning(devicea, sensora) != '': alert_text = get_alert_text_warning(devicea, sensora) return alert_text def alert_count_critical(): count = 0 for device in conf['devices']: for sensor in conf['devices'][device]['values'].keys(): if get_alert_text_critical(device, sensor) != '': count = count + 1 return count def alert_count_warning(): count = 0 for device in conf['devices']: for sensor in conf['devices'][device]['values'].keys(): if get_alert_text_warning(device, sensor) != '': count = count + 1 return count def alert_count(): count = 0 for device in conf['devices']: for sensor in conf['devices'][device]['values'].keys(): if get_alert_text_critical(device, sensor) != '' or get_alert_text_warning(device, sensor) != '': count = count + 1 return count def get_icon(): global oldtmpfile if oldtmpfile!='': os.remove(oldtmpfile) icon_path = tempfile.mktemp() oldtmpfile=icon_path color = 'green' if alert_count_critical() > 0: color = 'red' elif alert_count_warning() > 0: color = 'yellow' with open(icon_path, 'wb') as f: create_image(64, 64, alert_count(), color).save(f, 'PNG') return icon_path #def menun2(deviceg): # itemn2 = [] # submenu = Gtk.Menu() # for sensor in conf[deviceg]['values'].keys(): # text='' # if 'value' in conf[deviceg]['values'][sensor]: # alert_text = get_alert2(deviceg, sensor) # text='{}{}: {}'.format(alert_text, sensor, conf[deviceg]['values'][sensor]['value']) # else: # text=sensor # submenuitem = Gtk.MenuItem(text) # submenu.append(submenuitem) # return submenu def build_menu(): menu = Gtk.Menu() for device1 in conf['devices']: devname = conf['devices'][device1]['name'] conf['devices'][device1]['menuitem'] = Gtk.MenuItem(label=devname) submenu = Gtk.Menu() for sensor in conf['devices'][device1]['values'].keys(): conf['devices'][device1]['values'][sensor]['menuitem'] = Gtk.MenuItem(label=conf['devices'][device1]['values'][sensor]['name']) submenu.append(conf['devices'][device1]['values'][sensor]['menuitem']) conf['devices'][device1]['menuitem'].set_submenu(submenu) menu.append(conf['devices'][device1]['menuitem']) item_dashboard = Gtk.MenuItem(label='Open Dashboard') item_dashboard.connect('activate', gtkdashboard) menu.append(item_dashboard) item_quit = Gtk.MenuItem(label='Quit') item_quit.connect('activate', gtkquit) menu.append(item_quit) menu.show_all() return menu #def build_menu_old(): # global menu # global quitcount # global item_quit # #menu = Gtk.Menu() # menu.connect('popup-menu', menu_show) # #menu.connect('destroy', menu_hide) # for device1 in conf: # devname = conf[device1]['name'] # if get_alert(device1): devname = "!!ALERT!! " + devname # menuitem = Gtk.MenuItem(devname) # menuitem.set_submenu(menun2(device1)) # menu.append(menuitem) # # if quitcount == 0: # item_quit = Gtk.MenuItem('Quit') # item_quit.connect('select', menu_show) # print('Quit0') # menu.append(item_quit) # quitcount = quitcount + 1 # else: # #item_quit = Gtk.MenuItem('Quit') # item_quit.set_label(str(quitcount)) # print('QuitX') # #menu.append(item_quit) # #item_quit.show() # quitcount = quitcount + 1 # # print("Alert Count: {}".format(alert_count())) # # menu.show_all() # #menu.show_now() # return menu def update_menu(): appindicator.set_menu(build_menu()) def set_value(topic, value): global oldalertcount topicds = topic.rsplit("/", 1) devices=topicds[0] devices = devices.removeprefix(mqttprefix+'/') conf['devices'][devices]['values'][topicds[1]]['value'] = float(value) #update_menu() alert_text = get_alert_text(devices, topicds[1]) text='{}{}: {} {}'.format(alert_text, conf['devices'][devices]['values'][topicds[1]]['name'], conf['devices'][devices]['values'][topicds[1]]['value'], conf['devices'][devices]['values'][topicds[1]]['unit']) conf['devices'][devices]['values'][topicds[1]]['menuitem'].set_label(text) #conf['devices'][devices]['values'][topicds[1]]['menuitem'].set_label("{}".format(conf['devices'][devices]['values'][topicds[1]]['value'])) devname = conf['devices'][devices]['name'] #print(get_alert(devices)) #if get_alert(devices): devname = "! " + devname #if get_alert(devices): devname = "!!ALERT!! " + devname #conf['devices'][devices]['menuitem'].set_label(devname) if oldalertcount != (alert_count()): oldalertcount = alert_count() appindicator.set_icon_full(get_icon(), "mqtt-icon") os.system("notify-send '{}' '{}'".format(conf['devices'][devices]['name'], text)) def subscribe_mqtt(mqttc): for device in conf['devices']: #print(conf[device]) for sensor in conf['devices'][device]['values'].keys(): #print(sensor) tosubscribe = "{}/{}/{}".format(mqttprefix, device, sensor) mqttc.subscribe(tosubscribe, 0) print(tosubscribe) def on_connect(mqttc, obj, flags, rc): print("rc: " + str(rc)) #def on_subscribe(mqttc, obj, mid, granted_qos): # print("Subscribed: " + str(mid) + " " + str(granted_qos)) def on_message(client, userdata, msg): print(msg.topic+" "+str(msg.payload)) set_value(msg.topic, msg.payload) signal.signal(signal.SIGINT, signal_handler) appindicator.set_icon_full(get_icon(), "mqtt-icon") appindicator.set_title('MQTT Alert') appindicator.set_status(AppIndicator.IndicatorStatus.ACTIVE) appindicator.set_menu(build_menu()) set_value("model1/1/1/temperature1C", "25.1") #set_value("model2/2/2/humidity2", "75") #print(conf) mqttc = mqtt.Client() mqttc.on_message = on_message mqttc.on_connect = on_connect #mqttc.on_subscribe = on_subscribe connected = False while connected == False: try: mqttc.connect(mqtthost, 1883, 60) except: time.sleep(5) connected=False else: connected=True mqttc.loop_start() subscribe_mqtt(mqttc) Gtk.main()