aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ParrotZik.py204
-rwxr-xr-xParrotZikTray119
-rw-r--r--SysIndicator.py6
3 files changed, 234 insertions, 95 deletions
diff --git a/ParrotZik.py b/ParrotZik.py
index 514be50..6c1cd69 100644
--- a/ParrotZik.py
+++ b/ParrotZik.py
@@ -7,63 +7,111 @@ else:
import ParrotProtocol
from BeautifulSoup import BeautifulSoup
-class ParrotZik(object):
- def __init__(self, addr=None):
- uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb",
- "8B6814D3-6CE7-4498-9700-9312C1711F63"]
+def connect(addr=None):
+ uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb",
+ "8B6814D3-6CE7-4498-9700-9312C1711F63"]
+
+ if sys.platform == "darwin":
+ service_matches = lightblue.findservices(
+ name="Parrot RFcomm service", addr=addr)
+ else:
+ for uuid in uuids:
+ service_matches = bluetooth.find_service(uuid=uuid,
+ address=addr)
+ if service_matches:
+ break
+
+ if len(service_matches) == 0:
+ print "Failed to find Parrot Zik RFCOMM service"
+ return ParrotZikBase(ParrotZikApi(None))
+
+ if sys.platform == "darwin":
+ first_match = service_matches[0]
+ port = first_match[1]
+ name = first_match[2]
+ host = first_match[0]
+ else:
+ first_match = service_matches[0]
+ port = first_match["port"]
+ name = first_match["name"]
+ host = first_match["host"]
+
+ print "Connecting to \"%s\" on %s" % (name, host)
+
+ if sys.platform == "darwin":
+ sock = lightblue.socket()
+ else:
+ sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
+
+ sock.connect((host, port))
+
+ sock.send('\x00\x03\x00')
+ data = sock.recv(1024)
+ api = ParrotZikApi(sock)
+ if api.version.startswith('1'):
+ return ParrotZikVersion1(api)
+ else:
+ return ParrotZikVersion2(api)
+
+
+class ParrotZikApi(object):
+ def __init__(self, socket):
+ self.sock = socket
- if sys.platform == "darwin":
- service_matches = lightblue.findservices(
- name="Parrot RFcomm service", addr=addr)
- else:
- for uuid in uuids:
- service_matches = bluetooth.find_service(uuid=uuid,
- address=addr)
- if service_matches:
- break
-
- if len(service_matches) == 0:
- print "Failed to find Parrot Zik RFCOMM service"
- self.sock = ""
- return
+ @property
+ def version(self):
+ data = self.get("/api/software/version/get")
+ try:
+ return data.answer.software["version"]
+ except KeyError:
+ return data.answer.software['sip6']
- if sys.platform == "darwin":
- first_match = service_matches[0]
- port = first_match[1]
- name = first_match[2]
- host = first_match[0]
- else:
- first_match = service_matches[0]
- port = first_match["port"]
- name = first_match["name"]
- host = first_match["host"]
+ def get(self, message):
+ message = ParrotProtocol.getRequest(message)
+ return self.send_message(message)
- print "Connecting to \"%s\" on %s" % (name, host)
+ def set(self, message, arg):
+ message = ParrotProtocol.setRequest(message, str(arg).lower())
+ return self.send_message(message)
+ def send_message(self, message):
+ try:
+ self.sock.send(str(message))
+ except Exception:
+ self.sock = ""
+ return
if sys.platform == "darwin":
- self.sock = lightblue.socket()
+ data = self.sock.recv(30)
else:
- self.sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
+ data = self.sock.recv(7)
+ data = self.sock.recv(1024)
+ data = BeautifulSoup(data)
+ return data
- self.sock.connect((host, port))
+ def close(self):
+ self.sock.close()
- self.sock.send('\x00\x03\x00')
- data = self.sock.recv(1024)
+class ParrotZikBase(object):
+ def __init__(self, api):
+ self.api = api
self.BatteryLevel = 100
self.BatteryCharging = False
@property
+ def version(self):
+ return self.api.version
+
+ @property
def battery_state(self):
- data = self.get("/api/system/battery/get")
+ data = self.api.get("/api/system/battery/get")
return data.answer.system.battery["state"]
- @property
- def battery_level(self):
- data = self.get("/api/system/battery/get")
+ def get_battery_level(self, field_name):
+ data = self.api.get("/api/system/battery/get")
try:
- if data.answer.system.battery["level"] != '':
- self.BatteryLevel = data.answer.system.battery["level"]
+ if data.answer.system.battery[field_name] != '':
+ self.BatteryLevel = data.answer.system.battery[field_name]
if data.answer.system.battery["state"] == 'charging':
self.BatteryCharging = True
else:
@@ -79,37 +127,29 @@ class ParrotZik(object):
return self.BatteryLevel
@property
- def version(self):
- data = self.get("/api/software/version/get")
- try:
- return data.answer.software["version"]
- except KeyError:
- return data.answer.software['sip6']
-
- @property
def friendly_name(self):
- data = self.get("/api/bluetooth/friendlyname/get")
+ data = self.api.get("/api/bluetooth/friendlyname/get")
return data.answer.bluetooth["friendlyname"]
@property
def auto_connect(self):
- data = self.get("/api/system/auto_connection/enabled/get")
+ data = self.api.get("/api/system/auto_connection/enabled/get")
return self._result_to_bool(
data.answer.system.auto_connection["enabled"])
@auto_connect.setter
def auto_connect(self, arg):
- self.set("/api/system/auto_connection/enabled/set", arg)
+ self.api.get("/api/system/auto_connection/enabled/set", arg)
@property
def anc_phone_mode(self):
- data = self.get("/api/system/anc_phone_mode/enabled/get")
+ data = self.api.get("/api/system/anc_phone_mode/enabled/get")
return self._result_to_bool(
data.answer.system.anc_phone_mode["enabled"])
@property
def noise_cancel(self):
- data = self.get("/api/audio/noise_cancellation/enabled/get")
+ data = self.api.get("/api/audio/noise_cancellation/enabled/get")
try:
return self._result_to_bool(
data.answer.audio.noise_cancellation["enabled"])
@@ -118,24 +158,11 @@ class ParrotZik(object):
@noise_cancel.setter
def noise_cancel(self, arg):
- self.set("/api/audio/noise_cancellation/enabled/set", arg)
-
- @property
- def lou_reed_mode(self):
- data = self.get("/api/audio/specific_mode/enabled/get")
- try:
- return self._result_to_bool(
- data.answer.audio.specific_mode["enabled"])
- except TypeError:
- return False
-
- @lou_reed_mode.setter
- def lou_reed_mode(self, arg):
- self.set("/api/audio/specific_mode/enabled/set", arg)
+ self.api.get("/api/audio/noise_cancellation/enabled/set", arg)
@property
def concert_hall(self):
- data = self.get("/api/audio/sound_effect/enabled/get")
+ data = self.api.get("/api/audio/sound_effect/enabled/get")
try:
return self._result_to_bool(
data.answer.audio.sound_effect["enabled"])
@@ -144,7 +171,7 @@ class ParrotZik(object):
@concert_hall.setter
def concert_hall(self, arg):
- self.set("/api/audio/sound_effect/enabled/set", arg)
+ self.api.get("/api/audio/sound_effect/enabled/set", arg)
def _result_to_bool(self, result):
if result == "true":
@@ -154,27 +181,24 @@ class ParrotZik(object):
else:
raise AssertionError(result)
- def get(self, message):
- message = ParrotProtocol.getRequest(message)
- return self.send_message(message)
- def set(self, message, arg):
- message = ParrotProtocol.setRequest(message, str(arg).lower())
- return self.send_message(message)
+class ParrotZikVersion1(ParrotZikBase):
+ @property
+ def battery_level(self):
+ return self.get_battery_level('level')
- def send_message(self, message):
- try:
- self.sock.send(str(message))
- except Exception:
- self.sock = ""
- return
- if sys.platform == "darwin":
- data = self.sock.recv(30)
- else:
- data = self.sock.recv(7)
- data = self.sock.recv(1024)
- data = BeautifulSoup(data)
- return data
+ @property
+ def lou_reed_mode(self):
+ data = self.api.get("/api/audio/specific_mode/enabled/get")
+ return self._result_to_bool(
+ data.answer.audio.specific_mode["enabled"])
- def close(self):
- self.sock.close()
+ @lou_reed_mode.setter
+ def lou_reed_mode(self, arg):
+ self.api.get("/api/audio/specific_mode/enabled/set", arg)
+
+
+class ParrotZikVersion2(ParrotZikBase):
+ @property
+ def battery_level(self):
+ return self.get_battery_level('percent')
diff --git a/ParrotZikTray b/ParrotZikTray
index 2245807..b955a47 100755
--- a/ParrotZikTray
+++ b/ParrotZikTray
@@ -43,6 +43,7 @@ class ParrotZikIndicator(SysIndicator):
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)
@@ -53,7 +54,7 @@ class ParrotZikIndicator(SysIndicator):
@repeat
def reconnect(self):
if self.active_interface:
- if not self.active_interface.parrot.sock:
+ if not self.active_interface.connected:
print "Lost connection"
self.active_interface.deactivate()
else:
@@ -61,9 +62,12 @@ class ParrotZikIndicator(SysIndicator):
else:
mac = BluetoothPairedDevices.ParrotZikMac()
if mac:
- parrot = ParrotZik.ParrotZik(mac)
- if parrot.sock:
- self.version_1_interface.activate(parrot)
+ parrot = ParrotZik.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()
@@ -103,7 +107,7 @@ class ParrotZikBaseInterface(object):
@property
def connected(self):
if self.parrot:
- return self.parrot.sock
+ return self.parrot.api.sock
else:
return False
@@ -138,6 +142,9 @@ class ParrotZikBaseInterface(object):
self.parrot.auto_connection = self.auto_connection.get_active()
self.auto_connection.set_active(self.parrot.auto_connection)
+ def refresh(self):
+ raise NotImplementedError
+
class ParrotZikVersion1Interface(ParrotZikBaseInterface):
def __init__(self, indicator):
@@ -223,6 +230,108 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface):
self.deactivate()
+class ParrotZikVersion2Interface(ParrotZikBaseInterface):
+ def __init__(self, indicator):
+ 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.concert_hall_mode = MenuItem(
+ "Sound Mode", None, sensitive=True, checkitem=False, visible=False)
+ self.concert_hall_mode_submenu = Menu()
+ self.concert_hall_mode.set_submenu(self.concert_hall_mode_submenu)
+
+ self.concert_hall_mode_enabled = MenuItem("Enabled", None,
+ sensitive=True, checkitem=True)
+ self.concert_hall = MenuItem("Concert Hall", None,
+ sensitive=True, checkitem=True)
+ self.jazz_mode = MenuItem("Jazz Club", None,
+ sensitive=True, checkitem=True)
+ self.living_mode = MenuItem("Libing Room", None,
+ sensitive=True, checkitem=True)
+ self.silent_mode = MenuItem("Silent Room", None,
+ sensitive=True, checkitem=True)
+ self.concert_hall_mode_submenu.append(self.concert_hall_mode_enabled)
+ self.concert_hall_mode_submenu.append(self.concert_hall)
+ self.concert_hall_mode_submenu.append(self.jazz_mode)
+ self.concert_hall_mode_submenu.append(self.living_mode)
+ self.concert_hall_mode_submenu.append(self.silent_mode)
+ self.indicator.menu.append(self.concert_hall_mode)
+
+ self.flight_mode = MenuItem("Flight Mode", None,
+ 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()
+ super(ParrotZikVersion2Interface, self).activate(parrot)
+ self.noise_cancelation_enabled.set_active(self.parrot.noise_cancel)
+ # self.flight_mode.set_active(self.parrot.flight_mode)
+
+ 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 toggledummy(self, widget):
+ print(widget.get_name())
+
+ def refresh(self):
+ if self.connected:
+ print "Updating battery"
+ self.batteryLevel = int(self.parrot.battery_level)
+
+ if self.parrot.BatteryCharging:
+ self.batteryLevel = "Charging"
+ self.indicator.setIcon("zik-battery-charging")
+ self.batteryLevel = "Unknown"
+ self.batteryState = "Charging"
+ elif self.batteryLevel > 80:
+ self.indicator.setIcon("zik-battery-100")
+ self.batteryState = "In Use"
+ elif self.batteryLevel > 60:
+ self.indicator.setIcon("zik-battery-080")
+ self.batteryState = "In Use"
+ elif self.batteryLevel > 40:
+ self.indicator.setIcon("zik-battery-060")
+ self.batteryState = "In Use"
+ elif self.batteryLevel > 20:
+ self.indicator.setIcon("zik-battery-040")
+ self.batteryState = "In Use"
+ else:
+ self.indicator.setIcon("zik-battery-low")
+ self.batteryState = "In Use"
+
+ self.indicator.info_item.set_label("Connected to: " + self.name)
+ self.firmware_version.set_label(
+ "Firmware version: " + self.version)
+ self.battery_state.set_label("State: " + self.batteryState)
+ self.battery_level.set_label(
+ "Battery Level: " + str(self.batteryLevel))
+ else:
+ self.deactivate()
+
if __name__ == "__main__":
indicator = ParrotZikIndicator()
indicator.main()
diff --git a/SysIndicator.py b/SysIndicator.py
index 804b001..6aa4686 100644
--- a/SysIndicator.py
+++ b/SysIndicator.py
@@ -177,6 +177,9 @@ class MenuItemBase(object):
def hide(self):
self.base_item.hide()
+ def set_submenu(self, menu):
+ raise NotImplementedError
+
class GTKMenuItem(MenuItemBase):
def __init__(self, name, action, sensitive=True, checkitem=False, visible=True):
if checkitem:
@@ -199,6 +202,9 @@ class GTKMenuItem(MenuItemBase):
def set_label(self, option):
return self.base_item.set_label(option)
+ def set_submenu(self, menu):
+ self.base_item.set_submenu(menu.gtk_menu)
+
class NSMenuItem(MenuItemBase):
def __init__(self, name, action, sensitive=True, checkitem=False, visible=True):