Linux system tray Home Assistant Quick commands

I have been using Home Assistant for a while now and finding it very useful. I have also recently, due to the Covid-19 pandemic, been working from home, this has mean’t I have been listening to the radio on daily basis, however the hourly news updates, drive me nuts. I had been manually muting my audio system for the duration of the news update, however this does rely me un-muting said audio system. I then thought this would be an easy job for an app. This resulted in me creating a System Tray icon app that allows me to quickly trigger any device registered in Home Assistant.

This is what it looks like when I right click on the HomeAssistant icon displayed in my System Tray. Clicking on the “Yamaha Amp – Mute 02m 10s” results in muting my amplifier for 2 minutes and 10 seconds, the average time a news update lasts.

The code below is a good framework to start from. Basically you need to configure the address of your Home Assistant server on line 19 and then get the a Home Assistant Long Lived Access Key and enter this on line 22 You then need to define the menu items of the Home Assistant devices you want to be able to control, this is done on the lines 49 to 96. Lines 49 – 62 define each menu item that is displayed. Lines 65 – 73 add said menu items to the menu object. 76 – 84 associates actions with said menu items and 87 – 95 ensures that the menu items are displayed/shown in the menu.

You will also need to download this file and save it in the same folder as the HomeAssistantSystemTray.py file. This is the icon file used to display in the Home Assistant icon in the system tray.

Copy the Python code below into a file HomeAssistantSystemTray.py

#!/usr/bin/env python
"""
Author:      Ian Crane
Date:        17 Apr 2020
Description: Provides a quick click list of application actions hosted by HomeAssistant
"""

import gtk
import os
import sys
import time
import gobject
from requests import get,post

# ------------------------------------------------------------------------------------------------------------------------------------------------------v
# Application settings - Start

# The URL to the HomeAssistant server
homeAssistantURL = "http://<nameofserver/IP>:8123/"
# To get the Home Assistant Long-Lived Access Token goto the URL http://<homeassistantServer>:8123/profile (http://ltp-server:8123/profile) at the bottom of the page request a Long-Lived token
# when asked to enter a name put something like "HomeAssistant Systemtray App" you will then known what the Long-Lived token is used for.
homeAssistantLongLivedAccessToken = "<Homeassistant Long Lived Access Token> "

# Application settings - End
# ------------------------------------------------------------------------------------------------------------------------------------------------------v

YamAmpMuteDuration = 0

homeAssistantHeaders = {
    "Authorization": "Bearer " + homeAssistantLongLivedAccessToken,
    "content-type": "application/json",
}
YamAmp_Mute_Duration1Secs = 130
YamAmp_Mute_Duration2Secs = 3600

def message(data=None):
  "Function to display messages to the user."
  
  msg=gtk.MessageDialog(None, gtk.DIALOG_MODAL,gtk.MESSAGE_INFO, gtk.BUTTONS_OK, data)
  msg.run()
  msg.destroy()
 
def close_app(data=None):
   #systemTrayIcon.set_from_stock(gtk.STOCK_CONNECT)
   #message(data)
   gtk.main_quit()
 
def make_menu(event_button, event_time, data=None):
  global YamAmpMuteDuration
  menu = gtk.Menu()
  mnuItem_YamAmp_On = gtk.MenuItem("Yamaha Amp - Power On")
  mnuItem_YamAmp_Off = gtk.MenuItem("Yamaha Amp - Power Off")
  mnuItem_YamAmp_DVD = gtk.MenuItem("Yamaha Amp - DVD (Office PC)")
  mnuItem_YamAmp_MD = gtk.MenuItem("Yamaha Amp - MD (Bedside Radio)")
  mnuItem_YamAmp_VCR2 = gtk.MenuItem("Yamaha Amp - VCR2 (Office Laptop)")
  mnuItem_YamAmp_Mute = gtk.MenuItem("Yamaha Amp - Mute")
  muteSet = ""
  muteSet = " (Set)" if YamAmpMuteDuration == YamAmp_Mute_Duration1Secs  else ""
  mnuItem_YamAmp_MuteDuration1 = gtk.MenuItem("Yamaha Amp - Mute " + hms(YamAmp_Mute_Duration1Secs) + muteSet)
  muteSet = " (Set)" if YamAmpMuteDuration == YamAmp_Mute_Duration2Secs  else ""
  mnuItem_YamAmp_MuteDuration2 = gtk.MenuItem("Yamaha Amp - Mute " + hms(YamAmp_Mute_Duration2Secs) + muteSet)
  mnuItem_App_Close = gtk.MenuItem("Close App")
  
  #Append the menu items
  menu.append(mnuItem_YamAmp_On)
  menu.append(mnuItem_YamAmp_Off)
  menu.append(mnuItem_YamAmp_DVD)
  menu.append(mnuItem_YamAmp_MD)
  menu.append(mnuItem_YamAmp_VCR2)
  menu.append(mnuItem_YamAmp_Mute)
  menu.append(mnuItem_YamAmp_MuteDuration1) 
  menu.append(mnuItem_YamAmp_MuteDuration2) 
  menu.append(mnuItem_App_Close)

  #Add callbacks
  mnuItem_YamAmp_On.connect_object("activate", CallHAWebService, "script.yamaha_amplifier_on")
  mnuItem_YamAmp_Off.connect_object("activate", CallHAWebService, "script.yamaha_amplifier_off")
  mnuItem_YamAmp_DVD.connect_object("activate", CallHAWebService, "script.yamaha_amplifier_dvd")
  mnuItem_YamAmp_MD.connect_object("activate", CallHAWebService, "script.yamaha_amplifier_md")
  mnuItem_YamAmp_VCR2.connect_object("activate", CallHAWebService, "script.yamaha_amplifier_vcr2")
  mnuItem_YamAmp_Mute.connect_object("activate", CallHAWebService, "script.yamaha_amplifier_mute")
  mnuItem_YamAmp_MuteDuration1.connect_object("activate", SetYamAmpMuteDuration, YamAmp_Mute_Duration1Secs)
  mnuItem_YamAmp_MuteDuration2.connect_object("activate", SetYamAmpMuteDuration, YamAmp_Mute_Duration2Secs)
  mnuItem_App_Close.connect_object("activate", close_app, "Close App")

  #Show the menu items
  mnuItem_YamAmp_On.show()
  mnuItem_YamAmp_Off.show()
  mnuItem_YamAmp_DVD.show()
  mnuItem_YamAmp_MD.show()
  mnuItem_YamAmp_VCR2.show()
  mnuItem_YamAmp_Mute.show()
  mnuItem_YamAmp_MuteDuration1.show()
  mnuItem_YamAmp_MuteDuration2.show()
  mnuItem_App_Close.show()
  
  #Popup the menu
  menu.popup(None, None, None, event_button, event_time)

