#!/usr/bin/env python3 from gi.repository import AppIndicator3 from gi.repository import Gtk, GLib, GObject import gi import subprocess import threading import time gi.require_version('Gtk', '3.0') # Usaremos GTK 3 para mayor compatibilidad gi.require_version('AppIndicator3', '0.1') class BluetoothMenu: def __init__(self): self.app = 'bluetooth-menu' self.indicator = AppIndicator3.Indicator.new( self.app, "bluetooth-disabled-symbolic", # Icono inicial AppIndicator3.IndicatorCategory.SYSTEM_SERVICES ) self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) self.menu = Gtk.Menu() self.build_menu() self.indicator.set_menu(self.menu) # Iniciar hilo para actualizar el estado del Bluetooth self.update_thread = threading.Thread(target=self.update_status) self.update_thread.daemon = True self.update_thread.start() def build_menu(self): # Botón Encender item_on = Gtk.MenuItem(label='Encender Bluetooth') item_on.connect('activate', self.turn_on_bluetooth) self.menu.append(item_on) # Botón Apagar item_off = Gtk.MenuItem(label='Apagar Bluetooth') item_off.connect('activate', self.turn_off_bluetooth) self.menu.append(item_off) # Separador self.menu.append(Gtk.SeparatorMenuItem()) # Botón Salir item_quit = Gtk.MenuItem(label='Salir') item_quit.connect('activate', self.quit) self.menu.append(item_quit) self.menu.show_all() def turn_on_bluetooth(self, _): subprocess.run(['bluetoothctl', 'power', 'on']) def turn_off_bluetooth(self, _): subprocess.run(['bluetoothctl', 'power', 'off']) def quit(self, _): Gtk.main_quit() def update_status(self): # Bucle para actualizar el estado while True: GLib.idle_add(self.check_bluetooth_status) time.sleep(5) # Actualizar cada 5 segundos def check_bluetooth_status(self): # Verificar si el Bluetooth está encendido power_status = subprocess.getoutput( 'bluetoothctl show | grep "Powered:"') is_powered = 'yes' in power_status.lower() if not is_powered: # Bluetooth apagado self.indicator.set_icon_full( "/home/teraflops/Icons/bluetooth-poweredoff.png", "Bluetooth Apagado") self.indicator.set_label("", self.app) self.indicator.set_title("Bluetooth Apagado") else: # Bluetooth encendido, verificar si hay dispositivos conectados connected_devices = subprocess.getoutput( 'bluetoothctl devices Connected') if connected_devices: # Hay dispositivos conectados device_info = self.get_connected_device_info() self.indicator.set_icon_full( "/home/teraflops/Icons/bluetooth-connected.png", "Bluetooth Conectado") self.indicator.set_label("", self.app) self.indicator.set_title( f"Conectado a {device_info['name']} ({device_info['battery']}%)") else: # Bluetooth encendido pero sin dispositivos conectados self.indicator.set_icon_full( "/home/teraflops/Icons/bluetooth-poweredon.png", "Bluetooth Encendido") self.indicator.set_label("", self.app) self.indicator.set_title("Bluetooth Encendido") def get_connected_device_info(self): # Obtener la lista de dispositivos conectados devices = subprocess.getoutput('bluetoothctl devices Connected') if devices: for device_line in devices.strip().split('\n'): parts = device_line.strip().split(' ', 2) if len(parts) >= 2: device_mac = parts[1] device_name = parts[2] if len( parts) == 3 else 'Dispositivo Desconocido' # Obtener nivel de batería si está disponible battery_level = self.get_battery_level(device_mac) return {'name': device_name, 'battery': battery_level} return {'name': 'Desconocido', 'battery': 'N/A'} def get_battery_level(self, device_mac): try: # Ejecutar 'bluetoothctl info ' y obtener la salida info_output = subprocess.getoutput( f'bluetoothctl info {device_mac}') # Buscar la línea que contiene 'Battery Percentage' for line in info_output.split('\n'): if 'Battery Percentage' in line: # Extraer el porcentaje de batería battery_line = line.strip() # Formato esperado: 'Battery Percentage: 0x64 (100)' battery_percentage = battery_line.split('(')[1].strip(')%') return battery_percentage # Si no se encuentra la información de batería return 'N/A' except Exception as e: return 'N/A' def main(): BluetoothMenu() GObject.threads_init() Gtk.main() if __name__ == "__main__": main()