#!/usr/bin/env python import gtk import BluetoothPairedDevices from ParrotZik import BatteryStates from ParrotZik import connect from ParrotZik import Rooms from SysIndicator import MenuItem from SysIndicator import Menu from SysIndicator import SysIndicator REFRESH_FREQUENCY = 30000 RECONNECT_FREQUENCY = 5000 class repeat(object): def __init__(self, f): self.f = f self.id = None def __call__(self, cls): self.f(cls) def start(self, cls, frequency): if not self.id: def run(): self.f(cls) return True self.id = gtk.timeout_add(frequency, run) def stop(self): if self.id: gtk.timeout_remove(self.id) self.id = None class ParrotZikIndicator(SysIndicator): def __init__(self): self.menu = Menu() self.info_item = MenuItem("Parrot Zik Not connected..", None, sensitive=False) self.menu.append(self.info_item) self.version_1_interface = ParrotZikVersion1Interface(self) self.version_2_interface = ParrotZikVersion2Interface(self) self.quit = MenuItem("Quit", gtk.main_quit, checkitem=True) self.menu.append(self.quit) SysIndicator.__init__(self, icon="zik-audio-headset", menu=self.menu) self.active_interface = None @repeat def reconnect(self): if self.active_interface: if not self.active_interface.connected: print "Lost connection" self.active_interface.deactivate() else: self.reconnect.stop() else: mac = BluetoothPairedDevices.ParrotZikMac() if mac: parrot = connect(mac) if parrot.api.sock: if parrot.version.startswith('1'): self.version_1_interface.activate(parrot) else: self.version_2_interface.activate(parrot) self.autorefresh(self) self.autorefresh.start(self, REFRESH_FREQUENCY) self.reconnect.stop() print "Connected" else: print "Failed to connect to Parrot Zik %s" % mac @repeat def autorefresh(self): if self.active_interface: self.active_interface.refresh() else: self.reconnect.start(self, RECONNECT_FREQUENCY) self.autorefresh.stop() def main(self): self.reconnect.start(self, RECONNECT_FREQUENCY) SysIndicator.main(self) class ParrotZikBaseInterface(object): def __init__(self, indicator): self.indicator = indicator self.parrot = None self.battery_level = MenuItem("Battery Level:", None, sensitive=False, visible=False) self.battery_state = MenuItem("Battery State:", None, sensitive=False, visible=False) self.firmware_version = MenuItem("Firmware Version:", None, sensitive=False, visible=False) self.auto_connection = MenuItem("Auto Connection", self.toggleAuto, checkitem=True, visible=False) self.indicator.menu.append(self.battery_level) self.indicator.menu.append(self.battery_state) self.indicator.menu.append(self.firmware_version) self.indicator.menu.append(self.auto_connection) @property def connected(self): if self.parrot: return self.parrot.api.sock else: return False def activate(self, parrot): self.parrot = parrot self.battery_level.show() self.battery_state.show() self.firmware_version.show() self.auto_connection.show() self.indicator.info_item.set_label("Connected to: " + self.parrot.friendly_name) self.firmware_version.set_label( "Firmware version: " + self.parrot.version) self.auto_connection.set_active(self.parrot.auto_connect) self.indicator.active_interface = self self.indicator.menu.reposition() def deactivate(self): self.parrot = None self.battery_level.hide() self.battery_state.hide() self.firmware_version.hide() self.auto_connection.hide() self.indicator.setIcon("zik-audio-headset") self.indicator.info_item.set_label("Parrot Zik Not connected..") self.indicator.menu.reposition() self.indicator.active_interface = None def toggleAuto(self, widget): if self.connected: self.parrot.auto_connection = self.auto_connection.get_active() self.auto_connection.set_active(self.parrot.auto_connection) def refresh(self): if self.connected: print "Updating battery" battery_level = self.parrot.battery_level battery_state = self.parrot.battery_state if battery_state == BatteryStates.CHARGING: self.indicator.setIcon("zik-battery-charging") elif battery_level > 80: self.indicator.setIcon("zik-battery-100") elif battery_level > 60: self.indicator.setIcon("zik-battery-080") elif battery_level > 40: self.indicator.setIcon("zik-battery-060") elif battery_level > 20: self.indicator.setIcon("zik-battery-040") else: self.indicator.setIcon("zik-battery-low") self.battery_state.set_label( "State: " + BatteryStates.representation[battery_state]) self.battery_level.set_label( "Battery Level: " + str(battery_level)) else: self.deactivate() class ParrotZikVersion1Interface(ParrotZikBaseInterface): def __init__(self, indicator): super(ParrotZikVersion1Interface, self).__init__(indicator) self.noise_cancelation = MenuItem("Noise Cancellation", self.toggleANC, checkitem=True, visible=False) self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggleLouReedMode, checkitem=True, visible=False) self.concert_hall_mode = MenuItem( "Concert Hall Mode", self.toggleParrotConcertHall, checkitem=True, visible=False) self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.lou_reed_mode) self.indicator.menu.append(self.concert_hall_mode) def activate(self, parrot): self.noise_cancelation.show() self.lou_reed_mode.show() self.concert_hall_mode.show() super(ParrotZikVersion1Interface, self).activate(parrot) self.noise_cancelation.set_active(self.parrot.noise_cancel) self.lou_reed_mode.set_active(self.parrot.lou_reed_mode) self.concert_hall_mode.set_active(self.parrot.concert_hall) def deactivate(self): self.noise_cancelation.hide() self.lou_reed_mode.hide() self.concert_hall_mode.hide() super(ParrotZikVersion1Interface, self).deactivate() def toggleANC(self, widget): if self.connected: self.parrot.noise_cancel = self.noise_cancelation.get_active() self.noise_cancelation.set_active(self.parrot.noise_cancel) def toggleLouReedMode(self, widget): if self.connected: self.parrot.lou_reed_mode = self.lou_reed_mode.get_active() self.lou_reed_mode.set_active(self.parrot.lou_reed_mode) self.concert_hall_mode.set_active(self.parrot.concert_hall) self.concert_hall_mode.set_sensitive( not self.lou_reed_mode.get_active()) def toggleParrotConcertHall(self, widget): if self.connected: self.parrot.concert_hall = self.concert_hall_mode.get_active() self.concert_hall_mode.set_active(self.parrot.concert_hall) class ParrotZikVersion2Interface(ParrotZikBaseInterface): def __init__(self, indicator): self.dirty = False super(ParrotZikVersion2Interface, self).__init__(indicator) self.noise_cancelation = MenuItem("Noise Cancellation", None, sensitive=True, visible=False) self.noise_cancelation_submenu = Menu() self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) self.noise_cancelation_enabled = MenuItem("Enabled", self.toggleANC, sensitive=False, checkitem=True) self.noise_cancelation_mode0 = MenuItem("Mode0", self.toggledummy, sensitive=False, checkitem=True) self.noise_cancelation_mode1 = MenuItem("Mode1", self.toggledummy, sensitive=False, checkitem=True) self.noise_cancelation_mode2 = MenuItem("Mode2", self.toggledummy, sensitive=False, checkitem=True) self.noise_cancelation_mode3 = MenuItem("Mode3", self.toggledummy, sensitive=False, checkitem=True) self.noise_cancelation_submenu.append(self.noise_cancelation_enabled) self.noise_cancelation_submenu.append(self.noise_cancelation_mode0) self.noise_cancelation_submenu.append(self.noise_cancelation_mode1) self.noise_cancelation_submenu.append(self.noise_cancelation_mode2) self.noise_cancelation_submenu.append(self.noise_cancelation_mode3) self.indicator.menu.append(self.noise_cancelation) self.room_sound_effect = MenuItem( "Room Sound Effect", None, sensitive=True, checkitem=False, visible=False) self.room_sound_effect_submenu = Menu() self.room_sound_effect.set_submenu(self.room_sound_effect_submenu) self.room_sound_effect_enabled = MenuItem( "Enabled", self.toggle_room_sound_effect, sensitive=True, checkitem=True) self.rooms = MenuItem("Rooms", None, sensitive=True, checkitem=False) self.angle = MenuItem("Angle", None, sensitive=True, checkitem=False) self.room_sound_effect_submenu.append(self.room_sound_effect_enabled) self.room_sound_effect_submenu.append(self.rooms) self.room_sound_effect_submenu.append(self.angle) self.rooms_submenu = Menu() self.rooms.set_submenu(self.rooms_submenu) self.concert_hall_mode = MenuItem("Concert Hall", self.toggle_concert_hall_mode, sensitive=True, checkitem=True) self.jazz_mode = MenuItem("Jazz Club", self.toggle_jazz_club_mode, sensitive=True, checkitem=True) self.living_mode = MenuItem("Libing Room", self.toggle_living_room_mode, sensitive=True, checkitem=True) self.silent_mode = MenuItem("Silent Room", self.toggle_silent_room_mode, sensitive=True, checkitem=True) self.rooms_submenu.append(self.concert_hall_mode) self.rooms_submenu.append(self.jazz_mode) self.rooms_submenu.append(self.living_mode) self.rooms_submenu.append(self.silent_mode) self.indicator.menu.append(self.room_sound_effect) self.angle_submenu = Menu() self.angle.set_submenu(self.angle_submenu) self.angle_30 = MenuItem("30", self.toggle_angle_30, sensitive=True, checkitem=True) self.angle_60 = MenuItem("60", self.toggle_angle_60, sensitive=True, checkitem=True) self.angle_90 = MenuItem("90", self.toggle_angle_90, sensitive=True, checkitem=True) self.angle_120 = MenuItem("120", self.toggle_angle_120, sensitive=True, checkitem=True) self.angle_150 = MenuItem("150", self.toggle_angle_150, sensitive=True, checkitem=True) self.angle_180 = MenuItem("180", self.toggle_angle_180, sensitive=True, checkitem=True) self.angle_submenu.append(self.angle_30) self.angle_submenu.append(self.angle_60) self.angle_submenu.append(self.angle_90) self.angle_submenu.append(self.angle_120) self.angle_submenu.append(self.angle_150) self.angle_submenu.append(self.angle_180) self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, sensitive=True, checkitem=True, visible=False) self.indicator.menu.append(self.flight_mode) def activate(self, parrot): self.noise_cancelation.show() self.concert_hall_mode.show() self.flight_mode.show() self.room_sound_effect.show() super(ParrotZikVersion2Interface, self).activate(parrot) self.noise_cancelation_enabled.set_active(self.parrot.noise_cancel) self.flight_mode.set_active(self.parrot.flight_mode) self.read_sound_effect_room() self.read_sound_effect_angle() sound_effect = self.parrot.sound_effect self.room_sound_effect_enabled.set_active(sound_effect) self.concert_hall_mode.set_sensitive(sound_effect) self.jazz_mode.set_sensitive(sound_effect) self.living_mode.set_sensitive(sound_effect) self.silent_mode.set_sensitive(sound_effect) self.angle_30.set_sensitive(sound_effect) self.angle_60.set_sensitive(sound_effect) self.angle_90.set_sensitive(sound_effect) self.angle_120.set_sensitive(sound_effect) self.angle_150.set_sensitive(sound_effect) self.angle_180.set_sensitive(sound_effect) def deactivate(self): self.noise_cancelation.hide() self.concert_hall_mode.hide() self.flight_mode.hide() self.room_sound_effect.hide() super(ParrotZikVersion2Interface, self).deactivate() def toggleANC(self, widget): if self.connected: self.parrot.noise_cancel = self.noise_cancelation.get_active() self.noise_cancelation.set_active(self.parrot.noise_cancel) def toggle_flight_mode(self, widget): if self.connected: self.parrot.flight_mode = self.flight_mode.get_active() self.flight_mode.set_active(self.parrot.flight_mode) def toggledummy(self, widget): print(widget.get_name()) def toggle_concert_hall_mode(self, widget): self.toggle_room(Rooms.CONCERT_HALL) def toggle_jazz_club_mode(self, widget): self.toggle_room(Rooms.JAZZ_CLUB) def toggle_living_room_mode(self, widget): self.toggle_room(Rooms.LIVING_ROOM) def toggle_silent_room_mode(self, widget): self.toggle_room(Rooms.SILENT_ROOM) def toggle_room(self, room): if self.connected and not self.dirty: self.parrot.room = room self.dirty = True self.read_sound_effect_room() self.dirty = False def read_sound_effect_room(self): active_room = self.parrot.room room_to_menuitem_map = ( (Rooms.CONCERT_HALL, self.concert_hall_mode), (Rooms.JAZZ_CLUB, self.jazz_mode), (Rooms.LIVING_ROOM, self.living_mode), (Rooms.SILENT_ROOM, self.silent_mode), ) for room, menu_item in room_to_menuitem_map: menu_item.set_active(room == active_room) def toggle_room_sound_effect(self, widget): if self.connected: self.parrot.sound_effect = self.room_sound_effect_enabled.get_active() sound_effect = self.parrot.sound_effect self.room_sound_effect_enabled.set_active(sound_effect) self.concert_hall_mode.set_sensitive(sound_effect) self.jazz_mode.set_sensitive(sound_effect) self.living_mode.set_sensitive(sound_effect) self.silent_mode.set_sensitive(sound_effect) self.angle_30.set_sensitive(sound_effect) self.angle_60.set_sensitive(sound_effect) self.angle_90.set_sensitive(sound_effect) self.angle_120.set_sensitive(sound_effect) self.angle_150.set_sensitive(sound_effect) self.angle_180.set_sensitive(sound_effect) def toggle_angle_30(self, widget): self.toggle_angle(30) def toggle_angle_60(self, widget): self.toggle_angle(60) def toggle_angle_90(self, widget): self.toggle_angle(90) def toggle_angle_120(self, widget): self.toggle_angle(120) def toggle_angle_150(self, widget): self.toggle_angle(150) def toggle_angle_180(self, widget): self.toggle_angle(180) def toggle_angle(self, angle): if self.connected and not self.dirty: self.parrot.angle = angle self.dirty = True self.read_sound_effect_angle() self.dirty = False def read_sound_effect_angle(self): active_angle = self.parrot.angle angle_to_menuitem_map = ( (30, self.angle_30), (60, self.angle_60), (90, self.angle_90), (120, self.angle_120), (150, self.angle_150), (180, self.angle_180), ) for angle, menu_item in angle_to_menuitem_map: menu_item.set_active(angle == active_angle) if __name__ == "__main__": indicator = ParrotZikIndicator() indicator.main()