#!/usr/bin/env python3 # Hubitat Menu # v1.0 # Erick Ruiz de Chavez # Simple toggle menu for Hubitat devices. Requires the Toggle API App. # python # string(LIST_DEVICES_URL): List Devices URL. Provided by the Toggle API App. # boolean(USE_INTERNAL_URL=true): Whether to be use the internal or external toggle URL. # boolean(RUN_IN_TERMINAL=false): Whether to run the menu selections in a terminal window. (For debugging purposes). # boolean(SHOW_ICON=true): Whether to show the menu icon on the taskbar. # boolean(SHOW_TEXT=false): Whether to show the menu label on the taskbar. import json import os import sys from urllib.request import urlopen LIST_DEVICES_URL = os.getenv("LIST_DEVICES_URL") USE_INTERNAL_URL = os.getenv("USE_INTERNAL_URL", "true") == "true" RUN_IN_TERMINAL = os.getenv("RUN_IN_TERMINAL") == "true" SHOW_ICON = os.getenv("SHOW_ICON") == "true" SHOW_TEXT = os.getenv("SHOW_TEXT") == "true" def log_run(function_name): with open(".hubitat.log", mode="a", encoding="utf8") as file: content = f"FUNCTION: {function_name} | ARGS: {', '.join(sys.argv)} | LIST_DEVICES_URL: {LIST_DEVICES_URL} | USE_INTERNAL_URL: {USE_INTERNAL_URL} | RUN_IN_TERMINAL: {RUN_IN_TERMINAL}\n" file.write(content) def get_devices(list_devices_url): log_run("get_devices") devices = [] with urlopen(list_devices_url) as response: devices = json.loads(response.read().decode()) return devices def toggle_device(device_url): log_run("toggle_device") urlopen(device_url) return def print_menu(items): log_run("print_menu") menu_icon = ":house:" if SHOW_ICON else "" menu_label = "Hubitat" if SHOW_TEXT else "" menu_space = " " if SHOW_ICON and SHOW_TEXT else "" menu = menu_space.join([menu_icon, menu_label]) menus = [] menus.append(menu) menus.append("---") menus += items print("\n".join(menus)) def print_devices_menu(devices, use_internal_url, run_in_terminal): log_run("print_devices_menu") items = [] for device in devices: device_name = device["Name"] device_url = ( device["InternalURL"] if use_internal_url else device["ExternalURL"] ) script_path = os.path.realpath(__file__) segments = [] segments.append(device_name) segments.append(f'shell="{script_path}"') segments.append(f'param1="{device_url}"') if run_in_terminal: segments.append("terminal=true") items.append(" | ".join(segments)) items.sort() print_menu(items=items) def print_error_menu(): log_run("print_error_menu") print_menu( items=[ 'List Devices URL variable is missing! Please select "Open plugin..." from xbar\'s menu to configure the plugin.' ] ) def main(): log_run("main") if len(sys.argv) > 1: toggle_device(device_url=sys.argv[1]) return if LIST_DEVICES_URL is None: print_error_menu() return devices = get_devices(list_devices_url=LIST_DEVICES_URL) print_devices_menu( devices=devices, use_internal_url=USE_INTERNAL_URL, run_in_terminal=RUN_IN_TERMINAL, ) if __name__ == "__main__": main()