def CallHAWebService(script):
  webService = "api/services/script/turn_on"
  response = post(homeAssistantURL + webService, headers=homeAssistantHeaders, json={'entity_id' : script})
  if response.status_code != 200:

    if response.status_code == 401:
      advisoryInfo = "Unauthorised access, check that the Long-Lived access token is valid for the HomeAssistant server mentioned above. "
    message("The HTTP Error code [" + str(response.status_code) + "] returned when calling URL:\n " + homeAssistantURL + webService + "\n\n For the entity_id:" + script + "\n\n" + advisoryInfo)
 #response = post(homeAssistantURL + 'api/services/script/turn_on', headers=homeAssistantHeaders, json=jsonCommand)
  print(response)

def on_right_click(data, event_button, event_time):
    make_menu(event_button, event_time)
 
def on_left_click(event):
  about_dialog = gtk.AboutDialog()
  about_dialog.set_destroy_with_parent (True)
  about_dialog.set_icon_name ("HomeAssistant")
  about_dialog.set_name('Home Assistant Quick commands')
  about_dialog.set_version('0.1')
  about_dialog.set_copyright("(C) 2020 Ian Crane")
  about_dialog.set_comments("Program to quickly control items managed by Home Assistant\nHome Assistant URL = " + homeAssistantURL + "\n This application is running from the Python file " + __file__ )
  about_dialog.set_authors(['Ian Crane'])
  about_dialog.run()
  about_dialog.destroy()

def hms(seconds):
    h = seconds // 3600
    m = seconds % 3600 // 60
    s = seconds % 3600 % 60

    if h>0: 
      return '{:02d}h {:02d}m {:02d}s'.format(h, m, s)
    if m>0: 
      return '{:02d}m {:02d}s'.format(m, s)
    if s>0: 
      return '{:02d}s'.format(m, s)
   

def SetYamAmpMuteDuration(Duration):
  global YamAmpMuteDuration
  YamAmpMuteDuration = Duration
  CallHAWebService("script.yamaha_amplifier_mute")
  gobject.timeout_add(Duration*1000,ClearYamAmpMuteDuration,"script.yamaha_amplifier_mute")

def ClearYamAmpMuteDuration(Device):
  global YamAmpMuteDuration
  YamAmpMuteDuration = 0
  CallHAWebService("script.yamaha_amplifier_mute")
  #gobject.timeout_add(YamAmp_Mute_Duration1Secs*1000,CallHAWebService,"script.yamaha_amplifier_mute")

def get_script_path():
    return os.path.dirname(os.path.realpath(sys.argv[0]))

if __name__ == '__main__':
  #systemTrayIcon = gtk.status_icon_new_from_stock(disconnectedIcon)
  systemTrayIcon = gtk.status_icon_new_from_file( get_script_path() + '/homeassistanticon.png')
  systemTrayIcon.set_tooltip("Control devices managed by HomeAssistant")
  systemTrayIcon.connect('popup-menu', on_right_click)
  systemTrayIcon.connect('activate', on_left_click)
  #gobject.timeout_add(internetCheckIntervalSeconds*1000,ping_internet)
  gtk.main()

and do a

chmod a+x HomeAssistantSystemTray.py and then to run it

./HomeAssistantSystemTray.py &




%d bloggers like this: