From 419e24ce24087a3f0159fb5c7527eab766987155 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 13:40:17 +0200 Subject: Replace tabs with 4 spaces. --- BluetoothPairedDevices.py | 62 +++++------ ParrotProtocol.py | 20 ++-- ParrotZik.py | 270 +++++++++++++++++++++++----------------------- ParrotZikTray | 2 +- StatusAppMac.py | 2 +- SysIndicator.py | 4 +- 6 files changed, 180 insertions(+), 180 deletions(-) diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py index 6f9f673..e7b1e49 100644 --- a/BluetoothPairedDevices.py +++ b/BluetoothPairedDevices.py @@ -1,44 +1,44 @@ #!/usr/bin/python -import sys +import sys import re import os def ParrotZikMac(): - p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') - if sys.platform == "linux2": - out = os.popen("bluez-test-device list").read() - res = p.findall(out) - if len(res)>0: - return res[0] + p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') + if sys.platform == "linux2": + out = os.popen("bluez-test-device list").read() + res = p.findall(out) + if len(res)>0: + return res[0] - elif sys.platform == "darwin": - fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") - plist = binplist.BinaryPlist(file_obj=fd) - parsed_plist = plist.Parse() - try : - for mac in parsed_plist['PairedDevices']: - if p.match(mac.replace("-",":")): - return mac.replace("-",":") - except: - pass + elif sys.platform == "darwin": + fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") + plist = binplist.BinaryPlist(file_obj=fd) + parsed_plist = plist.Parse() + try : + for mac in parsed_plist['PairedDevices']: + if p.match(mac.replace("-",":")): + return mac.replace("-",":") + except: + pass - elif sys.platform == "win32": - aReg = _winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE) - aKey = _winreg.OpenKey(aReg, 'SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices') - for i in range(10): - try: - asubkey_name=_winreg.EnumKey(aKey,i) - mac =':'.join(asubkey_name[i:i+2] for i in range(0,12,2)) - res = p.findall(mac) - if len(res)>0: - return res[0] + elif sys.platform == "win32": + aReg = _winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE) + aKey = _winreg.OpenKey(aReg, 'SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices') + for i in range(10): + try: + asubkey_name=_winreg.EnumKey(aKey,i) + mac =':'.join(asubkey_name[i:i+2] for i in range(0,12,2)) + res = p.findall(mac) + if len(res)>0: + return res[0] - except EnvironmentError: - pass + except EnvironmentError: + pass if sys.platform == "darwin": - from binplist import binplist + from binplist import binplist elif sys.platform == "win32": - import _winreg \ No newline at end of file + import _winreg diff --git a/ParrotProtocol.py b/ParrotProtocol.py index 9324b8b..1973ba0 100644 --- a/ParrotProtocol.py +++ b/ParrotProtocol.py @@ -1,19 +1,19 @@ #!/usr/bin/env python def generateRequest(requestString): - message=bytearray() - message.extend(generateHeader(requestString)) - message.extend(bytearray(requestString)) - return message + message=bytearray() + message.extend(generateHeader(requestString)) + message.extend(bytearray(requestString)) + return message def generateHeader(requestString): - header = bytearray([0]) - header.append(len(requestString)+3) - header.append("\x80") - return header + header = bytearray([0]) + header.append(len(requestString)+3) + header.append("\x80") + return header def getRequest(apiString): - return generateRequest("GET "+apiString) + return generateRequest("GET "+apiString) def setRequest(apiString,args): - return generateRequest("SET "+apiString+"?arg="+args) \ No newline at end of file + return generateRequest("SET "+apiString+"?arg="+args) diff --git a/ParrotZik.py b/ParrotZik.py index 8a2fca6..327a136 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -2,145 +2,145 @@ import sys if sys.platform == "darwin": - import lightblue + import lightblue else: - import bluetooth + import bluetooth import ParrotProtocol import struct from BeautifulSoup import BeautifulSoup class ParrotZik(object): - def __init__(self,addr=None): - uuid = "0ef0f502-f0ee-46c9-986c-54ed027807fb" - - - if sys.platform == "darwin": - service_matches = lightblue.findservices( name = "Parrot RFcomm service", addr = addr ) - else: - service_matches = bluetooth.find_service( uuid = uuid, address = addr ) - - - if len(service_matches) == 0: - print "Failed to find Parrot Zik RFCOMM service" - self.sock ="" - return - - 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": - self.sock=lightblue.socket() - else: - self.sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) - - self.sock.connect((host, port)) - - self.sock.send('\x00\x03\x00') - data = self.sock.recv(1024) - - self.BatteryLevel = 100 - self.BatteryCharging = False - print "Connected" - - def getBatteryState(self): - data = self.sendGetMessage("/api/system/battery/get") - return data.answer.system.battery["state"] - - def getBatteryLevel(self): - data = self.sendGetMessage("/api/system/battery/get") - try: - if data.answer.system.battery["level"] <> '': - self.BatteryLevel = data.answer.system.battery["level"] - if data.answer.system.battery["state"] == 'charging': - self.BatteryCharging = True - else: - self.BatteryCharging = False - except: - pass - - try: - print "notification received" + data.notify["path"] - except: - pass - - return self.BatteryLevel - - def getVersion(self): - data = self.sendGetMessage("/api/software/version/get") - return data.answer.software["version"] - - def getFriendlyName(self): - data = self.sendGetMessage("/api/bluetooth/friendlyname/get") - return data.answer.bluetooth["friendlyname"] - - def getAutoConnection(self): - data = self.sendGetMessage("/api/system/auto_connection/enabled/get") - return data.answer.system.auto_connection["enabled"] - - def setAutoConnection(self,arg): - data = self.sendSetMessage("/api/system/auto_connection/enabled/set",arg) - return data - - def getAncPhoneMode(self): - data = self.sendGetMessage("/api/system/anc_phone_mode/enabled/get") - return data.answer.system.anc_phone_mode["enabled"] - - def getNoiseCancel(self): - data = self.sendGetMessage("/api/audio/noise_cancellation/enabled/get") - return data.answer.audio.noise_cancellation["enabled"] - - def setNoiseCancel(self,arg): - data = self.sendSetMessage("/api/audio/noise_cancellation/enabled/set",arg) - return data - - def getLouReedMode(self): - data = self.sendGetMessage("/api/audio/specific_mode/enabled/get") - return data.answer.audio.specific_mode["enabled"] - - def setLouReedMode(self,arg): - data = self.sendSetMessage("/api/audio/specific_mode/enabled/set",arg) - return data - - def getParrotConcertHall(self): - data = self.sendGetMessage("/api/audio/sound_effect/enabled/get") - return data.answer.audio.sound_effect["enabled"] - - def setParrotConcertHall(self,arg): - data = self.sendSetMessage("/api/audio/sound_effect/enabled/set",arg) - return data - - def sendGetMessage(self,message): - message = ParrotProtocol.getRequest(message) - return self.sendMessage(message) - - def sendSetMessage(self,message,arg): - message = ParrotProtocol.setRequest(message,arg) - return self.sendMessage(message) - - def sendMessage(self,message): - try: - self.sock.send(str(message)) - except: - 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 - - def Close(self): - self.sock.close() \ No newline at end of file + def __init__(self,addr=None): + uuid = "0ef0f502-f0ee-46c9-986c-54ed027807fb" + + + if sys.platform == "darwin": + service_matches = lightblue.findservices( name = "Parrot RFcomm service", addr = addr ) + else: + service_matches = bluetooth.find_service( uuid = uuid, address = addr ) + + + if len(service_matches) == 0: + print "Failed to find Parrot Zik RFCOMM service" + self.sock ="" + return + + 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": + self.sock=lightblue.socket() + else: + self.sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) + + self.sock.connect((host, port)) + + self.sock.send('\x00\x03\x00') + data = self.sock.recv(1024) + + self.BatteryLevel = 100 + self.BatteryCharging = False + print "Connected" + + def getBatteryState(self): + data = self.sendGetMessage("/api/system/battery/get") + return data.answer.system.battery["state"] + + def getBatteryLevel(self): + data = self.sendGetMessage("/api/system/battery/get") + try: + if data.answer.system.battery["level"] <> '': + self.BatteryLevel = data.answer.system.battery["level"] + if data.answer.system.battery["state"] == 'charging': + self.BatteryCharging = True + else: + self.BatteryCharging = False + except: + pass + + try: + print "notification received" + data.notify["path"] + except: + pass + + return self.BatteryLevel + + def getVersion(self): + data = self.sendGetMessage("/api/software/version/get") + return data.answer.software["version"] + + def getFriendlyName(self): + data = self.sendGetMessage("/api/bluetooth/friendlyname/get") + return data.answer.bluetooth["friendlyname"] + + def getAutoConnection(self): + data = self.sendGetMessage("/api/system/auto_connection/enabled/get") + return data.answer.system.auto_connection["enabled"] + + def setAutoConnection(self,arg): + data = self.sendSetMessage("/api/system/auto_connection/enabled/set",arg) + return data + + def getAncPhoneMode(self): + data = self.sendGetMessage("/api/system/anc_phone_mode/enabled/get") + return data.answer.system.anc_phone_mode["enabled"] + + def getNoiseCancel(self): + data = self.sendGetMessage("/api/audio/noise_cancellation/enabled/get") + return data.answer.audio.noise_cancellation["enabled"] + + def setNoiseCancel(self,arg): + data = self.sendSetMessage("/api/audio/noise_cancellation/enabled/set",arg) + return data + + def getLouReedMode(self): + data = self.sendGetMessage("/api/audio/specific_mode/enabled/get") + return data.answer.audio.specific_mode["enabled"] + + def setLouReedMode(self,arg): + data = self.sendSetMessage("/api/audio/specific_mode/enabled/set",arg) + return data + + def getParrotConcertHall(self): + data = self.sendGetMessage("/api/audio/sound_effect/enabled/get") + return data.answer.audio.sound_effect["enabled"] + + def setParrotConcertHall(self,arg): + data = self.sendSetMessage("/api/audio/sound_effect/enabled/set",arg) + return data + + def sendGetMessage(self,message): + message = ParrotProtocol.getRequest(message) + return self.sendMessage(message) + + def sendSetMessage(self,message,arg): + message = ParrotProtocol.setRequest(message,arg) + return self.sendMessage(message) + + def sendMessage(self,message): + try: + self.sock.send(str(message)) + except: + 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 + + def Close(self): + self.sock.close() diff --git a/ParrotZikTray b/ParrotZikTray index d9bdbc1..57464a7 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -171,4 +171,4 @@ class ParrotZikIndicator(SysIndicator): if __name__ == "__main__": indicator = ParrotZikIndicator() - indicator.main() \ No newline at end of file + indicator.main() diff --git a/StatusAppMac.py b/StatusAppMac.py index fc0bc64..109532f 100644 --- a/StatusAppMac.py +++ b/StatusAppMac.py @@ -22,4 +22,4 @@ class StatusApp(NSApplication): def clicked_(self, notification): self.mymenu.actions[notification._.title]() - NSLog('clicked!') \ No newline at end of file + NSLog('clicked!') diff --git a/SysIndicator.py b/SysIndicator.py index 3c79286..1b344c8 100644 --- a/SysIndicator.py +++ b/SysIndicator.py @@ -22,7 +22,7 @@ class SysIndicator: import appindicator self.icon_directory = os.path.sep + 'usr' + os.path.sep+ 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep if not os.path.isdir(self.icon_directory): - self.icon_directory = os.path.dirname(sys.argv[0]) + os.path.sep + 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep + self.icon_directory = os.path.dirname(sys.argv[0]) + os.path.sep + 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep self.statusicon = appindicator.Indicator("new-parrotzik-indicator", "indicator-messages", appindicator.CATEGORY_APPLICATION_STATUS) @@ -152,4 +152,4 @@ if __name__ == "__main__": menu.append(quit_item) indicator = SysIndicator(icon = "zik-audio-headset",menu = menu) - indicator.main() \ No newline at end of file + indicator.main() -- cgit v1.2.1 From b3912b7c65288aeb5324131cb20b83e9b0bca513 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 13:44:01 +0200 Subject: Remove unneeded interpreter information. --- BluetoothPairedDevices.py | 2 -- ParrotProtocol.py | 2 -- ParrotZik.py | 2 -- 3 files changed, 6 deletions(-) diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py index e7b1e49..96d1a8d 100644 --- a/BluetoothPairedDevices.py +++ b/BluetoothPairedDevices.py @@ -1,5 +1,3 @@ -#!/usr/bin/python - import sys import re import os diff --git a/ParrotProtocol.py b/ParrotProtocol.py index 1973ba0..1af6340 100644 --- a/ParrotProtocol.py +++ b/ParrotProtocol.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - def generateRequest(requestString): message=bytearray() message.extend(generateHeader(requestString)) diff --git a/ParrotZik.py b/ParrotZik.py index 327a136..200126e 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import sys if sys.platform == "darwin": import lightblue -- cgit v1.2.1 From c6442c2eb44c38d6cbe64f8ebe7b4132c70a6326 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 13:45:42 +0200 Subject: Remove unused imports. --- ParrotZik.py | 1 - ParrotZikTray | 3 --- StatusAppMac.py | 2 -- SysIndicator.py | 2 -- 4 files changed, 8 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 200126e..f7db9f2 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -5,7 +5,6 @@ else: import bluetooth import ParrotProtocol -import struct from BeautifulSoup import BeautifulSoup class ParrotZik(object): diff --git a/ParrotZikTray b/ParrotZikTray index 57464a7..9d392a3 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -1,9 +1,6 @@ #!/usr/bin/env python -import sys -import gtk import re -import os import ParrotZik import BluetoothPairedDevices from SysIndicator import * diff --git a/StatusAppMac.py b/StatusAppMac.py index 109532f..9ecd528 100644 --- a/StatusAppMac.py +++ b/StatusAppMac.py @@ -1,7 +1,5 @@ -import objc from Foundation import * from AppKit import * -from PyObjCTools import AppHelper class StatusApp(NSApplication): diff --git a/SysIndicator.py b/SysIndicator.py index 1b344c8..145f0bd 100644 --- a/SysIndicator.py +++ b/SysIndicator.py @@ -1,14 +1,12 @@ #!/usr/bin/env python import sys -import re import os import tempfile if sys.platform=="linux2" or sys.platform=="win32": import gtk elif sys.platform=="darwin": - import objc from Foundation import * from AppKit import * from PyObjCTools import AppHelper -- cgit v1.2.1 From 78db89e1086b63c2fdf38195d6b87f752b1ce70f Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 13:47:35 +0200 Subject: Move import to top. --- BluetoothPairedDevices.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py index 96d1a8d..52b9a7d 100644 --- a/BluetoothPairedDevices.py +++ b/BluetoothPairedDevices.py @@ -2,6 +2,11 @@ import sys import re import os +if sys.platform == "darwin": + from binplist import binplist +elif sys.platform == "win32": + import _winreg + def ParrotZikMac(): p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') @@ -35,8 +40,3 @@ def ParrotZikMac(): except EnvironmentError: pass - -if sys.platform == "darwin": - from binplist import binplist -elif sys.platform == "win32": - import _winreg -- cgit v1.2.1 From 7c7a156588b99dcd1d632a4d8ff6e53f46aef2e8 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 13:48:42 +0200 Subject: Fix import. --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index ffdac88..064cf67 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,10 @@ -from setuptools import setup import glob import sys if sys.platform=="win32": - import py2exe - from distutils.core import setup + from distutils.core import setup +else: + from setuptools import setup setup( -- cgit v1.2.1 From b7ccaa7015df61c101b3aa40e44feb2b5da287a0 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 14:07:20 +0200 Subject: Fix pep8. --- BluetoothPairedDevices.py | 20 ++++---- ParrotProtocol.py | 11 +++-- ParrotZik.py | 47 +++++++++--------- ParrotZikTray | 83 ++++++++++++++++++------------- StatusAppMac.py | 8 +-- SysIndicator.py | 122 ++++++++++++++++++++++++++-------------------- setup.py | 54 ++++++++++---------- 7 files changed, 191 insertions(+), 154 deletions(-) diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py index 52b9a7d..4cf0c2b 100644 --- a/BluetoothPairedDevices.py +++ b/BluetoothPairedDevices.py @@ -13,29 +13,31 @@ def ParrotZikMac(): if sys.platform == "linux2": out = os.popen("bluez-test-device list").read() res = p.findall(out) - if len(res)>0: + if len(res) > 0: return res[0] elif sys.platform == "darwin": fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") plist = binplist.BinaryPlist(file_obj=fd) parsed_plist = plist.Parse() - try : + try: for mac in parsed_plist['PairedDevices']: - if p.match(mac.replace("-",":")): - return mac.replace("-",":") + if p.match(mac.replace("-", ":")): + return mac.replace("-", ":") except: pass elif sys.platform == "win32": - aReg = _winreg.ConnectRegistry(None,_winreg.HKEY_LOCAL_MACHINE) - aKey = _winreg.OpenKey(aReg, 'SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices') + aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + aKey = _winreg.OpenKey( + aReg, 'SYSTEM\CurrentControlSet\Services\ + BTHPORT\Parameters\Devices') for i in range(10): try: - asubkey_name=_winreg.EnumKey(aKey,i) - mac =':'.join(asubkey_name[i:i+2] for i in range(0,12,2)) + asubkey_name = _winreg.EnumKey(aKey, i) + mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) res = p.findall(mac) - if len(res)>0: + if len(res) > 0: return res[0] except EnvironmentError: diff --git a/ParrotProtocol.py b/ParrotProtocol.py index 1af6340..bd09ed3 100644 --- a/ParrotProtocol.py +++ b/ParrotProtocol.py @@ -1,17 +1,20 @@ def generateRequest(requestString): - message=bytearray() + message = bytearray() message.extend(generateHeader(requestString)) message.extend(bytearray(requestString)) return message + def generateHeader(requestString): header = bytearray([0]) - header.append(len(requestString)+3) + header.append(len(requestString) + 3) header.append("\x80") return header + def getRequest(apiString): - return generateRequest("GET "+apiString) + return generateRequest("GET " + apiString) + def setRequest(apiString,args): - return generateRequest("SET "+apiString+"?arg="+args) + return generateRequest("SET " + apiString + "?arg=" + args) diff --git a/ParrotZik.py b/ParrotZik.py index f7db9f2..a934a90 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -8,19 +8,18 @@ import ParrotProtocol from BeautifulSoup import BeautifulSoup class ParrotZik(object): - def __init__(self,addr=None): + def __init__(self, addr=None): uuid = "0ef0f502-f0ee-46c9-986c-54ed027807fb" - if sys.platform == "darwin": - service_matches = lightblue.findservices( name = "Parrot RFcomm service", addr = addr ) + service_matches = lightblue.findservices( + name="Parrot RFcomm service", addr=addr) else: - service_matches = bluetooth.find_service( uuid = uuid, address = addr ) - + service_matches = bluetooth.find_service(uuid=uuid, address=addr) if len(service_matches) == 0: print "Failed to find Parrot Zik RFCOMM service" - self.sock ="" + self.sock = "" return if sys.platform == "darwin": @@ -37,9 +36,9 @@ class ParrotZik(object): print "Connecting to \"%s\" on %s" % (name, host) if sys.platform == "darwin": - self.sock=lightblue.socket() + self.sock = lightblue.socket() else: - self.sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) + self.sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) self.sock.connect((host, port)) @@ -57,7 +56,7 @@ class ParrotZik(object): def getBatteryLevel(self): data = self.sendGetMessage("/api/system/battery/get") try: - if data.answer.system.battery["level"] <> '': + if data.answer.system.battery["level"] != '': self.BatteryLevel = data.answer.system.battery["level"] if data.answer.system.battery["state"] == 'charging': self.BatteryCharging = True @@ -85,8 +84,9 @@ class ParrotZik(object): data = self.sendGetMessage("/api/system/auto_connection/enabled/get") return data.answer.system.auto_connection["enabled"] - def setAutoConnection(self,arg): - data = self.sendSetMessage("/api/system/auto_connection/enabled/set",arg) + def setAutoConnection(self, arg): + data = self.sendSetMessage("/api/system/auto_connection/enabled/set", + arg) return data def getAncPhoneMode(self): @@ -97,46 +97,47 @@ class ParrotZik(object): data = self.sendGetMessage("/api/audio/noise_cancellation/enabled/get") return data.answer.audio.noise_cancellation["enabled"] - def setNoiseCancel(self,arg): - data = self.sendSetMessage("/api/audio/noise_cancellation/enabled/set",arg) + def setNoiseCancel(self, arg): + data = self.sendSetMessage("/api/audio/noise_cancellation/enabled/set", + arg) return data def getLouReedMode(self): data = self.sendGetMessage("/api/audio/specific_mode/enabled/get") return data.answer.audio.specific_mode["enabled"] - def setLouReedMode(self,arg): - data = self.sendSetMessage("/api/audio/specific_mode/enabled/set",arg) + def setLouReedMode(self, arg): + data = self.sendSetMessage("/api/audio/specific_mode/enabled/set", arg) return data def getParrotConcertHall(self): data = self.sendGetMessage("/api/audio/sound_effect/enabled/get") return data.answer.audio.sound_effect["enabled"] - def setParrotConcertHall(self,arg): - data = self.sendSetMessage("/api/audio/sound_effect/enabled/set",arg) + def setParrotConcertHall(self, arg): + data = self.sendSetMessage("/api/audio/sound_effect/enabled/set", arg) return data - def sendGetMessage(self,message): + def sendGetMessage(self, message): message = ParrotProtocol.getRequest(message) return self.sendMessage(message) - def sendSetMessage(self,message,arg): - message = ParrotProtocol.setRequest(message,arg) + def sendSetMessage(self, message, arg): + message = ParrotProtocol.setRequest(message, arg) return self.sendMessage(message) - def sendMessage(self,message): + def sendMessage(self, message): try: self.sock.send(str(message)) except: - self.sock ="" + 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) + data = BeautifulSoup(data) return data def Close(self): diff --git a/ParrotZikTray b/ParrotZikTray index 9d392a3..f35662a 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -5,44 +5,57 @@ import ParrotZik import BluetoothPairedDevices from SysIndicator import * -UPDATE_FREQUENCY = 30 # seconds +# seconds +UPDATE_FREQUENCY = 30 + class ParrotZikIndicator(SysIndicator): def __init__(self): self.menu = UniversalMenu() - self.info_item = MenuItem("Parrot Zik Not connected..",None,sensitive = False) + self.info_item = MenuItem("Parrot Zik Not connected..", + None, sensitive=False) self.menu.append(self.info_item) - self.battery_level = MenuItem("Battery Level:",None,sensitive = False) + self.battery_level = MenuItem("Battery Level:", + None, sensitive=False) self.menu.append(self.battery_level) - self.battery_state = MenuItem("Battery State:",None,sensitive = False) + self.battery_state = MenuItem("Battery State:", + None, sensitive=False) self.menu.append(self.battery_state) - self.firmware_version = MenuItem("Firmware Version:",None,sensitive = False) + self.firmware_version = MenuItem("Firmware Version:", + None, sensitive=False) self.menu.append(self.firmware_version) - self.check = MenuItem("Noise Cancellation",self.toggleANC,sensitive = False, checkitem = True) + self.check = MenuItem("Noise Cancellation", self.toggleANC, + sensitive=False, checkitem=True) self.menu.append(self.check) - self.check2 = MenuItem("Auto Connection",self.toggleAuto,sensitive = False, checkitem = True) + self.check2 = MenuItem("Auto Connection", self.toggleAuto, + sensitive=False, checkitem=True) self.menu.append(self.check2) - self.check3 = MenuItem("Lou Reed Mode",self.toggleLouReedMode,sensitive = False, checkitem = True) + self.check3 = MenuItem("Lou Reed Mode", self.toggleLouReedMode, + sensitive=False, checkitem=True) self.menu.append(self.check3) - self.check4 = MenuItem("Concert Hall Mode",self.toggleParrotConcertHall,sensitive = False, checkitem = True) + self.check4 = MenuItem( + "Concert Hall Mode", self.toggleParrotConcertHall, + sensitive=False, checkitem=True) self.menu.append(self.check4) - self.quit = MenuItem("Quit",sys.exit,sensitive = True, checkitem = True) + self.quit = MenuItem("Quit", sys.exit, sensitive=True, checkitem=True) self.menu.append(self.quit) - SysIndicator.__init__(self,icon = "zik-audio-headset",menu = self.menu) + SysIndicator.__init__(self, icon="zik-audio-headset", menu=self.menu) - self.connected=False - self.p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') + self.connected = False + self.p = re.compile( + '90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}' + ) def EstablishConnection(self): if self.connected: @@ -52,7 +65,7 @@ class ParrotZikIndicator(SysIndicator): else: print "Connection already established" else: - mac=BluetoothPairedDevices.ParrotZikMac() + mac = BluetoothPairedDevices.ParrotZikMac() if mac: self.parrot = ParrotZik.ParrotZik(mac) if not self.parrot.sock: @@ -91,21 +104,21 @@ class ParrotZikIndicator(SysIndicator): self.CheckBattery() return True - def toggleANC(self,widget): + def toggleANC(self, widget): if self.connected: if self.check.get_active(): self.parrot.setNoiseCancel("true") else: self.parrot.setNoiseCancel("false") - def toggleAuto(self,widget): + def toggleAuto(self, widget): if self.connected: if self.check2.get_active(): self.parrot.setAutoConnection("true") else: self.parrot.setAutoConnection("false") - def toggleLouReedMode(self,widget): + def toggleLouReedMode(self, widget): if self.connected: if self.check3.get_active(): self.parrot.setLouReedMode("true") @@ -114,7 +127,7 @@ class ParrotZikIndicator(SysIndicator): self.parrot.setLouReedMode("false") self.check4.set_sensitive(True) - def toggleParrotConcertHall(self,widget): + def toggleParrotConcertHall(self, widget): if self.connected: if self.check4.get_active(): self.parrot.setParrotConcertHall("true") @@ -129,28 +142,30 @@ class ParrotZikIndicator(SysIndicator): if self.parrot.BatteryCharging: self.batteryLevel = "Charging" self.setIcon("zik-battery-charging") - self.batteryLevel="Unknown" - self.batteryState="Charging" - elif self.batteryLevel>80: + self.batteryLevel = "Unknown" + self.batteryState = "Charging" + elif self.batteryLevel > 80: self.setIcon("zik-battery-100") - self.batteryState="In Use" - elif self.batteryLevel>60: + self.batteryState = "In Use" + elif self.batteryLevel > 60: self.setIcon("zik-battery-080") - self.batteryState="In Use" - elif self.batteryLevel>40: + self.batteryState = "In Use" + elif self.batteryLevel > 40: self.setIcon("zik-battery-060") - self.batteryState="In Use" - elif self.batteryLevel>20: + self.batteryState = "In Use" + elif self.batteryLevel > 20: self.setIcon("zik-battery-040") - self.batteryState="In Use" + self.batteryState = "In Use" else: self.setIcon("zik-battery-low") - self.batteryState="In Use" - - self.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)) + self.batteryState = "In Use" + + self.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.setIcon("zik-audio-headset") self.info_item.set_label("Parrot Zik Not connected..") diff --git a/StatusAppMac.py b/StatusAppMac.py index 9ecd528..dccffe4 100644 --- a/StatusAppMac.py +++ b/StatusAppMac.py @@ -3,9 +3,10 @@ from AppKit import * class StatusApp(NSApplication): - def initMenu(self,menu): + def initMenu(self, menu): statusbar = NSStatusBar.systemStatusBar() - self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength) + self.statusitem = statusbar.statusItemWithLength_( + NSVariableStatusItemLength) self.mymenu = menu #add menu to statusitem @@ -13,7 +14,8 @@ class StatusApp(NSApplication): self.statusitem.setToolTip_('Parrot Zik Indicator') def setIcon(self,icon,icon_directory): - self.icon = NSImage.alloc().initByReferencingFile_(icon_directory+icon+'.png') + self.icon = NSImage.alloc().initByReferencingFile_( + icon_directory + icon + '.png') self.icon.setScalesWhenResized_(True) self.icon.setSize_((20, 20)) self.statusitem.setImage_(self.icon) diff --git a/SysIndicator.py b/SysIndicator.py index 145f0bd..ea93677 100644 --- a/SysIndicator.py +++ b/SysIndicator.py @@ -4,9 +4,9 @@ import sys import os import tempfile -if sys.platform=="linux2" or sys.platform=="win32": +if sys.platform == "linux2" or sys.platform == "win32": import gtk -elif sys.platform=="darwin": +elif sys.platform == "darwin": from Foundation import * from AppKit import * from PyObjCTools import AppHelper @@ -14,62 +14,76 @@ elif sys.platform=="darwin": class SysIndicator: - def __init__(self, icon,menu): - if sys.platform=="linux2": + def __init__(self, icon, menu): + if sys.platform == "linux2": self.menu = menu.gtk_menu import appindicator - self.icon_directory = os.path.sep + 'usr' + os.path.sep+ 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep + self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' + + os.path.sep + 'icons' + os.path.sep+'zik' + + os.path.sep) if not os.path.isdir(self.icon_directory): - self.icon_directory = os.path.dirname(sys.argv[0]) + os.path.sep + 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep - self.statusicon = appindicator.Indicator("new-parrotzik-indicator", - "indicator-messages", - appindicator.CATEGORY_APPLICATION_STATUS) + self.icon_directory = (os.path.dirname(sys.argv[0]) + + os.path.sep + 'share' + os.path.sep + + 'icons' + os.path.sep+'zik' + + os.path.sep) + self.statusicon = appindicator.Indicator( + "new-parrotzik-indicator", "indicator-messages", + appindicator.CATEGORY_APPLICATION_STATUS) self.statusicon.set_status(appindicator.STATUS_ACTIVE) self.statusicon.set_icon_theme_path(self.icon_directory) self.statusicon.set_menu(self.menu) - elif sys.platform=="win32": + elif sys.platform == "win32": self.menu = menu.gtk_menu - self.icon_directory = os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep+ 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + + os.path.sep + 'share' + os.path.sep+'icons' + + os.path.sep +'zik' + os.path.sep) self.statusicon = gtk.StatusIcon() self.statusicon.connect("popup-menu", self.gtk_right_click_event) self.statusicon.set_tooltip("Parrot Zik") - self.menu_shown=False - sys.stdout = open(tempfile.gettempdir()+os.path.sep+"zik_tray_stdout.log", "w") - sys.stderr = open(tempfile.gettempdir()+os.path.sep+"zik_tray_stderr.log", "w") - - elif sys.platform=="darwin": - self.icon_directory = os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep+ 'share' + os.path.sep+'icons' + os.path.sep+'zik'+ os.path.sep + self.menu_shown = False + sys.stdout = open(tempfile.gettempdir() + + os.path.sep+"zik_tray_stdout.log", "w") + sys.stderr = open(tempfile.gettempdir() + + os.path.sep+"zik_tray_stderr.log", "w") + + elif sys.platform == "darwin": + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' + + os.path.sep) self.statusicon = StatusApp.sharedApplication() self.statusicon.initMenu(menu) self.setIcon(icon) def setIcon(self, name): - if sys.platform=="linux2": + if sys.platform == "linux2": self.statusicon.set_icon(name) - elif sys.platform=="win32": - self.statusicon.set_from_file(self.icon_directory+name+'.png') - elif sys.platform=="darwin": - self.statusicon.setIcon(name,self.icon_directory) + elif sys.platform == "win32": + self.statusicon.set_from_file(self.icon_directory + name + '.png') + elif sys.platform == "darwin": + self.statusicon.setIcon(name, self.icon_directory) def gtk_right_click_event(self, icon, button, time): if not self.menu_shown: - self.menu_shown=True - self.menu.popup(None, None, gtk.status_icon_position_menu, button, time, self.statusicon) + self.menu_shown = True + self.menu.popup(None, None, gtk.status_icon_position_menu, + button, time, self.statusicon) else: - self.menu_shown=False + self.menu_shown = False self.menu.popdown() def main(self): - if sys.platform=="linux2" or sys.platform=="win32": + if sys.platform == "linux2" or sys.platform == "win32": gtk.main() - elif sys.platform=="darwin": + elif sys.platform == "darwin": #self.statusicon.run() AppHelper.runEventLoop() def show_about_dialog(self, widget): - if sys.platform=="linux2" or sys.platform=="win32": + if sys.platform == "linux2" or sys.platform == "win32": about_dialog = gtk.AboutDialog() about_dialog.set_destroy_with_parent(True) about_dialog.set_name("Parrot Zik Tray") @@ -81,73 +95,73 @@ class SysIndicator: class UniversalMenu: def __init__(self): - if sys.platform=="linux2" or sys.platform=="win32": + if sys.platform == "linux2" or sys.platform == "win32": self.gtk_menu = gtk.Menu() - elif sys.platform=="darwin": + elif sys.platform == "darwin": self.actions = {} self.menubarMenu = NSMenu.alloc().init() self.menubarMenu.setAutoenablesItems_(False) - - def append(self,MenuItem): - if sys.platform=="linux2" or sys.platform=="win32": + def append(self, MenuItem): + if sys.platform == "linux2" or sys.platform == "win32": self.gtk_menu.append(MenuItem.gtk_item) - elif sys.platform=="darwin": + elif sys.platform == "darwin": self.actions[MenuItem.title] = MenuItem.action self.menubarMenu.addItem_(MenuItem.nsmenu_item) class MenuItem: - def __init__(self,name,action,sensitive = True, checkitem = False): - if sys.platform=="linux2" or sys.platform=="win32": + def __init__(self, name, action, sensitive=True, checkitem=False): + if sys.platform == "linux2" or sys.platform == "win32": if checkitem: - self.gtk_item=gtk.CheckMenuItem(name) + self.gtk_item = gtk.CheckMenuItem(name) else: - self.gtk_item=gtk.MenuItem(name) + self.gtk_item = gtk.MenuItem(name) self.gtk_item.show() if action: self.gtk_item.connect("activate", action) - elif sys.platform=="darwin": + elif sys.platform == "darwin": self.title = name self.action = action - self.nsmenu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(name, 'clicked:', '') + self.nsmenu_item = ( + NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + name, 'clicked:', '')) self.set_sensitive(sensitive) - def set_sensitive(self,option): - if sys.platform=="linux2" or sys.platform=="win32": + def set_sensitive(self, option): + if sys.platform == "linux2" or sys.platform == "win32": return self.gtk_item.set_sensitive(option) - elif sys.platform=="darwin": + elif sys.platform == "darwin": self.nsmenu_item.setEnabled_(option) - def set_active(self,option): - if sys.platform=="linux2" or sys.platform=="win32": + def set_active(self, option): + if sys.platform == "linux2" or sys.platform == "win32": return self.gtk_item.set_active(option) - elif sys.platform=="darwin": + elif sys.platform == "darwin": self.nsmenu_item.setState_(option) def get_active(self): - if sys.platform=="linux2" or sys.platform=="win32": + if sys.platform == "linux2" or sys.platform == "win32": return self.gtk_item.get_active() - elif sys.platform=="darwin": + elif sys.platform == "darwin": print self.nsmenu_item.state return self.nsmenu_item.state - - def set_label(self,option): - if sys.platform=="linux2" or sys.platform=="win32": + def set_label(self, option): + if sys.platform == "linux2" or sys.platform == "win32": return self.gtk_item.set_label(option) - elif sys.platform=="darwin": + elif sys.platform == "darwin": self.title = option self.nsmenu_item.setTitle_(option) #self.rumps_item.title=option if __name__ == "__main__": - quit_item = MenuItem("Quit",sys.exit,True) + quit_item = MenuItem("Quit", sys.exit, True) menu = UniversalMenu() menu.append(quit_item) - indicator = SysIndicator(icon = "zik-audio-headset",menu = menu) + indicator = SysIndicator(icon="zik-audio-headset", menu=menu) indicator.main() diff --git a/setup.py b/setup.py index 064cf67..b919e8f 100644 --- a/setup.py +++ b/setup.py @@ -1,49 +1,49 @@ import glob import sys -if sys.platform=="win32": +if sys.platform == "win32": from distutils.core import setup else: from setuptools import setup setup( - name = 'parrotziktray', - description = 'Parrot Zik Tray Indicator', + name='parrotziktray', + description='Parrot Zik Tray Indicator', author="Dmitry Moiseev", author_email="m0sia@m0sia.ru", maintainer_email="m0sia@m0sia.ru", url="https://github.com/m0sia/pyParrotZik", license="'GPLv2+'", - version = '0.3', - - windows = [ - { - 'script': 'ParrotZikTray', - 'icon_resources': [(1, "./share/icons/zik/Headphone.ico")], - } - ], - - options = { - 'py2exe': { - #'packages':'encodings', - # Optionally omit gio, gtk.keysyms, and/or rsvg if you're not using them - 'includes': 'cairo, pango, pangocairo, atk, gobject, gio, gtk.keysyms, _winreg', - } - }, + version='0.3', + + windows=[ + { + 'script': 'ParrotZikTray', + 'icon_resources': [(1, "./share/icons/zik/Headphone.ico")], + } + ], + + options={ + 'py2exe': { + #'packages':'encodings', + # Optionally omit gio, gtk.keysyms, and/or rsvg if you're not using them + 'includes': 'cairo, pango, pangocairo, atk, gobject, gio, gtk.keysyms, _winreg', + } + }, data_files=[ - ("share/icons/zik", glob.glob("share/icons/zik/*.png")) - # If using GTK+'s built in SVG support, uncomment these - #os.path.join(gtk_base_path, '..', 'runtime', 'bin', 'gdk-pixbuf-query-loaders.exe'), - #os.path.join(gtk_base_path, '..', 'runtime', 'bin', 'libxml2-2.dll'), - ], + ("share/icons/zik", glob.glob("share/icons/zik/*.png")) + # If using GTK+'s built in SVG support, uncomment these + #os.path.join(gtk_base_path, '..', 'runtime', 'bin', 'gdk-pixbuf-query-loaders.exe'), + #os.path.join(gtk_base_path, '..', 'runtime', 'bin', 'libxml2-2.dll'), + ], install_requires=[ - 'BeautifulSoup','bluetooth' - ], + 'BeautifulSoup', 'bluetooth' + ], - py_modules=['ParrotZik','ParrotProtocol'], + py_modules=['ParrotZik', 'ParrotProtocol'], scripts=["ParrotZikTray"] ) -- cgit v1.2.1 From 6c1a6a589a99da15ab936bf11cf3640ba9b24182 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 14:10:00 +0200 Subject: Refactor. --- BluetoothPairedDevices.py | 2 +- ParrotZik.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py index 4cf0c2b..4190159 100644 --- a/BluetoothPairedDevices.py +++ b/BluetoothPairedDevices.py @@ -24,7 +24,7 @@ def ParrotZikMac(): for mac in parsed_plist['PairedDevices']: if p.match(mac.replace("-", ":")): return mac.replace("-", ":") - except: + except Exception: pass elif sys.platform == "win32": diff --git a/ParrotZik.py b/ParrotZik.py index a934a90..be84411 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -62,12 +62,12 @@ class ParrotZik(object): self.BatteryCharging = True else: self.BatteryCharging = False - except: + except Exception: pass try: print "notification received" + data.notify["path"] - except: + except Exception: pass return self.BatteryLevel @@ -129,7 +129,7 @@ class ParrotZik(object): def sendMessage(self, message): try: self.sock.send(str(message)) - except: + except Exception: self.sock = "" return if sys.platform == "darwin": -- cgit v1.2.1 From cac2d834faa85153fba2fca3c7faa1de34183b4d Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 14:27:54 +0200 Subject: Make ParrotZik more pythonic. --- ParrotZik.py | 83 ++++++++++++++++++++++++++++++++--------------------------- ParrotZikTray | 26 +++++++++---------- 2 files changed, 58 insertions(+), 51 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index be84411..65c3417 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -49,12 +49,14 @@ class ParrotZik(object): self.BatteryCharging = False print "Connected" - def getBatteryState(self): - data = self.sendGetMessage("/api/system/battery/get") + @property + def battery_state(self): + data = self.get("/api/system/battery/get") return data.answer.system.battery["state"] - def getBatteryLevel(self): - data = self.sendGetMessage("/api/system/battery/get") + @property + def battery_level(self): + data = self.get("/api/system/battery/get") try: if data.answer.system.battery["level"] != '': self.BatteryLevel = data.answer.system.battery["level"] @@ -72,61 +74,66 @@ class ParrotZik(object): return self.BatteryLevel - def getVersion(self): - data = self.sendGetMessage("/api/software/version/get") + @property + def version(self): + data = self.get("/api/software/version/get") return data.answer.software["version"] - def getFriendlyName(self): - data = self.sendGetMessage("/api/bluetooth/friendlyname/get") + @property + def friendly_name(self): + data = self.get("/api/bluetooth/friendlyname/get") return data.answer.bluetooth["friendlyname"] - def getAutoConnection(self): - data = self.sendGetMessage("/api/system/auto_connection/enabled/get") + @property + def auto_connect(self): + data = self.get("/api/system/auto_connection/enabled/get") return data.answer.system.auto_connection["enabled"] - def setAutoConnection(self, arg): - data = self.sendSetMessage("/api/system/auto_connection/enabled/set", - arg) - return data + @auto_connect.setter + def auto_connect(self, arg): + self.set("/api/system/auto_connection/enabled/set", arg) - def getAncPhoneMode(self): - data = self.sendGetMessage("/api/system/anc_phone_mode/enabled/get") + @property + def anc_phone_mode(self): + data = self.get("/api/system/anc_phone_mode/enabled/get") return data.answer.system.anc_phone_mode["enabled"] - def getNoiseCancel(self): - data = self.sendGetMessage("/api/audio/noise_cancellation/enabled/get") + @property + def noise_cancel(self): + data = self.get("/api/audio/noise_cancellation/enabled/get") return data.answer.audio.noise_cancellation["enabled"] - def setNoiseCancel(self, arg): - data = self.sendSetMessage("/api/audio/noise_cancellation/enabled/set", - arg) - return data + @noise_cancel.setter + def noise_cancel(self, arg): + self.set("/api/audio/noise_cancellation/enabled/set", arg) - def getLouReedMode(self): - data = self.sendGetMessage("/api/audio/specific_mode/enabled/get") + @property + def lou_reed_mode(self): + data = self.get("/api/audio/specific_mode/enabled/get") return data.answer.audio.specific_mode["enabled"] - def setLouReedMode(self, arg): - data = self.sendSetMessage("/api/audio/specific_mode/enabled/set", arg) - return data + @lou_reed_mode.setter + def lou_reed_mode(self, arg): + self.set("/api/audio/specific_mode/enabled/set", arg) - def getParrotConcertHall(self): - data = self.sendGetMessage("/api/audio/sound_effect/enabled/get") + @property + def concert_hall(self): + data = self.get("/api/audio/sound_effect/enabled/get") return data.answer.audio.sound_effect["enabled"] - def setParrotConcertHall(self, arg): - data = self.sendSetMessage("/api/audio/sound_effect/enabled/set", arg) - return data + @concert_hall.setter + def concert_hall(self, arg): + self.set("/api/audio/sound_effect/enabled/set", arg) - def sendGetMessage(self, message): + def get(self, message): message = ParrotProtocol.getRequest(message) - return self.sendMessage(message) + return self.send_message(message) - def sendSetMessage(self, message, arg): + def set(self, message, arg): message = ParrotProtocol.setRequest(message, arg) - return self.sendMessage(message) + return self.send_message(message) - def sendMessage(self, message): + def send_message(self, message): try: self.sock.send(str(message)) except Exception: @@ -140,5 +147,5 @@ class ParrotZik(object): data = BeautifulSoup(data) return data - def Close(self): + def close(self): self.sock.close() diff --git a/ParrotZikTray b/ParrotZikTray index f35662a..193f8d1 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -73,30 +73,30 @@ class ParrotZikIndicator(SysIndicator): return False self.connected = True - self.name = self.parrot.getFriendlyName() - self.version = self.parrot.getVersion() + self.name = self.parrot.friendly_name + self.version = self.parrot.version self.check.set_sensitive(True) self.check2.set_sensitive(True) self.check3.set_sensitive(True) self.check4.set_sensitive(True) - if self.parrot.getNoiseCancel() == "true": + if self.parrot.noise_cancel == "true": self.check.set_active(True) else: self.check.set_active(False) - if self.parrot.getAutoConnection() == "true": + if self.parrot.auto_connect == "true": self.check2.set_active(True) else: self.check2.set_active(False) - if self.parrot.getLouReedMode() == "true": + if self.parrot.lou_reed_mode == "true": self.check3.set_active(True) else: self.check3.set_active(False) - if self.parrot.getParrotConcertHall() == "true": + if self.parrot.concert_hall == "true": self.check4.set_active(True) else: self.check4.set_active(False) @@ -114,30 +114,30 @@ class ParrotZikIndicator(SysIndicator): def toggleAuto(self, widget): if self.connected: if self.check2.get_active(): - self.parrot.setAutoConnection("true") + self.parrot.auto_connection = "true" else: - self.parrot.setAutoConnection("false") + self.parrot.auto_connection = "false" def toggleLouReedMode(self, widget): if self.connected: if self.check3.get_active(): - self.parrot.setLouReedMode("true") + self.parrot.lou_reed_mode = "true" self.check4.set_sensitive(False) else: - self.parrot.setLouReedMode("false") + self.parrot.lou_reed_mode = "false" self.check4.set_sensitive(True) def toggleParrotConcertHall(self, widget): if self.connected: if self.check4.get_active(): - self.parrot.setParrotConcertHall("true") + self.parrot.concert_hall = "true" else: - self.parrot.setParrotConcertHall("false") + self.parrot.concert_hall = "false" def CheckBattery(self): if self.connected: print "Updating battery" - self.batteryLevel = int(self.parrot.getBatteryLevel()) + self.batteryLevel = int(self.parrot.battery_level) if self.parrot.BatteryCharging: self.batteryLevel = "Charging" -- cgit v1.2.1 From 0d692102cd94f70e78cf036cb9f64c485ea8b6a5 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 15:15:44 +0200 Subject: Add Zik 2.0 compatibility. --- BluetoothPairedDevices.py | 3 ++- ParrotZik.py | 19 +++++++++++++++---- ParrotZikTray | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py index 4190159..aa5b056 100644 --- a/BluetoothPairedDevices.py +++ b/BluetoothPairedDevices.py @@ -9,7 +9,8 @@ elif sys.platform == "win32": def ParrotZikMac(): - p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') + p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' + 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') if sys.platform == "linux2": out = os.popen("bluez-test-device list").read() res = p.findall(out) diff --git a/ParrotZik.py b/ParrotZik.py index 65c3417..551d19a 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -9,13 +9,18 @@ from BeautifulSoup import BeautifulSoup class ParrotZik(object): def __init__(self, addr=None): - uuid = "0ef0f502-f0ee-46c9-986c-54ed027807fb" + 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: - service_matches = bluetooth.find_service(uuid=uuid, address=addr) + 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" @@ -77,7 +82,10 @@ class ParrotZik(object): @property def version(self): data = self.get("/api/software/version/get") - return data.answer.software["version"] + try: + return data.answer.software["version"] + except KeyError: + return data.answer.software['sip6'] @property def friendly_name(self): @@ -110,7 +118,10 @@ class ParrotZik(object): @property def lou_reed_mode(self): data = self.get("/api/audio/specific_mode/enabled/get") - return data.answer.audio.specific_mode["enabled"] + try: + return data.answer.audio.specific_mode["enabled"] + except TypeError: + pass @lou_reed_mode.setter def lou_reed_mode(self, arg): diff --git a/ParrotZikTray b/ParrotZikTray index 193f8d1..1f934ea 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -107,9 +107,9 @@ class ParrotZikIndicator(SysIndicator): def toggleANC(self, widget): if self.connected: if self.check.get_active(): - self.parrot.setNoiseCancel("true") + self.parrot.noise_cancel = "true" else: - self.parrot.setNoiseCancel("false") + self.parrot.noise_cancel = "false" def toggleAuto(self, widget): if self.connected: -- cgit v1.2.1 From 215e013edafbf2688cf5dc1742716be919502ee5 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 19:03:25 +0200 Subject: Allow adding different zik version interfaces. --- ParrotZikTray | 232 +++++++++++++++++++++++++++++++++----------------------- SysIndicator.py | 24 +++++- 2 files changed, 160 insertions(+), 96 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 1f934ea..934062c 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -1,12 +1,33 @@ #!/usr/bin/env python -import re import ParrotZik import BluetoothPairedDevices from SysIndicator import * -# seconds -UPDATE_FREQUENCY = 30 +UPDATE_FREQUENCY = 1000 +RECONNECT_FREQUENCY = 5000 + +class repeat(object): + def __init__(self, f): + self.f = f + self.id = None + + 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 Stop(Exception): + pass class ParrotZikIndicator(SysIndicator): @@ -18,91 +39,128 @@ class ParrotZikIndicator(SysIndicator): None, sensitive=False) self.menu.append(self.info_item) - self.battery_level = MenuItem("Battery Level:", - None, sensitive=False) - self.menu.append(self.battery_level) - - self.battery_state = MenuItem("Battery State:", - None, sensitive=False) - self.menu.append(self.battery_state) - - self.firmware_version = MenuItem("Firmware Version:", - None, sensitive=False) - self.menu.append(self.firmware_version) - - self.check = MenuItem("Noise Cancellation", self.toggleANC, - sensitive=False, checkitem=True) - self.menu.append(self.check) - - self.check2 = MenuItem("Auto Connection", self.toggleAuto, - sensitive=False, checkitem=True) - self.menu.append(self.check2) - - self.check3 = MenuItem("Lou Reed Mode", self.toggleLouReedMode, - sensitive=False, checkitem=True) - self.menu.append(self.check3) - - self.check4 = MenuItem( - "Concert Hall Mode", self.toggleParrotConcertHall, - sensitive=False, checkitem=True) - self.menu.append(self.check4) - - self.quit = MenuItem("Quit", sys.exit, sensitive=True, checkitem=True) + self.version_1_interface = ParrotZikVersion1Interface(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.connected = False - self.p = re.compile( - '90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}' - ) + self.active_interface = None + @repeat def EstablishConnection(self): - if self.connected: - if not self.parrot.sock: + if self.active_interface: + if not self.active_interface.parrot.sock: print "Lost connection" - self.connected = False + self.active_interface.deactivate() else: - print "Connection already established" + self.EstablishConnection.stop() else: mac = BluetoothPairedDevices.ParrotZikMac() if mac: - self.parrot = ParrotZik.ParrotZik(mac) - if not self.parrot.sock: + parrot = ParrotZik.ParrotZik(mac) + if parrot.sock: + self.version_1_interface.activate(parrot) + self.CheckBattery.start(self, UPDATE_FREQUENCY) + self.EstablishConnection.stop() + print "Connected" + else: print "Failed to connect to Parrot Zik %s" % mac - return False - - self.connected = True - self.name = self.parrot.friendly_name - self.version = self.parrot.version - - self.check.set_sensitive(True) - self.check2.set_sensitive(True) - self.check3.set_sensitive(True) - self.check4.set_sensitive(True) - if self.parrot.noise_cancel == "true": - self.check.set_active(True) - else: - self.check.set_active(False) + @repeat + def CheckBattery(self): + if self.active_interface: + self.active_interface.CheckBattery() + else: + self.EstablishConnection.start(self, RECONNECT_FREQUENCY) + self.CheckBattery.stop() - if self.parrot.auto_connect == "true": - self.check2.set_active(True) - else: - self.check2.set_active(False) + def main(self): + self.EstablishConnection.start(self, RECONNECT_FREQUENCY) + SysIndicator.main(self) + +class ParrotZikVersion1Interface: + def __init__(self, indicator): + self.indicator = indicator + 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.check = MenuItem("Noise Cancellation", self.toggleANC, + checkitem=True, visible=False) + self.check2 = MenuItem("Auto Connection", self.toggleAuto, + checkitem=True, visible=False) + self.check3 = MenuItem("Lou Reed Mode", self.toggleLouReedMode, + checkitem=True, visible=False) + self.check4 = MenuItem( + "Concert Hall Mode", self.toggleParrotConcertHall, + 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.check) + self.indicator.menu.append(self.check2) + self.indicator.menu.append(self.check3) + self.indicator.menu.append(self.check4) + + @property + def connected(self): + if self.parrot: + return self.parrot.sock + else: + return False + + def activate(self, parrot): + self.parrot = parrot + self.battery_level.show() + self.battery_state.show() + self.firmware_version.show() + self.check.show() + self.check2.show() + self.check3.show() + self.check4.show() + + self.name = self.parrot.friendly_name + self.version = self.parrot.version + + if self.parrot.noise_cancel == "true": + self.check.set_active(True) + else: + self.check.set_active(False) - if self.parrot.lou_reed_mode == "true": - self.check3.set_active(True) - else: - self.check3.set_active(False) + if self.parrot.auto_connect == "true": + self.check2.set_active(True) + else: + self.check2.set_active(False) - if self.parrot.concert_hall == "true": - self.check4.set_active(True) - else: - self.check4.set_active(False) + if self.parrot.lou_reed_mode == "true": + self.check3.set_active(True) + else: + self.check3.set_active(False) - self.CheckBattery() - return True + if self.parrot.concert_hall == "true": + self.check4.set_active(True) + else: + self.check4.set_active(False) + + self.indicator.menu.reposition() + self.indicator.active_interface = self + + def deactivate(self): + self.parrot = None + self.battery_level.hide() + self.battery_state.hide() + self.firmware_version.hide() + self.check.hide() + self.check2.hide() + self.check3.hide() + self.check4.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 toggleANC(self, widget): if self.connected: @@ -126,7 +184,7 @@ class ParrotZikIndicator(SysIndicator): else: self.parrot.lou_reed_mode = "false" self.check4.set_sensitive(True) - + def toggleParrotConcertHall(self, widget): if self.connected: if self.check4.get_active(): @@ -138,48 +196,36 @@ class ParrotZikIndicator(SysIndicator): if self.connected: print "Updating battery" self.batteryLevel = int(self.parrot.battery_level) - + if self.parrot.BatteryCharging: self.batteryLevel = "Charging" - self.setIcon("zik-battery-charging") + self.indicator.setIcon("zik-battery-charging") self.batteryLevel = "Unknown" self.batteryState = "Charging" elif self.batteryLevel > 80: - self.setIcon("zik-battery-100") + self.indicator.setIcon("zik-battery-100") self.batteryState = "In Use" elif self.batteryLevel > 60: - self.setIcon("zik-battery-080") + self.indicator.setIcon("zik-battery-080") self.batteryState = "In Use" elif self.batteryLevel > 40: - self.setIcon("zik-battery-060") + self.indicator.setIcon("zik-battery-060") self.batteryState = "In Use" elif self.batteryLevel > 20: - self.setIcon("zik-battery-040") + self.indicator.setIcon("zik-battery-040") self.batteryState = "In Use" else: - self.setIcon("zik-battery-low") + self.indicator.setIcon("zik-battery-low") self.batteryState = "In Use" - self.info_item.set_label("Connected to: " + self.name) + 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.setIcon("zik-audio-headset") - self.info_item.set_label("Parrot Zik Not connected..") - self.check.set_sensitive(False) - self.check2.set_sensitive(False) - self.check3.set_sensitive(False) - self.check4.set_sensitive(False) - return True - - def main(self): - self.EstablishConnection() - gtk.timeout_add(UPDATE_FREQUENCY * 1000, self.EstablishConnection) - gtk.timeout_add(UPDATE_FREQUENCY * 1000, self.CheckBattery) - SysIndicator.main(self) + self.deactivate() if __name__ == "__main__": indicator = ParrotZikIndicator() diff --git a/SysIndicator.py b/SysIndicator.py index ea93677..e8d59be 100644 --- a/SysIndicator.py +++ b/SysIndicator.py @@ -109,14 +109,17 @@ class UniversalMenu: self.actions[MenuItem.title] = MenuItem.action self.menubarMenu.addItem_(MenuItem.nsmenu_item) + def reposition(self): + if sys.platform == "linux2" or sys.platform == "win32": + self.gtk_menu.reposition() + class MenuItem: - def __init__(self, name, action, sensitive=True, checkitem=False): + def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): if sys.platform == "linux2" or sys.platform == "win32": if checkitem: self.gtk_item = gtk.CheckMenuItem(name) else: self.gtk_item = gtk.MenuItem(name) - self.gtk_item.show() if action: self.gtk_item.connect("activate", action) @@ -126,8 +129,11 @@ class MenuItem: self.nsmenu_item = ( NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( name, 'clicked:', '')) - self.set_sensitive(sensitive) + if visible: + self.show() + else: + self.hide() def set_sensitive(self, option): if sys.platform == "linux2" or sys.platform == "win32": @@ -156,6 +162,18 @@ class MenuItem: self.nsmenu_item.setTitle_(option) #self.rumps_item.title=option + def show(self): + if sys.platform == "linux2" or sys.platform == "win32": + self.gtk_item.show() + elif sys.platform == "darwin": + self.nsmenu_item.show() + + def hide(self): + if sys.platform == "linux2" or sys.platform == "win32": + self.gtk_item.hide() + elif sys.platform == "darwin": + self.nsmenu_item.hide() + if __name__ == "__main__": quit_item = MenuItem("Quit", sys.exit, True) -- cgit v1.2.1 From 095b951a7706a743ff556035fe215cafc267d2a7 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 19:19:32 +0200 Subject: Refactor. --- ParrotZikTray | 66 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 934062c..9862774 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -88,22 +88,22 @@ class ParrotZikVersion1Interface: visible=False) self.firmware_version = MenuItem("Firmware Version:", None, sensitive=False, visible=False) - self.check = MenuItem("Noise Cancellation", self.toggleANC, - checkitem=True, visible=False) - self.check2 = MenuItem("Auto Connection", self.toggleAuto, - checkitem=True, visible=False) - self.check3 = MenuItem("Lou Reed Mode", self.toggleLouReedMode, - checkitem=True, visible=False) - self.check4 = MenuItem( + self.noise_cancelation = MenuItem("Noise Cancellation", self.toggleANC, + checkitem=True, visible=False) + self.auto_connection = MenuItem("Auto Connection", self.toggleAuto, + 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.battery_level) self.indicator.menu.append(self.battery_state) self.indicator.menu.append(self.firmware_version) - self.indicator.menu.append(self.check) - self.indicator.menu.append(self.check2) - self.indicator.menu.append(self.check3) - self.indicator.menu.append(self.check4) + self.indicator.menu.append(self.noise_cancelation) + self.indicator.menu.append(self.auto_connection) + self.indicator.menu.append(self.lou_reed_mode) + self.indicator.menu.append(self.concert_hall_mode) @property def connected(self): @@ -117,33 +117,33 @@ class ParrotZikVersion1Interface: self.battery_level.show() self.battery_state.show() self.firmware_version.show() - self.check.show() - self.check2.show() - self.check3.show() - self.check4.show() + self.noise_cancelation.show() + self.auto_connection.show() + self.lou_reed_mode.show() + self.concert_hall_mode.show() self.name = self.parrot.friendly_name self.version = self.parrot.version if self.parrot.noise_cancel == "true": - self.check.set_active(True) + self.noise_cancelation.set_active(True) else: - self.check.set_active(False) + self.noise_cancelation.set_active(False) if self.parrot.auto_connect == "true": - self.check2.set_active(True) + self.auto_connection.set_active(True) else: - self.check2.set_active(False) + self.auto_connection.set_active(False) if self.parrot.lou_reed_mode == "true": - self.check3.set_active(True) + self.lou_reed_mode.set_active(True) else: - self.check3.set_active(False) + self.lou_reed_mode.set_active(False) if self.parrot.concert_hall == "true": - self.check4.set_active(True) + self.concert_hall_mode.set_active(True) else: - self.check4.set_active(False) + self.concert_hall_mode.set_active(False) self.indicator.menu.reposition() self.indicator.active_interface = self @@ -153,10 +153,10 @@ class ParrotZikVersion1Interface: self.battery_level.hide() self.battery_state.hide() self.firmware_version.hide() - self.check.hide() - self.check2.hide() - self.check3.hide() - self.check4.hide() + self.noise_cancelation.hide() + self.auto_connection.hide() + self.lou_reed_mode.hide() + self.concert_hall_mode.hide() self.indicator.setIcon("zik-audio-headset") self.indicator.info_item.set_label("Parrot Zik Not connected..") self.indicator.menu.reposition() @@ -164,30 +164,30 @@ class ParrotZikVersion1Interface: def toggleANC(self, widget): if self.connected: - if self.check.get_active(): + if self.noise_cancelation.get_active(): self.parrot.noise_cancel = "true" else: self.parrot.noise_cancel = "false" def toggleAuto(self, widget): if self.connected: - if self.check2.get_active(): + if self.auto_connection.get_active(): self.parrot.auto_connection = "true" else: self.parrot.auto_connection = "false" def toggleLouReedMode(self, widget): if self.connected: - if self.check3.get_active(): + if self.lou_reed_mode.get_active(): self.parrot.lou_reed_mode = "true" - self.check4.set_sensitive(False) + self.concert_hall_mode.set_sensitive(False) else: self.parrot.lou_reed_mode = "false" - self.check4.set_sensitive(True) + self.concert_hall_mode.set_sensitive(True) def toggleParrotConcertHall(self, widget): if self.connected: - if self.check4.get_active(): + if self.concert_hall_mode.get_active(): self.parrot.concert_hall = "true" else: self.parrot.concert_hall = "false" -- cgit v1.2.1 From 0b259b140bfa455ff65cbe74907286d87de15d2e Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 19:32:58 +0200 Subject: Extract base interface. --- ParrotZikTray | 89 ++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 9862774..bd85db5 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -79,31 +79,22 @@ class ParrotZikIndicator(SysIndicator): self.EstablishConnection.start(self, RECONNECT_FREQUENCY) SysIndicator.main(self) -class ParrotZikVersion1Interface: +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.noise_cancelation = MenuItem("Noise Cancellation", self.toggleANC, - checkitem=True, visible=False) self.auto_connection = MenuItem("Auto Connection", self.toggleAuto, 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.battery_level) self.indicator.menu.append(self.battery_state) self.indicator.menu.append(self.firmware_version) - self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.auto_connection) - self.indicator.menu.append(self.lou_reed_mode) - self.indicator.menu.append(self.concert_hall_mode) @property def connected(self): @@ -117,24 +108,63 @@ class ParrotZikVersion1Interface: self.battery_level.show() self.battery_state.show() self.firmware_version.show() - self.noise_cancelation.show() self.auto_connection.show() - self.lou_reed_mode.show() - self.concert_hall_mode.show() self.name = self.parrot.friendly_name self.version = self.parrot.version - if self.parrot.noise_cancel == "true": - self.noise_cancelation.set_active(True) - else: - self.noise_cancelation.set_active(False) - if self.parrot.auto_connect == "true": self.auto_connection.set_active(True) else: self.auto_connection.set_active(False) + 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: + if self.auto_connection.get_active(): + self.parrot.auto_connection = "true" + else: + self.parrot.auto_connection = "false" + + +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) + + if self.parrot.noise_cancel == "true": + self.noise_cancelation.set_active(True) + else: + self.noise_cancelation.set_active(False) + if self.parrot.lou_reed_mode == "true": self.lou_reed_mode.set_active(True) else: @@ -145,22 +175,11 @@ class ParrotZikVersion1Interface: else: self.concert_hall_mode.set_active(False) - self.indicator.menu.reposition() - self.indicator.active_interface = self - def deactivate(self): - self.parrot = None - self.battery_level.hide() - self.battery_state.hide() - self.firmware_version.hide() self.noise_cancelation.hide() - self.auto_connection.hide() self.lou_reed_mode.hide() self.concert_hall_mode.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 + super(ParrotZikVersion1Interface, self).deactivate() def toggleANC(self, widget): if self.connected: @@ -169,13 +188,6 @@ class ParrotZikVersion1Interface: else: self.parrot.noise_cancel = "false" - def toggleAuto(self, widget): - if self.connected: - if self.auto_connection.get_active(): - self.parrot.auto_connection = "true" - else: - self.parrot.auto_connection = "false" - def toggleLouReedMode(self, widget): if self.connected: if self.lou_reed_mode.get_active(): @@ -227,6 +239,7 @@ class ParrotZikVersion1Interface: else: self.deactivate() + if __name__ == "__main__": indicator = ParrotZikIndicator() indicator.main() -- cgit v1.2.1 From 3093abbcd7d08680bf39ab2e9d404faecb433965 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 19:41:13 +0200 Subject: Refactor. --- ParrotZikTray | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index bd85db5..1e32e23 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -4,9 +4,10 @@ import ParrotZik import BluetoothPairedDevices from SysIndicator import * -UPDATE_FREQUENCY = 1000 +REFRESH_FREQUENCY = 1000 RECONNECT_FREQUENCY = 5000 + class repeat(object): def __init__(self, f): self.f = f @@ -48,35 +49,35 @@ class ParrotZikIndicator(SysIndicator): self.active_interface = None @repeat - def EstablishConnection(self): + def reconnect(self): if self.active_interface: if not self.active_interface.parrot.sock: print "Lost connection" self.active_interface.deactivate() else: - self.EstablishConnection.stop() + self.reconnect.stop() else: mac = BluetoothPairedDevices.ParrotZikMac() if mac: parrot = ParrotZik.ParrotZik(mac) if parrot.sock: self.version_1_interface.activate(parrot) - self.CheckBattery.start(self, UPDATE_FREQUENCY) - self.EstablishConnection.stop() + self.autorefresh.start(self, REFRESH_FREQUENCY) + self.reconnect.stop() print "Connected" else: print "Failed to connect to Parrot Zik %s" % mac @repeat - def CheckBattery(self): + def autorefresh(self): if self.active_interface: - self.active_interface.CheckBattery() + self.active_interface.refresh() else: - self.EstablishConnection.start(self, RECONNECT_FREQUENCY) - self.CheckBattery.stop() + self.reconnect.start(self, RECONNECT_FREQUENCY) + self.autorefresh.stop() def main(self): - self.EstablishConnection.start(self, RECONNECT_FREQUENCY) + self.reconnect.start(self, RECONNECT_FREQUENCY) SysIndicator.main(self) class ParrotZikBaseInterface(object): @@ -204,7 +205,7 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): else: self.parrot.concert_hall = "false" - def CheckBattery(self): + def refresh(self): if self.connected: print "Updating battery" self.batteryLevel = int(self.parrot.battery_level) -- cgit v1.2.1 From 566a27ff40c9478b2fd005890e39705082aceb9c Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 19:42:41 +0200 Subject: Fix imports. --- ParrotZikTray | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ParrotZikTray b/ParrotZikTray index 1e32e23..4518bc9 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -1,8 +1,11 @@ #!/usr/bin/env python +import gtk import ParrotZik import BluetoothPairedDevices -from SysIndicator import * +from SysIndicator import MenuItem +from SysIndicator import UniversalMenu +from SysIndicator import SysIndicator REFRESH_FREQUENCY = 1000 RECONNECT_FREQUENCY = 5000 -- cgit v1.2.1 From dfb630d52ccae6c8fdd70ab7210c32b327a4fed7 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 20:35:58 +0200 Subject: Refactor. --- ParrotZikTray | 4 +- SysIndicator.py | 315 +++++++++++++++++++++++++++++++++----------------------- 2 files changed, 191 insertions(+), 128 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 4518bc9..f66de17 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -4,7 +4,7 @@ import gtk import ParrotZik import BluetoothPairedDevices from SysIndicator import MenuItem -from SysIndicator import UniversalMenu +from SysIndicator import Menu from SysIndicator import SysIndicator REFRESH_FREQUENCY = 1000 @@ -37,7 +37,7 @@ class Stop(Exception): class ParrotZikIndicator(SysIndicator): def __init__(self): - self.menu = UniversalMenu() + self.menu = Menu() self.info_item = MenuItem("Parrot Zik Not connected..", None, sensitive=False) diff --git a/SysIndicator.py b/SysIndicator.py index e8d59be..804b001 100644 --- a/SysIndicator.py +++ b/SysIndicator.py @@ -13,59 +13,12 @@ elif sys.platform == "darwin": from StatusAppMac import StatusApp -class SysIndicator: - def __init__(self, icon, menu): - if sys.platform == "linux2": - self.menu = menu.gtk_menu - import appindicator - self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' - + os.path.sep + 'icons' + os.path.sep+'zik' - + os.path.sep) - if not os.path.isdir(self.icon_directory): - self.icon_directory = (os.path.dirname(sys.argv[0]) - + os.path.sep + 'share' + os.path.sep - + 'icons' + os.path.sep+'zik' - + os.path.sep) - self.statusicon = appindicator.Indicator( - "new-parrotzik-indicator", "indicator-messages", - appindicator.CATEGORY_APPLICATION_STATUS) - self.statusicon.set_status(appindicator.STATUS_ACTIVE) - self.statusicon.set_icon_theme_path(self.icon_directory) - self.statusicon.set_menu(self.menu) - - elif sys.platform == "win32": - self.menu = menu.gtk_menu - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) - + os.path.sep + 'share' + os.path.sep+'icons' - + os.path.sep +'zik' + os.path.sep) - self.statusicon = gtk.StatusIcon() - self.statusicon.connect("popup-menu", self.gtk_right_click_event) - self.statusicon.set_tooltip("Parrot Zik") - self.menu_shown = False - sys.stdout = open(tempfile.gettempdir() - + os.path.sep+"zik_tray_stdout.log", "w") - sys.stderr = open(tempfile.gettempdir() - + os.path.sep+"zik_tray_stderr.log", "w") - - elif sys.platform == "darwin": - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep - + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' - + os.path.sep) - self.statusicon = StatusApp.sharedApplication() - self.statusicon.initMenu(menu) - +class BaseIndicator(object): + def __init__(self, icon, menu, statusicon): + self.menu = menu + self.statusicon = statusicon self.setIcon(icon) - def setIcon(self, name): - if sys.platform == "linux2": - self.statusicon.set_icon(name) - elif sys.platform == "win32": - self.statusicon.set_from_file(self.icon_directory + name + '.png') - elif sys.platform == "darwin": - self.statusicon.setIcon(name, self.icon_directory) - def gtk_right_click_event(self, icon, button, time): if not self.menu_shown: self.menu_shown = True @@ -75,60 +28,131 @@ class SysIndicator: self.menu_shown = False self.menu.popdown() + def setIcon(self, name): + raise NotImplementedError + + def main(self): + raise NotImplementedError + + def show_about_dialog(self, widget): + raise NotImplementedError + + +class WindowsIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + + os.path.sep + 'share' + os.path.sep + 'icons' + + os.path.sep +'zik' + os.path.sep) + self.menu_shown = False + sys.stdout = open(tempfile.gettempdir() + + os.path.sep + "zik_tray_stdout.log", "w") + sys.stderr = open(tempfile.gettempdir() + + os.path.sep + "zik_tray_stderr.log", "w") + statusicon = gtk.StatusIcon() + statusicon.connect("popup-menu", self.gtk_right_click_event) + statusicon.set_tooltip("Parrot Zik") + super(WindowsIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_from_file(self.icon_directory + name + '.png') + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() + + +class LinuxIndicator(BaseIndicator): + def __init__(self, icon, menu): + import appindicator + self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' + + os.path.sep + 'icons' + os.path.sep+'zik' + + os.path.sep) + if not os.path.isdir(self.icon_directory): + self.icon_directory = (os.path.dirname(sys.argv[0]) + + os.path.sep + 'share' + os.path.sep + + 'icons' + os.path.sep+'zik' + + os.path.sep) + statusicon = appindicator.Indicator( + "new-parrotzik-indicator", "indicator-messages", + appindicator.CATEGORY_APPLICATION_STATUS) + statusicon.set_status(appindicator.STATUS_ACTIVE) + statusicon.set_icon_theme_path(self.icon_directory) + statusicon.set_menu(menu.gtk_menu) + super(LinuxIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_icon(name) + def main(self): - if sys.platform == "linux2" or sys.platform == "win32": - gtk.main() - elif sys.platform == "darwin": - #self.statusicon.run() - AppHelper.runEventLoop() + gtk.main() def show_about_dialog(self, widget): - if sys.platform == "linux2" or sys.platform == "win32": - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class UniversalMenu: + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() + + +class DarwinIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' + + os.path.sep) + statusicon = StatusApp.sharedApplication() + statusicon.initMenu(menu) + super(DarwinIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.setIcon(name, self.icon_directory) + + def main(self): + AppHelper.runEventLoop() + + def show_about_dialog(self, widget): + pass + + +class NSMenu(object): def __init__(self): - if sys.platform == "linux2" or sys.platform == "win32": - self.gtk_menu = gtk.Menu() - elif sys.platform == "darwin": - self.actions = {} - self.menubarMenu = NSMenu.alloc().init() - self.menubarMenu.setAutoenablesItems_(False) - - def append(self, MenuItem): - if sys.platform == "linux2" or sys.platform == "win32": - self.gtk_menu.append(MenuItem.gtk_item) - elif sys.platform == "darwin": - self.actions[MenuItem.title] = MenuItem.action - self.menubarMenu.addItem_(MenuItem.nsmenu_item) + self.actions = {} + self.menubarMenu = NSMenu.alloc().init() + self.menubarMenu.setAutoenablesItems_(False) + + def append(self, menu_item): + self.actions[menu_item.title] = menu_item.action + self.menubarMenu.addItem_(menu_item.nsmenu_item) def reposition(self): - if sys.platform == "linux2" or sys.platform == "win32": - self.gtk_menu.reposition() + # TODO + pass -class MenuItem: - def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): - if sys.platform == "linux2" or sys.platform == "win32": - if checkitem: - self.gtk_item = gtk.CheckMenuItem(name) - else: - self.gtk_item = gtk.MenuItem(name) - if action: - self.gtk_item.connect("activate", action) - - elif sys.platform == "darwin": - self.title = name - self.action = action - self.nsmenu_item = ( - NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( - name, 'clicked:', '')) +class GTKMenu(object): + def __init__(self): + self.gtk_menu = gtk.Menu() + + def append(self, menu_item): + self.gtk_menu.append(menu_item.base_item) + + def reposition(self): + self.gtk_menu.reposition() + + +class MenuItemBase(object): + def __init__(self, base_item, sensitive, visible): + self.base_item = base_item self.set_sensitive(sensitive) if visible: self.show() @@ -136,49 +160,88 @@ class MenuItem: self.hide() def set_sensitive(self, option): - if sys.platform == "linux2" or sys.platform == "win32": - return self.gtk_item.set_sensitive(option) - elif sys.platform == "darwin": - self.nsmenu_item.setEnabled_(option) + raise NotImplementedError def set_active(self, option): - if sys.platform == "linux2" or sys.platform == "win32": - return self.gtk_item.set_active(option) - elif sys.platform == "darwin": - self.nsmenu_item.setState_(option) + raise NotImplementedError def get_active(self): - if sys.platform == "linux2" or sys.platform == "win32": - return self.gtk_item.get_active() - elif sys.platform == "darwin": - print self.nsmenu_item.state - return self.nsmenu_item.state + raise NotImplementedError def set_label(self, option): - if sys.platform == "linux2" or sys.platform == "win32": - return self.gtk_item.set_label(option) - elif sys.platform == "darwin": - self.title = option - self.nsmenu_item.setTitle_(option) - #self.rumps_item.title=option + raise NotImplementedError def show(self): - if sys.platform == "linux2" or sys.platform == "win32": - self.gtk_item.show() - elif sys.platform == "darwin": - self.nsmenu_item.show() + self.base_item.show() def hide(self): - if sys.platform == "linux2" or sys.platform == "win32": - self.gtk_item.hide() - elif sys.platform == "darwin": - self.nsmenu_item.hide() + self.base_item.hide() + +class GTKMenuItem(MenuItemBase): + def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): + if checkitem: + gtk_item = gtk.CheckMenuItem(name) + else: + gtk_item = gtk.MenuItem(name) + if action: + gtk_item.connect("activate", action) + super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) + + def set_sensitive(self, option): + return self.base_item.set_sensitive(option) + + def set_active(self, option): + return self.base_item.set_active(option) + + def get_active(self): + return self.base_item.get_active() + + def set_label(self, option): + return self.base_item.set_label(option) + + +class NSMenuItem(MenuItemBase): + def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): + self.title = name + self.action = action + nsmenu_item = ( + NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + name, 'clicked:', '')) + super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) + + def set_sensitive(self, option): + self.base_item.setEnabled_(option) + + def set_active(self, option): + self.base_item.setState_(option) + + def get_active(self): + return self.base_item.state + + def set_label(self, option): + self.title = option + self.base_item.setTitle_(option) + +if sys.platform == 'linux2': + SysIndicator = LinuxIndicator + Menu = GTKMenu + MenuItem = GTKMenuItem +elif sys.platform == 'win32': + SysIndicator = WindowsIndicator + Menu = GTKMenu + MenuItem = GTKMenuItem +elif sys.platform == 'darwin': + SysIndicator = DarwinIndicator + Menu = NSMenu + MenuItem = NSMenuItem +else: + raise Exception('Platform not supported') if __name__ == "__main__": quit_item = MenuItem("Quit", sys.exit, True) - menu = UniversalMenu() + menu = Menu() menu.append(quit_item) indicator = SysIndicator(icon="zik-audio-headset", menu=menu) -- cgit v1.2.1 From 4d780ca17fd26bf963f0a530fb5cf50e4435f2b0 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 22:30:49 +0200 Subject: Refresh data less often. --- ParrotZik.py | 1 - ParrotZikTray | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 551d19a..d159927 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -52,7 +52,6 @@ class ParrotZik(object): self.BatteryLevel = 100 self.BatteryCharging = False - print "Connected" @property def battery_state(self): diff --git a/ParrotZikTray b/ParrotZikTray index f66de17..6a7ab69 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -7,7 +7,7 @@ from SysIndicator import MenuItem from SysIndicator import Menu from SysIndicator import SysIndicator -REFRESH_FREQUENCY = 1000 +REFRESH_FREQUENCY = 30000 RECONNECT_FREQUENCY = 5000 @@ -16,6 +16,9 @@ class repeat(object): self.f = f self.id = None + def __call__(self, cls): + self.f(cls) + def start(self, cls, frequency): if not self.id: def run(): @@ -65,6 +68,7 @@ class ParrotZikIndicator(SysIndicator): parrot = ParrotZik.ParrotZik(mac) if parrot.sock: self.version_1_interface.activate(parrot) + self.autorefresh(self) self.autorefresh.start(self, REFRESH_FREQUENCY) self.reconnect.stop() print "Connected" -- cgit v1.2.1 From efb6d2808391ffc006996cacc70273fd67f12513 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 22:31:29 +0200 Subject: Remove unneeded. --- ParrotZikTray | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 6a7ab69..ee492b2 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -33,10 +33,6 @@ class repeat(object): self.id = None -class Stop(Exception): - pass - - class ParrotZikIndicator(SysIndicator): def __init__(self): -- cgit v1.2.1 From a9cfa13c5718bac0dd62a2aef0c39bc05590e55e Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 12 Jun 2015 23:01:36 +0200 Subject: Display true values. --- ParrotZik.py | 33 ++++++++++++++++++++++++++------- ParrotZikTray | 51 +++++++++++++++------------------------------------ 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index d159927..514be50 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -94,7 +94,8 @@ class ParrotZik(object): @property def auto_connect(self): data = self.get("/api/system/auto_connection/enabled/get") - return data.answer.system.auto_connection["enabled"] + return self._result_to_bool( + data.answer.system.auto_connection["enabled"]) @auto_connect.setter def auto_connect(self, arg): @@ -103,12 +104,17 @@ class ParrotZik(object): @property def anc_phone_mode(self): data = self.get("/api/system/anc_phone_mode/enabled/get") - return data.answer.system.anc_phone_mode["enabled"] + 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") - return data.answer.audio.noise_cancellation["enabled"] + try: + return self._result_to_bool( + data.answer.audio.noise_cancellation["enabled"]) + except AttributeError: + return False @noise_cancel.setter def noise_cancel(self, arg): @@ -118,9 +124,10 @@ class ParrotZik(object): def lou_reed_mode(self): data = self.get("/api/audio/specific_mode/enabled/get") try: - return data.answer.audio.specific_mode["enabled"] + return self._result_to_bool( + data.answer.audio.specific_mode["enabled"]) except TypeError: - pass + return False @lou_reed_mode.setter def lou_reed_mode(self, arg): @@ -129,18 +136,30 @@ class ParrotZik(object): @property def concert_hall(self): data = self.get("/api/audio/sound_effect/enabled/get") - return data.answer.audio.sound_effect["enabled"] + try: + return self._result_to_bool( + data.answer.audio.sound_effect["enabled"]) + except AttributeError: + return False @concert_hall.setter def concert_hall(self, arg): self.set("/api/audio/sound_effect/enabled/set", arg) + def _result_to_bool(self, result): + if result == "true": + return True + elif result == "false": + return False + 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, arg) + message = ParrotProtocol.setRequest(message, str(arg).lower()) return self.send_message(message) def send_message(self, message): diff --git a/ParrotZikTray b/ParrotZikTray index ee492b2..2245807 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -117,10 +117,7 @@ class ParrotZikBaseInterface(object): self.name = self.parrot.friendly_name self.version = self.parrot.version - if self.parrot.auto_connect == "true": - self.auto_connection.set_active(True) - else: - self.auto_connection.set_active(False) + self.auto_connection.set_active(self.parrot.auto_connect) self.indicator.active_interface = self self.indicator.menu.reposition() @@ -138,10 +135,8 @@ class ParrotZikBaseInterface(object): def toggleAuto(self, widget): if self.connected: - if self.auto_connection.get_active(): - self.parrot.auto_connection = "true" - else: - self.parrot.auto_connection = "false" + self.parrot.auto_connection = self.auto_connection.get_active() + self.auto_connection.set_active(self.parrot.auto_connection) class ParrotZikVersion1Interface(ParrotZikBaseInterface): @@ -164,20 +159,9 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.concert_hall_mode.show() super(ParrotZikVersion1Interface, self).activate(parrot) - if self.parrot.noise_cancel == "true": - self.noise_cancelation.set_active(True) - else: - self.noise_cancelation.set_active(False) - - if self.parrot.lou_reed_mode == "true": - self.lou_reed_mode.set_active(True) - else: - self.lou_reed_mode.set_active(False) - - if self.parrot.concert_hall == "true": - self.concert_hall_mode.set_active(True) - else: - self.concert_hall_mode.set_active(False) + 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() @@ -187,26 +171,21 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): def toggleANC(self, widget): if self.connected: - if self.noise_cancelation.get_active(): - self.parrot.noise_cancel = "true" - else: - self.parrot.noise_cancel = "false" + 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: - if self.lou_reed_mode.get_active(): - self.parrot.lou_reed_mode = "true" - self.concert_hall_mode.set_sensitive(False) - else: - self.parrot.lou_reed_mode = "false" - self.concert_hall_mode.set_sensitive(True) + 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: - if self.concert_hall_mode.get_active(): - self.parrot.concert_hall = "true" - else: - self.parrot.concert_hall = "false" + self.parrot.concert_hall = self.concert_hall_mode.get_active() + self.concert_hall_mode.set_active(self.parrot.concert_hall) def refresh(self): if self.connected: -- cgit v1.2.1 From 2e8383760b2f32e8d068a4b235b6379cd3f06c17 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 00:06:19 +0200 Subject: First step of zik 2.0 feature implementation. --- ParrotZik.py | 204 +++++++++++++++++++++++++++++++------------------------- ParrotZikTray | 119 +++++++++++++++++++++++++++++++-- SysIndicator.py | 6 ++ 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: @@ -78,38 +126,30 @@ 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): -- cgit v1.2.1 From 2b0fb4d4f4747f991ef6abd3e26925c0e77433bb Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 00:14:43 +0200 Subject: Refactor. --- ParrotZikTray | 104 +++++++++++++++++++--------------------------------------- 1 file changed, 33 insertions(+), 71 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index b955a47..45aaaf0 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -143,7 +143,39 @@ class ParrotZikBaseInterface(object): self.auto_connection.set_active(self.parrot.auto_connection) def refresh(self): - raise NotImplementedError + 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() class ParrotZikVersion1Interface(ParrotZikBaseInterface): @@ -194,41 +226,6 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.parrot.concert_hall = self.concert_hall_mode.get_active() self.concert_hall_mode.set_active(self.parrot.concert_hall) - 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() - class ParrotZikVersion2Interface(ParrotZikBaseInterface): def __init__(self, indicator): @@ -297,41 +294,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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() -- cgit v1.2.1 From eb6fb90329b1bb0355e00bc588d3740c57ca87bc Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 00:26:23 +0200 Subject: Refactor battery state. --- ParrotZik.py | 31 ++++++++++++------------------- ParrotZikTray | 32 ++++++++++++++------------------ 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 6c1cd69..c47ce26 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -91,12 +91,20 @@ class ParrotZikApi(object): def close(self): self.sock.close() +class BatteryStates: + CHARGED = 'charged' + IN_USE = 'in_use' + CHARGING = 'charging' + representation = { + CHARGED: 'Charged', + IN_USE: 'In Use', + CHARGING: 'Charging', + } class ParrotZikBase(object): + def __init__(self, api): self.api = api - self.BatteryLevel = 100 - self.BatteryCharging = False @property def version(self): @@ -109,22 +117,7 @@ class ParrotZikBase(object): def get_battery_level(self, field_name): data = self.api.get("/api/system/battery/get") - try: - 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: - self.BatteryCharging = False - except Exception: - pass - - try: - print "notification received" + data.notify["path"] - except Exception: - pass - - return self.BatteryLevel + return data.answer.system.battery[field_name] @property def friendly_name(self): @@ -185,7 +178,7 @@ class ParrotZikBase(object): class ParrotZikVersion1(ParrotZikBase): @property def battery_level(self): - return self.get_battery_level('level') + return int(self.get_battery_level('level')) @property def lou_reed_mode(self): diff --git a/ParrotZikTray b/ParrotZikTray index 45aaaf0..a69abe4 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -1,8 +1,9 @@ #!/usr/bin/env python import gtk -import ParrotZik import BluetoothPairedDevices +from ParrotZik import BatteryStates +from ParrotZik import connect from SysIndicator import MenuItem from SysIndicator import Menu from SysIndicator import SysIndicator @@ -62,7 +63,7 @@ class ParrotZikIndicator(SysIndicator): else: mac = BluetoothPairedDevices.ParrotZikMac() if mac: - parrot = ParrotZik.connect(mac) + parrot = connect(mac) if parrot.api.sock: if parrot.version.startswith('1'): self.version_1_interface.activate(parrot) @@ -145,35 +146,29 @@ class ParrotZikBaseInterface(object): def refresh(self): if self.connected: print "Updating battery" - self.batteryLevel = int(self.parrot.battery_level) + battery_level = self.parrot.battery_level + battery_state = self.parrot.battery_state - if self.parrot.BatteryCharging: - self.batteryLevel = "Charging" + if battery_state == BatteryStates.CHARGING: self.indicator.setIcon("zik-battery-charging") - self.batteryLevel = "Unknown" - self.batteryState = "Charging" - elif self.batteryLevel > 80: + elif battery_level > 80: self.indicator.setIcon("zik-battery-100") - self.batteryState = "In Use" - elif self.batteryLevel > 60: + elif battery_level > 60: self.indicator.setIcon("zik-battery-080") - self.batteryState = "In Use" - elif self.batteryLevel > 40: + elif battery_level > 40: self.indicator.setIcon("zik-battery-060") - self.batteryState = "In Use" - elif self.batteryLevel > 20: + elif battery_level > 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_state.set_label( + "State: " + BatteryStates.representation[battery_state]) self.battery_level.set_label( - "Battery Level: " + str(self.batteryLevel)) + "Battery Level: " + str(battery_level)) else: self.deactivate() @@ -294,6 +289,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): def toggledummy(self, widget): print(widget.get_name()) + if __name__ == "__main__": indicator = ParrotZikIndicator() indicator.main() -- cgit v1.2.1 From d53188baa1c4175d2f9456ac722d35facb47f818 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 00:28:37 +0200 Subject: Refactor. --- ParrotZikTray | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index a69abe4..6de9e1c 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -119,8 +119,10 @@ class ParrotZikBaseInterface(object): self.firmware_version.show() self.auto_connection.show() - self.name = self.parrot.friendly_name - self.version = self.parrot.version + 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) @@ -162,9 +164,6 @@ class ParrotZikBaseInterface(object): else: self.indicator.setIcon("zik-battery-low") - 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: " + BatteryStates.representation[battery_state]) self.battery_level.set_label( -- cgit v1.2.1 From 7856465e1ab0ab69101996b12e93450c6bea160b Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 00:37:49 +0200 Subject: Add flight mode. --- ParrotZik.py | 9 +++++++++ ParrotZikTray | 9 +++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index c47ce26..7cb623d 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -195,3 +195,12 @@ class ParrotZikVersion2(ParrotZikBase): @property def battery_level(self): return self.get_battery_level('percent') + + @property + def flight_mode(self): + data = self.api.get('/api/flight_mode/get') + return self._result_to_bool(data.answer.flight_mode['enabled']) + + @flight_mode.setter + def flight_mode(self, arg): + self.api.set('/api/flight_mode/enable', arg) diff --git a/ParrotZikTray b/ParrotZikTray index 6de9e1c..9a96b9b 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -268,7 +268,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.concert_hall_mode_submenu.append(self.silent_mode) self.indicator.menu.append(self.concert_hall_mode) - self.flight_mode = MenuItem("Flight Mode", None, + self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, sensitive=True, checkitem=True, visible=False) self.indicator.menu.append(self.flight_mode) @@ -278,13 +278,18 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) + 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 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()) -- cgit v1.2.1 From b890260fb76f5685711e8f6b580f476f03f5e126 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 01:06:39 +0200 Subject: Complete zik 2 api. --- ParrotZik.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/ParrotZik.py b/ParrotZik.py index 7cb623d..af20b52 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -204,3 +204,45 @@ class ParrotZikVersion2(ParrotZikBase): @flight_mode.setter def flight_mode(self, arg): self.api.set('/api/flight_mode/enable', arg) + + @property + def room_size(self): + data = self.api.get('/api/audio/sound_effect/room_size/get') + return data.answer.audio.sound_effect['room_size'] + + @room_size.setter + def room_size(self, arg): + self.api.set('/api/audio/sound_effect/room_size/set', arg) + + @property + def external_noise(self): + data = self.api.get('/api/audio/noise/get') + return int(data.answer.audio.noise['external']) + + @property + def internal_noise(self): + data = self.api.get('/api/audio/noise/get') + return int(data.answer.audio.noise['internal']) + + @property + def angle(self): + data = self.api.get('/api/audio/sound_effect/angle/get') + return int(data.answer.audio.sound_effect['angle']) + + @angle.setter + def angle(self, arg): + self.api.set('/api/audio/sound_effect/angle/set', arg) + + @property + def noise_control(self): + data = self.api.get('/api/audio/noise_control/get') + return self._result_to_bool(data.answer.audio.noise_control['value']) + + @noise_control.setter + def noise_control(self, arg): + self.api.set('/api/audio/noise_control/set', arg) + + @property + def noise_control_enabled(self): + data = self.api.get('/api/audio/noise_control/enabled/get') + return self._result_to_bool(data.answer.audio.noise_control['enabled']) -- cgit v1.2.1 From cc46d275a0f89bdcd1c7b8f64dbc25e9c4b7beed Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 01:09:56 +0200 Subject: Fix flight_mode. --- ParrotZik.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParrotZik.py b/ParrotZik.py index af20b52..fe5c911 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -203,7 +203,7 @@ class ParrotZikVersion2(ParrotZikBase): @flight_mode.setter def flight_mode(self, arg): - self.api.set('/api/flight_mode/enable', arg) + self.api.set('/api/flight_mode/set', arg) @property def room_size(self): -- cgit v1.2.1 From 2dda7cdb0d159f5fd0c25766cc668ba8a4aa4c7d Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 01:13:41 +0200 Subject: Refactor. --- ParrotProtocol.py | 8 ++++---- ParrotZik.py | 56 +++++++++++++++++++++++++++---------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ParrotProtocol.py b/ParrotProtocol.py index bd09ed3..a844820 100644 --- a/ParrotProtocol.py +++ b/ParrotProtocol.py @@ -12,9 +12,9 @@ def generateHeader(requestString): return header -def getRequest(apiString): - return generateRequest("GET " + apiString) +def getRequest(resource): + return generateRequest("GET " + resource + '/get') -def setRequest(apiString,args): - return generateRequest("SET " + apiString + "?arg=" + args) +def setRequest(resource, args): + return generateRequest("SET " + resource + '/set' + "?arg=" + args) diff --git a/ParrotZik.py b/ParrotZik.py index fe5c911..0cdab71 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -60,18 +60,18 @@ class ParrotZikApi(object): @property def version(self): - data = self.get("/api/software/version/get") + data = self.get("/api/software/version") try: return data.answer.software["version"] except KeyError: return data.answer.software['sip6'] - def get(self, message): - message = ParrotProtocol.getRequest(message) + def get(self, resource): + message = ParrotProtocol.getRequest(resource) return self.send_message(message) - def set(self, message, arg): - message = ParrotProtocol.setRequest(message, str(arg).lower()) + def set(self, resource, arg): + message = ParrotProtocol.setRequest(resource, str(arg).lower()) return self.send_message(message) def send_message(self, message): @@ -112,37 +112,37 @@ class ParrotZikBase(object): @property def battery_state(self): - data = self.api.get("/api/system/battery/get") + data = self.api.get("/api/system/battery") return data.answer.system.battery["state"] def get_battery_level(self, field_name): - data = self.api.get("/api/system/battery/get") + data = self.api.get("/api/system/battery") return data.answer.system.battery[field_name] @property def friendly_name(self): - data = self.api.get("/api/bluetooth/friendlyname/get") + data = self.api.get("/api/bluetooth/friendlyname") return data.answer.bluetooth["friendlyname"] @property def auto_connect(self): - data = self.api.get("/api/system/auto_connection/enabled/get") + data = self.api.get("/api/system/auto_connection/enabled") return self._result_to_bool( data.answer.system.auto_connection["enabled"]) @auto_connect.setter def auto_connect(self, arg): - self.api.get("/api/system/auto_connection/enabled/set", arg) + self.api.get("/api/system/auto_connection/enabled", arg) @property def anc_phone_mode(self): - data = self.api.get("/api/system/anc_phone_mode/enabled/get") + data = self.api.get("/api/system/anc_phone_mode/enabled") return self._result_to_bool( data.answer.system.anc_phone_mode["enabled"]) @property def noise_cancel(self): - data = self.api.get("/api/audio/noise_cancellation/enabled/get") + data = self.api.get("/api/audio/noise_cancellation/enabled") try: return self._result_to_bool( data.answer.audio.noise_cancellation["enabled"]) @@ -151,11 +151,11 @@ class ParrotZikBase(object): @noise_cancel.setter def noise_cancel(self, arg): - self.api.get("/api/audio/noise_cancellation/enabled/set", arg) + self.api.get("/api/audio/noise_cancellation/enabled", arg) @property def concert_hall(self): - data = self.api.get("/api/audio/sound_effect/enabled/get") + data = self.api.get("/api/audio/sound_effect/enabled") try: return self._result_to_bool( data.answer.audio.sound_effect["enabled"]) @@ -164,7 +164,7 @@ class ParrotZikBase(object): @concert_hall.setter def concert_hall(self, arg): - self.api.get("/api/audio/sound_effect/enabled/set", arg) + self.api.get("/api/audio/sound_effect/enabled", arg) def _result_to_bool(self, result): if result == "true": @@ -182,13 +182,13 @@ class ParrotZikVersion1(ParrotZikBase): @property def lou_reed_mode(self): - data = self.api.get("/api/audio/specific_mode/enabled/get") + data = self.api.get("/api/audio/specific_mode/enabled") return self._result_to_bool( data.answer.audio.specific_mode["enabled"]) @lou_reed_mode.setter def lou_reed_mode(self, arg): - self.api.get("/api/audio/specific_mode/enabled/set", arg) + self.api.get("/api/audio/specific_mode/enabled", arg) class ParrotZikVersion2(ParrotZikBase): @@ -198,51 +198,51 @@ class ParrotZikVersion2(ParrotZikBase): @property def flight_mode(self): - data = self.api.get('/api/flight_mode/get') + data = self.api.get('/api/flight_mode') return self._result_to_bool(data.answer.flight_mode['enabled']) @flight_mode.setter def flight_mode(self, arg): - self.api.set('/api/flight_mode/set', arg) + self.api.set('/api/flight_mode', arg) @property def room_size(self): - data = self.api.get('/api/audio/sound_effect/room_size/get') + data = self.api.get('/api/audio/sound_effect/room_size') return data.answer.audio.sound_effect['room_size'] @room_size.setter def room_size(self, arg): - self.api.set('/api/audio/sound_effect/room_size/set', arg) + self.api.set('/api/audio/sound_effect/room_size', arg) @property def external_noise(self): - data = self.api.get('/api/audio/noise/get') + data = self.api.get('/api/audio/noise') return int(data.answer.audio.noise['external']) @property def internal_noise(self): - data = self.api.get('/api/audio/noise/get') + data = self.api.get('/api/audio/noise') return int(data.answer.audio.noise['internal']) @property def angle(self): - data = self.api.get('/api/audio/sound_effect/angle/get') + data = self.api.get('/api/audio/sound_effect/angle') return int(data.answer.audio.sound_effect['angle']) @angle.setter def angle(self, arg): - self.api.set('/api/audio/sound_effect/angle/set', arg) + self.api.set('/api/audio/sound_effect/angle', arg) @property def noise_control(self): - data = self.api.get('/api/audio/noise_control/get') + data = self.api.get('/api/audio/noise_control') return self._result_to_bool(data.answer.audio.noise_control['value']) @noise_control.setter def noise_control(self, arg): - self.api.set('/api/audio/noise_control/set', arg) + self.api.set('/api/audio/noise_control', arg) @property def noise_control_enabled(self): - data = self.api.get('/api/audio/noise_control/enabled/get') + data = self.api.get('/api/audio/noise_control/enabled') return self._result_to_bool(data.answer.audio.noise_control['enabled']) -- cgit v1.2.1 From 52fb4f7f5561c38631e279a403cd55d8a6632955 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 02:43:36 +0200 Subject: Add Room sound effect feature. --- ParrotZik.py | 28 ++++++++++++++++-- ParrotZikTray | 95 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 102 insertions(+), 21 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 0cdab71..80dc591 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -101,6 +101,19 @@ class BatteryStates: CHARGING: 'Charging', } +class Rooms: + CONCERT_HALL = 'concert' + JAZZ_CLUB = 'jazz' + LIVING_ROOM = 'living' + SILENT_ROOM = 'silent' + representation = { + CONCERT_HALL: 'Concert Hall', + JAZZ_CLUB: 'Jazz Club', + LIVING_ROOM: 'Living Room', + SILENT_ROOM: 'Silent Room', + } + + class ParrotZikBase(object): def __init__(self, api): @@ -206,12 +219,21 @@ class ParrotZikVersion2(ParrotZikBase): self.api.set('/api/flight_mode', arg) @property - def room_size(self): + def sound_effect(self): + data = self.api.get('/api/audio/sound_effect/enabled') + return self._result_to_bool(data.answer.audio.sound_effect['enabled']) + + @sound_effect.setter + def sound_effect(self, arg): + self.api.set('/api/audio/sound_effect/enabled', arg) + + @property + def room(self): data = self.api.get('/api/audio/sound_effect/room_size') return data.answer.audio.sound_effect['room_size'] - @room_size.setter - def room_size(self, arg): + @room.setter + def room(self, arg): self.api.set('/api/audio/sound_effect/room_size', arg) @property diff --git a/ParrotZikTray b/ParrotZikTray index 9a96b9b..67ccf65 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -4,6 +4,7 @@ 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 @@ -223,6 +224,7 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): 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) @@ -246,27 +248,28 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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, + 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.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", None, + self.living_mode = MenuItem("Libing Room", self.toggle_living_room_mode, sensitive=True, checkitem=True) - self.silent_mode = MenuItem("Silent Room", None, + self.silent_mode = MenuItem("Silent Room", self.toggle_silent_room_mode, 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.room_sound_effect_submenu.append(self.room_sound_effect_enabled) + self.room_sound_effect_submenu.append(self.concert_hall_mode) + self.room_sound_effect_submenu.append(self.jazz_mode) + self.room_sound_effect_submenu.append(self.living_mode) + self.room_sound_effect_submenu.append(self.silent_mode) + self.indicator.menu.append(self.room_sound_effect) self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, sensitive=True, checkitem=True, visible=False) @@ -276,9 +279,25 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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() + + 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) + + 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: @@ -293,6 +312,46 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) + if __name__ == "__main__": indicator = ParrotZikIndicator() -- cgit v1.2.1 From 2d12b23595a7c893231d5238f406054d040aac01 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 03:25:22 +0200 Subject: Fix flight mode. --- ParrotProtocol.py | 4 ++-- ParrotZik.py | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ParrotProtocol.py b/ParrotProtocol.py index a844820..a4e1677 100644 --- a/ParrotProtocol.py +++ b/ParrotProtocol.py @@ -13,8 +13,8 @@ def generateHeader(requestString): def getRequest(resource): - return generateRequest("GET " + resource + '/get') + return generateRequest("GET " + resource) def setRequest(resource, args): - return generateRequest("SET " + resource + '/set' + "?arg=" + args) + return generateRequest("SET " + resource + "?arg=" + args) diff --git a/ParrotZik.py b/ParrotZik.py index 80dc591..c6cfd92 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -67,11 +67,19 @@ class ParrotZikApi(object): return data.answer.software['sip6'] def get(self, resource): - message = ParrotProtocol.getRequest(resource) + message = ParrotProtocol.getRequest(resource + '/get') + return self.send_message(message) + + def toggle_on(self, resource): + message = ParrotProtocol.getRequest(resource + '/enable') + return self.send_message(message) + + def toggle_off(self, resource): + message = ParrotProtocol.getRequest(resource + '/disable') return self.send_message(message) def set(self, resource, arg): - message = ParrotProtocol.setRequest(resource, str(arg).lower()) + message = ParrotProtocol.setRequest(resource + '/set', str(arg).lower()) return self.send_message(message) def send_message(self, message): @@ -81,9 +89,9 @@ class ParrotZikApi(object): self.sock = "" return if sys.platform == "darwin": - data = self.sock.recv(30) + self.sock.recv(30) else: - data = self.sock.recv(7) + self.sock.recv(7) data = self.sock.recv(1024) data = BeautifulSoup(data) return data @@ -216,7 +224,10 @@ class ParrotZikVersion2(ParrotZikBase): @flight_mode.setter def flight_mode(self, arg): - self.api.set('/api/flight_mode', arg) + if arg: + self.api.toggle_on('/api/flight_mode') + else: + self.api.toggle_off('/api/flight_mode') @property def sound_effect(self): -- cgit v1.2.1 From 64bcb2f38bc47d9c4edd61fa0590da0698a6bc4b Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 03:35:34 +0200 Subject: Move rooms to submenu. --- ParrotZikTray | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 67ccf65..f2fe92a 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -255,6 +255,13 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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.room_sound_effect_submenu.append(self.room_sound_effect_enabled) + self.room_sound_effect_submenu.append(self.rooms) + + 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) @@ -264,11 +271,10 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): sensitive=True, checkitem=True) self.silent_mode = MenuItem("Silent Room", self.toggle_silent_room_mode, sensitive=True, checkitem=True) - self.room_sound_effect_submenu.append(self.room_sound_effect_enabled) - self.room_sound_effect_submenu.append(self.concert_hall_mode) - self.room_sound_effect_submenu.append(self.jazz_mode) - self.room_sound_effect_submenu.append(self.living_mode) - self.room_sound_effect_submenu.append(self.silent_mode) + 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.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, -- cgit v1.2.1 From 45b5c30c6775ae5407f6f9eac2de27aa69493eba Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 03:50:51 +0200 Subject: Add angle feature. --- ParrotZikTray | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/ParrotZikTray b/ParrotZikTray index f2fe92a..c23944d 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -256,8 +256,10 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) @@ -277,6 +279,27 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) @@ -290,6 +313,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) @@ -298,6 +322,13 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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() @@ -357,6 +388,50 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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__": -- cgit v1.2.1 From e9c6ffefde5885ed3a5ff0535843b834d77a5a09 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 03:57:11 +0200 Subject: Use info to convey message. --- ParrotZikTray | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index c23944d..c40640b 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -40,7 +40,7 @@ class ParrotZikIndicator(SysIndicator): self.menu = Menu() - self.info_item = MenuItem("Parrot Zik Not connected..", + self.info_item = MenuItem("Parrot Zik Not connected", None, sensitive=False) self.menu.append(self.info_item) @@ -57,13 +57,14 @@ class ParrotZikIndicator(SysIndicator): def reconnect(self): if self.active_interface: if not self.active_interface.connected: - print "Lost connection" + self.info_item.set_label("Lost connection") self.active_interface.deactivate() else: self.reconnect.stop() else: mac = BluetoothPairedDevices.ParrotZikMac() if mac: + self.info_item.set_label("Connecting") parrot = connect(mac) if parrot.api.sock: if parrot.version.startswith('1'): @@ -73,9 +74,10 @@ class ParrotZikIndicator(SysIndicator): self.autorefresh(self) self.autorefresh.start(self, REFRESH_FREQUENCY) self.reconnect.stop() - print "Connected" else: - print "Failed to connect to Parrot Zik %s" % mac + self.info_item.set_label("Failed to connect") + else: + self.info_item.set_label("Parrot Zik Not connected") @repeat def autorefresh(self): @@ -148,7 +150,6 @@ class ParrotZikBaseInterface(object): def refresh(self): if self.connected: - print "Updating battery" battery_level = self.parrot.battery_level battery_state = self.parrot.battery_state -- cgit v1.2.1 From 5c500c5770763f946392bd83b8f66954929f0120 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 04:20:01 +0200 Subject: Fix auto connection. --- ParrotZik.py | 2 +- ParrotZikTray | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index c6cfd92..98469d0 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -153,7 +153,7 @@ class ParrotZikBase(object): @auto_connect.setter def auto_connect(self, arg): - self.api.get("/api/system/auto_connection/enabled", arg) + self.api.set("/api/system/auto_connection/enabled", arg) @property def anc_phone_mode(self): diff --git a/ParrotZikTray b/ParrotZikTray index c40640b..4cc8574 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -145,8 +145,10 @@ class ParrotZikBaseInterface(object): 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) + self.parrot.auto_connect = self.auto_connection.get_active() + self.auto_connection.set_active(self.parrot.auto_connect) + else: + self.deactivate() def refresh(self): if self.connected: -- cgit v1.2.1 From 0be8866c0219b142a42ac552dfec320d1439d1e2 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 04:20:44 +0200 Subject: Deactivate interface on disconnection. --- ParrotZik.py | 1 - ParrotZikTray | 43 ++++++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 98469d0..638391a 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -123,7 +123,6 @@ class Rooms: class ParrotZikBase(object): - def __init__(self, api): self.api = api diff --git a/ParrotZikTray b/ParrotZikTray index 4cc8574..5d9325c 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -210,6 +210,8 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): if self.connected: self.parrot.noise_cancel = self.noise_cancelation.get_active() self.noise_cancelation.set_active(self.parrot.noise_cancel) + else: + self.deactivate() def toggleLouReedMode(self, widget): if self.connected: @@ -218,11 +220,15 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.concert_hall_mode.set_active(self.parrot.concert_hall) self.concert_hall_mode.set_sensitive( not self.lou_reed_mode.get_active()) + else: + self.deactivate() 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) + else: + self.deactivate() class ParrotZikVersion2Interface(ParrotZikBaseInterface): @@ -249,7 +255,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) @@ -280,7 +285,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) @@ -305,11 +309,12 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, sensitive=True, checkitem=True, visible=False) + self.indicator.menu.append(self.room_sound_effect) + self.indicator.menu.append(self.noise_cancelation) 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) @@ -343,11 +348,15 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): if self.connected: self.parrot.noise_cancel = self.noise_cancelation.get_active() self.noise_cancelation.set_active(self.parrot.noise_cancel) + else: + self.deactivate() 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) + else: + self.deactivate() def toggledummy(self, widget): print(widget.get_name()) @@ -365,11 +374,14 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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 + if self.connected: + if not self.dirty: + self.parrot.room = room + self.dirty = True + self.read_sound_effect_room() + self.dirty = False + else: + self.deactivate() def read_sound_effect_room(self): active_room = self.parrot.room @@ -397,6 +409,8 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.angle_120.set_sensitive(sound_effect) self.angle_150.set_sensitive(sound_effect) self.angle_180.set_sensitive(sound_effect) + else: + self.deactivate() def toggle_angle_30(self, widget): self.toggle_angle(30) @@ -417,11 +431,14 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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 + if self.connected: + if not self.dirty: + self.parrot.angle = angle + self.dirty = True + self.read_sound_effect_angle() + self.dirty = False + else: + self.deactivate() def read_sound_effect_angle(self): active_angle = self.parrot.angle -- cgit v1.2.1 From 2b55de38dcd540273fc66df8684ff105e7c74390 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sat, 13 Jun 2015 04:22:17 +0200 Subject: Ignore not anwser responses. --- ParrotZik.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 638391a..efa8732 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -92,8 +92,10 @@ class ParrotZikApi(object): self.sock.recv(30) else: self.sock.recv(7) - data = self.sock.recv(1024) - data = BeautifulSoup(data) + + data = BeautifulSoup(self.sock.recv(1024)) + if not hasattr(data, 'anwser'): + data = BeautifulSoup(self.sock.recv(1024)) return data def close(self): -- cgit v1.2.1 From da45da83c9d487e7b8ff8dca059b43f7769975b6 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:09:28 +0200 Subject: Remove default repeating of default argument. --- ParrotZikTray | 58 +++++++++++++++++++++++++--------------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 5d9325c..3b61754 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -235,21 +235,20 @@ 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 = MenuItem("Noise Cancellation", None, 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) + checkitem=True) self.noise_cancelation_mode0 = MenuItem("Mode0", self.toggledummy, - sensitive=False, checkitem=True) + checkitem=True) self.noise_cancelation_mode1 = MenuItem("Mode1", self.toggledummy, - sensitive=False, checkitem=True) + checkitem=True) self.noise_cancelation_mode2 = MenuItem("Mode2", self.toggledummy, - sensitive=False, checkitem=True) + checkitem=True) self.noise_cancelation_mode3 = MenuItem("Mode3", self.toggledummy, - sensitive=False, checkitem=True) + 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) @@ -257,14 +256,14 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_cancelation_submenu.append(self.noise_cancelation_mode3) self.room_sound_effect = MenuItem( - "Room Sound Effect", None, sensitive=True, checkitem=False, visible=False) + "Room Sound Effect", None, 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) + "Enabled", self.toggle_room_sound_effect, checkitem=True) + self.rooms = MenuItem("Rooms", None, checkitem=False) + self.angle = MenuItem("Angle", None, 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) @@ -272,15 +271,14 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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.concert_hall_mode = MenuItem( + "Concert Hall", self.toggle_concert_hall_mode, checkitem=True) + self.jazz_mode = MenuItem( + "Jazz Club", self.toggle_jazz_club_mode, checkitem=True) + self.living_mode = MenuItem( + "Libing Room", self.toggle_living_room_mode, checkitem=True) + self.silent_mode = MenuItem( + "Silent Room", self.toggle_silent_room_mode, checkitem=True) self.rooms_submenu.append(self.concert_hall_mode) self.rooms_submenu.append(self.jazz_mode) self.rooms_submenu.append(self.living_mode) @@ -288,18 +286,12 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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_30 = MenuItem("30", self.toggle_angle_30, checkitem=True) + self.angle_60 = MenuItem("60", self.toggle_angle_60, checkitem=True) + self.angle_90 = MenuItem("90", self.toggle_angle_90, checkitem=True) + self.angle_120 = MenuItem("120", self.toggle_angle_120, checkitem=True) + self.angle_150 = MenuItem("150", self.toggle_angle_150, checkitem=True) + self.angle_180 = MenuItem("180", self.toggle_angle_180, checkitem=True) self.angle_submenu.append(self.angle_30) self.angle_submenu.append(self.angle_60) self.angle_submenu.append(self.angle_90) @@ -308,7 +300,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.angle_submenu.append(self.angle_180) self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, - sensitive=True, checkitem=True, visible=False) + checkitem=True, visible=False) self.indicator.menu.append(self.room_sound_effect) self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.flight_mode) -- cgit v1.2.1 From f6a0309a3d00b7f80f41bfdf5a7d48fa8ae6f71a Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:17:24 +0200 Subject: Twicks to ParrotZik. --- ParrotZik.py | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index efa8732..b327338 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -165,28 +165,12 @@ class ParrotZikBase(object): @property def noise_cancel(self): data = self.api.get("/api/audio/noise_cancellation/enabled") - try: - return self._result_to_bool( - data.answer.audio.noise_cancellation["enabled"]) - except AttributeError: - return False + return self._result_to_bool( + data.answer.audio.noise_cancellation["enabled"]) @noise_cancel.setter def noise_cancel(self, arg): - self.api.get("/api/audio/noise_cancellation/enabled", arg) - - @property - def concert_hall(self): - data = self.api.get("/api/audio/sound_effect/enabled") - try: - return self._result_to_bool( - data.answer.audio.sound_effect["enabled"]) - except AttributeError: - return False - - @concert_hall.setter - def concert_hall(self, arg): - self.api.get("/api/audio/sound_effect/enabled", arg) + self.api.set("/api/audio/noise_cancellation/enabled", arg) def _result_to_bool(self, result): if result == "true": @@ -212,6 +196,16 @@ class ParrotZikVersion1(ParrotZikBase): def lou_reed_mode(self, arg): self.api.get("/api/audio/specific_mode/enabled", arg) + @property + def concert_hall(self): + data = self.api.get("/api/audio/sound_effect/enabled") + return self._result_to_bool( + data.answer.audio.sound_effect["enabled"]) + + @concert_hall.setter + def concert_hall(self, arg): + self.api.get("/api/audio/sound_effect/enabled", arg) + class ParrotZikVersion2(ParrotZikBase): @property -- cgit v1.2.1 From 8c69b3c2caf7703162a50696ac6ab70facca2154 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:18:42 +0200 Subject: Fix noise cancelation. --- ParrotZikTray | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 3b61754..61f76ab 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -338,8 +338,8 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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) + self.parrot.noise_cancel = self.noise_cancelation_enabled.get_active() + self.noise_cancelation_enabled.set_active(self.parrot.noise_cancel) else: self.deactivate() -- cgit v1.2.1 From 42f14d48ddc26f1dc1a88a4f5b9ecb2d79028331 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:24:27 +0200 Subject: Make names more pythonic. --- ParrotZik.py | 6 +++--- ParrotZikTray | 33 +++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index b327338..a79f410 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -163,13 +163,13 @@ class ParrotZikBase(object): data.answer.system.anc_phone_mode["enabled"]) @property - def noise_cancel(self): + def cancel_noise(self): data = self.api.get("/api/audio/noise_cancellation/enabled") return self._result_to_bool( data.answer.audio.noise_cancellation["enabled"]) - @noise_cancel.setter - def noise_cancel(self, arg): + @cancel_noise.setter + def cancel_noise(self, arg): self.api.set("/api/audio/noise_cancellation/enabled", arg) def _result_to_bool(self, result): diff --git a/ParrotZikTray b/ParrotZikTray index 61f76ab..7056f92 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -101,7 +101,7 @@ class ParrotZikBaseInterface(object): visible=False) self.firmware_version = MenuItem("Firmware Version:", None, sensitive=False, visible=False) - self.auto_connection = MenuItem("Auto Connection", self.toggleAuto, + self.auto_connection = MenuItem("Auto Connection", self.toggle_auto_connection, checkitem=True, visible=False) self.indicator.menu.append(self.battery_level) self.indicator.menu.append(self.battery_state) @@ -143,7 +143,7 @@ class ParrotZikBaseInterface(object): self.indicator.menu.reposition() self.indicator.active_interface = None - def toggleAuto(self, widget): + def toggle_auto_connection(self, widget): if self.connected: self.parrot.auto_connect = self.auto_connection.get_active() self.auto_connection.set_active(self.parrot.auto_connect) @@ -179,12 +179,13 @@ class ParrotZikBaseInterface(object): 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, + self.noise_cancelation = MenuItem( + "Noise Cancellation", self.toggle_noise_cancelation, + checkitem=True, visible=False) + self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, checkitem=True, visible=False) self.concert_hall_mode = MenuItem( - "Concert Hall Mode", self.toggleParrotConcertHall, + "Concert Hall Mode", self.toggle_parrot_concert_hall, checkitem=True, visible=False) self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.lou_reed_mode) @@ -206,14 +207,14 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.concert_hall_mode.hide() super(ParrotZikVersion1Interface, self).deactivate() - def toggleANC(self, widget): + def toggle_noise_cancelation(self, widget): if self.connected: - self.parrot.noise_cancel = self.noise_cancelation.get_active() - self.noise_cancelation.set_active(self.parrot.noise_cancel) + self.parrot.cancel_noise = self.noise_cancelation.get_active() + self.noise_cancelation.set_active(self.parrot.cancel_noise) else: self.deactivate() - def toggleLouReedMode(self, widget): + def toggle_lou_reed_mode(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) @@ -223,7 +224,7 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): else: self.deactivate() - def toggleParrotConcertHall(self, widget): + def toggle_parrot_concert_hall(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) @@ -239,7 +240,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_cancelation_submenu = Menu() self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) - self.noise_cancelation_enabled = MenuItem("Enabled", self.toggleANC, + self.noise_cancelation_enabled = MenuItem("Enabled", self.toggle_noise_cancelation, checkitem=True) self.noise_cancelation_mode0 = MenuItem("Mode0", self.toggledummy, checkitem=True) @@ -310,7 +311,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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.noise_cancelation_enabled.set_active(self.parrot.cancel_noise) self.flight_mode.set_active(self.parrot.flight_mode) self.read_sound_effect_room() self.read_sound_effect_angle() @@ -336,10 +337,10 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.room_sound_effect.hide() super(ParrotZikVersion2Interface, self).deactivate() - def toggleANC(self, widget): + def toggle_noise_cancelation(self, widget): if self.connected: - self.parrot.noise_cancel = self.noise_cancelation_enabled.get_active() - self.noise_cancelation_enabled.set_active(self.parrot.noise_cancel) + self.parrot.cancel_noise = self.noise_cancelation_enabled.get_active() + self.noise_cancelation_enabled.set_active(self.parrot.cancel_noise) else: self.deactivate() -- cgit v1.2.1 From 9656058a351237bbfdba4f9f93dae1bbf093d7e4 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:26:59 +0200 Subject: Ignore KeyboardInterrupt. --- ParrotZikTray | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 7056f92..faaa4a3 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -448,5 +448,8 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): if __name__ == "__main__": - indicator = ParrotZikIndicator() - indicator.main() + try: + indicator = ParrotZikIndicator() + indicator.main() + except KeyboardInterrupt: + pass -- cgit v1.2.1 From 43b6d6b941e57f9b073cc6c80ac7d840c3aaad21 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:44:05 +0200 Subject: Refactor. --- ParrotZikTray | 77 ++++++++++++++++++++++------------------------------------- 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index faaa4a3..6636a9e 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -1,4 +1,6 @@ #!/usr/bin/env python +import functools + import gtk import BluetoothPairedDevices @@ -234,7 +236,8 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): class ParrotZikVersion2Interface(ParrotZikBaseInterface): def __init__(self, indicator): - self.dirty = False + self.room_dirty = False + self.angle_dirty = False super(ParrotZikVersion2Interface, self).__init__(indicator) self.noise_cancelation = MenuItem("Noise Cancellation", None, visible=False) self.noise_cancelation_submenu = Menu() @@ -273,13 +276,13 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.rooms.set_submenu(self.rooms_submenu) self.concert_hall_mode = MenuItem( - "Concert Hall", self.toggle_concert_hall_mode, checkitem=True) + "Concert Hall", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) self.jazz_mode = MenuItem( - "Jazz Club", self.toggle_jazz_club_mode, checkitem=True) + "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) self.living_mode = MenuItem( - "Libing Room", self.toggle_living_room_mode, checkitem=True) + "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) self.silent_mode = MenuItem( - "Silent Room", self.toggle_silent_room_mode, checkitem=True) + "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), checkitem=True) self.rooms_submenu.append(self.concert_hall_mode) self.rooms_submenu.append(self.jazz_mode) self.rooms_submenu.append(self.living_mode) @@ -287,12 +290,18 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.angle_submenu = Menu() self.angle.set_submenu(self.angle_submenu) - self.angle_30 = MenuItem("30", self.toggle_angle_30, checkitem=True) - self.angle_60 = MenuItem("60", self.toggle_angle_60, checkitem=True) - self.angle_90 = MenuItem("90", self.toggle_angle_90, checkitem=True) - self.angle_120 = MenuItem("120", self.toggle_angle_120, checkitem=True) - self.angle_150 = MenuItem("150", self.toggle_angle_150, checkitem=True) - self.angle_180 = MenuItem("180", self.toggle_angle_180, checkitem=True) + self.angle_30 = MenuItem( + "30", functools.partial(self.toggle_angle, 30), checkitem=True) + self.angle_60 = MenuItem( + "60", functools.partial(self.toggle_angle, 60), checkitem=True) + self.angle_90 = MenuItem( + "90", functools.partial(self.toggle_angle, 90), checkitem=True) + self.angle_120 = MenuItem( + "120", functools.partial(self.toggle_angle, 120), checkitem=True) + self.angle_150 = MenuItem( + "150", functools.partial(self.toggle_angle, 150), checkitem=True) + self.angle_180 = MenuItem( + "180", functools.partial(self.toggle_angle, 180), checkitem=True) self.angle_submenu.append(self.angle_30) self.angle_submenu.append(self.angle_60) self.angle_submenu.append(self.angle_90) @@ -354,25 +363,13 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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): + def toggle_room(self, room, widget): if self.connected: - if not self.dirty: + if not self.room_dirty: self.parrot.room = room - self.dirty = True + self.room_dirty = True self.read_sound_effect_room() - self.dirty = False + self.room_dirty = False else: self.deactivate() @@ -405,31 +402,13 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): else: self.deactivate() - 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): + def toggle_angle(self, angle, widget): if self.connected: - if not self.dirty: + if not self.angle_dirty: self.parrot.angle = angle - self.dirty = True + self.angle_dirty = True self.read_sound_effect_angle() - self.dirty = False + self.angle_dirty = False else: self.deactivate() -- cgit v1.2.1 From ac763c2f9e34cdb8e8cc24f96941459f3944011c Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 13:46:02 +0200 Subject: Refactor. --- ParrotZikTray | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 6636a9e..e30631f 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -243,16 +243,16 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_cancelation_submenu = Menu() self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) - self.noise_cancelation_enabled = MenuItem("Enabled", self.toggle_noise_cancelation, - checkitem=True) - self.noise_cancelation_mode0 = MenuItem("Mode0", self.toggledummy, - checkitem=True) - self.noise_cancelation_mode1 = MenuItem("Mode1", self.toggledummy, - checkitem=True) - self.noise_cancelation_mode2 = MenuItem("Mode2", self.toggledummy, - checkitem=True) - self.noise_cancelation_mode3 = MenuItem("Mode3", self.toggledummy, - checkitem=True) + self.noise_cancelation_enabled = MenuItem( + "Enabled", self.toggle_noise_cancelation, checkitem=True) + self.noise_cancelation_mode0 = MenuItem( + "Mode0", self.toggledummy, checkitem=True) + self.noise_cancelation_mode1 = MenuItem( + "Mode1", self.toggledummy, checkitem=True) + self.noise_cancelation_mode2 = MenuItem( + "Mode2", self.toggledummy, checkitem=True) + self.noise_cancelation_mode3 = MenuItem( + "Mode3", self.toggledummy, 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) -- cgit v1.2.1 From 7e32d6a1829b99eac6e0150dd4a80062801d6ffe Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 15:31:04 +0200 Subject: Add reading noise_control. --- ParrotZik.py | 46 ++++++++++++++++++++++++++---------- ParrotZikTray | 75 ++++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index a79f410..1240d66 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -123,6 +123,28 @@ class Rooms: SILENT_ROOM: 'Silent Room', } +class NoiseControl(object): + def __init__(self, type, value): + self.type = type + self.value = value + + @classmethod + def from_noise_control(cls, noise_control): + return cls(noise_control['type'], int(noise_control['value'])) + + def __eq__(self, other): + return self.type == other.type and self.value == other.value + + def __str__(self): + return '{}++{}'.format(self.type, self.value) + +class NoiseControlTypes: + NOISE_CONTROL_MAX = NoiseControl('anc', 2) + NOISE_CONTROL_ON = NoiseControl('anc', 1) + NOISE_CONTROL_OFF = NoiseControl('off', 1) + STREET_MODE = NoiseControl('aoc', 1) + STREET_MODE_MAX = NoiseControl('aoc', 2) + class ParrotZikBase(object): def __init__(self, api): @@ -162,16 +184,6 @@ class ParrotZikBase(object): return self._result_to_bool( data.answer.system.anc_phone_mode["enabled"]) - @property - def cancel_noise(self): - data = self.api.get("/api/audio/noise_cancellation/enabled") - return self._result_to_bool( - data.answer.audio.noise_cancellation["enabled"]) - - @cancel_noise.setter - def cancel_noise(self, arg): - self.api.set("/api/audio/noise_cancellation/enabled", arg) - def _result_to_bool(self, result): if result == "true": return True @@ -206,6 +218,16 @@ class ParrotZikVersion1(ParrotZikBase): def concert_hall(self, arg): self.api.get("/api/audio/sound_effect/enabled", arg) + @property + def cancel_noise(self): + data = self.api.get("/api/audio/noise_cancellation/enabled") + return self._result_to_bool( + data.answer.audio.noise_cancellation["enabled"]) + + @cancel_noise.setter + def cancel_noise(self, arg): + self.api.set("/api/audio/noise_cancellation/enabled", arg) + class ParrotZikVersion2(ParrotZikBase): @property @@ -264,11 +286,11 @@ class ParrotZikVersion2(ParrotZikBase): @property def noise_control(self): data = self.api.get('/api/audio/noise_control') - return self._result_to_bool(data.answer.audio.noise_control['value']) + return NoiseControl.from_noise_control(data.answer.audio.noise_control) @noise_control.setter def noise_control(self, arg): - self.api.set('/api/audio/noise_control', arg) + pass @property def noise_control_enabled(self): diff --git a/ParrotZikTray b/ParrotZikTray index e30631f..07b631a 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -5,6 +5,7 @@ import gtk import BluetoothPairedDevices from ParrotZik import BatteryStates +from ParrotZik import NoiseControlTypes from ParrotZik import connect from ParrotZik import Rooms from SysIndicator import MenuItem @@ -238,26 +239,37 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): def __init__(self, indicator): self.room_dirty = False self.angle_dirty = False + self.noise_cancelation_dirty = False super(ParrotZikVersion2Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem("Noise Cancellation", None, visible=False) + self.noise_cancelation = MenuItem("Noise Control", None, visible=False) self.noise_cancelation_submenu = Menu() self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) - self.noise_cancelation_enabled = MenuItem( - "Enabled", self.toggle_noise_cancelation, checkitem=True) - self.noise_cancelation_mode0 = MenuItem( - "Mode0", self.toggledummy, checkitem=True) - self.noise_cancelation_mode1 = MenuItem( - "Mode1", self.toggledummy, checkitem=True) - self.noise_cancelation_mode2 = MenuItem( - "Mode2", self.toggledummy, checkitem=True) - self.noise_cancelation_mode3 = MenuItem( - "Mode3", self.toggledummy, 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.noise_control_cancelation_max = MenuItem( + "Max Calcelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True) + self.noise_control_cancelation_on = MenuItem( + "Normal Cancelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True) + self.noise_control_off = MenuItem( + "Off", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True) + self.noise_control_street_mode = MenuItem( + "Street Mode", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE), checkitem=True) + self.noise_control_street_mode_max = MenuItem( + "Street Mode Max", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE_MAX), checkitem=True) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) + self.noise_cancelation_submenu.append(self.noise_control_off) + self.noise_cancelation_submenu.append(self.noise_control_street_mode) + self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) self.room_sound_effect = MenuItem( "Room Sound Effect", None, visible=False) @@ -320,7 +332,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.flight_mode.show() self.room_sound_effect.show() super(ParrotZikVersion2Interface, self).activate(parrot) - self.noise_cancelation_enabled.set_active(self.parrot.cancel_noise) + self.read_noise_cancelation() self.flight_mode.set_active(self.parrot.flight_mode) self.read_sound_effect_room() self.read_sound_effect_angle() @@ -346,13 +358,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.room_sound_effect.hide() super(ParrotZikVersion2Interface, self).deactivate() - def toggle_noise_cancelation(self, widget): - if self.connected: - self.parrot.cancel_noise = self.noise_cancelation_enabled.get_active() - self.noise_cancelation_enabled.set_active(self.parrot.cancel_noise) - else: - self.deactivate() - def toggle_flight_mode(self, widget): if self.connected: self.parrot.flight_mode = self.flight_mode.get_active() @@ -425,6 +430,28 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): for angle, menu_item in angle_to_menuitem_map: menu_item.set_active(angle == active_angle) + def toggle_noise_cancelation(self, noise_calcelation, widget): + if self.connected: + if not self.noise_cancelation_dirty: + self.parrot.noise_control = noise_calcelation + self.noise_cancelation_dirty = True + self.read_noise_cancelation() + self.noise_cancelation_dirty = False + else: + self.deactivate() + + def read_noise_cancelation(self): + active_noise_control = self.parrot.noise_control + noise_control_to_menuitem_map = ( + (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), + (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), + (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), + (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), + (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), + ) + for noise_control, menu_item in noise_control_to_menuitem_map: + menu_item.set_active(active_noise_control == noise_control) + if __name__ == "__main__": try: -- cgit v1.2.1 From f3425cc12cdc5837625ae490ab2302ecfafc0453 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 17:48:33 +0200 Subject: Create api doc. --- ParrotZik.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ParrotZik.py b/ParrotZik.py index 1240d66..4f4ff07 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -194,6 +194,17 @@ class ParrotZikBase(object): class ParrotZikVersion1(ParrotZikBase): + ''' + Known resources: + * /api/software/version + * /api/system/battery + * /api/bluetooth/friendlyname + * /api/system/auto_connection/enabled + * /api/system/anc_phone_mode/enabled + * /api/audio/specific_mode/enabled + * /api/audio/sound_effect/enabled + * /api/audio/noise_cancellation/enabled + ''' @property def battery_level(self): return int(self.get_battery_level('level')) @@ -230,6 +241,22 @@ class ParrotZikVersion1(ParrotZikBase): class ParrotZikVersion2(ParrotZikBase): + ''' + Known resources: + * /api/software/version + * /api/system/battery + * /api/system/pi + * /api/bluetooth/friendlyname + * /api/system/auto_connection/enabled + * /api/system/anc_phone_mode/enabled + * /api/flight_mode + * /api/sound_effect/enabled + * /api/sound_effect/room_size + * /api/sound_effect/angle + * /api/audio/noise + * /api/audio/noise_control + * /api/audio/noise_control/enabled + ''' @property def battery_level(self): return self.get_battery_level('percent') -- cgit v1.2.1 From 1bf1b662ee8ed729a67c9bf07d1b184691a86785 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 17:58:21 +0200 Subject: Read battery on connection. --- ParrotZikTray | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ParrotZikTray b/ParrotZikTray index 07b631a..44a02d1 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -125,6 +125,7 @@ class ParrotZikBaseInterface(object): self.firmware_version.show() self.auto_connection.show() + self.read_battery() self.indicator.info_item.set_label("Connected to: " + self.parrot.friendly_name) self.firmware_version.set_label( @@ -154,6 +155,9 @@ class ParrotZikBaseInterface(object): self.deactivate() def refresh(self): + self.read_battery() + + def read_battery(self): if self.connected: battery_level = self.parrot.battery_level battery_state = self.parrot.battery_state -- cgit v1.2.1 From e3d2cb770e6e03513b6bf6ece70202c065279950 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 18:00:35 +0200 Subject: Show interface after data fetch. --- ParrotZikTray | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 44a02d1..52b8d12 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -120,19 +120,17 @@ class ParrotZikBaseInterface(object): def activate(self, parrot): self.parrot = parrot - self.battery_level.show() - self.battery_state.show() - self.firmware_version.show() - self.auto_connection.show() - self.read_battery() 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.battery_level.show() + self.battery_state.show() + self.firmware_version.show() + self.auto_connection.show() self.indicator.active_interface = self self.indicator.menu.reposition() -- cgit v1.2.1 From 68e3cde2b1d8eec9c823ce0969a6b6ee314dba38 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 18:26:04 +0200 Subject: Fix battery. --- ParrotZik.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParrotZik.py b/ParrotZik.py index 4f4ff07..6039952 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -161,7 +161,7 @@ class ParrotZikBase(object): def get_battery_level(self, field_name): data = self.api.get("/api/system/battery") - return data.answer.system.battery[field_name] + return int(data.answer.system.battery[field_name]) @property def friendly_name(self): -- cgit v1.2.1 From f43309aeb53cfe06354010227d08b44183bee765 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 18:29:34 +0200 Subject: Collect notifications. --- ParrotZik.py | 79 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/ParrotZik.py b/ParrotZik.py index 6039952..d07f8b9 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -57,14 +57,15 @@ def connect(addr=None): class ParrotZikApi(object): def __init__(self, socket): self.sock = socket + self.notifications = [] @property def version(self): - data = self.get("/api/software/version") + answer = self.get("/api/software/version") try: - return data.answer.software["version"] + return answer.software["version"] except KeyError: - return data.answer.software['sip6'] + return answer.software['sip6'] def get(self, resource): message = ParrotProtocol.getRequest(resource + '/get') @@ -94,9 +95,13 @@ class ParrotZikApi(object): self.sock.recv(7) data = BeautifulSoup(self.sock.recv(1024)) - if not hasattr(data, 'anwser'): + while not data.answer: + if data.notify: + self.notifications.append(data.notify) + else: + raise AssertionError('Unknown response') data = BeautifulSoup(self.sock.recv(1024)) - return data + return data.answer def close(self): self.sock.close() @@ -156,23 +161,23 @@ class ParrotZikBase(object): @property def battery_state(self): - data = self.api.get("/api/system/battery") - return data.answer.system.battery["state"] + answer = self.api.get("/api/system/battery") + return answer.system.battery["state"] def get_battery_level(self, field_name): - data = self.api.get("/api/system/battery") - return int(data.answer.system.battery[field_name]) + answer = self.api.get("/api/system/battery") + return int(answer.system.battery[field_name]) @property def friendly_name(self): - data = self.api.get("/api/bluetooth/friendlyname") - return data.answer.bluetooth["friendlyname"] + answer = self.api.get("/api/bluetooth/friendlyname") + return answer.bluetooth["friendlyname"] @property def auto_connect(self): - data = self.api.get("/api/system/auto_connection/enabled") + answer = self.api.get("/api/system/auto_connection/enabled") return self._result_to_bool( - data.answer.system.auto_connection["enabled"]) + answer.system.auto_connection["enabled"]) @auto_connect.setter def auto_connect(self, arg): @@ -180,9 +185,9 @@ class ParrotZikBase(object): @property def anc_phone_mode(self): - data = self.api.get("/api/system/anc_phone_mode/enabled") + answer = self.api.get("/api/system/anc_phone_mode/enabled") return self._result_to_bool( - data.answer.system.anc_phone_mode["enabled"]) + answer.system.anc_phone_mode["enabled"]) def _result_to_bool(self, result): if result == "true": @@ -211,9 +216,9 @@ class ParrotZikVersion1(ParrotZikBase): @property def lou_reed_mode(self): - data = self.api.get("/api/audio/specific_mode/enabled") + answer = self.api.get("/api/audio/specific_mode/enabled") return self._result_to_bool( - data.answer.audio.specific_mode["enabled"]) + answer.audio.specific_mode["enabled"]) @lou_reed_mode.setter def lou_reed_mode(self, arg): @@ -221,9 +226,9 @@ class ParrotZikVersion1(ParrotZikBase): @property def concert_hall(self): - data = self.api.get("/api/audio/sound_effect/enabled") + answer = self.api.get("/api/audio/sound_effect/enabled") return self._result_to_bool( - data.answer.audio.sound_effect["enabled"]) + answer.audio.sound_effect["enabled"]) @concert_hall.setter def concert_hall(self, arg): @@ -231,9 +236,9 @@ class ParrotZikVersion1(ParrotZikBase): @property def cancel_noise(self): - data = self.api.get("/api/audio/noise_cancellation/enabled") + answer = self.api.get("/api/audio/noise_cancellation/enabled") return self._result_to_bool( - data.answer.audio.noise_cancellation["enabled"]) + answer.audio.noise_cancellation["enabled"]) @cancel_noise.setter def cancel_noise(self, arg): @@ -263,8 +268,8 @@ class ParrotZikVersion2(ParrotZikBase): @property def flight_mode(self): - data = self.api.get('/api/flight_mode') - return self._result_to_bool(data.answer.flight_mode['enabled']) + answer = self.api.get('/api/flight_mode') + return self._result_to_bool(answer.flight_mode['enabled']) @flight_mode.setter def flight_mode(self, arg): @@ -275,8 +280,8 @@ class ParrotZikVersion2(ParrotZikBase): @property def sound_effect(self): - data = self.api.get('/api/audio/sound_effect/enabled') - return self._result_to_bool(data.answer.audio.sound_effect['enabled']) + answer = self.api.get('/api/audio/sound_effect/enabled') + return self._result_to_bool(answer.audio.sound_effect['enabled']) @sound_effect.setter def sound_effect(self, arg): @@ -284,8 +289,8 @@ class ParrotZikVersion2(ParrotZikBase): @property def room(self): - data = self.api.get('/api/audio/sound_effect/room_size') - return data.answer.audio.sound_effect['room_size'] + answer = self.api.get('/api/audio/sound_effect/room_size') + return answer.audio.sound_effect['room_size'] @room.setter def room(self, arg): @@ -293,18 +298,18 @@ class ParrotZikVersion2(ParrotZikBase): @property def external_noise(self): - data = self.api.get('/api/audio/noise') - return int(data.answer.audio.noise['external']) + answer = self.api.get('/api/audio/noise') + return int(answer.audio.noise['external']) @property def internal_noise(self): - data = self.api.get('/api/audio/noise') - return int(data.answer.audio.noise['internal']) + answer = self.api.get('/api/audio/noise') + return int(answer.audio.noise['internal']) @property def angle(self): - data = self.api.get('/api/audio/sound_effect/angle') - return int(data.answer.audio.sound_effect['angle']) + answer = self.api.get('/api/audio/sound_effect/angle') + return int(answer.audio.sound_effect['angle']) @angle.setter def angle(self, arg): @@ -312,8 +317,8 @@ class ParrotZikVersion2(ParrotZikBase): @property def noise_control(self): - data = self.api.get('/api/audio/noise_control') - return NoiseControl.from_noise_control(data.answer.audio.noise_control) + answer = self.api.get('/api/audio/noise_control') + return NoiseControl.from_noise_control(answer.audio.noise_control) @noise_control.setter def noise_control(self, arg): @@ -321,5 +326,5 @@ class ParrotZikVersion2(ParrotZikBase): @property def noise_control_enabled(self): - data = self.api.get('/api/audio/noise_control/enabled') - return self._result_to_bool(data.answer.audio.noise_control['enabled']) + answer = self.api.get('/api/audio/noise_control/enabled') + return self._result_to_bool(answer.audio.noise_control['enabled']) -- cgit v1.2.1 From 15948fd1d48c64fd7cc885ca0400bcd66daf3f13 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 22:01:33 +0200 Subject: Fix noise cancel in api version 1. --- ParrotZikTray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ParrotZikTray b/ParrotZikTray index 52b8d12..373e9ee 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -202,7 +202,7 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.concert_hall_mode.show() super(ParrotZikVersion1Interface, self).activate(parrot) - self.noise_cancelation.set_active(self.parrot.noise_cancel) + self.noise_cancelation.set_active(self.parrot.cancel_noise) self.lou_reed_mode.set_active(self.parrot.lou_reed_mode) self.concert_hall_mode.set_active(self.parrot.concert_hall) -- cgit v1.2.1 From 4c8ce6673e2efe96a36a2af2b774b3e43cc4a89c Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 22:27:44 +0200 Subject: Add resouce manager layer. --- ParrotZik.py | 172 ++++++++++++++++++---------------------------------- ParrotZikTray | 36 +++++++---- resource_manager.py | 135 +++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 4 files changed, 217 insertions(+), 128 deletions(-) create mode 100644 resource_manager.py diff --git a/ParrotZik.py b/ParrotZik.py index d07f8b9..8e4b31b 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -1,11 +1,14 @@ import sys + +from resource_manager import GenericResourceManager +from resource_manager import Version1ResourceManager +from resource_manager import Version2ResourceManager + if sys.platform == "darwin": import lightblue else: import bluetooth -import ParrotProtocol -from BeautifulSoup import BeautifulSoup def connect(addr=None): uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb", @@ -23,7 +26,7 @@ def connect(addr=None): if len(service_matches) == 0: print "Failed to find Parrot Zik RFCOMM service" - return ParrotZikBase(ParrotZikApi(None)) + return GenericResourceManager(None) if sys.platform == "darwin": first_match = service_matches[0] @@ -47,64 +50,9 @@ def connect(addr=None): 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 - self.notifications = [] - - @property - def version(self): - answer = self.get("/api/software/version") - try: - return answer.software["version"] - except KeyError: - return answer.software['sip6'] - - def get(self, resource): - message = ParrotProtocol.getRequest(resource + '/get') - return self.send_message(message) - - def toggle_on(self, resource): - message = ParrotProtocol.getRequest(resource + '/enable') - return self.send_message(message) - - def toggle_off(self, resource): - message = ParrotProtocol.getRequest(resource + '/disable') - return self.send_message(message) - - def set(self, resource, arg): - message = ParrotProtocol.setRequest(resource + '/set', 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.recv(30) - else: - self.sock.recv(7) + return GenericResourceManager(sock) - data = BeautifulSoup(self.sock.recv(1024)) - while not data.answer: - if data.notify: - self.notifications.append(data.notify) - else: - raise AssertionError('Unknown response') - data = BeautifulSoup(self.sock.recv(1024)) - return data.answer - def close(self): - self.sock.close() class BatteryStates: CHARGED = 'charged' @@ -152,40 +100,43 @@ class NoiseControlTypes: class ParrotZikBase(object): - def __init__(self, api): - self.api = api + def __init__(self, resource_manager): + self.resource_manager = resource_manager @property def version(self): - return self.api.version + return self.resource_manager.api_version + + def refresh_battery(self): + self.resource_manager.fetch('/api/system/battery') @property def battery_state(self): - answer = self.api.get("/api/system/battery") + answer = self.resource_manager.get("/api/system/battery") return answer.system.battery["state"] def get_battery_level(self, field_name): - answer = self.api.get("/api/system/battery") + answer = self.resource_manager.get("/api/system/battery") return int(answer.system.battery[field_name]) @property def friendly_name(self): - answer = self.api.get("/api/bluetooth/friendlyname") + answer = self.resource_manager.get("/api/bluetooth/friendlyname") return answer.bluetooth["friendlyname"] @property def auto_connect(self): - answer = self.api.get("/api/system/auto_connection/enabled") + answer = self.resource_manager.get("/api/system/auto_connection/enabled") return self._result_to_bool( answer.system.auto_connection["enabled"]) @auto_connect.setter def auto_connect(self, arg): - self.api.set("/api/system/auto_connection/enabled", arg) + self.resource_manager.set("/api/system/auto_connection/enabled", arg) @property def anc_phone_mode(self): - answer = self.api.get("/api/system/anc_phone_mode/enabled") + answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") return self._result_to_bool( answer.system.anc_phone_mode["enabled"]) @@ -199,125 +150,118 @@ class ParrotZikBase(object): class ParrotZikVersion1(ParrotZikBase): - ''' - Known resources: - * /api/software/version - * /api/system/battery - * /api/bluetooth/friendlyname - * /api/system/auto_connection/enabled - * /api/system/anc_phone_mode/enabled - * /api/audio/specific_mode/enabled - * /api/audio/sound_effect/enabled - * /api/audio/noise_cancellation/enabled - ''' + def __init__(self, resource_manager): + super(ParrotZikVersion1, self).__init__( + resource_manager.get_resource_manager( + Version1ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['version'] + @property def battery_level(self): return int(self.get_battery_level('level')) @property def lou_reed_mode(self): - answer = self.api.get("/api/audio/specific_mode/enabled") + answer = self.resource_manager.get("/api/audio/specific_mode/enabled") return self._result_to_bool( answer.audio.specific_mode["enabled"]) @lou_reed_mode.setter def lou_reed_mode(self, arg): - self.api.get("/api/audio/specific_mode/enabled", arg) + self.resource_manager.get("/api/audio/specific_mode/enabled", arg) @property def concert_hall(self): - answer = self.api.get("/api/audio/sound_effect/enabled") + answer = self.resource_manager.get("/api/audio/sound_effect/enabled") return self._result_to_bool( answer.audio.sound_effect["enabled"]) @concert_hall.setter def concert_hall(self, arg): - self.api.get("/api/audio/sound_effect/enabled", arg) + self.resource_manager.get("/api/audio/sound_effect/enabled", arg) @property def cancel_noise(self): - answer = self.api.get("/api/audio/noise_cancellation/enabled") + answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") return self._result_to_bool( answer.audio.noise_cancellation["enabled"]) @cancel_noise.setter def cancel_noise(self, arg): - self.api.set("/api/audio/noise_cancellation/enabled", arg) + self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) class ParrotZikVersion2(ParrotZikBase): - ''' - Known resources: - * /api/software/version - * /api/system/battery - * /api/system/pi - * /api/bluetooth/friendlyname - * /api/system/auto_connection/enabled - * /api/system/anc_phone_mode/enabled - * /api/flight_mode - * /api/sound_effect/enabled - * /api/sound_effect/room_size - * /api/sound_effect/angle - * /api/audio/noise - * /api/audio/noise_control - * /api/audio/noise_control/enabled - ''' + def __init__(self, resource_manager): + super(ParrotZikVersion2, self).__init__( + resource_manager.get_resource_manager( + Version2ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['sip6'] + @property def battery_level(self): return self.get_battery_level('percent') @property def flight_mode(self): - answer = self.api.get('/api/flight_mode') + answer = self.resource_manager.get('/api/flight_mode') return self._result_to_bool(answer.flight_mode['enabled']) @flight_mode.setter def flight_mode(self, arg): if arg: - self.api.toggle_on('/api/flight_mode') + self.resource_manager.toggle_on('/api/flight_mode') else: - self.api.toggle_off('/api/flight_mode') + self.resource_manager.toggle_off('/api/flight_mode') @property def sound_effect(self): - answer = self.api.get('/api/audio/sound_effect/enabled') + answer = self.resource_manager.get('/api/audio/sound_effect/enabled') return self._result_to_bool(answer.audio.sound_effect['enabled']) @sound_effect.setter def sound_effect(self, arg): - self.api.set('/api/audio/sound_effect/enabled', arg) + self.resource_manager.set('/api/audio/sound_effect/enabled', arg) @property def room(self): - answer = self.api.get('/api/audio/sound_effect/room_size') + answer = self.resource_manager.get('/api/audio/sound_effect/room_size') return answer.audio.sound_effect['room_size'] @room.setter def room(self, arg): - self.api.set('/api/audio/sound_effect/room_size', arg) + self.resource_manager.set('/api/audio/sound_effect/room_size', arg) @property def external_noise(self): - answer = self.api.get('/api/audio/noise') + answer = self.resource_manager.get('/api/audio/noise') return int(answer.audio.noise['external']) @property def internal_noise(self): - answer = self.api.get('/api/audio/noise') + answer = self.resource_manager.get('/api/audio/noise') return int(answer.audio.noise['internal']) @property def angle(self): - answer = self.api.get('/api/audio/sound_effect/angle') + answer = self.resource_manager.get('/api/audio/sound_effect/angle') return int(answer.audio.sound_effect['angle']) @angle.setter def angle(self, arg): - self.api.set('/api/audio/sound_effect/angle', arg) + self.resource_manager.set('/api/audio/sound_effect/angle', arg) @property def noise_control(self): - answer = self.api.get('/api/audio/noise_control') + answer = self.resource_manager.get('/api/audio/noise_control') return NoiseControl.from_noise_control(answer.audio.noise_control) @noise_control.setter @@ -326,5 +270,5 @@ class ParrotZikVersion2(ParrotZikBase): @property def noise_control_enabled(self): - answer = self.api.get('/api/audio/noise_control/enabled') + answer = self.resource_manager.get('/api/audio/noise_control/enabled') return self._result_to_bool(answer.audio.noise_control['enabled']) diff --git a/ParrotZikTray b/ParrotZikTray index 373e9ee..6850a3f 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -5,6 +5,8 @@ import gtk import BluetoothPairedDevices from ParrotZik import BatteryStates +from ParrotZik import ParrotZikVersion1 +from ParrotZik import ParrotZikVersion2 from ParrotZik import NoiseControlTypes from ParrotZik import connect from ParrotZik import Rooms @@ -68,12 +70,12 @@ class ParrotZikIndicator(SysIndicator): mac = BluetoothPairedDevices.ParrotZikMac() if mac: self.info_item.set_label("Connecting") - parrot = connect(mac) - if parrot.api.sock: - if parrot.version.startswith('1'): - self.version_1_interface.activate(parrot) + resource_manager = connect(mac) + if resource_manager.sock: + if resource_manager.api_version.startswith('1'): + self.version_1_interface.activate(resource_manager) else: - self.version_2_interface.activate(parrot) + self.version_2_interface.activate(resource_manager) self.autorefresh(self) self.autorefresh.start(self, REFRESH_FREQUENCY) self.reconnect.stop() @@ -114,12 +116,12 @@ class ParrotZikBaseInterface(object): @property def connected(self): if self.parrot: - return self.parrot.api.sock + return self.parrot.resource_manager.sock else: return False - def activate(self, parrot): - self.parrot = parrot + def activate(self, resource_manager): + self.parrot = self.parrot_class(resource_manager) self.read_battery() self.indicator.info_item.set_label("Connected to: " + self.parrot.friendly_name) @@ -134,6 +136,10 @@ class ParrotZikBaseInterface(object): self.indicator.active_interface = self self.indicator.menu.reposition() + @property + def parrot_class(self): + raise NotImplementedError + def deactivate(self): self.parrot = None self.battery_level.hide() @@ -157,9 +163,9 @@ class ParrotZikBaseInterface(object): def read_battery(self): if self.connected: + self.parrot.refresh_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: @@ -182,6 +188,8 @@ class ParrotZikBaseInterface(object): class ParrotZikVersion1Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion1 + def __init__(self, indicator): super(ParrotZikVersion1Interface, self).__init__(indicator) self.noise_cancelation = MenuItem( @@ -196,11 +204,11 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.lou_reed_mode) self.indicator.menu.append(self.concert_hall_mode) - def activate(self, parrot): + def activate(self, resource_manager): self.noise_cancelation.show() self.lou_reed_mode.show() self.concert_hall_mode.show() - super(ParrotZikVersion1Interface, self).activate(parrot) + super(ParrotZikVersion1Interface, self).activate(resource_manager) self.noise_cancelation.set_active(self.parrot.cancel_noise) self.lou_reed_mode.set_active(self.parrot.lou_reed_mode) @@ -238,6 +246,8 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): class ParrotZikVersion2Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion2 + def __init__(self, indicator): self.room_dirty = False self.angle_dirty = False @@ -329,11 +339,11 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.flight_mode) - def activate(self, parrot): + def activate(self, resource_manager): self.noise_cancelation.show() self.flight_mode.show() self.room_sound_effect.show() - super(ParrotZikVersion2Interface, self).activate(parrot) + super(ParrotZikVersion2Interface, self).activate(resource_manager) self.read_noise_cancelation() self.flight_mode.set_active(self.parrot.flight_mode) self.read_sound_effect_room() diff --git a/resource_manager.py b/resource_manager.py new file mode 100644 index 0000000..1a6e224 --- /dev/null +++ b/resource_manager.py @@ -0,0 +1,135 @@ +import sys +from BeautifulSoup import BeautifulSoup +import ParrotProtocol + + +class ResourceManagerBase(object): + resources = [ + ] + + def __init__(self, socket, resource_values=None): + self.sock = socket + self.resource_values = resource_values or {} + + def get(self, resource): + try: + return self.resource_values[resource] + except KeyError: + return self.fetch(resource) + + def fetch(self, resource): + assert resource in self.resources, 'Unknown resource {}'.format(resource) + message = ParrotProtocol.getRequest(resource + '/get') + result = self.send_message(message) + self.resource_values[resource] = result + return result + + def toggle_on(self, resource): + assert resource in self.resources, 'Unknown resource {}'.format(resource) + message = ParrotProtocol.getRequest(resource + '/enable') + self.send_message(message) + self.fetch(resource) + + def toggle_off(self, resource): + assert resource in self.resources, 'Unknown resource {}'.format(resource) + message = ParrotProtocol.getRequest(resource + '/disable') + self.send_message(message) + self.fetch(resource) + + def set(self, resource, arg): + assert resource in self.resources, 'Unknown resource {}'.format(resource) + message = ParrotProtocol.setRequest(resource + '/set', str(arg).lower()) + self.send_message(message) + self.fetch(resource) + + def send_message(self, message): + try: + self.sock.send(str(message)) + except Exception: + self.sock = "" + return + else: + return self.get_answer() + + def get_answer(self): + data = self.receive_message() + while not data.answer: + if data.notify: + self.handle_notification(data.notify) + else: + raise AssertionError('Unknown response') + data = self.receive_message() + return data.answer + + def handle_notification(self, notification): + + self.fetch(notification['path'].rsplit('/', 1)[0].encode('utf-8')) + + def receive_message(self): + if sys.platform == "darwin": + self.sock.recv(30) + else: + self.sock.recv(7) + return BeautifulSoup(self.sock.recv(1024)) + + def close(self): + self.sock.close() + + +class GenericResourceManager(ResourceManagerBase): + resources = { + '/api/software/version', + } + + def __init__(self, sock): + super(GenericResourceManager, self).__init__(sock) + self.notifications = [] + + def handle_notification(self, notification): + self.notifications.append(notification) + + def get_resource_manager(self, resource_manager_class): + resource_manager = resource_manager_class(self.sock, self.resource_values) + for notitifaction in self.notifications: + resource_manager.handle_notification(notitifaction) + return resource_manager + + @property + def api_version(self): + answer = self.get("/api/software/version") + try: + return answer.software["version"] + except KeyError: + return answer.software['sip6'] + + +class Version1ResourceManager(ResourceManagerBase): + resources = { + '/api/software/version', + '/api/system/battery', + '/api/bluetooth/friendlyname', + '/api/system/auto_connection/enabled', + '/api/system/anc_phone_mode/enabled', + '/api/audio/specific_mode/enabled', + '/api/audio/sound_effect/enabled', + '/api/audio/noise_cancellation/enabled', + } + +class Version2ResourceManager(ResourceManagerBase): + resources = { + '/api/software/version', + '/api/system/battery', + '/api/system/pi', + '/api/bluetooth/friendlyname', + '/api/system/auto_connection/enabled', + '/api/system/anc_phone_mode/enabled', + '/api/flight_mode', + '/api/audio/sound_effect/enabled', + '/api/audio/sound_effect/room_size', + '/api/audio/sound_effect/angle', + '/api/audio/noise', + '/api/audio/noise_control', + '/api/audio/noise_control/enabled', + '/api/audio/track/metadata', + } + diff --git a/setup.py b/setup.py index b919e8f..de58f17 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ setup( 'BeautifulSoup', 'bluetooth' ], - py_modules=['ParrotZik', 'ParrotProtocol'], + py_modules=['ParrotZik', 'ParrotProtocol', 'resource_manager'], scripts=["ParrotZikTray"] ) -- cgit v1.2.1 From 1bae288e1e03210b25f7159adb43581f1d18a353 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 23:05:22 +0200 Subject: Restrict methods. --- resource_manager.py | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/resource_manager.py b/resource_manager.py index 1a6e224..b343807 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -19,6 +19,7 @@ class ResourceManagerBase(object): def fetch(self, resource): assert resource in self.resources, 'Unknown resource {}'.format(resource) + assert 'get' in self.resources[resource], 'Unhandled method' message = ParrotProtocol.getRequest(resource + '/get') result = self.send_message(message) self.resource_values[resource] = result @@ -26,18 +27,21 @@ class ResourceManagerBase(object): def toggle_on(self, resource): assert resource in self.resources, 'Unknown resource {}'.format(resource) + assert 'enable' in self.resources[resource], 'Unhandled method' message = ParrotProtocol.getRequest(resource + '/enable') self.send_message(message) self.fetch(resource) def toggle_off(self, resource): assert resource in self.resources, 'Unknown resource {}'.format(resource) + assert 'disable' in self.resources[resource], 'Unhandled method' message = ParrotProtocol.getRequest(resource + '/disable') self.send_message(message) self.fetch(resource) def set(self, resource, arg): assert resource in self.resources, 'Unknown resource {}'.format(resource) + assert 'set' in self.resources[resource], 'Unhandled method' message = ParrotProtocol.setRequest(resource + '/set', str(arg).lower()) self.send_message(message) self.fetch(resource) @@ -78,7 +82,7 @@ class ResourceManagerBase(object): class GenericResourceManager(ResourceManagerBase): resources = { - '/api/software/version', + '/api/software/version': ['get'], } def __init__(self, sock): @@ -105,31 +109,31 @@ class GenericResourceManager(ResourceManagerBase): class Version1ResourceManager(ResourceManagerBase): resources = { - '/api/software/version', - '/api/system/battery', - '/api/bluetooth/friendlyname', - '/api/system/auto_connection/enabled', - '/api/system/anc_phone_mode/enabled', - '/api/audio/specific_mode/enabled', - '/api/audio/sound_effect/enabled', - '/api/audio/noise_cancellation/enabled', + '/api/software/version': ['get'], + '/api/system/battery': ['get'], + '/api/bluetooth/friendlyname': ['get'], + '/api/system/auto_connection/enabled': ['get', 'set'], + '/api/system/anc_phone_mode/enabled': ['get', 'set'], + '/api/audio/specific_mode/enabled': ['get', 'set'], + '/api/audio/sound_effect/enabled': ['get', 'set'], + '/api/audio/noise_cancellation/enabled': ['get', 'set'], } class Version2ResourceManager(ResourceManagerBase): resources = { - '/api/software/version', - '/api/system/battery', - '/api/system/pi', - '/api/bluetooth/friendlyname', - '/api/system/auto_connection/enabled', - '/api/system/anc_phone_mode/enabled', - '/api/flight_mode', - '/api/audio/sound_effect/enabled', - '/api/audio/sound_effect/room_size', - '/api/audio/sound_effect/angle', - '/api/audio/noise', - '/api/audio/noise_control', - '/api/audio/noise_control/enabled', - '/api/audio/track/metadata', + '/api/software/version': ['get'], + '/api/system/battery': ['get'], + '/api/system/pi': ['get'], + '/api/bluetooth/friendlyname': ['get'], + '/api/system/auto_connection/enabled': ['get', 'set'], + '/api/system/anc_phone_mode/enabled': ['get', 'set'], + '/api/flight_mode': ['get', 'enable', 'disable'], + '/api/audio/sound_effect/enabled': ['get', 'set'], + '/api/audio/sound_effect/room_size': ['get', 'set'], + '/api/audio/sound_effect/angle': ['get', 'set'], + '/api/audio/noise': ['get'], + '/api/audio/noise_control': ['get'], + '/api/audio/noise_control/enabled': ['get', 'set'], + '/api/audio/track/metadata': ['get'], } -- cgit v1.2.1 From 43d3e73661ae265d0af314303310ed4dcb1ce780 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 23:26:05 +0200 Subject: Refactor. --- resource_manager.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/resource_manager.py b/resource_manager.py index b343807..695314b 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -18,34 +18,31 @@ class ResourceManagerBase(object): return self.fetch(resource) def fetch(self, resource): - assert resource in self.resources, 'Unknown resource {}'.format(resource) - assert 'get' in self.resources[resource], 'Unhandled method' - message = ParrotProtocol.getRequest(resource + '/get') - result = self.send_message(message) + result = self.send_message(self._create_message(resource, 'get')) self.resource_values[resource] = result return result def toggle_on(self, resource): - assert resource in self.resources, 'Unknown resource {}'.format(resource) - assert 'enable' in self.resources[resource], 'Unhandled method' - message = ParrotProtocol.getRequest(resource + '/enable') - self.send_message(message) + self.send_message(self._create_message(resource, 'enable')) self.fetch(resource) def toggle_off(self, resource): - assert resource in self.resources, 'Unknown resource {}'.format(resource) - assert 'disable' in self.resources[resource], 'Unhandled method' - message = ParrotProtocol.getRequest(resource + '/disable') - self.send_message(message) + self.send_message(self._create_message(resource, 'disable')) self.fetch(resource) def set(self, resource, arg): - assert resource in self.resources, 'Unknown resource {}'.format(resource) - assert 'set' in self.resources[resource], 'Unhandled method' - message = ParrotProtocol.setRequest(resource + '/set', str(arg).lower()) - self.send_message(message) + self.send_message(self._create_message(resource, 'set', arg)) self.fetch(resource) + def _create_message(self, resource, method, arg=None): + assert resource in self.resources, 'Unknown resource {}'.format(resource) + assert method in self.resources[resource], 'Unhandled method {} for {}'.format( + method, resource) + if method == 'set': + return ParrotProtocol.setRequest(resource + '/' + method, str(arg).lower()) + else: + return ParrotProtocol.getRequest(resource + '/' + method) + def send_message(self, message): try: self.sock.send(str(message)) -- cgit v1.2.1 From 2ce4b4e99cd139ff1ce2976c317218beaa5a16c6 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 23:37:06 +0200 Subject: Refactor. --- resource_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resource_manager.py b/resource_manager.py index 695314b..8aa4fb8 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -63,8 +63,10 @@ class ResourceManagerBase(object): return data.answer def handle_notification(self, notification): + self.fetch(self._clean_path(notification['path'])) - self.fetch(notification['path'].rsplit('/', 1)[0].encode('utf-8')) + def _clean_path(self, path): + return path.rsplit('/', 1)[0].encode('utf-8') def receive_message(self): if sys.platform == "darwin": -- cgit v1.2.1 From ebb7d4799f00c6ebb2cb1f53dcce4e1b1cc884f3 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 23:48:29 +0200 Subject: Fix notifications responses colliding with request response.. --- resource_manager.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resource_manager.py b/resource_manager.py index 8aa4fb8..8dcf6bc 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -54,12 +54,15 @@ class ResourceManagerBase(object): def get_answer(self): data = self.receive_message() + notifications = [] while not data.answer: if data.notify: - self.handle_notification(data.notify) + notifications.append(data.notify) else: raise AssertionError('Unknown response') data = self.receive_message() + for notification in notifications: + self.handle_notification(notification) return data.answer def handle_notification(self, notification): -- cgit v1.2.1 From 46123a0a78149a8832e9201f33de3a8dfa520c4b Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Sun, 14 Jun 2015 23:54:28 +0200 Subject: Perform one fetch per notification path. --- resource_manager.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/resource_manager.py b/resource_manager.py index 8dcf6bc..752efe4 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -1,3 +1,4 @@ +from operator import itemgetter import sys from BeautifulSoup import BeautifulSoup import ParrotProtocol @@ -61,12 +62,14 @@ class ResourceManagerBase(object): else: raise AssertionError('Unknown response') data = self.receive_message() - for notification in notifications: - self.handle_notification(notification) + self.handle_notifications(notifications) return data.answer - def handle_notification(self, notification): - self.fetch(self._clean_path(notification['path'])) + def handle_notifications(self, notifications): + paths = map(itemgetter('path'), notifications) + clean_paths = set(map(self._clean_path, paths)) + for path in clean_paths: + self.fetch(path) def _clean_path(self, path): return path.rsplit('/', 1)[0].encode('utf-8') @@ -96,8 +99,7 @@ class GenericResourceManager(ResourceManagerBase): def get_resource_manager(self, resource_manager_class): resource_manager = resource_manager_class(self.sock, self.resource_values) - for notitifaction in self.notifications: - resource_manager.handle_notification(notitifaction) + resource_manager.handle_notifications(self.notifications) return resource_manager @property -- cgit v1.2.1 From e130a18d3c46f311d095819ab901b2fca57fcea3 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 00:13:44 +0200 Subject: Create message class. --- ParrotProtocol.py | 20 -------------------- message.py | 30 ++++++++++++++++++++++++++++++ resource_manager.py | 10 +++------- setup.py | 2 +- 4 files changed, 34 insertions(+), 28 deletions(-) delete mode 100644 ParrotProtocol.py create mode 100644 message.py diff --git a/ParrotProtocol.py b/ParrotProtocol.py deleted file mode 100644 index a4e1677..0000000 --- a/ParrotProtocol.py +++ /dev/null @@ -1,20 +0,0 @@ -def generateRequest(requestString): - message = bytearray() - message.extend(generateHeader(requestString)) - message.extend(bytearray(requestString)) - return message - - -def generateHeader(requestString): - header = bytearray([0]) - header.append(len(requestString) + 3) - header.append("\x80") - return header - - -def getRequest(resource): - return generateRequest("GET " + resource) - - -def setRequest(resource, args): - return generateRequest("SET " + resource + "?arg=" + args) diff --git a/message.py b/message.py new file mode 100644 index 0000000..214b6f9 --- /dev/null +++ b/message.py @@ -0,0 +1,30 @@ +class Message: + def __init__(self, resource, method, arg=None): + self.method = method + self.resource = resource + self.arg = arg + + def __str__(self): + return str(self.request) + + @property + def request(self): + message = bytearray() + message.extend(self.header) + message.extend(bytearray(self.request_string)) + return message + + @property + def header(self): + header = bytearray([0]) + header.append(len(self.request_string) + 3) + header.append("\x80") + return header + + @property + def request_string(self): + if self.method == 'set': + return 'SET {}/{}?arg={}'.format(self.resource, self.method, + str(self.arg).lower()) + else: + return 'GET {}/{}'.format(self.resource, self.method) diff --git a/resource_manager.py b/resource_manager.py index 752efe4..fb3b5f3 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -1,8 +1,8 @@ from operator import itemgetter import sys from BeautifulSoup import BeautifulSoup -import ParrotProtocol +from message import Message class ResourceManagerBase(object): resources = [ @@ -37,12 +37,8 @@ class ResourceManagerBase(object): def _create_message(self, resource, method, arg=None): assert resource in self.resources, 'Unknown resource {}'.format(resource) - assert method in self.resources[resource], 'Unhandled method {} for {}'.format( - method, resource) - if method == 'set': - return ParrotProtocol.setRequest(resource + '/' + method, str(arg).lower()) - else: - return ParrotProtocol.getRequest(resource + '/' + method) + assert method in self.resources[resource], 'Unhandled method {} for {}'.format(method, resource) + return Message(resource, method, arg) def send_message(self, message): try: diff --git a/setup.py b/setup.py index de58f17..9bb3ae7 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ setup( 'BeautifulSoup', 'bluetooth' ], - py_modules=['ParrotZik', 'ParrotProtocol', 'resource_manager'], + py_modules=['ParrotZik', 'message', 'resource_manager'], scripts=["ParrotZikTray"] ) -- cgit v1.2.1 From 21cf625f6970c001c9f14bdbc603a104e544b9e1 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 00:17:20 +0200 Subject: Don't fetch notification for recent fetched paths. --- resource_manager.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resource_manager.py b/resource_manager.py index fb3b5f3..f0703ac 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -47,9 +47,9 @@ class ResourceManagerBase(object): self.sock = "" return else: - return self.get_answer() + return self.get_answer(message) - def get_answer(self): + def get_answer(self, message): data = self.receive_message() notifications = [] while not data.answer: @@ -58,14 +58,15 @@ class ResourceManagerBase(object): else: raise AssertionError('Unknown response') data = self.receive_message() - self.handle_notifications(notifications) + self.handle_notifications(notifications, message.resource) return data.answer - def handle_notifications(self, notifications): + def handle_notifications(self, notifications, resource): paths = map(itemgetter('path'), notifications) clean_paths = set(map(self._clean_path, paths)) for path in clean_paths: - self.fetch(path) + if resource != path: + self.fetch(path) def _clean_path(self, path): return path.rsplit('/', 1)[0].encode('utf-8') @@ -95,7 +96,7 @@ class GenericResourceManager(ResourceManagerBase): def get_resource_manager(self, resource_manager_class): resource_manager = resource_manager_class(self.sock, self.resource_values) - resource_manager.handle_notifications(self.notifications) + resource_manager.handle_notifications(self.notifications, '/api/software/version') return resource_manager @property -- cgit v1.2.1 From ffa76dd958282735c1b39793351a075a3d1a64ac Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 01:10:40 +0200 Subject: Refactor. --- BluetoothPairedDevices.py | 45 ---------------------- ParrotZik.py | 52 ------------------------- ParrotZikTray | 6 +-- bluetooth_paired_devices.py | 92 +++++++++++++++++++++++++++++++++++++++++++++ resource_manager.py | 3 +- 5 files changed, 97 insertions(+), 101 deletions(-) delete mode 100644 BluetoothPairedDevices.py create mode 100644 bluetooth_paired_devices.py diff --git a/BluetoothPairedDevices.py b/BluetoothPairedDevices.py deleted file mode 100644 index aa5b056..0000000 --- a/BluetoothPairedDevices.py +++ /dev/null @@ -1,45 +0,0 @@ -import sys -import re -import os - -if sys.platform == "darwin": - from binplist import binplist -elif sys.platform == "win32": - import _winreg - - -def ParrotZikMac(): - p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' - 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') - if sys.platform == "linux2": - out = os.popen("bluez-test-device list").read() - res = p.findall(out) - if len(res) > 0: - return res[0] - - elif sys.platform == "darwin": - fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") - plist = binplist.BinaryPlist(file_obj=fd) - parsed_plist = plist.Parse() - try: - for mac in parsed_plist['PairedDevices']: - if p.match(mac.replace("-", ":")): - return mac.replace("-", ":") - except Exception: - pass - - elif sys.platform == "win32": - aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - aKey = _winreg.OpenKey( - aReg, 'SYSTEM\CurrentControlSet\Services\ - BTHPORT\Parameters\Devices') - for i in range(10): - try: - asubkey_name = _winreg.EnumKey(aKey, i) - mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) - res = p.findall(mac) - if len(res) > 0: - return res[0] - - except EnvironmentError: - pass diff --git a/ParrotZik.py b/ParrotZik.py index 8e4b31b..52414b5 100644 --- a/ParrotZik.py +++ b/ParrotZik.py @@ -1,58 +1,6 @@ -import sys - -from resource_manager import GenericResourceManager from resource_manager import Version1ResourceManager from resource_manager import Version2ResourceManager -if sys.platform == "darwin": - import lightblue -else: - import bluetooth - - -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 GenericResourceManager(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) - return GenericResourceManager(sock) - - class BatteryStates: CHARGED = 'charged' diff --git a/ParrotZikTray b/ParrotZikTray index 6850a3f..e43ac90 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -3,12 +3,12 @@ import functools import gtk -import BluetoothPairedDevices +import bluetooth_paired_devices from ParrotZik import BatteryStates from ParrotZik import ParrotZikVersion1 from ParrotZik import ParrotZikVersion2 from ParrotZik import NoiseControlTypes -from ParrotZik import connect +from bluetooth_paired_devices import connect from ParrotZik import Rooms from SysIndicator import MenuItem from SysIndicator import Menu @@ -67,7 +67,7 @@ class ParrotZikIndicator(SysIndicator): else: self.reconnect.stop() else: - mac = BluetoothPairedDevices.ParrotZikMac() + mac = bluetooth_paired_devices.get_parrot_zik_mac() if mac: self.info_item.set_label("Connecting") resource_manager = connect(mac) diff --git a/bluetooth_paired_devices.py b/bluetooth_paired_devices.py new file mode 100644 index 0000000..139ca3d --- /dev/null +++ b/bluetooth_paired_devices.py @@ -0,0 +1,92 @@ +import sys +import re +import os + +from resource_manager import GenericResourceManager + +if sys.platform == "darwin": + from binplist import binplist + import lightblue +else: + import bluetooth + if sys.platform == "win32": + import _winreg + + +def get_parrot_zik_mac(): + p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' + 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') + if sys.platform == "linux2": + out = os.popen("bluez-test-device list").read() + res = p.findall(out) + if len(res) > 0: + return res[0] + + elif sys.platform == "darwin": + fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") + plist = binplist.BinaryPlist(file_obj=fd) + parsed_plist = plist.Parse() + try: + for mac in parsed_plist['PairedDevices']: + if p.match(mac.replace("-", ":")): + return mac.replace("-", ":") + except Exception: + pass + + elif sys.platform == "win32": + aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + aKey = _winreg.OpenKey( + aReg, 'SYSTEM\CurrentControlSet\Services\ + BTHPORT\Parameters\Devices') + for i in range(10): + try: + asubkey_name = _winreg.EnumKey(aKey, i) + mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) + res = p.findall(mac) + if len(res) > 0: + return res[0] + + except EnvironmentError: + pass + + +def connect(addr=None): + if sys.platform == "darwin": + service_matches = lightblue.findservices( + name="Parrot RFcomm service", addr=addr) + else: + uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb", + "8B6814D3-6CE7-4498-9700-9312C1711F63"] + service_matches = [] + 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 GenericResourceManager(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') + sock.recv(1024) + return GenericResourceManager(sock) diff --git a/resource_manager.py b/resource_manager.py index f0703ac..ddd39fb 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -1,9 +1,11 @@ from operator import itemgetter import sys + from BeautifulSoup import BeautifulSoup from message import Message + class ResourceManagerBase(object): resources = [ ] @@ -137,4 +139,3 @@ class Version2ResourceManager(ResourceManagerBase): '/api/audio/noise_control/enabled': ['get', 'set'], '/api/audio/track/metadata': ['get'], } - -- cgit v1.2.1 From 8dd3e12ec52cf993856bc0ea3601cc1c07acce1b Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 01:52:50 +0200 Subject: Handle connection errors through Exceptions. --- ParrotZikTray | 38 +++++++++++++++++++---------------- bluetooth_paired_devices.py | 48 ++++++++++++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index e43ac90..55713b3 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -67,22 +67,27 @@ class ParrotZikIndicator(SysIndicator): else: self.reconnect.stop() else: - mac = bluetooth_paired_devices.get_parrot_zik_mac() - if mac: - self.info_item.set_label("Connecting") - resource_manager = connect(mac) - if resource_manager.sock: - if resource_manager.api_version.startswith('1'): - self.version_1_interface.activate(resource_manager) - else: - self.version_2_interface.activate(resource_manager) - self.autorefresh(self) - self.autorefresh.start(self, REFRESH_FREQUENCY) - self.reconnect.stop() - else: - self.info_item.set_label("Failed to connect") + self.info("Trying to connect") + try: + resource_manager = connect() + except bluetooth_paired_devices.BluetoothIsNotOn: + self.info("Bluetooth is turned off") + except bluetooth_paired_devices.DeviceNotConnected: + self.info("Parrot Zik Not connected") + except bluetooth_paired_devices.ConnectionFailure: + self.info("Failed to connect") else: - self.info_item.set_label("Parrot Zik Not connected") + if resource_manager.api_version.startswith('1'): + self.version_1_interface.activate(resource_manager) + else: + self.version_2_interface.activate(resource_manager) + self.autorefresh(self) + self.autorefresh.start(self, REFRESH_FREQUENCY) + self.reconnect.stop() + + def info(self, message): + self.info_item.set_label(message) + print(message) @repeat def autorefresh(self): @@ -123,8 +128,7 @@ class ParrotZikBaseInterface(object): def activate(self, resource_manager): self.parrot = self.parrot_class(resource_manager) self.read_battery() - self.indicator.info_item.set_label("Connected to: " - + self.parrot.friendly_name) + self.indicator.info("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) diff --git a/bluetooth_paired_devices.py b/bluetooth_paired_devices.py index 139ca3d..5ab060f 100644 --- a/bluetooth_paired_devices.py +++ b/bluetooth_paired_devices.py @@ -17,11 +17,16 @@ def get_parrot_zik_mac(): p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') if sys.platform == "linux2": - out = os.popen("bluez-test-device list").read() - res = p.findall(out) - if len(res) > 0: - return res[0] - + bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) + if bluetooth_on == 1: + out = os.popen("bluez-test-device list").read() + res = p.findall(out) + if len(res) > 0: + return res[0] + else: + raise DeviceNotConnected + else: + raise BluetoothIsNotOn elif sys.platform == "darwin": fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") plist = binplist.BinaryPlist(file_obj=fd) @@ -30,6 +35,8 @@ def get_parrot_zik_mac(): for mac in parsed_plist['PairedDevices']: if p.match(mac.replace("-", ":")): return mac.replace("-", ":") + else: + raise DeviceNotConnected except Exception: pass @@ -45,41 +52,38 @@ def get_parrot_zik_mac(): res = p.findall(mac) if len(res) > 0: return res[0] - + else: + raise DeviceNotConnected except EnvironmentError: pass -def connect(addr=None): +def connect(): + mac = get_parrot_zik_mac() if sys.platform == "darwin": service_matches = lightblue.findservices( - name="Parrot RFcomm service", addr=addr) + name="Parrot RFcomm service", addr=mac) else: uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb", "8B6814D3-6CE7-4498-9700-9312C1711F63"] service_matches = [] for uuid in uuids: - service_matches = bluetooth.find_service(uuid=uuid, address=addr) + service_matches = bluetooth.find_service(uuid=uuid, address=mac) if service_matches: break if len(service_matches) == 0: - print "Failed to find Parrot Zik RFCOMM service" - return GenericResourceManager(None) + raise ConnectionFailure if sys.platform == "darwin": first_match = service_matches[0] - port = first_match[1] - name = first_match[2] host = first_match[0] + port = first_match[1] 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: @@ -90,3 +94,15 @@ def connect(addr=None): sock.send('\x00\x03\x00') sock.recv(1024) return GenericResourceManager(sock) + + +class DeviceNotConnected(Exception): + pass + + +class ConnectionFailure(Exception): + pass + + +class BluetoothIsNotOn(Exception): + pass -- cgit v1.2.1 From bd0c2445f53e8c049fe7cc4c1b4e2e0a11418bc1 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 01:56:01 +0200 Subject: Ignore bluetooth error. --- bluetooth_paired_devices.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bluetooth_paired_devices.py b/bluetooth_paired_devices.py index 5ab060f..ce86d53 100644 --- a/bluetooth_paired_devices.py +++ b/bluetooth_paired_devices.py @@ -68,7 +68,10 @@ def connect(): "8B6814D3-6CE7-4498-9700-9312C1711F63"] service_matches = [] for uuid in uuids: - service_matches = bluetooth.find_service(uuid=uuid, address=mac) + try: + service_matches = bluetooth.find_service(uuid=uuid, address=mac) + except bluetooth.btcommon.BluetoothError: + pass if service_matches: break @@ -79,14 +82,11 @@ def connect(): first_match = service_matches[0] host = first_match[0] port = first_match[1] + sock = lightblue.socket() else: first_match = service_matches[0] port = first_match["port"] host = first_match["host"] - - if sys.platform == "darwin": - sock = lightblue.socket() - else: sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) sock.connect((host, port)) -- cgit v1.2.1 From eac6cdf7521d6514072e1f91958bbc0f1bc29b70 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 01:56:23 +0200 Subject: Refactor. --- bluetooth_paired_devices.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bluetooth_paired_devices.py b/bluetooth_paired_devices.py index ce86d53..fead080 100644 --- a/bluetooth_paired_devices.py +++ b/bluetooth_paired_devices.py @@ -77,14 +77,13 @@ def connect(): if len(service_matches) == 0: raise ConnectionFailure + first_match = service_matches[0] if sys.platform == "darwin": - first_match = service_matches[0] host = first_match[0] port = first_match[1] sock = lightblue.socket() else: - first_match = service_matches[0] port = first_match["port"] host = first_match["host"] sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) -- cgit v1.2.1 From fde8202e397eff82993c738010e1519a00e7430d Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 02:59:24 +0200 Subject: Handle disconnection through exceptions. --- ParrotZikTray | 117 ++++++++++++++++++++++++---------------------------- resource_manager.py | 10 +++-- 2 files changed, 60 insertions(+), 67 deletions(-) diff --git a/ParrotZikTray b/ParrotZikTray index 55713b3..4c86adf 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -13,6 +13,7 @@ from ParrotZik import Rooms from SysIndicator import MenuItem from SysIndicator import Menu from SysIndicator import SysIndicator +import resource_manager REFRESH_FREQUENCY = 30000 RECONNECT_FREQUENCY = 5000 @@ -61,15 +62,11 @@ class ParrotZikIndicator(SysIndicator): @repeat def reconnect(self): if self.active_interface: - if not self.active_interface.connected: - self.info_item.set_label("Lost connection") - self.active_interface.deactivate() - else: - self.reconnect.stop() + self.reconnect.stop() else: self.info("Trying to connect") try: - resource_manager = connect() + manager = connect() except bluetooth_paired_devices.BluetoothIsNotOn: self.info("Bluetooth is turned off") except bluetooth_paired_devices.DeviceNotConnected: @@ -77,13 +74,18 @@ class ParrotZikIndicator(SysIndicator): except bluetooth_paired_devices.ConnectionFailure: self.info("Failed to connect") else: - if resource_manager.api_version.startswith('1'): - self.version_1_interface.activate(resource_manager) + if manager.api_version.startswith('1'): + interface = self.version_1_interface + else: + interface = self.version_2_interface + try: + interface.activate(manager) + except resource_manager.DeviceDisconnected: + interface.deactivate() else: - self.version_2_interface.activate(resource_manager) - self.autorefresh(self) - self.autorefresh.start(self, REFRESH_FREQUENCY) - self.reconnect.stop() + self.autorefresh(self) + self.autorefresh.start(self, REFRESH_FREQUENCY) + self.reconnect.stop() def info(self, message): self.info_item.set_label(message) @@ -118,21 +120,13 @@ class ParrotZikBaseInterface(object): self.indicator.menu.append(self.firmware_version) self.indicator.menu.append(self.auto_connection) - @property - def connected(self): - if self.parrot: - return self.parrot.resource_manager.sock - else: - return False - - def activate(self, resource_manager): - self.parrot = self.parrot_class(resource_manager) + def activate(self, manager): + self.parrot = self.parrot_class(manager) self.read_battery() self.indicator.info("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.battery_level.show() self.battery_state.show() self.firmware_version.show() @@ -150,26 +144,29 @@ class ParrotZikBaseInterface(object): 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 + self.indicator.setIcon("zik-audio-headset") + self.indicator.info('Lost Connection') def toggle_auto_connection(self, widget): - if self.connected: + try: self.parrot.auto_connect = self.auto_connection.get_active() self.auto_connection.set_active(self.parrot.auto_connect) - else: + except resource_manager.DeviceDisconnected: self.deactivate() def refresh(self): self.read_battery() def read_battery(self): - if self.connected: + try: self.parrot.refresh_battery() battery_level = self.parrot.battery_level battery_state = self.parrot.battery_state + except resource_manager.DeviceDisconnected: + self.deactivate() + else: if battery_state == BatteryStates.CHARGING: self.indicator.setIcon("zik-battery-charging") elif battery_level > 80: @@ -187,8 +184,6 @@ class ParrotZikBaseInterface(object): "State: " + BatteryStates.representation[battery_state]) self.battery_level.set_label( "Battery Level: " + str(battery_level)) - else: - self.deactivate() class ParrotZikVersion1Interface(ParrotZikBaseInterface): @@ -208,12 +203,11 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.lou_reed_mode) self.indicator.menu.append(self.concert_hall_mode) - def activate(self, resource_manager): + def activate(self, manager): self.noise_cancelation.show() self.lou_reed_mode.show() self.concert_hall_mode.show() - super(ParrotZikVersion1Interface, self).activate(resource_manager) - + super(ParrotZikVersion1Interface, self).activate(manager) self.noise_cancelation.set_active(self.parrot.cancel_noise) self.lou_reed_mode.set_active(self.parrot.lou_reed_mode) self.concert_hall_mode.set_active(self.parrot.concert_hall) @@ -225,27 +219,27 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): super(ParrotZikVersion1Interface, self).deactivate() def toggle_noise_cancelation(self, widget): - if self.connected: + try: self.parrot.cancel_noise = self.noise_cancelation.get_active() self.noise_cancelation.set_active(self.parrot.cancel_noise) - else: + except resource_manager.DeviceDisconnected: self.deactivate() def toggle_lou_reed_mode(self, widget): - if self.connected: + try: 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()) - else: + except resource_manager.DeviceDisconnected: self.deactivate() def toggle_parrot_concert_hall(self, widget): - if self.connected: + try: self.parrot.concert_hall = self.concert_hall_mode.get_active() self.concert_hall_mode.set_active(self.parrot.concert_hall) - else: + except resource_manager.DeviceDisconnected: self.deactivate() @@ -343,17 +337,17 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.flight_mode) - def activate(self, resource_manager): + def activate(self, manager): self.noise_cancelation.show() self.flight_mode.show() self.room_sound_effect.show() - super(ParrotZikVersion2Interface, self).activate(resource_manager) - self.read_noise_cancelation() + super(ParrotZikVersion2Interface, self).activate(manager) + self._read_noise_cancelation() self.flight_mode.set_active(self.parrot.flight_mode) - self.read_sound_effect_room() - self.read_sound_effect_angle() - + 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) @@ -375,26 +369,23 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): super(ParrotZikVersion2Interface, self).deactivate() def toggle_flight_mode(self, widget): - if self.connected: + try: self.parrot.flight_mode = self.flight_mode.get_active() self.flight_mode.set_active(self.parrot.flight_mode) - else: + except resource_manager.DeviceDisconnected: self.deactivate() - def toggledummy(self, widget): - print(widget.get_name()) - def toggle_room(self, room, widget): - if self.connected: + try: if not self.room_dirty: self.parrot.room = room self.room_dirty = True - self.read_sound_effect_room() + self._read_sound_effect_room() self.room_dirty = False - else: + except resource_manager.DeviceDisconnected: self.deactivate() - def read_sound_effect_room(self): + def _read_sound_effect_room(self): active_room = self.parrot.room room_to_menuitem_map = ( (Rooms.CONCERT_HALL, self.concert_hall_mode), @@ -406,7 +397,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): menu_item.set_active(room == active_room) def toggle_room_sound_effect(self, widget): - if self.connected: + try: 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) @@ -420,20 +411,20 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.angle_120.set_sensitive(sound_effect) self.angle_150.set_sensitive(sound_effect) self.angle_180.set_sensitive(sound_effect) - else: + except resource_manager.DeviceDisconnected: self.deactivate() def toggle_angle(self, angle, widget): - if self.connected: + try: if not self.angle_dirty: self.parrot.angle = angle self.angle_dirty = True - self.read_sound_effect_angle() + self._read_sound_effect_angle() self.angle_dirty = False - else: + except resource_manager.DeviceDisconnected: self.deactivate() - def read_sound_effect_angle(self): + def _read_sound_effect_angle(self): active_angle = self.parrot.angle angle_to_menuitem_map = ( (30, self.angle_30), @@ -447,16 +438,16 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): menu_item.set_active(angle == active_angle) def toggle_noise_cancelation(self, noise_calcelation, widget): - if self.connected: + try: if not self.noise_cancelation_dirty: self.parrot.noise_control = noise_calcelation self.noise_cancelation_dirty = True - self.read_noise_cancelation() + self._read_noise_cancelation() self.noise_cancelation_dirty = False - else: + except resource_manager.DeviceDisconnected: self.deactivate() - def read_noise_cancelation(self): + def _read_noise_cancelation(self): active_noise_control = self.parrot.noise_control noise_control_to_menuitem_map = ( (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), diff --git a/resource_manager.py b/resource_manager.py index ddd39fb..6bb8eb7 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -1,3 +1,4 @@ +import bluetooth from operator import itemgetter import sys @@ -45,11 +46,9 @@ class ResourceManagerBase(object): def send_message(self, message): try: self.sock.send(str(message)) - except Exception: - self.sock = "" - return - else: return self.get_answer(message) + except bluetooth.btcommon.BluetoothError: + raise DeviceDisconnected def get_answer(self, message): data = self.receive_message() @@ -139,3 +138,6 @@ class Version2ResourceManager(ResourceManagerBase): '/api/audio/noise_control/enabled': ['get', 'set'], '/api/audio/track/metadata': ['get'], } + +class DeviceDisconnected(Exception): + pass -- cgit v1.2.1 From 3c471f39667477fcdd83efb44dad4fc3968ca535 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 03:06:49 +0200 Subject: Deactivation of interface starts reconnection. --- ParrotZikTray | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ParrotZikTray b/ParrotZikTray index 4c86adf..d5b113c 100755 --- a/ParrotZikTray +++ b/ParrotZikTray @@ -1,5 +1,6 @@ #!/usr/bin/env python import functools +from threading import Lock import gtk @@ -23,22 +24,27 @@ class repeat(object): def __init__(self, f): self.f = f self.id = None + self.lock = Lock() def __call__(self, cls): self.f(cls) def start(self, cls, frequency): + self.lock.acquire() if not self.id: def run(): self.f(cls) return True self.id = gtk.timeout_add(frequency, run) + self.lock.release() def stop(self): + self.lock.acquire() if self.id: gtk.timeout_remove(self.id) self.id = None + self.lock.release() class ParrotZikIndicator(SysIndicator): @@ -148,6 +154,7 @@ class ParrotZikBaseInterface(object): self.indicator.active_interface = None self.indicator.setIcon("zik-audio-headset") self.indicator.info('Lost Connection') + self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) def toggle_auto_connection(self, widget): try: -- cgit v1.2.1 From ac531e0ca0b17902821966530629e434d0cdf9f7 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 03:09:17 +0200 Subject: Make names more pythonic --- ParrotZik.py | 222 ------------------------- ParrotZikTray | 475 ------------------------------------------------------ StatusAppMac.py | 25 --- SysIndicator.py | 254 ----------------------------- indicator.py | 254 +++++++++++++++++++++++++++++ parrot_zik.py | 222 +++++++++++++++++++++++++ parrot_zik_tray | 475 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 6 +- status_app_mac.py | 25 +++ 9 files changed, 979 insertions(+), 979 deletions(-) delete mode 100644 ParrotZik.py delete mode 100755 ParrotZikTray delete mode 100644 StatusAppMac.py delete mode 100644 SysIndicator.py create mode 100644 indicator.py create mode 100644 parrot_zik.py create mode 100755 parrot_zik_tray create mode 100644 status_app_mac.py diff --git a/ParrotZik.py b/ParrotZik.py deleted file mode 100644 index 52414b5..0000000 --- a/ParrotZik.py +++ /dev/null @@ -1,222 +0,0 @@ -from resource_manager import Version1ResourceManager -from resource_manager import Version2ResourceManager - - -class BatteryStates: - CHARGED = 'charged' - IN_USE = 'in_use' - CHARGING = 'charging' - representation = { - CHARGED: 'Charged', - IN_USE: 'In Use', - CHARGING: 'Charging', - } - -class Rooms: - CONCERT_HALL = 'concert' - JAZZ_CLUB = 'jazz' - LIVING_ROOM = 'living' - SILENT_ROOM = 'silent' - representation = { - CONCERT_HALL: 'Concert Hall', - JAZZ_CLUB: 'Jazz Club', - LIVING_ROOM: 'Living Room', - SILENT_ROOM: 'Silent Room', - } - -class NoiseControl(object): - def __init__(self, type, value): - self.type = type - self.value = value - - @classmethod - def from_noise_control(cls, noise_control): - return cls(noise_control['type'], int(noise_control['value'])) - - def __eq__(self, other): - return self.type == other.type and self.value == other.value - - def __str__(self): - return '{}++{}'.format(self.type, self.value) - -class NoiseControlTypes: - NOISE_CONTROL_MAX = NoiseControl('anc', 2) - NOISE_CONTROL_ON = NoiseControl('anc', 1) - NOISE_CONTROL_OFF = NoiseControl('off', 1) - STREET_MODE = NoiseControl('aoc', 1) - STREET_MODE_MAX = NoiseControl('aoc', 2) - - -class ParrotZikBase(object): - def __init__(self, resource_manager): - self.resource_manager = resource_manager - - @property - def version(self): - return self.resource_manager.api_version - - def refresh_battery(self): - self.resource_manager.fetch('/api/system/battery') - - @property - def battery_state(self): - answer = self.resource_manager.get("/api/system/battery") - return answer.system.battery["state"] - - def get_battery_level(self, field_name): - answer = self.resource_manager.get("/api/system/battery") - return int(answer.system.battery[field_name]) - - @property - def friendly_name(self): - answer = self.resource_manager.get("/api/bluetooth/friendlyname") - return answer.bluetooth["friendlyname"] - - @property - def auto_connect(self): - answer = self.resource_manager.get("/api/system/auto_connection/enabled") - return self._result_to_bool( - answer.system.auto_connection["enabled"]) - - @auto_connect.setter - def auto_connect(self, arg): - self.resource_manager.set("/api/system/auto_connection/enabled", arg) - - @property - def anc_phone_mode(self): - answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") - return self._result_to_bool( - answer.system.anc_phone_mode["enabled"]) - - def _result_to_bool(self, result): - if result == "true": - return True - elif result == "false": - return False - else: - raise AssertionError(result) - - -class ParrotZikVersion1(ParrotZikBase): - def __init__(self, resource_manager): - super(ParrotZikVersion1, self).__init__( - resource_manager.get_resource_manager( - Version1ResourceManager)) - - @property - def version(self): - answer = self.resource_manager.get('/api/software/version') - return answer.software['version'] - - @property - def battery_level(self): - return int(self.get_battery_level('level')) - - @property - def lou_reed_mode(self): - answer = self.resource_manager.get("/api/audio/specific_mode/enabled") - return self._result_to_bool( - answer.audio.specific_mode["enabled"]) - - @lou_reed_mode.setter - def lou_reed_mode(self, arg): - self.resource_manager.get("/api/audio/specific_mode/enabled", arg) - - @property - def concert_hall(self): - answer = self.resource_manager.get("/api/audio/sound_effect/enabled") - return self._result_to_bool( - answer.audio.sound_effect["enabled"]) - - @concert_hall.setter - def concert_hall(self, arg): - self.resource_manager.get("/api/audio/sound_effect/enabled", arg) - - @property - def cancel_noise(self): - answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") - return self._result_to_bool( - answer.audio.noise_cancellation["enabled"]) - - @cancel_noise.setter - def cancel_noise(self, arg): - self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) - - -class ParrotZikVersion2(ParrotZikBase): - def __init__(self, resource_manager): - super(ParrotZikVersion2, self).__init__( - resource_manager.get_resource_manager( - Version2ResourceManager)) - - @property - def version(self): - answer = self.resource_manager.get('/api/software/version') - return answer.software['sip6'] - - @property - def battery_level(self): - return self.get_battery_level('percent') - - @property - def flight_mode(self): - answer = self.resource_manager.get('/api/flight_mode') - return self._result_to_bool(answer.flight_mode['enabled']) - - @flight_mode.setter - def flight_mode(self, arg): - if arg: - self.resource_manager.toggle_on('/api/flight_mode') - else: - self.resource_manager.toggle_off('/api/flight_mode') - - @property - def sound_effect(self): - answer = self.resource_manager.get('/api/audio/sound_effect/enabled') - return self._result_to_bool(answer.audio.sound_effect['enabled']) - - @sound_effect.setter - def sound_effect(self, arg): - self.resource_manager.set('/api/audio/sound_effect/enabled', arg) - - @property - def room(self): - answer = self.resource_manager.get('/api/audio/sound_effect/room_size') - return answer.audio.sound_effect['room_size'] - - @room.setter - def room(self, arg): - self.resource_manager.set('/api/audio/sound_effect/room_size', arg) - - @property - def external_noise(self): - answer = self.resource_manager.get('/api/audio/noise') - return int(answer.audio.noise['external']) - - @property - def internal_noise(self): - answer = self.resource_manager.get('/api/audio/noise') - return int(answer.audio.noise['internal']) - - @property - def angle(self): - answer = self.resource_manager.get('/api/audio/sound_effect/angle') - return int(answer.audio.sound_effect['angle']) - - @angle.setter - def angle(self, arg): - self.resource_manager.set('/api/audio/sound_effect/angle', arg) - - @property - def noise_control(self): - answer = self.resource_manager.get('/api/audio/noise_control') - return NoiseControl.from_noise_control(answer.audio.noise_control) - - @noise_control.setter - def noise_control(self, arg): - pass - - @property - def noise_control_enabled(self): - answer = self.resource_manager.get('/api/audio/noise_control/enabled') - return self._result_to_bool(answer.audio.noise_control['enabled']) diff --git a/ParrotZikTray b/ParrotZikTray deleted file mode 100755 index d5b113c..0000000 --- a/ParrotZikTray +++ /dev/null @@ -1,475 +0,0 @@ -#!/usr/bin/env python -import functools -from threading import Lock - -import gtk - -import bluetooth_paired_devices -from ParrotZik import BatteryStates -from ParrotZik import ParrotZikVersion1 -from ParrotZik import ParrotZikVersion2 -from ParrotZik import NoiseControlTypes -from bluetooth_paired_devices import connect -from ParrotZik import Rooms -from SysIndicator import MenuItem -from SysIndicator import Menu -from SysIndicator import SysIndicator -import resource_manager - -REFRESH_FREQUENCY = 30000 -RECONNECT_FREQUENCY = 5000 - - -class repeat(object): - def __init__(self, f): - self.f = f - self.id = None - self.lock = Lock() - - def __call__(self, cls): - self.f(cls) - - def start(self, cls, frequency): - self.lock.acquire() - if not self.id: - def run(): - self.f(cls) - return True - - self.id = gtk.timeout_add(frequency, run) - self.lock.release() - - def stop(self): - self.lock.acquire() - if self.id: - gtk.timeout_remove(self.id) - self.id = None - self.lock.release() - - -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: - self.reconnect.stop() - else: - self.info("Trying to connect") - try: - manager = connect() - except bluetooth_paired_devices.BluetoothIsNotOn: - self.info("Bluetooth is turned off") - except bluetooth_paired_devices.DeviceNotConnected: - self.info("Parrot Zik Not connected") - except bluetooth_paired_devices.ConnectionFailure: - self.info("Failed to connect") - else: - if manager.api_version.startswith('1'): - interface = self.version_1_interface - else: - interface = self.version_2_interface - try: - interface.activate(manager) - except resource_manager.DeviceDisconnected: - interface.deactivate() - else: - self.autorefresh(self) - self.autorefresh.start(self, REFRESH_FREQUENCY) - self.reconnect.stop() - - def info(self, message): - self.info_item.set_label(message) - print(message) - - @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.toggle_auto_connection, - 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) - - def activate(self, manager): - self.parrot = self.parrot_class(manager) - self.read_battery() - self.indicator.info("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.battery_level.show() - self.battery_state.show() - self.firmware_version.show() - self.auto_connection.show() - self.indicator.active_interface = self - self.indicator.menu.reposition() - - @property - def parrot_class(self): - raise NotImplementedError - - def deactivate(self): - self.parrot = None - self.battery_level.hide() - self.battery_state.hide() - self.firmware_version.hide() - self.auto_connection.hide() - self.indicator.menu.reposition() - self.indicator.active_interface = None - self.indicator.setIcon("zik-audio-headset") - self.indicator.info('Lost Connection') - self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) - - def toggle_auto_connection(self, widget): - try: - self.parrot.auto_connect = self.auto_connection.get_active() - self.auto_connection.set_active(self.parrot.auto_connect) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def refresh(self): - self.read_battery() - - def read_battery(self): - try: - self.parrot.refresh_battery() - battery_level = self.parrot.battery_level - battery_state = self.parrot.battery_state - except resource_manager.DeviceDisconnected: - self.deactivate() - else: - 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)) - - -class ParrotZikVersion1Interface(ParrotZikBaseInterface): - parrot_class = ParrotZikVersion1 - - def __init__(self, indicator): - super(ParrotZikVersion1Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem( - "Noise Cancellation", self.toggle_noise_cancelation, - checkitem=True, visible=False) - self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, - checkitem=True, visible=False) - self.concert_hall_mode = MenuItem( - "Concert Hall Mode", self.toggle_parrot_concert_hall, - 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, manager): - self.noise_cancelation.show() - self.lou_reed_mode.show() - self.concert_hall_mode.show() - super(ParrotZikVersion1Interface, self).activate(manager) - self.noise_cancelation.set_active(self.parrot.cancel_noise) - 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 toggle_noise_cancelation(self, widget): - try: - self.parrot.cancel_noise = self.noise_cancelation.get_active() - self.noise_cancelation.set_active(self.parrot.cancel_noise) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_lou_reed_mode(self, widget): - try: - 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()) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_parrot_concert_hall(self, widget): - try: - self.parrot.concert_hall = self.concert_hall_mode.get_active() - self.concert_hall_mode.set_active(self.parrot.concert_hall) - except resource_manager.DeviceDisconnected: - self.deactivate() - - -class ParrotZikVersion2Interface(ParrotZikBaseInterface): - parrot_class = ParrotZikVersion2 - - def __init__(self, indicator): - self.room_dirty = False - self.angle_dirty = False - self.noise_cancelation_dirty = False - super(ParrotZikVersion2Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem("Noise Control", None, visible=False) - self.noise_cancelation_submenu = Menu() - self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) - - self.noise_control_cancelation_max = MenuItem( - "Max Calcelation", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True) - self.noise_control_cancelation_on = MenuItem( - "Normal Cancelation", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True) - self.noise_control_off = MenuItem( - "Off", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True) - self.noise_control_street_mode = MenuItem( - "Street Mode", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE), checkitem=True) - self.noise_control_street_mode_max = MenuItem( - "Street Mode Max", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE_MAX), checkitem=True) - self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) - self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) - self.noise_cancelation_submenu.append(self.noise_control_off) - self.noise_cancelation_submenu.append(self.noise_control_street_mode) - self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) - - self.room_sound_effect = MenuItem( - "Room Sound Effect", None, 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, checkitem=True) - self.rooms = MenuItem("Rooms", None, checkitem=False) - self.angle = MenuItem("Angle", None, 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", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) - self.jazz_mode = MenuItem( - "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) - self.living_mode = MenuItem( - "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) - self.silent_mode = MenuItem( - "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), 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.angle_submenu = Menu() - self.angle.set_submenu(self.angle_submenu) - self.angle_30 = MenuItem( - "30", functools.partial(self.toggle_angle, 30), checkitem=True) - self.angle_60 = MenuItem( - "60", functools.partial(self.toggle_angle, 60), checkitem=True) - self.angle_90 = MenuItem( - "90", functools.partial(self.toggle_angle, 90), checkitem=True) - self.angle_120 = MenuItem( - "120", functools.partial(self.toggle_angle, 120), checkitem=True) - self.angle_150 = MenuItem( - "150", functools.partial(self.toggle_angle, 150), checkitem=True) - self.angle_180 = MenuItem( - "180", functools.partial(self.toggle_angle, 180), 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, - checkitem=True, visible=False) - self.indicator.menu.append(self.room_sound_effect) - self.indicator.menu.append(self.noise_cancelation) - self.indicator.menu.append(self.flight_mode) - - def activate(self, manager): - self.noise_cancelation.show() - self.flight_mode.show() - self.room_sound_effect.show() - super(ParrotZikVersion2Interface, self).activate(manager) - self._read_noise_cancelation() - 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 toggle_flight_mode(self, widget): - try: - self.parrot.flight_mode = self.flight_mode.get_active() - self.flight_mode.set_active(self.parrot.flight_mode) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_room(self, room, widget): - try: - if not self.room_dirty: - self.parrot.room = room - self.room_dirty = True - self._read_sound_effect_room() - self.room_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - 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): - try: - 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) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_angle(self, angle, widget): - try: - if not self.angle_dirty: - self.parrot.angle = angle - self.angle_dirty = True - self._read_sound_effect_angle() - self.angle_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - 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) - - def toggle_noise_cancelation(self, noise_calcelation, widget): - try: - if not self.noise_cancelation_dirty: - self.parrot.noise_control = noise_calcelation - self.noise_cancelation_dirty = True - self._read_noise_cancelation() - self.noise_cancelation_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - def _read_noise_cancelation(self): - active_noise_control = self.parrot.noise_control - noise_control_to_menuitem_map = ( - (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), - (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), - (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), - (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), - (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), - ) - for noise_control, menu_item in noise_control_to_menuitem_map: - menu_item.set_active(active_noise_control == noise_control) - - -if __name__ == "__main__": - try: - indicator = ParrotZikIndicator() - indicator.main() - except KeyboardInterrupt: - pass diff --git a/StatusAppMac.py b/StatusAppMac.py deleted file mode 100644 index dccffe4..0000000 --- a/StatusAppMac.py +++ /dev/null @@ -1,25 +0,0 @@ -from Foundation import * -from AppKit import * - -class StatusApp(NSApplication): - - def initMenu(self, menu): - statusbar = NSStatusBar.systemStatusBar() - self.statusitem = statusbar.statusItemWithLength_( - NSVariableStatusItemLength) - - self.mymenu = menu - #add menu to statusitem - self.statusitem.setMenu_(menu.menubarMenu) - self.statusitem.setToolTip_('Parrot Zik Indicator') - - def setIcon(self,icon,icon_directory): - self.icon = NSImage.alloc().initByReferencingFile_( - icon_directory + icon + '.png') - self.icon.setScalesWhenResized_(True) - self.icon.setSize_((20, 20)) - self.statusitem.setImage_(self.icon) - - def clicked_(self, notification): - self.mymenu.actions[notification._.title]() - NSLog('clicked!') diff --git a/SysIndicator.py b/SysIndicator.py deleted file mode 100644 index 6aa4686..0000000 --- a/SysIndicator.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env python - -import sys -import os -import tempfile - -if sys.platform == "linux2" or sys.platform == "win32": - import gtk -elif sys.platform == "darwin": - from Foundation import * - from AppKit import * - from PyObjCTools import AppHelper - from StatusAppMac import StatusApp - - -class BaseIndicator(object): - def __init__(self, icon, menu, statusicon): - self.menu = menu - self.statusicon = statusicon - self.setIcon(icon) - - def gtk_right_click_event(self, icon, button, time): - if not self.menu_shown: - self.menu_shown = True - self.menu.popup(None, None, gtk.status_icon_position_menu, - button, time, self.statusicon) - else: - self.menu_shown = False - self.menu.popdown() - - def setIcon(self, name): - raise NotImplementedError - - def main(self): - raise NotImplementedError - - def show_about_dialog(self, widget): - raise NotImplementedError - - -class WindowsIndicator(BaseIndicator): - def __init__(self, icon, menu): - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) - + os.path.sep + 'share' + os.path.sep + 'icons' - + os.path.sep +'zik' + os.path.sep) - self.menu_shown = False - sys.stdout = open(tempfile.gettempdir() - + os.path.sep + "zik_tray_stdout.log", "w") - sys.stderr = open(tempfile.gettempdir() - + os.path.sep + "zik_tray_stderr.log", "w") - statusicon = gtk.StatusIcon() - statusicon.connect("popup-menu", self.gtk_right_click_event) - statusicon.set_tooltip("Parrot Zik") - super(WindowsIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.set_from_file(self.icon_directory + name + '.png') - - def main(self): - gtk.main() - - def show_about_dialog(self, widget): - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class LinuxIndicator(BaseIndicator): - def __init__(self, icon, menu): - import appindicator - self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' - + os.path.sep + 'icons' + os.path.sep+'zik' - + os.path.sep) - if not os.path.isdir(self.icon_directory): - self.icon_directory = (os.path.dirname(sys.argv[0]) - + os.path.sep + 'share' + os.path.sep - + 'icons' + os.path.sep+'zik' - + os.path.sep) - statusicon = appindicator.Indicator( - "new-parrotzik-indicator", "indicator-messages", - appindicator.CATEGORY_APPLICATION_STATUS) - statusicon.set_status(appindicator.STATUS_ACTIVE) - statusicon.set_icon_theme_path(self.icon_directory) - statusicon.set_menu(menu.gtk_menu) - super(LinuxIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.set_icon(name) - - def main(self): - gtk.main() - - def show_about_dialog(self, widget): - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class DarwinIndicator(BaseIndicator): - def __init__(self, icon, menu): - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep - + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' - + os.path.sep) - statusicon = StatusApp.sharedApplication() - statusicon.initMenu(menu) - super(DarwinIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.setIcon(name, self.icon_directory) - - def main(self): - AppHelper.runEventLoop() - - def show_about_dialog(self, widget): - pass - - -class NSMenu(object): - def __init__(self): - self.actions = {} - self.menubarMenu = NSMenu.alloc().init() - self.menubarMenu.setAutoenablesItems_(False) - - def append(self, menu_item): - self.actions[menu_item.title] = menu_item.action - self.menubarMenu.addItem_(menu_item.nsmenu_item) - - def reposition(self): - # TODO - pass - -class GTKMenu(object): - def __init__(self): - self.gtk_menu = gtk.Menu() - - def append(self, menu_item): - self.gtk_menu.append(menu_item.base_item) - - def reposition(self): - self.gtk_menu.reposition() - - -class MenuItemBase(object): - def __init__(self, base_item, sensitive, visible): - self.base_item = base_item - self.set_sensitive(sensitive) - if visible: - self.show() - else: - self.hide() - - def set_sensitive(self, option): - raise NotImplementedError - - def set_active(self, option): - raise NotImplementedError - - def get_active(self): - raise NotImplementedError - - def set_label(self, option): - raise NotImplementedError - - def show(self): - self.base_item.show() - - 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: - gtk_item = gtk.CheckMenuItem(name) - else: - gtk_item = gtk.MenuItem(name) - if action: - gtk_item.connect("activate", action) - super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) - - def set_sensitive(self, option): - return self.base_item.set_sensitive(option) - - def set_active(self, option): - return self.base_item.set_active(option) - - def get_active(self): - return self.base_item.get_active() - - 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): - self.title = name - self.action = action - nsmenu_item = ( - NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( - name, 'clicked:', '')) - super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) - - def set_sensitive(self, option): - self.base_item.setEnabled_(option) - - def set_active(self, option): - self.base_item.setState_(option) - - def get_active(self): - return self.base_item.state - - def set_label(self, option): - self.title = option - self.base_item.setTitle_(option) - -if sys.platform == 'linux2': - SysIndicator = LinuxIndicator - Menu = GTKMenu - MenuItem = GTKMenuItem -elif sys.platform == 'win32': - SysIndicator = WindowsIndicator - Menu = GTKMenu - MenuItem = GTKMenuItem -elif sys.platform == 'darwin': - SysIndicator = DarwinIndicator - Menu = NSMenu - MenuItem = NSMenuItem -else: - raise Exception('Platform not supported') - -if __name__ == "__main__": - - quit_item = MenuItem("Quit", sys.exit, True) - - menu = Menu() - menu.append(quit_item) - - indicator = SysIndicator(icon="zik-audio-headset", menu=menu) - indicator.main() diff --git a/indicator.py b/indicator.py new file mode 100644 index 0000000..05ffec7 --- /dev/null +++ b/indicator.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python + +import sys +import os +import tempfile + +if sys.platform == "linux2" or sys.platform == "win32": + import gtk +elif sys.platform == "darwin": + from Foundation import * + from AppKit import * + from PyObjCTools import AppHelper + from status_app_mac import StatusApp + + +class BaseIndicator(object): + def __init__(self, icon, menu, statusicon): + self.menu = menu + self.statusicon = statusicon + self.setIcon(icon) + + def gtk_right_click_event(self, icon, button, time): + if not self.menu_shown: + self.menu_shown = True + self.menu.popup(None, None, gtk.status_icon_position_menu, + button, time, self.statusicon) + else: + self.menu_shown = False + self.menu.popdown() + + def setIcon(self, name): + raise NotImplementedError + + def main(self): + raise NotImplementedError + + def show_about_dialog(self, widget): + raise NotImplementedError + + +class WindowsIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + + os.path.sep + 'share' + os.path.sep + 'icons' + + os.path.sep +'zik' + os.path.sep) + self.menu_shown = False + sys.stdout = open(tempfile.gettempdir() + + os.path.sep + "zik_tray_stdout.log", "w") + sys.stderr = open(tempfile.gettempdir() + + os.path.sep + "zik_tray_stderr.log", "w") + statusicon = gtk.StatusIcon() + statusicon.connect("popup-menu", self.gtk_right_click_event) + statusicon.set_tooltip("Parrot Zik") + super(WindowsIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_from_file(self.icon_directory + name + '.png') + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() + + +class LinuxIndicator(BaseIndicator): + def __init__(self, icon, menu): + import appindicator + self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' + + os.path.sep + 'icons' + os.path.sep+'zik' + + os.path.sep) + if not os.path.isdir(self.icon_directory): + self.icon_directory = (os.path.dirname(sys.argv[0]) + + os.path.sep + 'share' + os.path.sep + + 'icons' + os.path.sep+'zik' + + os.path.sep) + statusicon = appindicator.Indicator( + "new-parrotzik-indicator", "indicator-messages", + appindicator.CATEGORY_APPLICATION_STATUS) + statusicon.set_status(appindicator.STATUS_ACTIVE) + statusicon.set_icon_theme_path(self.icon_directory) + statusicon.set_menu(menu.gtk_menu) + super(LinuxIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_icon(name) + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() + + +class DarwinIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' + + os.path.sep) + statusicon = StatusApp.sharedApplication() + statusicon.initMenu(menu) + super(DarwinIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.setIcon(name, self.icon_directory) + + def main(self): + AppHelper.runEventLoop() + + def show_about_dialog(self, widget): + pass + + +class NSMenu(object): + def __init__(self): + self.actions = {} + self.menubarMenu = NSMenu.alloc().init() + self.menubarMenu.setAutoenablesItems_(False) + + def append(self, menu_item): + self.actions[menu_item.title] = menu_item.action + self.menubarMenu.addItem_(menu_item.nsmenu_item) + + def reposition(self): + # TODO + pass + +class GTKMenu(object): + def __init__(self): + self.gtk_menu = gtk.Menu() + + def append(self, menu_item): + self.gtk_menu.append(menu_item.base_item) + + def reposition(self): + self.gtk_menu.reposition() + + +class MenuItemBase(object): + def __init__(self, base_item, sensitive, visible): + self.base_item = base_item + self.set_sensitive(sensitive) + if visible: + self.show() + else: + self.hide() + + def set_sensitive(self, option): + raise NotImplementedError + + def set_active(self, option): + raise NotImplementedError + + def get_active(self): + raise NotImplementedError + + def set_label(self, option): + raise NotImplementedError + + def show(self): + self.base_item.show() + + 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: + gtk_item = gtk.CheckMenuItem(name) + else: + gtk_item = gtk.MenuItem(name) + if action: + gtk_item.connect("activate", action) + super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) + + def set_sensitive(self, option): + return self.base_item.set_sensitive(option) + + def set_active(self, option): + return self.base_item.set_active(option) + + def get_active(self): + return self.base_item.get_active() + + 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): + self.title = name + self.action = action + nsmenu_item = ( + NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + name, 'clicked:', '')) + super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) + + def set_sensitive(self, option): + self.base_item.setEnabled_(option) + + def set_active(self, option): + self.base_item.setState_(option) + + def get_active(self): + return self.base_item.state + + def set_label(self, option): + self.title = option + self.base_item.setTitle_(option) + +if sys.platform == 'linux2': + SysIndicator = LinuxIndicator + Menu = GTKMenu + MenuItem = GTKMenuItem +elif sys.platform == 'win32': + SysIndicator = WindowsIndicator + Menu = GTKMenu + MenuItem = GTKMenuItem +elif sys.platform == 'darwin': + SysIndicator = DarwinIndicator + Menu = NSMenu + MenuItem = NSMenuItem +else: + raise Exception('Platform not supported') + +if __name__ == "__main__": + + quit_item = MenuItem("Quit", sys.exit, True) + + menu = Menu() + menu.append(quit_item) + + indicator = SysIndicator(icon="zik-audio-headset", menu=menu) + indicator.main() diff --git a/parrot_zik.py b/parrot_zik.py new file mode 100644 index 0000000..52414b5 --- /dev/null +++ b/parrot_zik.py @@ -0,0 +1,222 @@ +from resource_manager import Version1ResourceManager +from resource_manager import Version2ResourceManager + + +class BatteryStates: + CHARGED = 'charged' + IN_USE = 'in_use' + CHARGING = 'charging' + representation = { + CHARGED: 'Charged', + IN_USE: 'In Use', + CHARGING: 'Charging', + } + +class Rooms: + CONCERT_HALL = 'concert' + JAZZ_CLUB = 'jazz' + LIVING_ROOM = 'living' + SILENT_ROOM = 'silent' + representation = { + CONCERT_HALL: 'Concert Hall', + JAZZ_CLUB: 'Jazz Club', + LIVING_ROOM: 'Living Room', + SILENT_ROOM: 'Silent Room', + } + +class NoiseControl(object): + def __init__(self, type, value): + self.type = type + self.value = value + + @classmethod + def from_noise_control(cls, noise_control): + return cls(noise_control['type'], int(noise_control['value'])) + + def __eq__(self, other): + return self.type == other.type and self.value == other.value + + def __str__(self): + return '{}++{}'.format(self.type, self.value) + +class NoiseControlTypes: + NOISE_CONTROL_MAX = NoiseControl('anc', 2) + NOISE_CONTROL_ON = NoiseControl('anc', 1) + NOISE_CONTROL_OFF = NoiseControl('off', 1) + STREET_MODE = NoiseControl('aoc', 1) + STREET_MODE_MAX = NoiseControl('aoc', 2) + + +class ParrotZikBase(object): + def __init__(self, resource_manager): + self.resource_manager = resource_manager + + @property + def version(self): + return self.resource_manager.api_version + + def refresh_battery(self): + self.resource_manager.fetch('/api/system/battery') + + @property + def battery_state(self): + answer = self.resource_manager.get("/api/system/battery") + return answer.system.battery["state"] + + def get_battery_level(self, field_name): + answer = self.resource_manager.get("/api/system/battery") + return int(answer.system.battery[field_name]) + + @property + def friendly_name(self): + answer = self.resource_manager.get("/api/bluetooth/friendlyname") + return answer.bluetooth["friendlyname"] + + @property + def auto_connect(self): + answer = self.resource_manager.get("/api/system/auto_connection/enabled") + return self._result_to_bool( + answer.system.auto_connection["enabled"]) + + @auto_connect.setter + def auto_connect(self, arg): + self.resource_manager.set("/api/system/auto_connection/enabled", arg) + + @property + def anc_phone_mode(self): + answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") + return self._result_to_bool( + answer.system.anc_phone_mode["enabled"]) + + def _result_to_bool(self, result): + if result == "true": + return True + elif result == "false": + return False + else: + raise AssertionError(result) + + +class ParrotZikVersion1(ParrotZikBase): + def __init__(self, resource_manager): + super(ParrotZikVersion1, self).__init__( + resource_manager.get_resource_manager( + Version1ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['version'] + + @property + def battery_level(self): + return int(self.get_battery_level('level')) + + @property + def lou_reed_mode(self): + answer = self.resource_manager.get("/api/audio/specific_mode/enabled") + return self._result_to_bool( + answer.audio.specific_mode["enabled"]) + + @lou_reed_mode.setter + def lou_reed_mode(self, arg): + self.resource_manager.get("/api/audio/specific_mode/enabled", arg) + + @property + def concert_hall(self): + answer = self.resource_manager.get("/api/audio/sound_effect/enabled") + return self._result_to_bool( + answer.audio.sound_effect["enabled"]) + + @concert_hall.setter + def concert_hall(self, arg): + self.resource_manager.get("/api/audio/sound_effect/enabled", arg) + + @property + def cancel_noise(self): + answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") + return self._result_to_bool( + answer.audio.noise_cancellation["enabled"]) + + @cancel_noise.setter + def cancel_noise(self, arg): + self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) + + +class ParrotZikVersion2(ParrotZikBase): + def __init__(self, resource_manager): + super(ParrotZikVersion2, self).__init__( + resource_manager.get_resource_manager( + Version2ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['sip6'] + + @property + def battery_level(self): + return self.get_battery_level('percent') + + @property + def flight_mode(self): + answer = self.resource_manager.get('/api/flight_mode') + return self._result_to_bool(answer.flight_mode['enabled']) + + @flight_mode.setter + def flight_mode(self, arg): + if arg: + self.resource_manager.toggle_on('/api/flight_mode') + else: + self.resource_manager.toggle_off('/api/flight_mode') + + @property + def sound_effect(self): + answer = self.resource_manager.get('/api/audio/sound_effect/enabled') + return self._result_to_bool(answer.audio.sound_effect['enabled']) + + @sound_effect.setter + def sound_effect(self, arg): + self.resource_manager.set('/api/audio/sound_effect/enabled', arg) + + @property + def room(self): + answer = self.resource_manager.get('/api/audio/sound_effect/room_size') + return answer.audio.sound_effect['room_size'] + + @room.setter + def room(self, arg): + self.resource_manager.set('/api/audio/sound_effect/room_size', arg) + + @property + def external_noise(self): + answer = self.resource_manager.get('/api/audio/noise') + return int(answer.audio.noise['external']) + + @property + def internal_noise(self): + answer = self.resource_manager.get('/api/audio/noise') + return int(answer.audio.noise['internal']) + + @property + def angle(self): + answer = self.resource_manager.get('/api/audio/sound_effect/angle') + return int(answer.audio.sound_effect['angle']) + + @angle.setter + def angle(self, arg): + self.resource_manager.set('/api/audio/sound_effect/angle', arg) + + @property + def noise_control(self): + answer = self.resource_manager.get('/api/audio/noise_control') + return NoiseControl.from_noise_control(answer.audio.noise_control) + + @noise_control.setter + def noise_control(self, arg): + pass + + @property + def noise_control_enabled(self): + answer = self.resource_manager.get('/api/audio/noise_control/enabled') + return self._result_to_bool(answer.audio.noise_control['enabled']) diff --git a/parrot_zik_tray b/parrot_zik_tray new file mode 100755 index 0000000..f6cc4a0 --- /dev/null +++ b/parrot_zik_tray @@ -0,0 +1,475 @@ +#!/usr/bin/env python +import functools +from threading import Lock + +import gtk + +import bluetooth_paired_devices +from parrot_zik import BatteryStates +from parrot_zik import ParrotZikVersion1 +from parrot_zik import ParrotZikVersion2 +from parrot_zik import NoiseControlTypes +from bluetooth_paired_devices import connect +from parrot_zik import Rooms +from indicator import MenuItem +from indicator import Menu +from indicator import SysIndicator +import resource_manager + +REFRESH_FREQUENCY = 30000 +RECONNECT_FREQUENCY = 5000 + + +class repeat(object): + def __init__(self, f): + self.f = f + self.id = None + self.lock = Lock() + + def __call__(self, cls): + self.f(cls) + + def start(self, cls, frequency): + self.lock.acquire() + if not self.id: + def run(): + self.f(cls) + return True + + self.id = gtk.timeout_add(frequency, run) + self.lock.release() + + def stop(self): + self.lock.acquire() + if self.id: + gtk.timeout_remove(self.id) + self.id = None + self.lock.release() + + +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: + self.reconnect.stop() + else: + self.info("Trying to connect") + try: + manager = connect() + except bluetooth_paired_devices.BluetoothIsNotOn: + self.info("Bluetooth is turned off") + except bluetooth_paired_devices.DeviceNotConnected: + self.info("Parrot Zik Not connected") + except bluetooth_paired_devices.ConnectionFailure: + self.info("Failed to connect") + else: + if manager.api_version.startswith('1'): + interface = self.version_1_interface + else: + interface = self.version_2_interface + try: + interface.activate(manager) + except resource_manager.DeviceDisconnected: + interface.deactivate() + else: + self.autorefresh(self) + self.autorefresh.start(self, REFRESH_FREQUENCY) + self.reconnect.stop() + + def info(self, message): + self.info_item.set_label(message) + print(message) + + @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.toggle_auto_connection, + 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) + + def activate(self, manager): + self.parrot = self.parrot_class(manager) + self.read_battery() + self.indicator.info("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.battery_level.show() + self.battery_state.show() + self.firmware_version.show() + self.auto_connection.show() + self.indicator.active_interface = self + self.indicator.menu.reposition() + + @property + def parrot_class(self): + raise NotImplementedError + + def deactivate(self): + self.parrot = None + self.battery_level.hide() + self.battery_state.hide() + self.firmware_version.hide() + self.auto_connection.hide() + self.indicator.menu.reposition() + self.indicator.active_interface = None + self.indicator.setIcon("zik-audio-headset") + self.indicator.info('Lost Connection') + self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) + + def toggle_auto_connection(self, widget): + try: + self.parrot.auto_connect = self.auto_connection.get_active() + self.auto_connection.set_active(self.parrot.auto_connect) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def refresh(self): + self.read_battery() + + def read_battery(self): + try: + self.parrot.refresh_battery() + battery_level = self.parrot.battery_level + battery_state = self.parrot.battery_state + except resource_manager.DeviceDisconnected: + self.deactivate() + else: + 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)) + + +class ParrotZikVersion1Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion1 + + def __init__(self, indicator): + super(ParrotZikVersion1Interface, self).__init__(indicator) + self.noise_cancelation = MenuItem( + "Noise Cancellation", self.toggle_noise_cancelation, + checkitem=True, visible=False) + self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, + checkitem=True, visible=False) + self.concert_hall_mode = MenuItem( + "Concert Hall Mode", self.toggle_parrot_concert_hall, + 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, manager): + self.noise_cancelation.show() + self.lou_reed_mode.show() + self.concert_hall_mode.show() + super(ParrotZikVersion1Interface, self).activate(manager) + self.noise_cancelation.set_active(self.parrot.cancel_noise) + 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 toggle_noise_cancelation(self, widget): + try: + self.parrot.cancel_noise = self.noise_cancelation.get_active() + self.noise_cancelation.set_active(self.parrot.cancel_noise) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_lou_reed_mode(self, widget): + try: + 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()) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_parrot_concert_hall(self, widget): + try: + self.parrot.concert_hall = self.concert_hall_mode.get_active() + self.concert_hall_mode.set_active(self.parrot.concert_hall) + except resource_manager.DeviceDisconnected: + self.deactivate() + + +class ParrotZikVersion2Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion2 + + def __init__(self, indicator): + self.room_dirty = False + self.angle_dirty = False + self.noise_cancelation_dirty = False + super(ParrotZikVersion2Interface, self).__init__(indicator) + self.noise_cancelation = MenuItem("Noise Control", None, visible=False) + self.noise_cancelation_submenu = Menu() + self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) + + self.noise_control_cancelation_max = MenuItem( + "Max Calcelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True) + self.noise_control_cancelation_on = MenuItem( + "Normal Cancelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True) + self.noise_control_off = MenuItem( + "Off", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True) + self.noise_control_street_mode = MenuItem( + "Street Mode", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE), checkitem=True) + self.noise_control_street_mode_max = MenuItem( + "Street Mode Max", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE_MAX), checkitem=True) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) + self.noise_cancelation_submenu.append(self.noise_control_off) + self.noise_cancelation_submenu.append(self.noise_control_street_mode) + self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) + + self.room_sound_effect = MenuItem( + "Room Sound Effect", None, 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, checkitem=True) + self.rooms = MenuItem("Rooms", None, checkitem=False) + self.angle = MenuItem("Angle", None, 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", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) + self.jazz_mode = MenuItem( + "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) + self.living_mode = MenuItem( + "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) + self.silent_mode = MenuItem( + "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), 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.angle_submenu = Menu() + self.angle.set_submenu(self.angle_submenu) + self.angle_30 = MenuItem( + "30", functools.partial(self.toggle_angle, 30), checkitem=True) + self.angle_60 = MenuItem( + "60", functools.partial(self.toggle_angle, 60), checkitem=True) + self.angle_90 = MenuItem( + "90", functools.partial(self.toggle_angle, 90), checkitem=True) + self.angle_120 = MenuItem( + "120", functools.partial(self.toggle_angle, 120), checkitem=True) + self.angle_150 = MenuItem( + "150", functools.partial(self.toggle_angle, 150), checkitem=True) + self.angle_180 = MenuItem( + "180", functools.partial(self.toggle_angle, 180), 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, + checkitem=True, visible=False) + self.indicator.menu.append(self.room_sound_effect) + self.indicator.menu.append(self.noise_cancelation) + self.indicator.menu.append(self.flight_mode) + + def activate(self, manager): + self.noise_cancelation.show() + self.flight_mode.show() + self.room_sound_effect.show() + super(ParrotZikVersion2Interface, self).activate(manager) + self._read_noise_cancelation() + 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 toggle_flight_mode(self, widget): + try: + self.parrot.flight_mode = self.flight_mode.get_active() + self.flight_mode.set_active(self.parrot.flight_mode) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_room(self, room, widget): + try: + if not self.room_dirty: + self.parrot.room = room + self.room_dirty = True + self._read_sound_effect_room() + self.room_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + 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): + try: + 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) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_angle(self, angle, widget): + try: + if not self.angle_dirty: + self.parrot.angle = angle + self.angle_dirty = True + self._read_sound_effect_angle() + self.angle_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + 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) + + def toggle_noise_cancelation(self, noise_calcelation, widget): + try: + if not self.noise_cancelation_dirty: + self.parrot.noise_control = noise_calcelation + self.noise_cancelation_dirty = True + self._read_noise_cancelation() + self.noise_cancelation_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + def _read_noise_cancelation(self): + active_noise_control = self.parrot.noise_control + noise_control_to_menuitem_map = ( + (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), + (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), + (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), + (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), + (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), + ) + for noise_control, menu_item in noise_control_to_menuitem_map: + menu_item.set_active(active_noise_control == noise_control) + + +if __name__ == "__main__": + try: + indicator = ParrotZikIndicator() + indicator.main() + except KeyboardInterrupt: + pass diff --git a/setup.py b/setup.py index 9bb3ae7..7156620 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( windows=[ { - 'script': 'ParrotZikTray', + 'script': 'parrot_zik_tray', 'icon_resources': [(1, "./share/icons/zik/Headphone.ico")], } ], @@ -43,7 +43,7 @@ setup( 'BeautifulSoup', 'bluetooth' ], - py_modules=['ParrotZik', 'message', 'resource_manager'], + py_modules=['parrot_zik', 'message', 'resource_manager'], - scripts=["ParrotZikTray"] + scripts=["parrot_zik_tray"] ) diff --git a/status_app_mac.py b/status_app_mac.py new file mode 100644 index 0000000..dccffe4 --- /dev/null +++ b/status_app_mac.py @@ -0,0 +1,25 @@ +from Foundation import * +from AppKit import * + +class StatusApp(NSApplication): + + def initMenu(self, menu): + statusbar = NSStatusBar.systemStatusBar() + self.statusitem = statusbar.statusItemWithLength_( + NSVariableStatusItemLength) + + self.mymenu = menu + #add menu to statusitem + self.statusitem.setMenu_(menu.menubarMenu) + self.statusitem.setToolTip_('Parrot Zik Indicator') + + def setIcon(self,icon,icon_directory): + self.icon = NSImage.alloc().initByReferencingFile_( + icon_directory + icon + '.png') + self.icon.setScalesWhenResized_(True) + self.icon.setSize_((20, 20)) + self.statusitem.setImage_(self.icon) + + def clicked_(self, notification): + self.mymenu.actions[notification._.title]() + NSLog('clicked!') -- cgit v1.2.1 From 72ae1ce983ede231a581d3c41f0ddea5c7ddf092 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 03:12:00 +0200 Subject: Turn off noise cancelation. --- parrot_zik_tray | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parrot_zik_tray b/parrot_zik_tray index f6cc4a0..71f6231 100755 --- a/parrot_zik_tray +++ b/parrot_zik_tray @@ -265,23 +265,23 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_control_cancelation_max = MenuItem( "Max Calcelation", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True) + NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True, sensitive=False) self.noise_control_cancelation_on = MenuItem( "Normal Cancelation", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True) + NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True, sensitive=False) self.noise_control_off = MenuItem( "Off", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True) + NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True, sensitive=False) self.noise_control_street_mode = MenuItem( "Street Mode", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE), checkitem=True) + NoiseControlTypes.STREET_MODE), checkitem=True, sensitive=False) self.noise_control_street_mode_max = MenuItem( "Street Mode Max", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE_MAX), checkitem=True) + NoiseControlTypes.STREET_MODE_MAX), checkitem=True, sensitive=False) self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) self.noise_cancelation_submenu.append(self.noise_control_off) -- cgit v1.2.1 From c595202f27eabebee4dd3be7d1d6c71404fc58be Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 03:45:48 +0200 Subject: Add rest of zik 2.0 api. --- resource_manager.py | 55 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/resource_manager.py b/resource_manager.py index 6bb8eb7..daf6ecd 100644 --- a/resource_manager.py +++ b/resource_manager.py @@ -123,20 +123,53 @@ class Version1ResourceManager(ResourceManagerBase): class Version2ResourceManager(ResourceManagerBase): resources = { + '/api/account/username': ['get', 'set'], + '/api/appli_version': ['set'], + '/api/audio/counter': ['get'], + '/api/audio/equalizer/enabled': ['get', 'set'], + '/api/audio/equalizer/preset_id': ['set'], + '/api/audio/equalizer/preset_value': ['set'], + '/api/audio/noise_cancellation/enabled': ['get', 'set'], + '/api/audio/noise_control/enabled': ['get', 'set'], + '/api/audio/noise_control': ['get'], + '/api/audio/noise_control/phone_mode': ['get', 'set'], + '/api/audio/noise': ['get'], + '/api/audio/param_equalizer/value': ['set'], + '/api/audio/preset/bypass': ['get', 'set'], + '/api/audio/preset/': ['clear_all'], + '/api/audio/preset/counter': ['get'], + '/api/audio/preset/current': ['get'], + '/api/audio/preset': ['download', 'activate', 'save', 'remove', 'cancel_producer'], + '/api/audio/preset/synchro': ['start', 'stop'], + '/api/audio/smart_audio_tune': ['get', 'set'], + '/api/audio/sound_effect/angle': ['get', 'set'], + '/api/audio/sound_effect/enabled': ['get', 'set'], + '/api/audio/sound_effect': ['get'], + '/api/audio/sound_effect/room_size': ['get', 'set'], + '/api/audio/source': ['get'], + '/api/audio/specific_mode/enabled': ['get', 'set'], + '/api/audio/thumb_equalizer/value': ['get', 'set'], + '/api/audio/track/metadata': ['get', 'force'], + '/api/bluetooth/friendlyname': ['get', 'set'], + '/api/flight_mode': ['get', 'enable', 'disable'], + '/api/software/download_check_state': ['get'], + '/api/software/download_size': ['set'], + '/api/software/tts': ['get', 'enable', 'disable'], + '/api/software/version_checking': ['get'], '/api/software/version': ['get'], + '/api/system/anc_phone_mode/enabled': ['get', 'set'], + '/api/system/auto_connection/enabled': ['get', 'set'], + '/api/system/auto_power_off': ['get', 'set'], + '/api/system/auto_power_off/presets_list': ['get'], + '/api/system/battery/forecast': ['get'], '/api/system/battery': ['get'], + '/api/system/bt_address': ['get'], + '/api/system': ['calibrate'], + '/api/system/color': ['get'], + '/api/system/device_type': ['get'], + '/api/system/': ['factory_reset'], + '/api/system/head_detection/enabled': ['get', 'set'], '/api/system/pi': ['get'], - '/api/bluetooth/friendlyname': ['get'], - '/api/system/auto_connection/enabled': ['get', 'set'], - '/api/system/anc_phone_mode/enabled': ['get', 'set'], - '/api/flight_mode': ['get', 'enable', 'disable'], - '/api/audio/sound_effect/enabled': ['get', 'set'], - '/api/audio/sound_effect/room_size': ['get', 'set'], - '/api/audio/sound_effect/angle': ['get', 'set'], - '/api/audio/noise': ['get'], - '/api/audio/noise_control': ['get'], - '/api/audio/noise_control/enabled': ['get', 'set'], - '/api/audio/track/metadata': ['get'], } class DeviceDisconnected(Exception): -- cgit v1.2.1 From 55255db75378f39807371bb7e434cc943fd66f27 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 03:52:14 +0200 Subject: Fix concert hall mode disapear on disconnect. --- parrot_zik_tray | 1 - 1 file changed, 1 deletion(-) diff --git a/parrot_zik_tray b/parrot_zik_tray index 71f6231..b3deaa2 100755 --- a/parrot_zik_tray +++ b/parrot_zik_tray @@ -370,7 +370,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): 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() -- cgit v1.2.1 From 947a9f7d10bc3c54939cfa72dab27b2e64034318 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 11:33:33 +0200 Subject: Create packet. --- bluetooth_paired_devices.py | 107 -------- indicator.py | 254 ------------------ message.py | 30 --- parrot_zik.py | 222 --------------- parrot_zik/__init__.py | 0 parrot_zik/bluetooth_paired_devices.py | 107 ++++++++ parrot_zik/indicator.py | 254 ++++++++++++++++++ parrot_zik/message.py | 30 +++ parrot_zik/parrot_zik_model.py | 222 +++++++++++++++ parrot_zik/parrot_zik_tray | 472 ++++++++++++++++++++++++++++++++ parrot_zik/resource_manager.py | 176 ++++++++++++ parrot_zik/status_app_mac.py | 25 ++ parrot_zik_tray | 474 --------------------------------- resource_manager.py | 176 ------------ setup.py | 7 +- status_app_mac.py | 25 -- 16 files changed, 1289 insertions(+), 1292 deletions(-) delete mode 100644 bluetooth_paired_devices.py delete mode 100644 indicator.py delete mode 100644 message.py delete mode 100644 parrot_zik.py create mode 100644 parrot_zik/__init__.py create mode 100644 parrot_zik/bluetooth_paired_devices.py create mode 100644 parrot_zik/indicator.py create mode 100644 parrot_zik/message.py create mode 100644 parrot_zik/parrot_zik_model.py create mode 100755 parrot_zik/parrot_zik_tray create mode 100644 parrot_zik/resource_manager.py create mode 100644 parrot_zik/status_app_mac.py delete mode 100755 parrot_zik_tray delete mode 100644 resource_manager.py delete mode 100644 status_app_mac.py diff --git a/bluetooth_paired_devices.py b/bluetooth_paired_devices.py deleted file mode 100644 index fead080..0000000 --- a/bluetooth_paired_devices.py +++ /dev/null @@ -1,107 +0,0 @@ -import sys -import re -import os - -from resource_manager import GenericResourceManager - -if sys.platform == "darwin": - from binplist import binplist - import lightblue -else: - import bluetooth - if sys.platform == "win32": - import _winreg - - -def get_parrot_zik_mac(): - p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' - 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') - if sys.platform == "linux2": - bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) - if bluetooth_on == 1: - out = os.popen("bluez-test-device list").read() - res = p.findall(out) - if len(res) > 0: - return res[0] - else: - raise DeviceNotConnected - else: - raise BluetoothIsNotOn - elif sys.platform == "darwin": - fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") - plist = binplist.BinaryPlist(file_obj=fd) - parsed_plist = plist.Parse() - try: - for mac in parsed_plist['PairedDevices']: - if p.match(mac.replace("-", ":")): - return mac.replace("-", ":") - else: - raise DeviceNotConnected - except Exception: - pass - - elif sys.platform == "win32": - aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - aKey = _winreg.OpenKey( - aReg, 'SYSTEM\CurrentControlSet\Services\ - BTHPORT\Parameters\Devices') - for i in range(10): - try: - asubkey_name = _winreg.EnumKey(aKey, i) - mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) - res = p.findall(mac) - if len(res) > 0: - return res[0] - else: - raise DeviceNotConnected - except EnvironmentError: - pass - - -def connect(): - mac = get_parrot_zik_mac() - if sys.platform == "darwin": - service_matches = lightblue.findservices( - name="Parrot RFcomm service", addr=mac) - else: - uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb", - "8B6814D3-6CE7-4498-9700-9312C1711F63"] - service_matches = [] - for uuid in uuids: - try: - service_matches = bluetooth.find_service(uuid=uuid, address=mac) - except bluetooth.btcommon.BluetoothError: - pass - if service_matches: - break - - if len(service_matches) == 0: - raise ConnectionFailure - first_match = service_matches[0] - - if sys.platform == "darwin": - host = first_match[0] - port = first_match[1] - sock = lightblue.socket() - else: - port = first_match["port"] - host = first_match["host"] - sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) - - sock.connect((host, port)) - - sock.send('\x00\x03\x00') - sock.recv(1024) - return GenericResourceManager(sock) - - -class DeviceNotConnected(Exception): - pass - - -class ConnectionFailure(Exception): - pass - - -class BluetoothIsNotOn(Exception): - pass diff --git a/indicator.py b/indicator.py deleted file mode 100644 index 05ffec7..0000000 --- a/indicator.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env python - -import sys -import os -import tempfile - -if sys.platform == "linux2" or sys.platform == "win32": - import gtk -elif sys.platform == "darwin": - from Foundation import * - from AppKit import * - from PyObjCTools import AppHelper - from status_app_mac import StatusApp - - -class BaseIndicator(object): - def __init__(self, icon, menu, statusicon): - self.menu = menu - self.statusicon = statusicon - self.setIcon(icon) - - def gtk_right_click_event(self, icon, button, time): - if not self.menu_shown: - self.menu_shown = True - self.menu.popup(None, None, gtk.status_icon_position_menu, - button, time, self.statusicon) - else: - self.menu_shown = False - self.menu.popdown() - - def setIcon(self, name): - raise NotImplementedError - - def main(self): - raise NotImplementedError - - def show_about_dialog(self, widget): - raise NotImplementedError - - -class WindowsIndicator(BaseIndicator): - def __init__(self, icon, menu): - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) - + os.path.sep + 'share' + os.path.sep + 'icons' - + os.path.sep +'zik' + os.path.sep) - self.menu_shown = False - sys.stdout = open(tempfile.gettempdir() - + os.path.sep + "zik_tray_stdout.log", "w") - sys.stderr = open(tempfile.gettempdir() - + os.path.sep + "zik_tray_stderr.log", "w") - statusicon = gtk.StatusIcon() - statusicon.connect("popup-menu", self.gtk_right_click_event) - statusicon.set_tooltip("Parrot Zik") - super(WindowsIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.set_from_file(self.icon_directory + name + '.png') - - def main(self): - gtk.main() - - def show_about_dialog(self, widget): - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class LinuxIndicator(BaseIndicator): - def __init__(self, icon, menu): - import appindicator - self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' - + os.path.sep + 'icons' + os.path.sep+'zik' - + os.path.sep) - if not os.path.isdir(self.icon_directory): - self.icon_directory = (os.path.dirname(sys.argv[0]) - + os.path.sep + 'share' + os.path.sep - + 'icons' + os.path.sep+'zik' - + os.path.sep) - statusicon = appindicator.Indicator( - "new-parrotzik-indicator", "indicator-messages", - appindicator.CATEGORY_APPLICATION_STATUS) - statusicon.set_status(appindicator.STATUS_ACTIVE) - statusicon.set_icon_theme_path(self.icon_directory) - statusicon.set_menu(menu.gtk_menu) - super(LinuxIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.set_icon(name) - - def main(self): - gtk.main() - - def show_about_dialog(self, widget): - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class DarwinIndicator(BaseIndicator): - def __init__(self, icon, menu): - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep - + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' - + os.path.sep) - statusicon = StatusApp.sharedApplication() - statusicon.initMenu(menu) - super(DarwinIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.setIcon(name, self.icon_directory) - - def main(self): - AppHelper.runEventLoop() - - def show_about_dialog(self, widget): - pass - - -class NSMenu(object): - def __init__(self): - self.actions = {} - self.menubarMenu = NSMenu.alloc().init() - self.menubarMenu.setAutoenablesItems_(False) - - def append(self, menu_item): - self.actions[menu_item.title] = menu_item.action - self.menubarMenu.addItem_(menu_item.nsmenu_item) - - def reposition(self): - # TODO - pass - -class GTKMenu(object): - def __init__(self): - self.gtk_menu = gtk.Menu() - - def append(self, menu_item): - self.gtk_menu.append(menu_item.base_item) - - def reposition(self): - self.gtk_menu.reposition() - - -class MenuItemBase(object): - def __init__(self, base_item, sensitive, visible): - self.base_item = base_item - self.set_sensitive(sensitive) - if visible: - self.show() - else: - self.hide() - - def set_sensitive(self, option): - raise NotImplementedError - - def set_active(self, option): - raise NotImplementedError - - def get_active(self): - raise NotImplementedError - - def set_label(self, option): - raise NotImplementedError - - def show(self): - self.base_item.show() - - 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: - gtk_item = gtk.CheckMenuItem(name) - else: - gtk_item = gtk.MenuItem(name) - if action: - gtk_item.connect("activate", action) - super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) - - def set_sensitive(self, option): - return self.base_item.set_sensitive(option) - - def set_active(self, option): - return self.base_item.set_active(option) - - def get_active(self): - return self.base_item.get_active() - - 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): - self.title = name - self.action = action - nsmenu_item = ( - NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( - name, 'clicked:', '')) - super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) - - def set_sensitive(self, option): - self.base_item.setEnabled_(option) - - def set_active(self, option): - self.base_item.setState_(option) - - def get_active(self): - return self.base_item.state - - def set_label(self, option): - self.title = option - self.base_item.setTitle_(option) - -if sys.platform == 'linux2': - SysIndicator = LinuxIndicator - Menu = GTKMenu - MenuItem = GTKMenuItem -elif sys.platform == 'win32': - SysIndicator = WindowsIndicator - Menu = GTKMenu - MenuItem = GTKMenuItem -elif sys.platform == 'darwin': - SysIndicator = DarwinIndicator - Menu = NSMenu - MenuItem = NSMenuItem -else: - raise Exception('Platform not supported') - -if __name__ == "__main__": - - quit_item = MenuItem("Quit", sys.exit, True) - - menu = Menu() - menu.append(quit_item) - - indicator = SysIndicator(icon="zik-audio-headset", menu=menu) - indicator.main() diff --git a/message.py b/message.py deleted file mode 100644 index 214b6f9..0000000 --- a/message.py +++ /dev/null @@ -1,30 +0,0 @@ -class Message: - def __init__(self, resource, method, arg=None): - self.method = method - self.resource = resource - self.arg = arg - - def __str__(self): - return str(self.request) - - @property - def request(self): - message = bytearray() - message.extend(self.header) - message.extend(bytearray(self.request_string)) - return message - - @property - def header(self): - header = bytearray([0]) - header.append(len(self.request_string) + 3) - header.append("\x80") - return header - - @property - def request_string(self): - if self.method == 'set': - return 'SET {}/{}?arg={}'.format(self.resource, self.method, - str(self.arg).lower()) - else: - return 'GET {}/{}'.format(self.resource, self.method) diff --git a/parrot_zik.py b/parrot_zik.py deleted file mode 100644 index 52414b5..0000000 --- a/parrot_zik.py +++ /dev/null @@ -1,222 +0,0 @@ -from resource_manager import Version1ResourceManager -from resource_manager import Version2ResourceManager - - -class BatteryStates: - CHARGED = 'charged' - IN_USE = 'in_use' - CHARGING = 'charging' - representation = { - CHARGED: 'Charged', - IN_USE: 'In Use', - CHARGING: 'Charging', - } - -class Rooms: - CONCERT_HALL = 'concert' - JAZZ_CLUB = 'jazz' - LIVING_ROOM = 'living' - SILENT_ROOM = 'silent' - representation = { - CONCERT_HALL: 'Concert Hall', - JAZZ_CLUB: 'Jazz Club', - LIVING_ROOM: 'Living Room', - SILENT_ROOM: 'Silent Room', - } - -class NoiseControl(object): - def __init__(self, type, value): - self.type = type - self.value = value - - @classmethod - def from_noise_control(cls, noise_control): - return cls(noise_control['type'], int(noise_control['value'])) - - def __eq__(self, other): - return self.type == other.type and self.value == other.value - - def __str__(self): - return '{}++{}'.format(self.type, self.value) - -class NoiseControlTypes: - NOISE_CONTROL_MAX = NoiseControl('anc', 2) - NOISE_CONTROL_ON = NoiseControl('anc', 1) - NOISE_CONTROL_OFF = NoiseControl('off', 1) - STREET_MODE = NoiseControl('aoc', 1) - STREET_MODE_MAX = NoiseControl('aoc', 2) - - -class ParrotZikBase(object): - def __init__(self, resource_manager): - self.resource_manager = resource_manager - - @property - def version(self): - return self.resource_manager.api_version - - def refresh_battery(self): - self.resource_manager.fetch('/api/system/battery') - - @property - def battery_state(self): - answer = self.resource_manager.get("/api/system/battery") - return answer.system.battery["state"] - - def get_battery_level(self, field_name): - answer = self.resource_manager.get("/api/system/battery") - return int(answer.system.battery[field_name]) - - @property - def friendly_name(self): - answer = self.resource_manager.get("/api/bluetooth/friendlyname") - return answer.bluetooth["friendlyname"] - - @property - def auto_connect(self): - answer = self.resource_manager.get("/api/system/auto_connection/enabled") - return self._result_to_bool( - answer.system.auto_connection["enabled"]) - - @auto_connect.setter - def auto_connect(self, arg): - self.resource_manager.set("/api/system/auto_connection/enabled", arg) - - @property - def anc_phone_mode(self): - answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") - return self._result_to_bool( - answer.system.anc_phone_mode["enabled"]) - - def _result_to_bool(self, result): - if result == "true": - return True - elif result == "false": - return False - else: - raise AssertionError(result) - - -class ParrotZikVersion1(ParrotZikBase): - def __init__(self, resource_manager): - super(ParrotZikVersion1, self).__init__( - resource_manager.get_resource_manager( - Version1ResourceManager)) - - @property - def version(self): - answer = self.resource_manager.get('/api/software/version') - return answer.software['version'] - - @property - def battery_level(self): - return int(self.get_battery_level('level')) - - @property - def lou_reed_mode(self): - answer = self.resource_manager.get("/api/audio/specific_mode/enabled") - return self._result_to_bool( - answer.audio.specific_mode["enabled"]) - - @lou_reed_mode.setter - def lou_reed_mode(self, arg): - self.resource_manager.get("/api/audio/specific_mode/enabled", arg) - - @property - def concert_hall(self): - answer = self.resource_manager.get("/api/audio/sound_effect/enabled") - return self._result_to_bool( - answer.audio.sound_effect["enabled"]) - - @concert_hall.setter - def concert_hall(self, arg): - self.resource_manager.get("/api/audio/sound_effect/enabled", arg) - - @property - def cancel_noise(self): - answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") - return self._result_to_bool( - answer.audio.noise_cancellation["enabled"]) - - @cancel_noise.setter - def cancel_noise(self, arg): - self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) - - -class ParrotZikVersion2(ParrotZikBase): - def __init__(self, resource_manager): - super(ParrotZikVersion2, self).__init__( - resource_manager.get_resource_manager( - Version2ResourceManager)) - - @property - def version(self): - answer = self.resource_manager.get('/api/software/version') - return answer.software['sip6'] - - @property - def battery_level(self): - return self.get_battery_level('percent') - - @property - def flight_mode(self): - answer = self.resource_manager.get('/api/flight_mode') - return self._result_to_bool(answer.flight_mode['enabled']) - - @flight_mode.setter - def flight_mode(self, arg): - if arg: - self.resource_manager.toggle_on('/api/flight_mode') - else: - self.resource_manager.toggle_off('/api/flight_mode') - - @property - def sound_effect(self): - answer = self.resource_manager.get('/api/audio/sound_effect/enabled') - return self._result_to_bool(answer.audio.sound_effect['enabled']) - - @sound_effect.setter - def sound_effect(self, arg): - self.resource_manager.set('/api/audio/sound_effect/enabled', arg) - - @property - def room(self): - answer = self.resource_manager.get('/api/audio/sound_effect/room_size') - return answer.audio.sound_effect['room_size'] - - @room.setter - def room(self, arg): - self.resource_manager.set('/api/audio/sound_effect/room_size', arg) - - @property - def external_noise(self): - answer = self.resource_manager.get('/api/audio/noise') - return int(answer.audio.noise['external']) - - @property - def internal_noise(self): - answer = self.resource_manager.get('/api/audio/noise') - return int(answer.audio.noise['internal']) - - @property - def angle(self): - answer = self.resource_manager.get('/api/audio/sound_effect/angle') - return int(answer.audio.sound_effect['angle']) - - @angle.setter - def angle(self, arg): - self.resource_manager.set('/api/audio/sound_effect/angle', arg) - - @property - def noise_control(self): - answer = self.resource_manager.get('/api/audio/noise_control') - return NoiseControl.from_noise_control(answer.audio.noise_control) - - @noise_control.setter - def noise_control(self, arg): - pass - - @property - def noise_control_enabled(self): - answer = self.resource_manager.get('/api/audio/noise_control/enabled') - return self._result_to_bool(answer.audio.noise_control['enabled']) diff --git a/parrot_zik/__init__.py b/parrot_zik/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py new file mode 100644 index 0000000..eb1ec09 --- /dev/null +++ b/parrot_zik/bluetooth_paired_devices.py @@ -0,0 +1,107 @@ +import sys +import re +import os + +from parrot_zik.resource_manager import GenericResourceManager + +if sys.platform == "darwin": + from binplist import binplist + import lightblue +else: + import bluetooth + if sys.platform == "win32": + import _winreg + + +def get_parrot_zik_mac(): + p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' + 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') + if sys.platform == "linux2": + bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) + if bluetooth_on == 1: + out = os.popen("bluez-test-device list").read() + res = p.findall(out) + if len(res) > 0: + return res[0] + else: + raise DeviceNotConnected + else: + raise BluetoothIsNotOn + elif sys.platform == "darwin": + fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") + plist = binplist.BinaryPlist(file_obj=fd) + parsed_plist = plist.Parse() + try: + for mac in parsed_plist['PairedDevices']: + if p.match(mac.replace("-", ":")): + return mac.replace("-", ":") + else: + raise DeviceNotConnected + except Exception: + pass + + elif sys.platform == "win32": + aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + aKey = _winreg.OpenKey( + aReg, 'SYSTEM\CurrentControlSet\Services\ + BTHPORT\Parameters\Devices') + for i in range(10): + try: + asubkey_name = _winreg.EnumKey(aKey, i) + mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) + res = p.findall(mac) + if len(res) > 0: + return res[0] + else: + raise DeviceNotConnected + except EnvironmentError: + pass + + +def connect(): + mac = get_parrot_zik_mac() + if sys.platform == "darwin": + service_matches = lightblue.findservices( + name="Parrot RFcomm service", addr=mac) + else: + uuids = ["0ef0f502-f0ee-46c9-986c-54ed027807fb", + "8B6814D3-6CE7-4498-9700-9312C1711F63"] + service_matches = [] + for uuid in uuids: + try: + service_matches = bluetooth.find_service(uuid=uuid, address=mac) + except bluetooth.btcommon.BluetoothError: + pass + if service_matches: + break + + if len(service_matches) == 0: + raise ConnectionFailure + first_match = service_matches[0] + + if sys.platform == "darwin": + host = first_match[0] + port = first_match[1] + sock = lightblue.socket() + else: + port = first_match["port"] + host = first_match["host"] + sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) + + sock.connect((host, port)) + + sock.send('\x00\x03\x00') + sock.recv(1024) + return GenericResourceManager(sock) + + +class DeviceNotConnected(Exception): + pass + + +class ConnectionFailure(Exception): + pass + + +class BluetoothIsNotOn(Exception): + pass diff --git a/parrot_zik/indicator.py b/parrot_zik/indicator.py new file mode 100644 index 0000000..2691113 --- /dev/null +++ b/parrot_zik/indicator.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python + +import sys +import os +import tempfile + +if sys.platform == "linux2" or sys.platform == "win32": + import gtk +elif sys.platform == "darwin": + from Foundation import * + from AppKit import * + from PyObjCTools import AppHelper + from status_app_mac import StatusApp + + +class BaseIndicator(object): + def __init__(self, icon, menu, statusicon): + self.menu = menu + self.statusicon = statusicon + self.setIcon(icon) + + def gtk_right_click_event(self, icon, button, time): + if not self.menu_shown: + self.menu_shown = True + self.menu.popup(None, None, gtk.status_icon_position_menu, + button, time, self.statusicon) + else: + self.menu_shown = False + self.menu.popdown() + + def setIcon(self, name): + raise NotImplementedError + + def main(self): + raise NotImplementedError + + def show_about_dialog(self, widget): + raise NotImplementedError + + +class WindowsIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + '..' + + os.path.sep + 'share' + os.path.sep + 'icons' + + os.path.sep +'zik' + os.path.sep) + self.menu_shown = False + sys.stdout = open(tempfile.gettempdir() + + os.path.sep + "zik_tray_stdout.log", "w") + sys.stderr = open(tempfile.gettempdir() + + os.path.sep + "zik_tray_stderr.log", "w") + statusicon = gtk.StatusIcon() + statusicon.connect("popup-menu", self.gtk_right_click_event) + statusicon.set_tooltip("Parrot Zik") + super(WindowsIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_from_file(self.icon_directory + name + '.png') + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() + + +class LinuxIndicator(BaseIndicator): + def __init__(self, icon, menu): + import appindicator + self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' + + os.path.sep + 'icons' + os.path.sep+'zik' + + os.path.sep) + if not os.path.isdir(self.icon_directory): + self.icon_directory = (os.path.dirname(sys.argv[0]) + os.path.sep + '..' + + os.path.sep + 'share' + os.path.sep + + 'icons' + os.path.sep+'zik' + + os.path.sep) + statusicon = appindicator.Indicator( + "new-parrotzik-indicator", "indicator-messages", + appindicator.CATEGORY_APPLICATION_STATUS) + statusicon.set_status(appindicator.STATUS_ACTIVE) + statusicon.set_icon_theme_path(self.icon_directory) + statusicon.set_menu(menu.gtk_menu) + super(LinuxIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_icon(name) + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() + + +class DarwinIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = ( + os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + '..' + os.path.sep + + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' + + os.path.sep) + statusicon = StatusApp.sharedApplication() + statusicon.initMenu(menu) + super(DarwinIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.setIcon(name, self.icon_directory) + + def main(self): + AppHelper.runEventLoop() + + def show_about_dialog(self, widget): + pass + + +class NSMenu(object): + def __init__(self): + self.actions = {} + self.menubarMenu = NSMenu.alloc().init() + self.menubarMenu.setAutoenablesItems_(False) + + def append(self, menu_item): + self.actions[menu_item.title] = menu_item.action + self.menubarMenu.addItem_(menu_item.nsmenu_item) + + def reposition(self): + # TODO + pass + +class GTKMenu(object): + def __init__(self): + self.gtk_menu = gtk.Menu() + + def append(self, menu_item): + self.gtk_menu.append(menu_item.base_item) + + def reposition(self): + self.gtk_menu.reposition() + + +class MenuItemBase(object): + def __init__(self, base_item, sensitive, visible): + self.base_item = base_item + self.set_sensitive(sensitive) + if visible: + self.show() + else: + self.hide() + + def set_sensitive(self, option): + raise NotImplementedError + + def set_active(self, option): + raise NotImplementedError + + def get_active(self): + raise NotImplementedError + + def set_label(self, option): + raise NotImplementedError + + def show(self): + self.base_item.show() + + 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: + gtk_item = gtk.CheckMenuItem(name) + else: + gtk_item = gtk.MenuItem(name) + if action: + gtk_item.connect("activate", action) + super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) + + def set_sensitive(self, option): + return self.base_item.set_sensitive(option) + + def set_active(self, option): + return self.base_item.set_active(option) + + def get_active(self): + return self.base_item.get_active() + + 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): + self.title = name + self.action = action + nsmenu_item = ( + NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + name, 'clicked:', '')) + super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) + + def set_sensitive(self, option): + self.base_item.setEnabled_(option) + + def set_active(self, option): + self.base_item.setState_(option) + + def get_active(self): + return self.base_item.state + + def set_label(self, option): + self.title = option + self.base_item.setTitle_(option) + +if sys.platform == 'linux2': + SysIndicator = LinuxIndicator + Menu = GTKMenu + MenuItem = GTKMenuItem +elif sys.platform == 'win32': + SysIndicator = WindowsIndicator + Menu = GTKMenu + MenuItem = GTKMenuItem +elif sys.platform == 'darwin': + SysIndicator = DarwinIndicator + Menu = NSMenu + MenuItem = NSMenuItem +else: + raise Exception('Platform not supported') + +if __name__ == "__main__": + + quit_item = MenuItem("Quit", sys.exit, True) + + menu = Menu() + menu.append(quit_item) + + indicator = SysIndicator(icon="zik-audio-headset", menu=menu) + indicator.main() diff --git a/parrot_zik/message.py b/parrot_zik/message.py new file mode 100644 index 0000000..214b6f9 --- /dev/null +++ b/parrot_zik/message.py @@ -0,0 +1,30 @@ +class Message: + def __init__(self, resource, method, arg=None): + self.method = method + self.resource = resource + self.arg = arg + + def __str__(self): + return str(self.request) + + @property + def request(self): + message = bytearray() + message.extend(self.header) + message.extend(bytearray(self.request_string)) + return message + + @property + def header(self): + header = bytearray([0]) + header.append(len(self.request_string) + 3) + header.append("\x80") + return header + + @property + def request_string(self): + if self.method == 'set': + return 'SET {}/{}?arg={}'.format(self.resource, self.method, + str(self.arg).lower()) + else: + return 'GET {}/{}'.format(self.resource, self.method) diff --git a/parrot_zik/parrot_zik_model.py b/parrot_zik/parrot_zik_model.py new file mode 100644 index 0000000..e15200f --- /dev/null +++ b/parrot_zik/parrot_zik_model.py @@ -0,0 +1,222 @@ +from parrot_zik.resource_manager import Version1ResourceManager +from parrot_zik.resource_manager import Version2ResourceManager + + +class BatteryStates: + CHARGED = 'charged' + IN_USE = 'in_use' + CHARGING = 'charging' + representation = { + CHARGED: 'Charged', + IN_USE: 'In Use', + CHARGING: 'Charging', + } + +class Rooms: + CONCERT_HALL = 'concert' + JAZZ_CLUB = 'jazz' + LIVING_ROOM = 'living' + SILENT_ROOM = 'silent' + representation = { + CONCERT_HALL: 'Concert Hall', + JAZZ_CLUB: 'Jazz Club', + LIVING_ROOM: 'Living Room', + SILENT_ROOM: 'Silent Room', + } + +class NoiseControl(object): + def __init__(self, type, value): + self.type = type + self.value = value + + @classmethod + def from_noise_control(cls, noise_control): + return cls(noise_control['type'], int(noise_control['value'])) + + def __eq__(self, other): + return self.type == other.type and self.value == other.value + + def __str__(self): + return '{}++{}'.format(self.type, self.value) + +class NoiseControlTypes: + NOISE_CONTROL_MAX = NoiseControl('anc', 2) + NOISE_CONTROL_ON = NoiseControl('anc', 1) + NOISE_CONTROL_OFF = NoiseControl('off', 1) + STREET_MODE = NoiseControl('aoc', 1) + STREET_MODE_MAX = NoiseControl('aoc', 2) + + +class ParrotZikBase(object): + def __init__(self, resource_manager): + self.resource_manager = resource_manager + + @property + def version(self): + return self.resource_manager.api_version + + def refresh_battery(self): + self.resource_manager.fetch('/api/system/battery') + + @property + def battery_state(self): + answer = self.resource_manager.get("/api/system/battery") + return answer.system.battery["state"] + + def get_battery_level(self, field_name): + answer = self.resource_manager.get("/api/system/battery") + return int(answer.system.battery[field_name]) + + @property + def friendly_name(self): + answer = self.resource_manager.get("/api/bluetooth/friendlyname") + return answer.bluetooth["friendlyname"] + + @property + def auto_connect(self): + answer = self.resource_manager.get("/api/system/auto_connection/enabled") + return self._result_to_bool( + answer.system.auto_connection["enabled"]) + + @auto_connect.setter + def auto_connect(self, arg): + self.resource_manager.set("/api/system/auto_connection/enabled", arg) + + @property + def anc_phone_mode(self): + answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") + return self._result_to_bool( + answer.system.anc_phone_mode["enabled"]) + + def _result_to_bool(self, result): + if result == "true": + return True + elif result == "false": + return False + else: + raise AssertionError(result) + + +class ParrotZikVersion1(ParrotZikBase): + def __init__(self, resource_manager): + super(ParrotZikVersion1, self).__init__( + resource_manager.get_resource_manager( + Version1ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['version'] + + @property + def battery_level(self): + return int(self.get_battery_level('level')) + + @property + def lou_reed_mode(self): + answer = self.resource_manager.get("/api/audio/specific_mode/enabled") + return self._result_to_bool( + answer.audio.specific_mode["enabled"]) + + @lou_reed_mode.setter + def lou_reed_mode(self, arg): + self.resource_manager.get("/api/audio/specific_mode/enabled", arg) + + @property + def concert_hall(self): + answer = self.resource_manager.get("/api/audio/sound_effect/enabled") + return self._result_to_bool( + answer.audio.sound_effect["enabled"]) + + @concert_hall.setter + def concert_hall(self, arg): + self.resource_manager.get("/api/audio/sound_effect/enabled", arg) + + @property + def cancel_noise(self): + answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") + return self._result_to_bool( + answer.audio.noise_cancellation["enabled"]) + + @cancel_noise.setter + def cancel_noise(self, arg): + self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) + + +class ParrotZikVersion2(ParrotZikBase): + def __init__(self, resource_manager): + super(ParrotZikVersion2, self).__init__( + resource_manager.get_resource_manager( + Version2ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['sip6'] + + @property + def battery_level(self): + return self.get_battery_level('percent') + + @property + def flight_mode(self): + answer = self.resource_manager.get('/api/flight_mode') + return self._result_to_bool(answer.flight_mode['enabled']) + + @flight_mode.setter + def flight_mode(self, arg): + if arg: + self.resource_manager.toggle_on('/api/flight_mode') + else: + self.resource_manager.toggle_off('/api/flight_mode') + + @property + def sound_effect(self): + answer = self.resource_manager.get('/api/audio/sound_effect/enabled') + return self._result_to_bool(answer.audio.sound_effect['enabled']) + + @sound_effect.setter + def sound_effect(self, arg): + self.resource_manager.set('/api/audio/sound_effect/enabled', arg) + + @property + def room(self): + answer = self.resource_manager.get('/api/audio/sound_effect/room_size') + return answer.audio.sound_effect['room_size'] + + @room.setter + def room(self, arg): + self.resource_manager.set('/api/audio/sound_effect/room_size', arg) + + @property + def external_noise(self): + answer = self.resource_manager.get('/api/audio/noise') + return int(answer.audio.noise['external']) + + @property + def internal_noise(self): + answer = self.resource_manager.get('/api/audio/noise') + return int(answer.audio.noise['internal']) + + @property + def angle(self): + answer = self.resource_manager.get('/api/audio/sound_effect/angle') + return int(answer.audio.sound_effect['angle']) + + @angle.setter + def angle(self, arg): + self.resource_manager.set('/api/audio/sound_effect/angle', arg) + + @property + def noise_control(self): + answer = self.resource_manager.get('/api/audio/noise_control') + return NoiseControl.from_noise_control(answer.audio.noise_control) + + @noise_control.setter + def noise_control(self, arg): + pass + + @property + def noise_control_enabled(self): + answer = self.resource_manager.get('/api/audio/noise_control/enabled') + return self._result_to_bool(answer.audio.noise_control['enabled']) diff --git a/parrot_zik/parrot_zik_tray b/parrot_zik/parrot_zik_tray new file mode 100755 index 0000000..dcdacd0 --- /dev/null +++ b/parrot_zik/parrot_zik_tray @@ -0,0 +1,472 @@ +#!/usr/bin/env python +import functools +from threading import Lock +import gtk + +from parrot_zik import resource_manager +from parrot_zik import bluetooth_paired_devices +from parrot_zik.parrot_zik_model import BatteryStates +from parrot_zik.parrot_zik_model import ParrotZikVersion1 +from parrot_zik.parrot_zik_model import ParrotZikVersion2 +from parrot_zik.parrot_zik_model import NoiseControlTypes +from parrot_zik.parrot_zik_model import Rooms +from parrot_zik.indicator import MenuItem +from parrot_zik.indicator import Menu +from parrot_zik.indicator import SysIndicator + +REFRESH_FREQUENCY = 30000 +RECONNECT_FREQUENCY = 5000 + + +class repeat(object): + def __init__(self, f): + self.f = f + self.id = None + self.lock = Lock() + + def __call__(self, cls): + self.f(cls) + + def start(self, cls, frequency): + self.lock.acquire() + if not self.id: + def run(): + self.f(cls) + return True + + self.id = gtk.timeout_add(frequency, run) + self.lock.release() + + def stop(self): + self.lock.acquire() + if self.id: + gtk.timeout_remove(self.id) + self.id = None + self.lock.release() + + +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: + self.reconnect.stop() + else: + self.info("Trying to connect") + try: + manager = bluetooth_paired_devices.connect() + except bluetooth_paired_devices.BluetoothIsNotOn: + self.info("Bluetooth is turned off") + except bluetooth_paired_devices.DeviceNotConnected: + self.info("Parrot Zik Not connected") + except bluetooth_paired_devices.ConnectionFailure: + self.info("Failed to connect") + else: + if manager.api_version.startswith('1'): + interface = self.version_1_interface + else: + interface = self.version_2_interface + try: + interface.activate(manager) + except resource_manager.DeviceDisconnected: + interface.deactivate() + else: + self.autorefresh(self) + self.autorefresh.start(self, REFRESH_FREQUENCY) + self.reconnect.stop() + + def info(self, message): + self.info_item.set_label(message) + print(message) + + @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.toggle_auto_connection, + 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) + + def activate(self, manager): + self.parrot = self.parrot_class(manager) + self.read_battery() + self.indicator.info("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.battery_level.show() + self.battery_state.show() + self.firmware_version.show() + self.auto_connection.show() + self.indicator.active_interface = self + self.indicator.menu.reposition() + + @property + def parrot_class(self): + raise NotImplementedError + + def deactivate(self): + self.parrot = None + self.battery_level.hide() + self.battery_state.hide() + self.firmware_version.hide() + self.auto_connection.hide() + self.indicator.menu.reposition() + self.indicator.active_interface = None + self.indicator.setIcon("zik-audio-headset") + self.indicator.info('Lost Connection') + self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) + + def toggle_auto_connection(self, widget): + try: + self.parrot.auto_connect = self.auto_connection.get_active() + self.auto_connection.set_active(self.parrot.auto_connect) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def refresh(self): + self.read_battery() + + def read_battery(self): + try: + self.parrot.refresh_battery() + battery_level = self.parrot.battery_level + battery_state = self.parrot.battery_state + except resource_manager.DeviceDisconnected: + self.deactivate() + else: + 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)) + + +class ParrotZikVersion1Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion1 + + def __init__(self, indicator): + super(ParrotZikVersion1Interface, self).__init__(indicator) + self.noise_cancelation = MenuItem( + "Noise Cancellation", self.toggle_noise_cancelation, + checkitem=True, visible=False) + self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, + checkitem=True, visible=False) + self.concert_hall_mode = MenuItem( + "Concert Hall Mode", self.toggle_parrot_concert_hall, + 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, manager): + self.noise_cancelation.show() + self.lou_reed_mode.show() + self.concert_hall_mode.show() + super(ParrotZikVersion1Interface, self).activate(manager) + self.noise_cancelation.set_active(self.parrot.cancel_noise) + 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 toggle_noise_cancelation(self, widget): + try: + self.parrot.cancel_noise = self.noise_cancelation.get_active() + self.noise_cancelation.set_active(self.parrot.cancel_noise) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_lou_reed_mode(self, widget): + try: + 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()) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_parrot_concert_hall(self, widget): + try: + self.parrot.concert_hall = self.concert_hall_mode.get_active() + self.concert_hall_mode.set_active(self.parrot.concert_hall) + except resource_manager.DeviceDisconnected: + self.deactivate() + + +class ParrotZikVersion2Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion2 + + def __init__(self, indicator): + self.room_dirty = False + self.angle_dirty = False + self.noise_cancelation_dirty = False + super(ParrotZikVersion2Interface, self).__init__(indicator) + self.noise_cancelation = MenuItem("Noise Control", None, visible=False) + self.noise_cancelation_submenu = Menu() + self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) + + self.noise_control_cancelation_max = MenuItem( + "Max Calcelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True, sensitive=False) + self.noise_control_cancelation_on = MenuItem( + "Normal Cancelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True, sensitive=False) + self.noise_control_off = MenuItem( + "Off", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True, sensitive=False) + self.noise_control_street_mode = MenuItem( + "Street Mode", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE), checkitem=True, sensitive=False) + self.noise_control_street_mode_max = MenuItem( + "Street Mode Max", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE_MAX), checkitem=True, sensitive=False) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) + self.noise_cancelation_submenu.append(self.noise_control_off) + self.noise_cancelation_submenu.append(self.noise_control_street_mode) + self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) + + self.room_sound_effect = MenuItem( + "Room Sound Effect", None, 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, checkitem=True) + self.rooms = MenuItem("Rooms", None, checkitem=False) + self.angle = MenuItem("Angle", None, 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", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) + self.jazz_mode = MenuItem( + "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) + self.living_mode = MenuItem( + "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) + self.silent_mode = MenuItem( + "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), 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.angle_submenu = Menu() + self.angle.set_submenu(self.angle_submenu) + self.angle_30 = MenuItem( + "30", functools.partial(self.toggle_angle, 30), checkitem=True) + self.angle_60 = MenuItem( + "60", functools.partial(self.toggle_angle, 60), checkitem=True) + self.angle_90 = MenuItem( + "90", functools.partial(self.toggle_angle, 90), checkitem=True) + self.angle_120 = MenuItem( + "120", functools.partial(self.toggle_angle, 120), checkitem=True) + self.angle_150 = MenuItem( + "150", functools.partial(self.toggle_angle, 150), checkitem=True) + self.angle_180 = MenuItem( + "180", functools.partial(self.toggle_angle, 180), 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, + checkitem=True, visible=False) + self.indicator.menu.append(self.room_sound_effect) + self.indicator.menu.append(self.noise_cancelation) + self.indicator.menu.append(self.flight_mode) + + def activate(self, manager): + self.noise_cancelation.show() + self.flight_mode.show() + self.room_sound_effect.show() + super(ParrotZikVersion2Interface, self).activate(manager) + self._read_noise_cancelation() + 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.flight_mode.hide() + self.room_sound_effect.hide() + super(ParrotZikVersion2Interface, self).deactivate() + + def toggle_flight_mode(self, widget): + try: + self.parrot.flight_mode = self.flight_mode.get_active() + self.flight_mode.set_active(self.parrot.flight_mode) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_room(self, room, widget): + try: + if not self.room_dirty: + self.parrot.room = room + self.room_dirty = True + self._read_sound_effect_room() + self.room_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + 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): + try: + 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) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_angle(self, angle, widget): + try: + if not self.angle_dirty: + self.parrot.angle = angle + self.angle_dirty = True + self._read_sound_effect_angle() + self.angle_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + 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) + + def toggle_noise_cancelation(self, noise_calcelation, widget): + try: + if not self.noise_cancelation_dirty: + self.parrot.noise_control = noise_calcelation + self.noise_cancelation_dirty = True + self._read_noise_cancelation() + self.noise_cancelation_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + def _read_noise_cancelation(self): + active_noise_control = self.parrot.noise_control + noise_control_to_menuitem_map = ( + (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), + (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), + (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), + (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), + (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), + ) + for noise_control, menu_item in noise_control_to_menuitem_map: + menu_item.set_active(active_noise_control == noise_control) + + +if __name__ == "__main__": + try: + indicator = ParrotZikIndicator() + indicator.main() + except KeyboardInterrupt: + pass diff --git a/parrot_zik/resource_manager.py b/parrot_zik/resource_manager.py new file mode 100644 index 0000000..8b63e8c --- /dev/null +++ b/parrot_zik/resource_manager.py @@ -0,0 +1,176 @@ +import bluetooth +from operator import itemgetter +import sys + +from BeautifulSoup import BeautifulSoup + +from parrot_zik.message import Message + + +class ResourceManagerBase(object): + resources = [ + ] + + def __init__(self, socket, resource_values=None): + self.sock = socket + self.resource_values = resource_values or {} + + def get(self, resource): + try: + return self.resource_values[resource] + except KeyError: + return self.fetch(resource) + + def fetch(self, resource): + result = self.send_message(self._create_message(resource, 'get')) + self.resource_values[resource] = result + return result + + def toggle_on(self, resource): + self.send_message(self._create_message(resource, 'enable')) + self.fetch(resource) + + def toggle_off(self, resource): + self.send_message(self._create_message(resource, 'disable')) + self.fetch(resource) + + def set(self, resource, arg): + self.send_message(self._create_message(resource, 'set', arg)) + self.fetch(resource) + + def _create_message(self, resource, method, arg=None): + assert resource in self.resources, 'Unknown resource {}'.format(resource) + assert method in self.resources[resource], 'Unhandled method {} for {}'.format(method, resource) + return Message(resource, method, arg) + + def send_message(self, message): + try: + self.sock.send(str(message)) + return self.get_answer(message) + except bluetooth.btcommon.BluetoothError: + raise DeviceDisconnected + + def get_answer(self, message): + data = self.receive_message() + notifications = [] + while not data.answer: + if data.notify: + notifications.append(data.notify) + else: + raise AssertionError('Unknown response') + data = self.receive_message() + self.handle_notifications(notifications, message.resource) + return data.answer + + def handle_notifications(self, notifications, resource): + paths = map(itemgetter('path'), notifications) + clean_paths = set(map(self._clean_path, paths)) + for path in clean_paths: + if resource != path: + self.fetch(path) + + def _clean_path(self, path): + return path.rsplit('/', 1)[0].encode('utf-8') + + def receive_message(self): + if sys.platform == "darwin": + self.sock.recv(30) + else: + self.sock.recv(7) + return BeautifulSoup(self.sock.recv(1024)) + + def close(self): + self.sock.close() + + +class GenericResourceManager(ResourceManagerBase): + resources = { + '/api/software/version': ['get'], + } + + def __init__(self, sock): + super(GenericResourceManager, self).__init__(sock) + self.notifications = [] + + def handle_notification(self, notification): + self.notifications.append(notification) + + def get_resource_manager(self, resource_manager_class): + resource_manager = resource_manager_class(self.sock, self.resource_values) + resource_manager.handle_notifications(self.notifications, '/api/software/version') + return resource_manager + + @property + def api_version(self): + answer = self.get("/api/software/version") + try: + return answer.software["version"] + except KeyError: + return answer.software['sip6'] + + +class Version1ResourceManager(ResourceManagerBase): + resources = { + '/api/software/version': ['get'], + '/api/system/battery': ['get'], + '/api/bluetooth/friendlyname': ['get'], + '/api/system/auto_connection/enabled': ['get', 'set'], + '/api/system/anc_phone_mode/enabled': ['get', 'set'], + '/api/audio/specific_mode/enabled': ['get', 'set'], + '/api/audio/sound_effect/enabled': ['get', 'set'], + '/api/audio/noise_cancellation/enabled': ['get', 'set'], + } + +class Version2ResourceManager(ResourceManagerBase): + resources = { + '/api/account/username': ['get', 'set'], + '/api/appli_version': ['set'], + '/api/audio/counter': ['get'], + '/api/audio/equalizer/enabled': ['get', 'set'], + '/api/audio/equalizer/preset_id': ['set'], + '/api/audio/equalizer/preset_value': ['set'], + '/api/audio/noise_cancellation/enabled': ['get', 'set'], + '/api/audio/noise_control/enabled': ['get', 'set'], + '/api/audio/noise_control': ['get'], + '/api/audio/noise_control/phone_mode': ['get', 'set'], + '/api/audio/noise': ['get'], + '/api/audio/param_equalizer/value': ['set'], + '/api/audio/preset/bypass': ['get', 'set'], + '/api/audio/preset/': ['clear_all'], + '/api/audio/preset/counter': ['get'], + '/api/audio/preset/current': ['get'], + '/api/audio/preset': ['download', 'activate', 'save', 'remove', 'cancel_producer'], + '/api/audio/preset/synchro': ['start', 'stop'], + '/api/audio/smart_audio_tune': ['get', 'set'], + '/api/audio/sound_effect/angle': ['get', 'set'], + '/api/audio/sound_effect/enabled': ['get', 'set'], + '/api/audio/sound_effect': ['get'], + '/api/audio/sound_effect/room_size': ['get', 'set'], + '/api/audio/source': ['get'], + '/api/audio/specific_mode/enabled': ['get', 'set'], + '/api/audio/thumb_equalizer/value': ['get', 'set'], + '/api/audio/track/metadata': ['get', 'force'], + '/api/bluetooth/friendlyname': ['get', 'set'], + '/api/flight_mode': ['get', 'enable', 'disable'], + '/api/software/download_check_state': ['get'], + '/api/software/download_size': ['set'], + '/api/software/tts': ['get', 'enable', 'disable'], + '/api/software/version_checking': ['get'], + '/api/software/version': ['get'], + '/api/system/anc_phone_mode/enabled': ['get', 'set'], + '/api/system/auto_connection/enabled': ['get', 'set'], + '/api/system/auto_power_off': ['get', 'set'], + '/api/system/auto_power_off/presets_list': ['get'], + '/api/system/battery/forecast': ['get'], + '/api/system/battery': ['get'], + '/api/system/bt_address': ['get'], + '/api/system': ['calibrate'], + '/api/system/color': ['get'], + '/api/system/device_type': ['get'], + '/api/system/': ['factory_reset'], + '/api/system/head_detection/enabled': ['get', 'set'], + '/api/system/pi': ['get'], + } + +class DeviceDisconnected(Exception): + pass diff --git a/parrot_zik/status_app_mac.py b/parrot_zik/status_app_mac.py new file mode 100644 index 0000000..dccffe4 --- /dev/null +++ b/parrot_zik/status_app_mac.py @@ -0,0 +1,25 @@ +from Foundation import * +from AppKit import * + +class StatusApp(NSApplication): + + def initMenu(self, menu): + statusbar = NSStatusBar.systemStatusBar() + self.statusitem = statusbar.statusItemWithLength_( + NSVariableStatusItemLength) + + self.mymenu = menu + #add menu to statusitem + self.statusitem.setMenu_(menu.menubarMenu) + self.statusitem.setToolTip_('Parrot Zik Indicator') + + def setIcon(self,icon,icon_directory): + self.icon = NSImage.alloc().initByReferencingFile_( + icon_directory + icon + '.png') + self.icon.setScalesWhenResized_(True) + self.icon.setSize_((20, 20)) + self.statusitem.setImage_(self.icon) + + def clicked_(self, notification): + self.mymenu.actions[notification._.title]() + NSLog('clicked!') diff --git a/parrot_zik_tray b/parrot_zik_tray deleted file mode 100755 index b3deaa2..0000000 --- a/parrot_zik_tray +++ /dev/null @@ -1,474 +0,0 @@ -#!/usr/bin/env python -import functools -from threading import Lock - -import gtk - -import bluetooth_paired_devices -from parrot_zik import BatteryStates -from parrot_zik import ParrotZikVersion1 -from parrot_zik import ParrotZikVersion2 -from parrot_zik import NoiseControlTypes -from bluetooth_paired_devices import connect -from parrot_zik import Rooms -from indicator import MenuItem -from indicator import Menu -from indicator import SysIndicator -import resource_manager - -REFRESH_FREQUENCY = 30000 -RECONNECT_FREQUENCY = 5000 - - -class repeat(object): - def __init__(self, f): - self.f = f - self.id = None - self.lock = Lock() - - def __call__(self, cls): - self.f(cls) - - def start(self, cls, frequency): - self.lock.acquire() - if not self.id: - def run(): - self.f(cls) - return True - - self.id = gtk.timeout_add(frequency, run) - self.lock.release() - - def stop(self): - self.lock.acquire() - if self.id: - gtk.timeout_remove(self.id) - self.id = None - self.lock.release() - - -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: - self.reconnect.stop() - else: - self.info("Trying to connect") - try: - manager = connect() - except bluetooth_paired_devices.BluetoothIsNotOn: - self.info("Bluetooth is turned off") - except bluetooth_paired_devices.DeviceNotConnected: - self.info("Parrot Zik Not connected") - except bluetooth_paired_devices.ConnectionFailure: - self.info("Failed to connect") - else: - if manager.api_version.startswith('1'): - interface = self.version_1_interface - else: - interface = self.version_2_interface - try: - interface.activate(manager) - except resource_manager.DeviceDisconnected: - interface.deactivate() - else: - self.autorefresh(self) - self.autorefresh.start(self, REFRESH_FREQUENCY) - self.reconnect.stop() - - def info(self, message): - self.info_item.set_label(message) - print(message) - - @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.toggle_auto_connection, - 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) - - def activate(self, manager): - self.parrot = self.parrot_class(manager) - self.read_battery() - self.indicator.info("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.battery_level.show() - self.battery_state.show() - self.firmware_version.show() - self.auto_connection.show() - self.indicator.active_interface = self - self.indicator.menu.reposition() - - @property - def parrot_class(self): - raise NotImplementedError - - def deactivate(self): - self.parrot = None - self.battery_level.hide() - self.battery_state.hide() - self.firmware_version.hide() - self.auto_connection.hide() - self.indicator.menu.reposition() - self.indicator.active_interface = None - self.indicator.setIcon("zik-audio-headset") - self.indicator.info('Lost Connection') - self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) - - def toggle_auto_connection(self, widget): - try: - self.parrot.auto_connect = self.auto_connection.get_active() - self.auto_connection.set_active(self.parrot.auto_connect) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def refresh(self): - self.read_battery() - - def read_battery(self): - try: - self.parrot.refresh_battery() - battery_level = self.parrot.battery_level - battery_state = self.parrot.battery_state - except resource_manager.DeviceDisconnected: - self.deactivate() - else: - 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)) - - -class ParrotZikVersion1Interface(ParrotZikBaseInterface): - parrot_class = ParrotZikVersion1 - - def __init__(self, indicator): - super(ParrotZikVersion1Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem( - "Noise Cancellation", self.toggle_noise_cancelation, - checkitem=True, visible=False) - self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, - checkitem=True, visible=False) - self.concert_hall_mode = MenuItem( - "Concert Hall Mode", self.toggle_parrot_concert_hall, - 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, manager): - self.noise_cancelation.show() - self.lou_reed_mode.show() - self.concert_hall_mode.show() - super(ParrotZikVersion1Interface, self).activate(manager) - self.noise_cancelation.set_active(self.parrot.cancel_noise) - 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 toggle_noise_cancelation(self, widget): - try: - self.parrot.cancel_noise = self.noise_cancelation.get_active() - self.noise_cancelation.set_active(self.parrot.cancel_noise) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_lou_reed_mode(self, widget): - try: - 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()) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_parrot_concert_hall(self, widget): - try: - self.parrot.concert_hall = self.concert_hall_mode.get_active() - self.concert_hall_mode.set_active(self.parrot.concert_hall) - except resource_manager.DeviceDisconnected: - self.deactivate() - - -class ParrotZikVersion2Interface(ParrotZikBaseInterface): - parrot_class = ParrotZikVersion2 - - def __init__(self, indicator): - self.room_dirty = False - self.angle_dirty = False - self.noise_cancelation_dirty = False - super(ParrotZikVersion2Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem("Noise Control", None, visible=False) - self.noise_cancelation_submenu = Menu() - self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) - - self.noise_control_cancelation_max = MenuItem( - "Max Calcelation", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True, sensitive=False) - self.noise_control_cancelation_on = MenuItem( - "Normal Cancelation", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True, sensitive=False) - self.noise_control_off = MenuItem( - "Off", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True, sensitive=False) - self.noise_control_street_mode = MenuItem( - "Street Mode", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE), checkitem=True, sensitive=False) - self.noise_control_street_mode_max = MenuItem( - "Street Mode Max", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE_MAX), checkitem=True, sensitive=False) - self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) - self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) - self.noise_cancelation_submenu.append(self.noise_control_off) - self.noise_cancelation_submenu.append(self.noise_control_street_mode) - self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) - - self.room_sound_effect = MenuItem( - "Room Sound Effect", None, 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, checkitem=True) - self.rooms = MenuItem("Rooms", None, checkitem=False) - self.angle = MenuItem("Angle", None, 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", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) - self.jazz_mode = MenuItem( - "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) - self.living_mode = MenuItem( - "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) - self.silent_mode = MenuItem( - "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), 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.angle_submenu = Menu() - self.angle.set_submenu(self.angle_submenu) - self.angle_30 = MenuItem( - "30", functools.partial(self.toggle_angle, 30), checkitem=True) - self.angle_60 = MenuItem( - "60", functools.partial(self.toggle_angle, 60), checkitem=True) - self.angle_90 = MenuItem( - "90", functools.partial(self.toggle_angle, 90), checkitem=True) - self.angle_120 = MenuItem( - "120", functools.partial(self.toggle_angle, 120), checkitem=True) - self.angle_150 = MenuItem( - "150", functools.partial(self.toggle_angle, 150), checkitem=True) - self.angle_180 = MenuItem( - "180", functools.partial(self.toggle_angle, 180), 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, - checkitem=True, visible=False) - self.indicator.menu.append(self.room_sound_effect) - self.indicator.menu.append(self.noise_cancelation) - self.indicator.menu.append(self.flight_mode) - - def activate(self, manager): - self.noise_cancelation.show() - self.flight_mode.show() - self.room_sound_effect.show() - super(ParrotZikVersion2Interface, self).activate(manager) - self._read_noise_cancelation() - 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.flight_mode.hide() - self.room_sound_effect.hide() - super(ParrotZikVersion2Interface, self).deactivate() - - def toggle_flight_mode(self, widget): - try: - self.parrot.flight_mode = self.flight_mode.get_active() - self.flight_mode.set_active(self.parrot.flight_mode) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_room(self, room, widget): - try: - if not self.room_dirty: - self.parrot.room = room - self.room_dirty = True - self._read_sound_effect_room() - self.room_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - 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): - try: - 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) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_angle(self, angle, widget): - try: - if not self.angle_dirty: - self.parrot.angle = angle - self.angle_dirty = True - self._read_sound_effect_angle() - self.angle_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - 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) - - def toggle_noise_cancelation(self, noise_calcelation, widget): - try: - if not self.noise_cancelation_dirty: - self.parrot.noise_control = noise_calcelation - self.noise_cancelation_dirty = True - self._read_noise_cancelation() - self.noise_cancelation_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - def _read_noise_cancelation(self): - active_noise_control = self.parrot.noise_control - noise_control_to_menuitem_map = ( - (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), - (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), - (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), - (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), - (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), - ) - for noise_control, menu_item in noise_control_to_menuitem_map: - menu_item.set_active(active_noise_control == noise_control) - - -if __name__ == "__main__": - try: - indicator = ParrotZikIndicator() - indicator.main() - except KeyboardInterrupt: - pass diff --git a/resource_manager.py b/resource_manager.py deleted file mode 100644 index daf6ecd..0000000 --- a/resource_manager.py +++ /dev/null @@ -1,176 +0,0 @@ -import bluetooth -from operator import itemgetter -import sys - -from BeautifulSoup import BeautifulSoup - -from message import Message - - -class ResourceManagerBase(object): - resources = [ - ] - - def __init__(self, socket, resource_values=None): - self.sock = socket - self.resource_values = resource_values or {} - - def get(self, resource): - try: - return self.resource_values[resource] - except KeyError: - return self.fetch(resource) - - def fetch(self, resource): - result = self.send_message(self._create_message(resource, 'get')) - self.resource_values[resource] = result - return result - - def toggle_on(self, resource): - self.send_message(self._create_message(resource, 'enable')) - self.fetch(resource) - - def toggle_off(self, resource): - self.send_message(self._create_message(resource, 'disable')) - self.fetch(resource) - - def set(self, resource, arg): - self.send_message(self._create_message(resource, 'set', arg)) - self.fetch(resource) - - def _create_message(self, resource, method, arg=None): - assert resource in self.resources, 'Unknown resource {}'.format(resource) - assert method in self.resources[resource], 'Unhandled method {} for {}'.format(method, resource) - return Message(resource, method, arg) - - def send_message(self, message): - try: - self.sock.send(str(message)) - return self.get_answer(message) - except bluetooth.btcommon.BluetoothError: - raise DeviceDisconnected - - def get_answer(self, message): - data = self.receive_message() - notifications = [] - while not data.answer: - if data.notify: - notifications.append(data.notify) - else: - raise AssertionError('Unknown response') - data = self.receive_message() - self.handle_notifications(notifications, message.resource) - return data.answer - - def handle_notifications(self, notifications, resource): - paths = map(itemgetter('path'), notifications) - clean_paths = set(map(self._clean_path, paths)) - for path in clean_paths: - if resource != path: - self.fetch(path) - - def _clean_path(self, path): - return path.rsplit('/', 1)[0].encode('utf-8') - - def receive_message(self): - if sys.platform == "darwin": - self.sock.recv(30) - else: - self.sock.recv(7) - return BeautifulSoup(self.sock.recv(1024)) - - def close(self): - self.sock.close() - - -class GenericResourceManager(ResourceManagerBase): - resources = { - '/api/software/version': ['get'], - } - - def __init__(self, sock): - super(GenericResourceManager, self).__init__(sock) - self.notifications = [] - - def handle_notification(self, notification): - self.notifications.append(notification) - - def get_resource_manager(self, resource_manager_class): - resource_manager = resource_manager_class(self.sock, self.resource_values) - resource_manager.handle_notifications(self.notifications, '/api/software/version') - return resource_manager - - @property - def api_version(self): - answer = self.get("/api/software/version") - try: - return answer.software["version"] - except KeyError: - return answer.software['sip6'] - - -class Version1ResourceManager(ResourceManagerBase): - resources = { - '/api/software/version': ['get'], - '/api/system/battery': ['get'], - '/api/bluetooth/friendlyname': ['get'], - '/api/system/auto_connection/enabled': ['get', 'set'], - '/api/system/anc_phone_mode/enabled': ['get', 'set'], - '/api/audio/specific_mode/enabled': ['get', 'set'], - '/api/audio/sound_effect/enabled': ['get', 'set'], - '/api/audio/noise_cancellation/enabled': ['get', 'set'], - } - -class Version2ResourceManager(ResourceManagerBase): - resources = { - '/api/account/username': ['get', 'set'], - '/api/appli_version': ['set'], - '/api/audio/counter': ['get'], - '/api/audio/equalizer/enabled': ['get', 'set'], - '/api/audio/equalizer/preset_id': ['set'], - '/api/audio/equalizer/preset_value': ['set'], - '/api/audio/noise_cancellation/enabled': ['get', 'set'], - '/api/audio/noise_control/enabled': ['get', 'set'], - '/api/audio/noise_control': ['get'], - '/api/audio/noise_control/phone_mode': ['get', 'set'], - '/api/audio/noise': ['get'], - '/api/audio/param_equalizer/value': ['set'], - '/api/audio/preset/bypass': ['get', 'set'], - '/api/audio/preset/': ['clear_all'], - '/api/audio/preset/counter': ['get'], - '/api/audio/preset/current': ['get'], - '/api/audio/preset': ['download', 'activate', 'save', 'remove', 'cancel_producer'], - '/api/audio/preset/synchro': ['start', 'stop'], - '/api/audio/smart_audio_tune': ['get', 'set'], - '/api/audio/sound_effect/angle': ['get', 'set'], - '/api/audio/sound_effect/enabled': ['get', 'set'], - '/api/audio/sound_effect': ['get'], - '/api/audio/sound_effect/room_size': ['get', 'set'], - '/api/audio/source': ['get'], - '/api/audio/specific_mode/enabled': ['get', 'set'], - '/api/audio/thumb_equalizer/value': ['get', 'set'], - '/api/audio/track/metadata': ['get', 'force'], - '/api/bluetooth/friendlyname': ['get', 'set'], - '/api/flight_mode': ['get', 'enable', 'disable'], - '/api/software/download_check_state': ['get'], - '/api/software/download_size': ['set'], - '/api/software/tts': ['get', 'enable', 'disable'], - '/api/software/version_checking': ['get'], - '/api/software/version': ['get'], - '/api/system/anc_phone_mode/enabled': ['get', 'set'], - '/api/system/auto_connection/enabled': ['get', 'set'], - '/api/system/auto_power_off': ['get', 'set'], - '/api/system/auto_power_off/presets_list': ['get'], - '/api/system/battery/forecast': ['get'], - '/api/system/battery': ['get'], - '/api/system/bt_address': ['get'], - '/api/system': ['calibrate'], - '/api/system/color': ['get'], - '/api/system/device_type': ['get'], - '/api/system/': ['factory_reset'], - '/api/system/head_detection/enabled': ['get', 'set'], - '/api/system/pi': ['get'], - } - -class DeviceDisconnected(Exception): - pass diff --git a/setup.py b/setup.py index 7156620..19c391b 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( windows=[ { - 'script': 'parrot_zik_tray', + 'script': 'parrot_zik/parrot_zik_tray', 'icon_resources': [(1, "./share/icons/zik/Headphone.ico")], } ], @@ -43,7 +43,6 @@ setup( 'BeautifulSoup', 'bluetooth' ], - py_modules=['parrot_zik', 'message', 'resource_manager'], - - scripts=["parrot_zik_tray"] + packages=['parrot_zik'], + scripts=["parrot_zik/parrot_zik_tray"] ) diff --git a/status_app_mac.py b/status_app_mac.py deleted file mode 100644 index dccffe4..0000000 --- a/status_app_mac.py +++ /dev/null @@ -1,25 +0,0 @@ -from Foundation import * -from AppKit import * - -class StatusApp(NSApplication): - - def initMenu(self, menu): - statusbar = NSStatusBar.systemStatusBar() - self.statusitem = statusbar.statusItemWithLength_( - NSVariableStatusItemLength) - - self.mymenu = menu - #add menu to statusitem - self.statusitem.setMenu_(menu.menubarMenu) - self.statusitem.setToolTip_('Parrot Zik Indicator') - - def setIcon(self,icon,icon_directory): - self.icon = NSImage.alloc().initByReferencingFile_( - icon_directory + icon + '.png') - self.icon.setScalesWhenResized_(True) - self.icon.setSize_((20, 20)) - self.statusitem.setImage_(self.icon) - - def clicked_(self, notification): - self.mymenu.actions[notification._.title]() - NSLog('clicked!') -- cgit v1.2.1 From 793b4d11fe6e7a188d5594cad5f7861225e0dd58 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 11:42:11 +0200 Subject: Refactor. --- parrot_zik/indicator.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/parrot_zik/indicator.py b/parrot_zik/indicator.py index 2691113..e121e92 100644 --- a/parrot_zik/indicator.py +++ b/parrot_zik/indicator.py @@ -40,15 +40,11 @@ class BaseIndicator(object): class WindowsIndicator(BaseIndicator): def __init__(self, icon, menu): - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + '..' - + os.path.sep + 'share' + os.path.sep + 'icons' - + os.path.sep +'zik' + os.path.sep) + self.icon_directory = os.path.join( + os.path.dirname(os.path.realpath(sys.argv[0])), '..', 'share', 'icons', 'zik') self.menu_shown = False - sys.stdout = open(tempfile.gettempdir() - + os.path.sep + "zik_tray_stdout.log", "w") - sys.stderr = open(tempfile.gettempdir() - + os.path.sep + "zik_tray_stderr.log", "w") + sys.stdout = open(os.path.join(tempfile.gettempdir(), "zik_tray_stdout.log", "w")) + sys.stderr = open(os.path.join(tempfile.gettempdir(), "zik_tray_stderr.log", "w")) statusicon = gtk.StatusIcon() statusicon.connect("popup-menu", self.gtk_right_click_event) statusicon.set_tooltip("Parrot Zik") @@ -73,14 +69,9 @@ class WindowsIndicator(BaseIndicator): class LinuxIndicator(BaseIndicator): def __init__(self, icon, menu): import appindicator - self.icon_directory = (os.path.sep + 'usr' + os.path.sep + 'share' - + os.path.sep + 'icons' + os.path.sep+'zik' - + os.path.sep) + self.icon_directory = os.path.join('/', 'usr', 'share', 'icons', 'zik') if not os.path.isdir(self.icon_directory): - self.icon_directory = (os.path.dirname(sys.argv[0]) + os.path.sep + '..' - + os.path.sep + 'share' + os.path.sep - + 'icons' + os.path.sep+'zik' - + os.path.sep) + self.icon_directory = os.path.join(os.path.dirname(sys.argv[0]), '..', 'share', 'icons', 'zik') statusicon = appindicator.Indicator( "new-parrotzik-indicator", "indicator-messages", appindicator.CATEGORY_APPLICATION_STATUS) @@ -107,10 +98,8 @@ class LinuxIndicator(BaseIndicator): class DarwinIndicator(BaseIndicator): def __init__(self, icon, menu): - self.icon_directory = ( - os.path.dirname(os.path.realpath(sys.argv[0])) + os.path.sep + '..' + os.path.sep - + 'share' + os.path.sep + 'icons' + os.path.sep + 'zik' - + os.path.sep) + self.icon_directory = os.path.join( + os.path.dirname(os.path.realpath(sys.argv[0])), '..', 'share', 'icons', 'zik') statusicon = StatusApp.sharedApplication() statusicon.initMenu(menu) super(DarwinIndicator, self).__init__(icon, menu, statusicon) -- cgit v1.2.1 From 21ed2889c4001d7338bfc4e356a567d5471893b1 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 11:52:45 +0200 Subject: Fix package name. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 19c391b..51a83e1 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ setup( ], install_requires=[ - 'BeautifulSoup', 'bluetooth' + 'BeautifulSoup', 'pybluez' ], packages=['parrot_zik'], -- cgit v1.2.1 From b4ff541fd77d4076051e57b748fc5817e0cc1e25 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 12:41:30 +0200 Subject: Make into proper package. --- parrot_zik/bluetooth_paired_devices.py | 2 +- parrot_zik/indicator.py | 6 +++--- parrot_zik/parrot_zik_model.py | 4 ++-- parrot_zik/resource_manager.py | 2 +- setup.py | 3 ++- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index eb1ec09..726731c 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -2,7 +2,7 @@ import sys import re import os -from parrot_zik.resource_manager import GenericResourceManager +from .resource_manager import GenericResourceManager if sys.platform == "darwin": from binplist import binplist diff --git a/parrot_zik/indicator.py b/parrot_zik/indicator.py index e121e92..b6b6bea 100644 --- a/parrot_zik/indicator.py +++ b/parrot_zik/indicator.py @@ -41,7 +41,7 @@ class BaseIndicator(object): class WindowsIndicator(BaseIndicator): def __init__(self, icon, menu): self.icon_directory = os.path.join( - os.path.dirname(os.path.realpath(sys.argv[0])), '..', 'share', 'icons', 'zik') + os.path.dirname(os.path.realpath(sys.argv[0])), 'share', 'icons', 'zik') self.menu_shown = False sys.stdout = open(os.path.join(tempfile.gettempdir(), "zik_tray_stdout.log", "w")) sys.stderr = open(os.path.join(tempfile.gettempdir(), "zik_tray_stderr.log", "w")) @@ -71,7 +71,7 @@ class LinuxIndicator(BaseIndicator): import appindicator self.icon_directory = os.path.join('/', 'usr', 'share', 'icons', 'zik') if not os.path.isdir(self.icon_directory): - self.icon_directory = os.path.join(os.path.dirname(sys.argv[0]), '..', 'share', 'icons', 'zik') + self.icon_directory = os.path.join('share', 'icons', 'zik') statusicon = appindicator.Indicator( "new-parrotzik-indicator", "indicator-messages", appindicator.CATEGORY_APPLICATION_STATUS) @@ -99,7 +99,7 @@ class LinuxIndicator(BaseIndicator): class DarwinIndicator(BaseIndicator): def __init__(self, icon, menu): self.icon_directory = os.path.join( - os.path.dirname(os.path.realpath(sys.argv[0])), '..', 'share', 'icons', 'zik') + os.path.dirname(os.path.realpath(sys.argv[0])), 'share', 'icons', 'zik') statusicon = StatusApp.sharedApplication() statusicon.initMenu(menu) super(DarwinIndicator, self).__init__(icon, menu, statusicon) diff --git a/parrot_zik/parrot_zik_model.py b/parrot_zik/parrot_zik_model.py index e15200f..e6a8bc7 100644 --- a/parrot_zik/parrot_zik_model.py +++ b/parrot_zik/parrot_zik_model.py @@ -1,5 +1,5 @@ -from parrot_zik.resource_manager import Version1ResourceManager -from parrot_zik.resource_manager import Version2ResourceManager +from .resource_manager import Version1ResourceManager +from .resource_manager import Version2ResourceManager class BatteryStates: diff --git a/parrot_zik/resource_manager.py b/parrot_zik/resource_manager.py index 8b63e8c..8a9cd46 100644 --- a/parrot_zik/resource_manager.py +++ b/parrot_zik/resource_manager.py @@ -4,7 +4,7 @@ import sys from BeautifulSoup import BeautifulSoup -from parrot_zik.message import Message +from .message import Message class ResourceManagerBase(object): diff --git a/setup.py b/setup.py index 51a83e1..de72f13 100644 --- a/setup.py +++ b/setup.py @@ -44,5 +44,6 @@ setup( ], packages=['parrot_zik'], - scripts=["parrot_zik/parrot_zik_tray"] + scripts=["parrot_zik/parrot_zik_tray"], + include_package_data=True, ) -- cgit v1.2.1 From 8c724233f95dec5a871bb1eb39da621902d3fcd1 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 12:53:26 +0200 Subject: Refactor. Move. --- parrot_zik/interface/__init__.py | 0 parrot_zik/interface/base.py | 89 ++++++++++ parrot_zik/interface/version1.py | 61 +++++++ parrot_zik/interface/version2.py | 224 ++++++++++++++++++++++++ parrot_zik/parrot_zik_tray | 364 +-------------------------------------- setup.py | 2 +- 6 files changed, 377 insertions(+), 363 deletions(-) create mode 100644 parrot_zik/interface/__init__.py create mode 100644 parrot_zik/interface/base.py create mode 100644 parrot_zik/interface/version1.py create mode 100644 parrot_zik/interface/version2.py diff --git a/parrot_zik/interface/__init__.py b/parrot_zik/interface/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/parrot_zik/interface/base.py b/parrot_zik/interface/base.py new file mode 100644 index 0000000..9ddf47a --- /dev/null +++ b/parrot_zik/interface/base.py @@ -0,0 +1,89 @@ +from .. import resource_manager +from ..indicator import MenuItem +from ..parrot_zik_model import BatteryStates + +RECONNECT_FREQUENCY = 5000 + + +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.toggle_auto_connection, + 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) + + def activate(self, manager): + self.parrot = self.parrot_class(manager) + self.read_battery() + self.indicator.info("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.battery_level.show() + self.battery_state.show() + self.firmware_version.show() + self.auto_connection.show() + self.indicator.active_interface = self + self.indicator.menu.reposition() + + @property + def parrot_class(self): + raise NotImplementedError + + def deactivate(self): + self.parrot = None + self.battery_level.hide() + self.battery_state.hide() + self.firmware_version.hide() + self.auto_connection.hide() + self.indicator.menu.reposition() + self.indicator.active_interface = None + self.indicator.setIcon("zik-audio-headset") + self.indicator.info('Lost Connection') + self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) + + def toggle_auto_connection(self, widget): + try: + self.parrot.auto_connect = self.auto_connection.get_active() + self.auto_connection.set_active(self.parrot.auto_connect) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def refresh(self): + self.read_battery() + + def read_battery(self): + try: + self.parrot.refresh_battery() + battery_level = self.parrot.battery_level + battery_state = self.parrot.battery_state + except resource_manager.DeviceDisconnected: + self.deactivate() + else: + 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)) diff --git a/parrot_zik/interface/version1.py b/parrot_zik/interface/version1.py new file mode 100644 index 0000000..5a00441 --- /dev/null +++ b/parrot_zik/interface/version1.py @@ -0,0 +1,61 @@ +from .. import resource_manager +from ..indicator import MenuItem +from ..interface.base import ParrotZikBaseInterface +from ..parrot_zik_model import ParrotZikVersion1 + + +class ParrotZikVersion1Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion1 + + def __init__(self, indicator): + super(ParrotZikVersion1Interface, self).__init__(indicator) + self.noise_cancelation = MenuItem( + "Noise Cancellation", self.toggle_noise_cancelation, + checkitem=True, visible=False) + self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, + checkitem=True, visible=False) + self.concert_hall_mode = MenuItem( + "Concert Hall Mode", self.toggle_parrot_concert_hall, + 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, manager): + self.noise_cancelation.show() + self.lou_reed_mode.show() + self.concert_hall_mode.show() + super(ParrotZikVersion1Interface, self).activate(manager) + self.noise_cancelation.set_active(self.parrot.cancel_noise) + 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 toggle_noise_cancelation(self, widget): + try: + self.parrot.cancel_noise = self.noise_cancelation.get_active() + self.noise_cancelation.set_active(self.parrot.cancel_noise) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_lou_reed_mode(self, widget): + try: + 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()) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_parrot_concert_hall(self, widget): + try: + self.parrot.concert_hall = self.concert_hall_mode.get_active() + self.concert_hall_mode.set_active(self.parrot.concert_hall) + except resource_manager.DeviceDisconnected: + self.deactivate() diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py new file mode 100644 index 0000000..fc4af21 --- /dev/null +++ b/parrot_zik/interface/version2.py @@ -0,0 +1,224 @@ +import functools + +from .. import resource_manager +from ..indicator import MenuItem, Menu +from .base import ParrotZikBaseInterface +from ..parrot_zik_model import ParrotZikVersion2 +from ..parrot_zik_model import NoiseControlTypes +from ..parrot_zik_model import Rooms + + +class ParrotZikVersion2Interface(ParrotZikBaseInterface): + parrot_class = ParrotZikVersion2 + + def __init__(self, indicator): + self.room_dirty = False + self.angle_dirty = False + self.noise_cancelation_dirty = False + super(ParrotZikVersion2Interface, self).__init__(indicator) + self.noise_cancelation = MenuItem("Noise Control", None, visible=False) + self.noise_cancelation_submenu = Menu() + self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) + + self.noise_control_cancelation_max = MenuItem( + "Max Calcelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True, sensitive=False) + self.noise_control_cancelation_on = MenuItem( + "Normal Cancelation", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True, sensitive=False) + self.noise_control_off = MenuItem( + "Off", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True, sensitive=False) + self.noise_control_street_mode = MenuItem( + "Street Mode", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE), checkitem=True, sensitive=False) + self.noise_control_street_mode_max = MenuItem( + "Street Mode Max", functools.partial( + self.toggle_noise_cancelation, + NoiseControlTypes.STREET_MODE_MAX), checkitem=True, sensitive=False) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) + self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) + self.noise_cancelation_submenu.append(self.noise_control_off) + self.noise_cancelation_submenu.append(self.noise_control_street_mode) + self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) + + self.room_sound_effect = MenuItem( + "Room Sound Effect", None, 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, checkitem=True) + self.rooms = MenuItem("Rooms", None, checkitem=False) + self.angle = MenuItem("Angle", None, 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", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) + self.jazz_mode = MenuItem( + "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) + self.living_mode = MenuItem( + "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) + self.silent_mode = MenuItem( + "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), 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.angle_submenu = Menu() + self.angle.set_submenu(self.angle_submenu) + self.angle_30 = MenuItem( + "30", functools.partial(self.toggle_angle, 30), checkitem=True) + self.angle_60 = MenuItem( + "60", functools.partial(self.toggle_angle, 60), checkitem=True) + self.angle_90 = MenuItem( + "90", functools.partial(self.toggle_angle, 90), checkitem=True) + self.angle_120 = MenuItem( + "120", functools.partial(self.toggle_angle, 120), checkitem=True) + self.angle_150 = MenuItem( + "150", functools.partial(self.toggle_angle, 150), checkitem=True) + self.angle_180 = MenuItem( + "180", functools.partial(self.toggle_angle, 180), 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, + checkitem=True, visible=False) + self.indicator.menu.append(self.room_sound_effect) + self.indicator.menu.append(self.noise_cancelation) + self.indicator.menu.append(self.flight_mode) + + def activate(self, manager): + self.noise_cancelation.show() + self.flight_mode.show() + self.room_sound_effect.show() + super(ParrotZikVersion2Interface, self).activate(manager) + self._read_noise_cancelation() + 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.flight_mode.hide() + self.room_sound_effect.hide() + super(ParrotZikVersion2Interface, self).deactivate() + + def toggle_flight_mode(self, widget): + try: + self.parrot.flight_mode = self.flight_mode.get_active() + self.flight_mode.set_active(self.parrot.flight_mode) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_room(self, room, widget): + try: + if not self.room_dirty: + self.parrot.room = room + self.room_dirty = True + self._read_sound_effect_room() + self.room_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + 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): + try: + 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) + except resource_manager.DeviceDisconnected: + self.deactivate() + + def toggle_angle(self, angle, widget): + try: + if not self.angle_dirty: + self.parrot.angle = angle + self.angle_dirty = True + self._read_sound_effect_angle() + self.angle_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + 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) + + def toggle_noise_cancelation(self, noise_calcelation, widget): + try: + if not self.noise_cancelation_dirty: + self.parrot.noise_control = noise_calcelation + self.noise_cancelation_dirty = True + self._read_noise_cancelation() + self.noise_cancelation_dirty = False + except resource_manager.DeviceDisconnected: + self.deactivate() + + def _read_noise_cancelation(self): + active_noise_control = self.parrot.noise_control + noise_control_to_menuitem_map = ( + (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), + (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), + (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), + (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), + (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), + ) + for noise_control, menu_item in noise_control_to_menuitem_map: + menu_item.set_active(active_noise_control == noise_control) diff --git a/parrot_zik/parrot_zik_tray b/parrot_zik/parrot_zik_tray index dcdacd0..ae57e4d 100755 --- a/parrot_zik/parrot_zik_tray +++ b/parrot_zik/parrot_zik_tray @@ -1,15 +1,11 @@ #!/usr/bin/env python -import functools from threading import Lock import gtk +from parrot_zik.interface.version1 import ParrotZikVersion1Interface +from parrot_zik.interface.version2 import ParrotZikVersion2Interface from parrot_zik import resource_manager from parrot_zik import bluetooth_paired_devices -from parrot_zik.parrot_zik_model import BatteryStates -from parrot_zik.parrot_zik_model import ParrotZikVersion1 -from parrot_zik.parrot_zik_model import ParrotZikVersion2 -from parrot_zik.parrot_zik_model import NoiseControlTypes -from parrot_zik.parrot_zik_model import Rooms from parrot_zik.indicator import MenuItem from parrot_zik.indicator import Menu from parrot_zik.indicator import SysIndicator @@ -107,362 +103,6 @@ class ParrotZikIndicator(SysIndicator): 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.toggle_auto_connection, - 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) - - def activate(self, manager): - self.parrot = self.parrot_class(manager) - self.read_battery() - self.indicator.info("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.battery_level.show() - self.battery_state.show() - self.firmware_version.show() - self.auto_connection.show() - self.indicator.active_interface = self - self.indicator.menu.reposition() - - @property - def parrot_class(self): - raise NotImplementedError - - def deactivate(self): - self.parrot = None - self.battery_level.hide() - self.battery_state.hide() - self.firmware_version.hide() - self.auto_connection.hide() - self.indicator.menu.reposition() - self.indicator.active_interface = None - self.indicator.setIcon("zik-audio-headset") - self.indicator.info('Lost Connection') - self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY) - - def toggle_auto_connection(self, widget): - try: - self.parrot.auto_connect = self.auto_connection.get_active() - self.auto_connection.set_active(self.parrot.auto_connect) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def refresh(self): - self.read_battery() - - def read_battery(self): - try: - self.parrot.refresh_battery() - battery_level = self.parrot.battery_level - battery_state = self.parrot.battery_state - except resource_manager.DeviceDisconnected: - self.deactivate() - else: - 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)) - - -class ParrotZikVersion1Interface(ParrotZikBaseInterface): - parrot_class = ParrotZikVersion1 - - def __init__(self, indicator): - super(ParrotZikVersion1Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem( - "Noise Cancellation", self.toggle_noise_cancelation, - checkitem=True, visible=False) - self.lou_reed_mode = MenuItem("Lou Reed Mode", self.toggle_lou_reed_mode, - checkitem=True, visible=False) - self.concert_hall_mode = MenuItem( - "Concert Hall Mode", self.toggle_parrot_concert_hall, - 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, manager): - self.noise_cancelation.show() - self.lou_reed_mode.show() - self.concert_hall_mode.show() - super(ParrotZikVersion1Interface, self).activate(manager) - self.noise_cancelation.set_active(self.parrot.cancel_noise) - 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 toggle_noise_cancelation(self, widget): - try: - self.parrot.cancel_noise = self.noise_cancelation.get_active() - self.noise_cancelation.set_active(self.parrot.cancel_noise) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_lou_reed_mode(self, widget): - try: - 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()) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_parrot_concert_hall(self, widget): - try: - self.parrot.concert_hall = self.concert_hall_mode.get_active() - self.concert_hall_mode.set_active(self.parrot.concert_hall) - except resource_manager.DeviceDisconnected: - self.deactivate() - - -class ParrotZikVersion2Interface(ParrotZikBaseInterface): - parrot_class = ParrotZikVersion2 - - def __init__(self, indicator): - self.room_dirty = False - self.angle_dirty = False - self.noise_cancelation_dirty = False - super(ParrotZikVersion2Interface, self).__init__(indicator) - self.noise_cancelation = MenuItem("Noise Control", None, visible=False) - self.noise_cancelation_submenu = Menu() - self.noise_cancelation.set_submenu(self.noise_cancelation_submenu) - - self.noise_control_cancelation_max = MenuItem( - "Max Calcelation", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True, sensitive=False) - self.noise_control_cancelation_on = MenuItem( - "Normal Cancelation", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True, sensitive=False) - self.noise_control_off = MenuItem( - "Off", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True, sensitive=False) - self.noise_control_street_mode = MenuItem( - "Street Mode", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE), checkitem=True, sensitive=False) - self.noise_control_street_mode_max = MenuItem( - "Street Mode Max", functools.partial( - self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE_MAX), checkitem=True, sensitive=False) - self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) - self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) - self.noise_cancelation_submenu.append(self.noise_control_off) - self.noise_cancelation_submenu.append(self.noise_control_street_mode) - self.noise_cancelation_submenu.append(self.noise_control_street_mode_max) - - self.room_sound_effect = MenuItem( - "Room Sound Effect", None, 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, checkitem=True) - self.rooms = MenuItem("Rooms", None, checkitem=False) - self.angle = MenuItem("Angle", None, 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", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True) - self.jazz_mode = MenuItem( - "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True) - self.living_mode = MenuItem( - "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True) - self.silent_mode = MenuItem( - "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), 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.angle_submenu = Menu() - self.angle.set_submenu(self.angle_submenu) - self.angle_30 = MenuItem( - "30", functools.partial(self.toggle_angle, 30), checkitem=True) - self.angle_60 = MenuItem( - "60", functools.partial(self.toggle_angle, 60), checkitem=True) - self.angle_90 = MenuItem( - "90", functools.partial(self.toggle_angle, 90), checkitem=True) - self.angle_120 = MenuItem( - "120", functools.partial(self.toggle_angle, 120), checkitem=True) - self.angle_150 = MenuItem( - "150", functools.partial(self.toggle_angle, 150), checkitem=True) - self.angle_180 = MenuItem( - "180", functools.partial(self.toggle_angle, 180), 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, - checkitem=True, visible=False) - self.indicator.menu.append(self.room_sound_effect) - self.indicator.menu.append(self.noise_cancelation) - self.indicator.menu.append(self.flight_mode) - - def activate(self, manager): - self.noise_cancelation.show() - self.flight_mode.show() - self.room_sound_effect.show() - super(ParrotZikVersion2Interface, self).activate(manager) - self._read_noise_cancelation() - 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.flight_mode.hide() - self.room_sound_effect.hide() - super(ParrotZikVersion2Interface, self).deactivate() - - def toggle_flight_mode(self, widget): - try: - self.parrot.flight_mode = self.flight_mode.get_active() - self.flight_mode.set_active(self.parrot.flight_mode) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_room(self, room, widget): - try: - if not self.room_dirty: - self.parrot.room = room - self.room_dirty = True - self._read_sound_effect_room() - self.room_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - 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): - try: - 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) - except resource_manager.DeviceDisconnected: - self.deactivate() - - def toggle_angle(self, angle, widget): - try: - if not self.angle_dirty: - self.parrot.angle = angle - self.angle_dirty = True - self._read_sound_effect_angle() - self.angle_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - 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) - - def toggle_noise_cancelation(self, noise_calcelation, widget): - try: - if not self.noise_cancelation_dirty: - self.parrot.noise_control = noise_calcelation - self.noise_cancelation_dirty = True - self._read_noise_cancelation() - self.noise_cancelation_dirty = False - except resource_manager.DeviceDisconnected: - self.deactivate() - - def _read_noise_cancelation(self): - active_noise_control = self.parrot.noise_control - noise_control_to_menuitem_map = ( - (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max), - (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on), - (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off), - (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode), - (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max), - ) - for noise_control, menu_item in noise_control_to_menuitem_map: - menu_item.set_active(active_noise_control == noise_control) - if __name__ == "__main__": try: diff --git a/setup.py b/setup.py index de72f13..d4a8d96 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ setup( 'BeautifulSoup', 'pybluez' ], - packages=['parrot_zik'], + packages=['parrot_zik', 'parrot_zik.interface'], scripts=["parrot_zik/parrot_zik_tray"], include_package_data=True, ) -- cgit v1.2.1 From 65f9c06e00c78c382451458ea1d8a9dad1016fb0 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 12:55:18 +0200 Subject: Refactor. Move --- parrot_zik/parrot_zik_tray | 28 +--------------------------- parrot_zik/utils.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 27 deletions(-) create mode 100644 parrot_zik/utils.py diff --git a/parrot_zik/parrot_zik_tray b/parrot_zik/parrot_zik_tray index ae57e4d..914a37e 100755 --- a/parrot_zik/parrot_zik_tray +++ b/parrot_zik/parrot_zik_tray @@ -1,5 +1,4 @@ #!/usr/bin/env python -from threading import Lock import gtk from parrot_zik.interface.version1 import ParrotZikVersion1Interface @@ -9,37 +8,12 @@ from parrot_zik import bluetooth_paired_devices from parrot_zik.indicator import MenuItem from parrot_zik.indicator import Menu from parrot_zik.indicator import SysIndicator +from parrot_zik.utils import repeat REFRESH_FREQUENCY = 30000 RECONNECT_FREQUENCY = 5000 -class repeat(object): - def __init__(self, f): - self.f = f - self.id = None - self.lock = Lock() - - def __call__(self, cls): - self.f(cls) - - def start(self, cls, frequency): - self.lock.acquire() - if not self.id: - def run(): - self.f(cls) - return True - - self.id = gtk.timeout_add(frequency, run) - self.lock.release() - - def stop(self): - self.lock.acquire() - if self.id: - gtk.timeout_remove(self.id) - self.id = None - self.lock.release() - class ParrotZikIndicator(SysIndicator): def __init__(self): diff --git a/parrot_zik/utils.py b/parrot_zik/utils.py new file mode 100644 index 0000000..18b878d --- /dev/null +++ b/parrot_zik/utils.py @@ -0,0 +1,31 @@ +from threading import Lock + +import gtk + + +class repeat(object): + def __init__(self, f): + self.f = f + self.id = None + self.lock = Lock() + + def __call__(self, cls): + self.f(cls) + + def start(self, cls, frequency): + self.lock.acquire() + if not self.id: + def run(): + self.f(cls) + return True + + self.id = gtk.timeout_add(frequency, run) + self.lock.release() + + def stop(self): + self.lock.acquire() + if self.id: + gtk.timeout_remove(self.id) + self.id = None + self.lock.release() + -- cgit v1.2.1 From df5aa3102f9d0257224ee9423afdfd42f00592ac Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 13:20:28 +0200 Subject: Refactor. Move. --- parrot_zik/indicator.py | 243 ----------------------------------- parrot_zik/indicator/__init__.py | 23 ++++ parrot_zik/indicator/base.py | 44 +++++++ parrot_zik/indicator/gtk_wrapping.py | 40 ++++++ parrot_zik/indicator/linux.py | 44 +++++++ parrot_zik/indicator/mac.py | 66 ++++++++++ parrot_zik/indicator/windows.py | 43 +++++++ setup.py | 2 +- 8 files changed, 261 insertions(+), 244 deletions(-) delete mode 100644 parrot_zik/indicator.py create mode 100644 parrot_zik/indicator/__init__.py create mode 100644 parrot_zik/indicator/base.py create mode 100644 parrot_zik/indicator/gtk_wrapping.py create mode 100644 parrot_zik/indicator/linux.py create mode 100644 parrot_zik/indicator/mac.py create mode 100644 parrot_zik/indicator/windows.py diff --git a/parrot_zik/indicator.py b/parrot_zik/indicator.py deleted file mode 100644 index b6b6bea..0000000 --- a/parrot_zik/indicator.py +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/env python - -import sys -import os -import tempfile - -if sys.platform == "linux2" or sys.platform == "win32": - import gtk -elif sys.platform == "darwin": - from Foundation import * - from AppKit import * - from PyObjCTools import AppHelper - from status_app_mac import StatusApp - - -class BaseIndicator(object): - def __init__(self, icon, menu, statusicon): - self.menu = menu - self.statusicon = statusicon - self.setIcon(icon) - - def gtk_right_click_event(self, icon, button, time): - if not self.menu_shown: - self.menu_shown = True - self.menu.popup(None, None, gtk.status_icon_position_menu, - button, time, self.statusicon) - else: - self.menu_shown = False - self.menu.popdown() - - def setIcon(self, name): - raise NotImplementedError - - def main(self): - raise NotImplementedError - - def show_about_dialog(self, widget): - raise NotImplementedError - - -class WindowsIndicator(BaseIndicator): - def __init__(self, icon, menu): - self.icon_directory = os.path.join( - os.path.dirname(os.path.realpath(sys.argv[0])), 'share', 'icons', 'zik') - self.menu_shown = False - sys.stdout = open(os.path.join(tempfile.gettempdir(), "zik_tray_stdout.log", "w")) - sys.stderr = open(os.path.join(tempfile.gettempdir(), "zik_tray_stderr.log", "w")) - statusicon = gtk.StatusIcon() - statusicon.connect("popup-menu", self.gtk_right_click_event) - statusicon.set_tooltip("Parrot Zik") - super(WindowsIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.set_from_file(self.icon_directory + name + '.png') - - def main(self): - gtk.main() - - def show_about_dialog(self, widget): - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class LinuxIndicator(BaseIndicator): - def __init__(self, icon, menu): - import appindicator - self.icon_directory = os.path.join('/', 'usr', 'share', 'icons', 'zik') - if not os.path.isdir(self.icon_directory): - self.icon_directory = os.path.join('share', 'icons', 'zik') - statusicon = appindicator.Indicator( - "new-parrotzik-indicator", "indicator-messages", - appindicator.CATEGORY_APPLICATION_STATUS) - statusicon.set_status(appindicator.STATUS_ACTIVE) - statusicon.set_icon_theme_path(self.icon_directory) - statusicon.set_menu(menu.gtk_menu) - super(LinuxIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.set_icon(name) - - def main(self): - gtk.main() - - def show_about_dialog(self, widget): - about_dialog = gtk.AboutDialog() - about_dialog.set_destroy_with_parent(True) - about_dialog.set_name("Parrot Zik Tray") - about_dialog.set_version("0.3") - about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) - about_dialog.run() - about_dialog.destroy() - - -class DarwinIndicator(BaseIndicator): - def __init__(self, icon, menu): - self.icon_directory = os.path.join( - os.path.dirname(os.path.realpath(sys.argv[0])), 'share', 'icons', 'zik') - statusicon = StatusApp.sharedApplication() - statusicon.initMenu(menu) - super(DarwinIndicator, self).__init__(icon, menu, statusicon) - - def setIcon(self, name): - self.statusicon.setIcon(name, self.icon_directory) - - def main(self): - AppHelper.runEventLoop() - - def show_about_dialog(self, widget): - pass - - -class NSMenu(object): - def __init__(self): - self.actions = {} - self.menubarMenu = NSMenu.alloc().init() - self.menubarMenu.setAutoenablesItems_(False) - - def append(self, menu_item): - self.actions[menu_item.title] = menu_item.action - self.menubarMenu.addItem_(menu_item.nsmenu_item) - - def reposition(self): - # TODO - pass - -class GTKMenu(object): - def __init__(self): - self.gtk_menu = gtk.Menu() - - def append(self, menu_item): - self.gtk_menu.append(menu_item.base_item) - - def reposition(self): - self.gtk_menu.reposition() - - -class MenuItemBase(object): - def __init__(self, base_item, sensitive, visible): - self.base_item = base_item - self.set_sensitive(sensitive) - if visible: - self.show() - else: - self.hide() - - def set_sensitive(self, option): - raise NotImplementedError - - def set_active(self, option): - raise NotImplementedError - - def get_active(self): - raise NotImplementedError - - def set_label(self, option): - raise NotImplementedError - - def show(self): - self.base_item.show() - - 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: - gtk_item = gtk.CheckMenuItem(name) - else: - gtk_item = gtk.MenuItem(name) - if action: - gtk_item.connect("activate", action) - super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) - - def set_sensitive(self, option): - return self.base_item.set_sensitive(option) - - def set_active(self, option): - return self.base_item.set_active(option) - - def get_active(self): - return self.base_item.get_active() - - 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): - self.title = name - self.action = action - nsmenu_item = ( - NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( - name, 'clicked:', '')) - super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) - - def set_sensitive(self, option): - self.base_item.setEnabled_(option) - - def set_active(self, option): - self.base_item.setState_(option) - - def get_active(self): - return self.base_item.state - - def set_label(self, option): - self.title = option - self.base_item.setTitle_(option) - -if sys.platform == 'linux2': - SysIndicator = LinuxIndicator - Menu = GTKMenu - MenuItem = GTKMenuItem -elif sys.platform == 'win32': - SysIndicator = WindowsIndicator - Menu = GTKMenu - MenuItem = GTKMenuItem -elif sys.platform == 'darwin': - SysIndicator = DarwinIndicator - Menu = NSMenu - MenuItem = NSMenuItem -else: - raise Exception('Platform not supported') - -if __name__ == "__main__": - - quit_item = MenuItem("Quit", sys.exit, True) - - menu = Menu() - menu.append(quit_item) - - indicator = SysIndicator(icon="zik-audio-headset", menu=menu) - indicator.main() diff --git a/parrot_zik/indicator/__init__.py b/parrot_zik/indicator/__init__.py new file mode 100644 index 0000000..aeda305 --- /dev/null +++ b/parrot_zik/indicator/__init__.py @@ -0,0 +1,23 @@ +__all__ = ('SysIndicator', 'Menu', 'MenuItem') + +import sys + +if sys.platform == 'linux2': + import linux + import gtk_wrapping + SysIndicator = linux.LinuxIndicator + Menu = gtk_wrapping.GTKMenu + MenuItem = gtk_wrapping.GTKMenuItem +elif sys.platform == 'win32': + import gtk_wrapping + import windows + SysIndicator = windows.WindowsIndicator + Menu = gtk_wrapping.GTKMenu + MenuItem = gtk_wrapping.GTKMenuItem +elif sys.platform == 'darwin': + import mac + SysIndicator = mac.DarwinIndicator + Menu = mac.NSMenu + MenuItem = mac.NSMenuItem +else: + raise Exception('Platform not supported') diff --git a/parrot_zik/indicator/base.py b/parrot_zik/indicator/base.py new file mode 100644 index 0000000..7101790 --- /dev/null +++ b/parrot_zik/indicator/base.py @@ -0,0 +1,44 @@ +class BaseIndicator(object): + def __init__(self, icon, menu, statusicon): + self.menu = menu + self.statusicon = statusicon + self.setIcon(icon) + + def setIcon(self, name): + raise NotImplementedError + + def main(self): + raise NotImplementedError + + def show_about_dialog(self, widget): + raise NotImplementedError + +class MenuItemBase(object): + def __init__(self, base_item, sensitive, visible): + self.base_item = base_item + self.set_sensitive(sensitive) + if visible: + self.show() + else: + self.hide() + + def set_sensitive(self, option): + raise NotImplementedError + + def set_active(self, option): + raise NotImplementedError + + def get_active(self): + raise NotImplementedError + + def set_label(self, option): + raise NotImplementedError + + def show(self): + self.base_item.show() + + def hide(self): + self.base_item.hide() + + def set_submenu(self, menu): + raise NotImplementedError diff --git a/parrot_zik/indicator/gtk_wrapping.py b/parrot_zik/indicator/gtk_wrapping.py new file mode 100644 index 0000000..9494adc --- /dev/null +++ b/parrot_zik/indicator/gtk_wrapping.py @@ -0,0 +1,40 @@ +import gtk + +from .base import MenuItemBase + + +class GTKMenu(object): + def __init__(self): + self.gtk_menu = gtk.Menu() + + def append(self, menu_item): + self.gtk_menu.append(menu_item.base_item) + + def reposition(self): + self.gtk_menu.reposition() + + +class GTKMenuItem(MenuItemBase): + def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): + if checkitem: + gtk_item = gtk.CheckMenuItem(name) + else: + gtk_item = gtk.MenuItem(name) + if action: + gtk_item.connect("activate", action) + super(GTKMenuItem, self).__init__(gtk_item, sensitive, visible) + + def set_sensitive(self, option): + return self.base_item.set_sensitive(option) + + def set_active(self, option): + return self.base_item.set_active(option) + + def get_active(self): + return self.base_item.get_active() + + 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) diff --git a/parrot_zik/indicator/linux.py b/parrot_zik/indicator/linux.py new file mode 100644 index 0000000..cbec1dd --- /dev/null +++ b/parrot_zik/indicator/linux.py @@ -0,0 +1,44 @@ +import os + +import gtk + +from .base import BaseIndicator + + +class LinuxIndicator(BaseIndicator): + def __init__(self, icon, menu): + import appindicator + self.icon_directory = os.path.join('/', 'usr', 'share', 'icons', 'zik') + if not os.path.isdir(self.icon_directory): + self.icon_directory = os.path.join('share', 'icons', 'zik') + statusicon = appindicator.Indicator( + "new-parrotzik-indicator", "indicator-messages", + appindicator.CATEGORY_APPLICATION_STATUS) + statusicon.set_status(appindicator.STATUS_ACTIVE) + statusicon.set_icon_theme_path(self.icon_directory) + statusicon.set_menu(menu.gtk_menu) + super(LinuxIndicator, self).__init__(icon, menu, statusicon) + + def gtk_right_click_event(self, icon, button, time): + if not self.menu_shown: + self.menu_shown = True + self.menu.popup(None, None, gtk.status_icon_position_menu, + button, time, self.statusicon) + else: + self.menu_shown = False + self.menu.poVpdown() + + def setIcon(self, name): + self.statusicon.set_icon(name) + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() diff --git a/parrot_zik/indicator/mac.py b/parrot_zik/indicator/mac.py new file mode 100644 index 0000000..8fdd1e6 --- /dev/null +++ b/parrot_zik/indicator/mac.py @@ -0,0 +1,66 @@ +import os +import sys + +from Foundation import * +from AppKit import * +from PyObjCTools import AppHelper + +from .base import BaseIndicator +from .base import MenuItemBase +from ..status_app_mac import StatusApp + + +class DarwinIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = os.path.join( + os.path.dirname(os.path.realpath(sys.argv[0])), 'share', 'icons', 'zik') + statusicon = StatusApp.sharedApplication() + statusicon.initMenu(menu) + super(DarwinIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.setIcon(name, self.icon_directory) + + def main(self): + AppHelper.runEventLoop() + + def show_about_dialog(self, widget): + pass + + +class NSMenu(object): + def __init__(self): + self.actions = {} + self.menubarMenu = NSMenu.alloc().init() + self.menubarMenu.setAutoenablesItems_(False) + + def append(self, menu_item): + self.actions[menu_item.title] = menu_item.action + self.menubarMenu.addItem_(menu_item.nsmenu_item) + + def reposition(self): + # TODO + pass + + +class NSMenuItem(MenuItemBase): + def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): + self.title = name + self.action = action + nsmenu_item = ( + NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( + name, 'clicked:', '')) + super(NSMenuItem, self).__init__(nsmenu_item, sensitive, visible) + + def set_sensitive(self, option): + self.base_item.setEnabled_(option) + + def set_active(self, option): + self.base_item.setState_(option) + + def get_active(self): + return self.base_item.state + + def set_label(self, option): + self.title = option + self.base_item.setTitle_(option) diff --git a/parrot_zik/indicator/windows.py b/parrot_zik/indicator/windows.py new file mode 100644 index 0000000..0f81e55 --- /dev/null +++ b/parrot_zik/indicator/windows.py @@ -0,0 +1,43 @@ +import sys +import tempfile +import gtk +import os + +from .base import BaseIndicator + + +class WindowsIndicator(BaseIndicator): + def __init__(self, icon, menu): + self.icon_directory = os.path.join( + os.path.dirname(os.path.realpath(sys.argv[0])), 'share', 'icons', 'zik') + self.menu_shown = False + sys.stdout = open(os.path.join(tempfile.gettempdir(), "zik_tray_stdout.log", "w")) + sys.stderr = open(os.path.join(tempfile.gettempdir(), "zik_tray_stderr.log", "w")) + statusicon = gtk.StatusIcon() + statusicon.connect("popup-menu", self.gtk_right_click_event) + statusicon.set_tooltip("Parrot Zik") + super(WindowsIndicator, self).__init__(icon, menu, statusicon) + + def gtk_right_click_event(self, icon, button, time): + if not self.menu_shown: + self.menu_shown = True + self.menu.popup(None, None, gtk.status_icon_position_menu, + button, time, self.statusicon) + else: + self.menu_shown = False + self.menu.poVpdown() + + def setIcon(self, name): + self.statusicon.set_from_file(self.icon_directory + name + '.png') + + def main(self): + gtk.main() + + def show_about_dialog(self, widget): + about_dialog = gtk.AboutDialog() + about_dialog.set_destroy_with_parent(True) + about_dialog.set_name("Parrot Zik Tray") + about_dialog.set_version("0.3") + about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) + about_dialog.run() + about_dialog.destroy() diff --git a/setup.py b/setup.py index d4a8d96..4600764 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ setup( 'BeautifulSoup', 'pybluez' ], - packages=['parrot_zik', 'parrot_zik.interface'], + packages=['parrot_zik', 'parrot_zik.interface', 'parrot_zik.indicator'], scripts=["parrot_zik/parrot_zik_tray"], include_package_data=True, ) -- cgit v1.2.1 From 3b4f022722e43d5821f4d2276018242c88cb1ed3 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 13:30:06 +0200 Subject: Fix quit wrapping. --- parrot_zik/indicator/base.py | 3 +++ parrot_zik/indicator/linux.py | 3 +++ parrot_zik/indicator/mac.py | 3 +++ parrot_zik/indicator/windows.py | 3 +++ parrot_zik/parrot_zik_tray | 5 ++--- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/parrot_zik/indicator/base.py b/parrot_zik/indicator/base.py index 7101790..8204fa9 100644 --- a/parrot_zik/indicator/base.py +++ b/parrot_zik/indicator/base.py @@ -13,6 +13,9 @@ class BaseIndicator(object): def show_about_dialog(self, widget): raise NotImplementedError + def quit(self, _): + raise NotImplementedError + class MenuItemBase(object): def __init__(self, base_item, sensitive, visible): self.base_item = base_item diff --git a/parrot_zik/indicator/linux.py b/parrot_zik/indicator/linux.py index cbec1dd..ff06587 100644 --- a/parrot_zik/indicator/linux.py +++ b/parrot_zik/indicator/linux.py @@ -34,6 +34,9 @@ class LinuxIndicator(BaseIndicator): def main(self): gtk.main() + def quit(self, _): + gtk.main_quit() + def show_about_dialog(self, widget): about_dialog = gtk.AboutDialog() about_dialog.set_destroy_with_parent(True) diff --git a/parrot_zik/indicator/mac.py b/parrot_zik/indicator/mac.py index 8fdd1e6..d28ee26 100644 --- a/parrot_zik/indicator/mac.py +++ b/parrot_zik/indicator/mac.py @@ -27,6 +27,9 @@ class DarwinIndicator(BaseIndicator): def show_about_dialog(self, widget): pass + def quit(self, _): + pass + class NSMenu(object): def __init__(self): diff --git a/parrot_zik/indicator/windows.py b/parrot_zik/indicator/windows.py index 0f81e55..118f620 100644 --- a/parrot_zik/indicator/windows.py +++ b/parrot_zik/indicator/windows.py @@ -33,6 +33,9 @@ class WindowsIndicator(BaseIndicator): def main(self): gtk.main() + def quit(self, _): + gtk.main_quit() + def show_about_dialog(self, widget): about_dialog = gtk.AboutDialog() about_dialog.set_destroy_with_parent(True) diff --git a/parrot_zik/parrot_zik_tray b/parrot_zik/parrot_zik_tray index 914a37e..0e5b951 100755 --- a/parrot_zik/parrot_zik_tray +++ b/parrot_zik/parrot_zik_tray @@ -1,5 +1,4 @@ #!/usr/bin/env python -import gtk from parrot_zik.interface.version1 import ParrotZikVersion1Interface from parrot_zik.interface.version2 import ParrotZikVersion2Interface @@ -26,8 +25,8 @@ class ParrotZikIndicator(SysIndicator): 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) + self.quit_item = MenuItem("Quit", self.quit, checkitem=True) + self.menu.append(self.quit_item) SysIndicator.__init__(self, icon="zik-audio-headset", menu=self.menu) -- cgit v1.2.1 From f291feaa8a33645850818f811ba8d7f9eb9d4c31 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 13:41:06 +0200 Subject: Refactor. --- parrot_zik/indicator/base.py | 3 +- parrot_zik/indicator/linux.py | 3 +- parrot_zik/indicator/mac.py | 3 +- parrot_zik/indicator/windows.py | 3 +- parrot_zik/parrot_zik_tray | 85 ----------------------------------------- parrot_zik/parrot_zik_tray.py | 80 ++++++++++++++++++++++++++++++++++++++ setup.py | 6 ++- 7 files changed, 93 insertions(+), 90 deletions(-) delete mode 100755 parrot_zik/parrot_zik_tray create mode 100755 parrot_zik/parrot_zik_tray.py diff --git a/parrot_zik/indicator/base.py b/parrot_zik/indicator/base.py index 8204fa9..b29368e 100644 --- a/parrot_zik/indicator/base.py +++ b/parrot_zik/indicator/base.py @@ -7,7 +7,8 @@ class BaseIndicator(object): def setIcon(self, name): raise NotImplementedError - def main(self): + @classmethod + def main(cls): raise NotImplementedError def show_about_dialog(self, widget): diff --git a/parrot_zik/indicator/linux.py b/parrot_zik/indicator/linux.py index ff06587..fc0f425 100644 --- a/parrot_zik/indicator/linux.py +++ b/parrot_zik/indicator/linux.py @@ -31,7 +31,8 @@ class LinuxIndicator(BaseIndicator): def setIcon(self, name): self.statusicon.set_icon(name) - def main(self): + @classmethod + def main(cls): gtk.main() def quit(self, _): diff --git a/parrot_zik/indicator/mac.py b/parrot_zik/indicator/mac.py index d28ee26..232e010 100644 --- a/parrot_zik/indicator/mac.py +++ b/parrot_zik/indicator/mac.py @@ -21,7 +21,8 @@ class DarwinIndicator(BaseIndicator): def setIcon(self, name): self.statusicon.setIcon(name, self.icon_directory) - def main(self): + @classmethod + def main(cls): AppHelper.runEventLoop() def show_about_dialog(self, widget): diff --git a/parrot_zik/indicator/windows.py b/parrot_zik/indicator/windows.py index 118f620..79a4ef3 100644 --- a/parrot_zik/indicator/windows.py +++ b/parrot_zik/indicator/windows.py @@ -30,7 +30,8 @@ class WindowsIndicator(BaseIndicator): def setIcon(self, name): self.statusicon.set_from_file(self.icon_directory + name + '.png') - def main(self): + @classmethod + def main(cls): gtk.main() def quit(self, _): diff --git a/parrot_zik/parrot_zik_tray b/parrot_zik/parrot_zik_tray deleted file mode 100755 index 0e5b951..0000000 --- a/parrot_zik/parrot_zik_tray +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python - -from parrot_zik.interface.version1 import ParrotZikVersion1Interface -from parrot_zik.interface.version2 import ParrotZikVersion2Interface -from parrot_zik import resource_manager -from parrot_zik import bluetooth_paired_devices -from parrot_zik.indicator import MenuItem -from parrot_zik.indicator import Menu -from parrot_zik.indicator import SysIndicator -from parrot_zik.utils import repeat - -REFRESH_FREQUENCY = 30000 -RECONNECT_FREQUENCY = 5000 - - - -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_item = MenuItem("Quit", self.quit, checkitem=True) - self.menu.append(self.quit_item) - - SysIndicator.__init__(self, icon="zik-audio-headset", menu=self.menu) - - self.active_interface = None - - @repeat - def reconnect(self): - if self.active_interface: - self.reconnect.stop() - else: - self.info("Trying to connect") - try: - manager = bluetooth_paired_devices.connect() - except bluetooth_paired_devices.BluetoothIsNotOn: - self.info("Bluetooth is turned off") - except bluetooth_paired_devices.DeviceNotConnected: - self.info("Parrot Zik Not connected") - except bluetooth_paired_devices.ConnectionFailure: - self.info("Failed to connect") - else: - if manager.api_version.startswith('1'): - interface = self.version_1_interface - else: - interface = self.version_2_interface - try: - interface.activate(manager) - except resource_manager.DeviceDisconnected: - interface.deactivate() - else: - self.autorefresh(self) - self.autorefresh.start(self, REFRESH_FREQUENCY) - self.reconnect.stop() - - def info(self, message): - self.info_item.set_label(message) - print(message) - - @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) - - -if __name__ == "__main__": - try: - indicator = ParrotZikIndicator() - indicator.main() - except KeyboardInterrupt: - pass diff --git a/parrot_zik/parrot_zik_tray.py b/parrot_zik/parrot_zik_tray.py new file mode 100755 index 0000000..35931d7 --- /dev/null +++ b/parrot_zik/parrot_zik_tray.py @@ -0,0 +1,80 @@ +from parrot_zik.interface.version1 import ParrotZikVersion1Interface +from parrot_zik.interface.version2 import ParrotZikVersion2Interface +from parrot_zik import resource_manager +from parrot_zik import bluetooth_paired_devices +from parrot_zik.indicator import MenuItem +from parrot_zik.indicator import Menu +from parrot_zik.indicator import SysIndicator +from parrot_zik.utils import repeat + +REFRESH_FREQUENCY = 30000 +RECONNECT_FREQUENCY = 5000 + + + +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_item = MenuItem("Quit", self.quit, checkitem=True) + self.menu.append(self.quit_item) + + SysIndicator.__init__(self, icon="zik-audio-headset", menu=self.menu) + + self.active_interface = None + + @repeat + def reconnect(self): + if self.active_interface: + self.reconnect.stop() + else: + self.info("Trying to connect") + try: + manager = bluetooth_paired_devices.connect() + except bluetooth_paired_devices.BluetoothIsNotOn: + self.info("Bluetooth is turned off") + except bluetooth_paired_devices.DeviceNotConnected: + self.info("Parrot Zik Not connected") + except bluetooth_paired_devices.ConnectionFailure: + self.info("Failed to connect") + else: + if manager.api_version.startswith('1'): + interface = self.version_1_interface + else: + interface = self.version_2_interface + try: + interface.activate(manager) + except resource_manager.DeviceDisconnected: + interface.deactivate() + else: + self.autorefresh(self) + self.autorefresh.start(self, REFRESH_FREQUENCY) + self.reconnect.stop() + + def info(self, message): + self.info_item.set_label(message) + print(message) + + @repeat + def autorefresh(self): + if self.active_interface: + self.active_interface.refresh() + else: + self.reconnect.start(self, RECONNECT_FREQUENCY) + self.autorefresh.stop() + + @classmethod + def main(cls): + try: + indicator = cls() + cls.reconnect.start(indicator, RECONNECT_FREQUENCY) + super(ParrotZikIndicator, cls).main() + except KeyboardInterrupt: + pass diff --git a/setup.py b/setup.py index 4600764..89d083a 100644 --- a/setup.py +++ b/setup.py @@ -44,6 +44,10 @@ setup( ], packages=['parrot_zik', 'parrot_zik.interface', 'parrot_zik.indicator'], - scripts=["parrot_zik/parrot_zik_tray"], + entry_points={ + 'console_scripts': [ + 'parrot_zik_tray=parrot_zik.parrot_zik_tray:ParrotZikIndicator.main', + ] + }, include_package_data=True, ) -- cgit v1.2.1 From afa654af0a2d2e6b34b47af52ed214977b7a3e12 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 13:56:44 +0200 Subject: Refactor. Move. --- parrot_zik/interface/base.py | 2 +- parrot_zik/interface/version1.py | 2 +- parrot_zik/interface/version2.py | 6 +- parrot_zik/model/__init__.py | 0 parrot_zik/model/base.py | 58 ++++++++++ parrot_zik/model/version1.py | 48 +++++++++ parrot_zik/model/version2.py | 118 +++++++++++++++++++++ parrot_zik/parrot_zik_model.py | 222 --------------------------------------- setup.py | 2 +- 9 files changed, 230 insertions(+), 228 deletions(-) create mode 100644 parrot_zik/model/__init__.py create mode 100644 parrot_zik/model/base.py create mode 100644 parrot_zik/model/version1.py create mode 100644 parrot_zik/model/version2.py delete mode 100644 parrot_zik/parrot_zik_model.py diff --git a/parrot_zik/interface/base.py b/parrot_zik/interface/base.py index 9ddf47a..1611874 100644 --- a/parrot_zik/interface/base.py +++ b/parrot_zik/interface/base.py @@ -1,6 +1,6 @@ from .. import resource_manager from ..indicator import MenuItem -from ..parrot_zik_model import BatteryStates +from ..model.base import BatteryStates RECONNECT_FREQUENCY = 5000 diff --git a/parrot_zik/interface/version1.py b/parrot_zik/interface/version1.py index 5a00441..1af71ec 100644 --- a/parrot_zik/interface/version1.py +++ b/parrot_zik/interface/version1.py @@ -1,7 +1,7 @@ from .. import resource_manager from ..indicator import MenuItem from ..interface.base import ParrotZikBaseInterface -from ..parrot_zik_model import ParrotZikVersion1 +from ..model.version1 import ParrotZikVersion1 class ParrotZikVersion1Interface(ParrotZikBaseInterface): diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py index fc4af21..ff21004 100644 --- a/parrot_zik/interface/version2.py +++ b/parrot_zik/interface/version2.py @@ -3,9 +3,9 @@ import functools from .. import resource_manager from ..indicator import MenuItem, Menu from .base import ParrotZikBaseInterface -from ..parrot_zik_model import ParrotZikVersion2 -from ..parrot_zik_model import NoiseControlTypes -from ..parrot_zik_model import Rooms +from ..model.version2 import ParrotZikVersion2 +from ..model.version2 import NoiseControlTypes +from ..model.version2 import Rooms class ParrotZikVersion2Interface(ParrotZikBaseInterface): diff --git a/parrot_zik/model/__init__.py b/parrot_zik/model/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/parrot_zik/model/base.py b/parrot_zik/model/base.py new file mode 100644 index 0000000..0cd4652 --- /dev/null +++ b/parrot_zik/model/base.py @@ -0,0 +1,58 @@ +class ParrotZikBase(object): + def __init__(self, resource_manager): + self.resource_manager = resource_manager + + @property + def version(self): + return self.resource_manager.api_version + + def refresh_battery(self): + self.resource_manager.fetch('/api/system/battery') + + @property + def battery_state(self): + answer = self.resource_manager.get("/api/system/battery") + return answer.system.battery["state"] + + def get_battery_level(self, field_name): + answer = self.resource_manager.get("/api/system/battery") + return int(answer.system.battery[field_name]) + + @property + def friendly_name(self): + answer = self.resource_manager.get("/api/bluetooth/friendlyname") + return answer.bluetooth["friendlyname"] + + @property + def auto_connect(self): + answer = self.resource_manager.get("/api/system/auto_connection/enabled") + return self._result_to_bool( + answer.system.auto_connection["enabled"]) + + @auto_connect.setter + def auto_connect(self, arg): + self.resource_manager.set("/api/system/auto_connection/enabled", arg) + + @property + def anc_phone_mode(self): + answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") + return self._result_to_bool( + answer.system.anc_phone_mode["enabled"]) + + def _result_to_bool(self, result): + if result == "true": + return True + elif result == "false": + return False + else: + raise AssertionError(result) + +class BatteryStates: + CHARGED = 'charged' + IN_USE = 'in_use' + CHARGING = 'charging' + representation = { + CHARGED: 'Charged', + IN_USE: 'In Use', + CHARGING: 'Charging', + } diff --git a/parrot_zik/model/version1.py b/parrot_zik/model/version1.py new file mode 100644 index 0000000..b39684f --- /dev/null +++ b/parrot_zik/model/version1.py @@ -0,0 +1,48 @@ +from .base import ParrotZikBase +from ..resource_manager import Version1ResourceManager + + +class ParrotZikVersion1(ParrotZikBase): + def __init__(self, resource_manager): + super(ParrotZikVersion1, self).__init__( + resource_manager.get_resource_manager( + Version1ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['version'] + + @property + def battery_level(self): + return int(self.get_battery_level('level')) + + @property + def lou_reed_mode(self): + answer = self.resource_manager.get("/api/audio/specific_mode/enabled") + return self._result_to_bool( + answer.audio.specific_mode["enabled"]) + + @lou_reed_mode.setter + def lou_reed_mode(self, arg): + self.resource_manager.get("/api/audio/specific_mode/enabled", arg) + + @property + def concert_hall(self): + answer = self.resource_manager.get("/api/audio/sound_effect/enabled") + return self._result_to_bool( + answer.audio.sound_effect["enabled"]) + + @concert_hall.setter + def concert_hall(self, arg): + self.resource_manager.get("/api/audio/sound_effect/enabled", arg) + + @property + def cancel_noise(self): + answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") + return self._result_to_bool( + answer.audio.noise_cancellation["enabled"]) + + @cancel_noise.setter + def cancel_noise(self, arg): + self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) \ No newline at end of file diff --git a/parrot_zik/model/version2.py b/parrot_zik/model/version2.py new file mode 100644 index 0000000..9ef6267 --- /dev/null +++ b/parrot_zik/model/version2.py @@ -0,0 +1,118 @@ +from .base import ParrotZikBase +from ..resource_manager import Version2ResourceManager + + +class ParrotZikVersion2(ParrotZikBase): + def __init__(self, resource_manager): + super(ParrotZikVersion2, self).__init__( + resource_manager.get_resource_manager( + Version2ResourceManager)) + + @property + def version(self): + answer = self.resource_manager.get('/api/software/version') + return answer.software['sip6'] + + @property + def battery_level(self): + return self.get_battery_level('percent') + + @property + def flight_mode(self): + answer = self.resource_manager.get('/api/flight_mode') + return self._result_to_bool(answer.flight_mode['enabled']) + + @flight_mode.setter + def flight_mode(self, arg): + if arg: + self.resource_manager.toggle_on('/api/flight_mode') + else: + self.resource_manager.toggle_off('/api/flight_mode') + + @property + def sound_effect(self): + answer = self.resource_manager.get('/api/audio/sound_effect/enabled') + return self._result_to_bool(answer.audio.sound_effect['enabled']) + + @sound_effect.setter + def sound_effect(self, arg): + self.resource_manager.set('/api/audio/sound_effect/enabled', arg) + + @property + def room(self): + answer = self.resource_manager.get('/api/audio/sound_effect/room_size') + return answer.audio.sound_effect['room_size'] + + @room.setter + def room(self, arg): + self.resource_manager.set('/api/audio/sound_effect/room_size', arg) + + @property + def external_noise(self): + answer = self.resource_manager.get('/api/audio/noise') + return int(answer.audio.noise['external']) + + @property + def internal_noise(self): + answer = self.resource_manager.get('/api/audio/noise') + return int(answer.audio.noise['internal']) + + @property + def angle(self): + answer = self.resource_manager.get('/api/audio/sound_effect/angle') + return int(answer.audio.sound_effect['angle']) + + @angle.setter + def angle(self, arg): + self.resource_manager.set('/api/audio/sound_effect/angle', arg) + + @property + def noise_control(self): + answer = self.resource_manager.get('/api/audio/noise_control') + return NoiseControl.from_noise_control(answer.audio.noise_control) + + @noise_control.setter + def noise_control(self, arg): + pass + + @property + def noise_control_enabled(self): + answer = self.resource_manager.get('/api/audio/noise_control/enabled') + return self._result_to_bool(answer.audio.noise_control['enabled']) + + +class NoiseControl(object): + def __init__(self, type, value): + self.type = type + self.value = value + + @classmethod + def from_noise_control(cls, noise_control): + return cls(noise_control['type'], int(noise_control['value'])) + + def __eq__(self, other): + return self.type == other.type and self.value == other.value + + def __str__(self): + return '{}++{}'.format(self.type, self.value) + + +class NoiseControlTypes: + NOISE_CONTROL_MAX = NoiseControl('anc', 2) + NOISE_CONTROL_ON = NoiseControl('anc', 1) + NOISE_CONTROL_OFF = NoiseControl('off', 1) + STREET_MODE = NoiseControl('aoc', 1) + STREET_MODE_MAX = NoiseControl('aoc', 2) + + +class Rooms: + CONCERT_HALL = 'concert' + JAZZ_CLUB = 'jazz' + LIVING_ROOM = 'living' + SILENT_ROOM = 'silent' + representation = { + CONCERT_HALL: 'Concert Hall', + JAZZ_CLUB: 'Jazz Club', + LIVING_ROOM: 'Living Room', + SILENT_ROOM: 'Silent Room', + } \ No newline at end of file diff --git a/parrot_zik/parrot_zik_model.py b/parrot_zik/parrot_zik_model.py deleted file mode 100644 index e6a8bc7..0000000 --- a/parrot_zik/parrot_zik_model.py +++ /dev/null @@ -1,222 +0,0 @@ -from .resource_manager import Version1ResourceManager -from .resource_manager import Version2ResourceManager - - -class BatteryStates: - CHARGED = 'charged' - IN_USE = 'in_use' - CHARGING = 'charging' - representation = { - CHARGED: 'Charged', - IN_USE: 'In Use', - CHARGING: 'Charging', - } - -class Rooms: - CONCERT_HALL = 'concert' - JAZZ_CLUB = 'jazz' - LIVING_ROOM = 'living' - SILENT_ROOM = 'silent' - representation = { - CONCERT_HALL: 'Concert Hall', - JAZZ_CLUB: 'Jazz Club', - LIVING_ROOM: 'Living Room', - SILENT_ROOM: 'Silent Room', - } - -class NoiseControl(object): - def __init__(self, type, value): - self.type = type - self.value = value - - @classmethod - def from_noise_control(cls, noise_control): - return cls(noise_control['type'], int(noise_control['value'])) - - def __eq__(self, other): - return self.type == other.type and self.value == other.value - - def __str__(self): - return '{}++{}'.format(self.type, self.value) - -class NoiseControlTypes: - NOISE_CONTROL_MAX = NoiseControl('anc', 2) - NOISE_CONTROL_ON = NoiseControl('anc', 1) - NOISE_CONTROL_OFF = NoiseControl('off', 1) - STREET_MODE = NoiseControl('aoc', 1) - STREET_MODE_MAX = NoiseControl('aoc', 2) - - -class ParrotZikBase(object): - def __init__(self, resource_manager): - self.resource_manager = resource_manager - - @property - def version(self): - return self.resource_manager.api_version - - def refresh_battery(self): - self.resource_manager.fetch('/api/system/battery') - - @property - def battery_state(self): - answer = self.resource_manager.get("/api/system/battery") - return answer.system.battery["state"] - - def get_battery_level(self, field_name): - answer = self.resource_manager.get("/api/system/battery") - return int(answer.system.battery[field_name]) - - @property - def friendly_name(self): - answer = self.resource_manager.get("/api/bluetooth/friendlyname") - return answer.bluetooth["friendlyname"] - - @property - def auto_connect(self): - answer = self.resource_manager.get("/api/system/auto_connection/enabled") - return self._result_to_bool( - answer.system.auto_connection["enabled"]) - - @auto_connect.setter - def auto_connect(self, arg): - self.resource_manager.set("/api/system/auto_connection/enabled", arg) - - @property - def anc_phone_mode(self): - answer = self.resource_manager.get("/api/system/anc_phone_mode/enabled") - return self._result_to_bool( - answer.system.anc_phone_mode["enabled"]) - - def _result_to_bool(self, result): - if result == "true": - return True - elif result == "false": - return False - else: - raise AssertionError(result) - - -class ParrotZikVersion1(ParrotZikBase): - def __init__(self, resource_manager): - super(ParrotZikVersion1, self).__init__( - resource_manager.get_resource_manager( - Version1ResourceManager)) - - @property - def version(self): - answer = self.resource_manager.get('/api/software/version') - return answer.software['version'] - - @property - def battery_level(self): - return int(self.get_battery_level('level')) - - @property - def lou_reed_mode(self): - answer = self.resource_manager.get("/api/audio/specific_mode/enabled") - return self._result_to_bool( - answer.audio.specific_mode["enabled"]) - - @lou_reed_mode.setter - def lou_reed_mode(self, arg): - self.resource_manager.get("/api/audio/specific_mode/enabled", arg) - - @property - def concert_hall(self): - answer = self.resource_manager.get("/api/audio/sound_effect/enabled") - return self._result_to_bool( - answer.audio.sound_effect["enabled"]) - - @concert_hall.setter - def concert_hall(self, arg): - self.resource_manager.get("/api/audio/sound_effect/enabled", arg) - - @property - def cancel_noise(self): - answer = self.resource_manager.get("/api/audio/noise_cancellation/enabled") - return self._result_to_bool( - answer.audio.noise_cancellation["enabled"]) - - @cancel_noise.setter - def cancel_noise(self, arg): - self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) - - -class ParrotZikVersion2(ParrotZikBase): - def __init__(self, resource_manager): - super(ParrotZikVersion2, self).__init__( - resource_manager.get_resource_manager( - Version2ResourceManager)) - - @property - def version(self): - answer = self.resource_manager.get('/api/software/version') - return answer.software['sip6'] - - @property - def battery_level(self): - return self.get_battery_level('percent') - - @property - def flight_mode(self): - answer = self.resource_manager.get('/api/flight_mode') - return self._result_to_bool(answer.flight_mode['enabled']) - - @flight_mode.setter - def flight_mode(self, arg): - if arg: - self.resource_manager.toggle_on('/api/flight_mode') - else: - self.resource_manager.toggle_off('/api/flight_mode') - - @property - def sound_effect(self): - answer = self.resource_manager.get('/api/audio/sound_effect/enabled') - return self._result_to_bool(answer.audio.sound_effect['enabled']) - - @sound_effect.setter - def sound_effect(self, arg): - self.resource_manager.set('/api/audio/sound_effect/enabled', arg) - - @property - def room(self): - answer = self.resource_manager.get('/api/audio/sound_effect/room_size') - return answer.audio.sound_effect['room_size'] - - @room.setter - def room(self, arg): - self.resource_manager.set('/api/audio/sound_effect/room_size', arg) - - @property - def external_noise(self): - answer = self.resource_manager.get('/api/audio/noise') - return int(answer.audio.noise['external']) - - @property - def internal_noise(self): - answer = self.resource_manager.get('/api/audio/noise') - return int(answer.audio.noise['internal']) - - @property - def angle(self): - answer = self.resource_manager.get('/api/audio/sound_effect/angle') - return int(answer.audio.sound_effect['angle']) - - @angle.setter - def angle(self, arg): - self.resource_manager.set('/api/audio/sound_effect/angle', arg) - - @property - def noise_control(self): - answer = self.resource_manager.get('/api/audio/noise_control') - return NoiseControl.from_noise_control(answer.audio.noise_control) - - @noise_control.setter - def noise_control(self, arg): - pass - - @property - def noise_control_enabled(self): - answer = self.resource_manager.get('/api/audio/noise_control/enabled') - return self._result_to_bool(answer.audio.noise_control['enabled']) diff --git a/setup.py b/setup.py index 89d083a..d1fd926 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ setup( 'BeautifulSoup', 'pybluez' ], - packages=['parrot_zik', 'parrot_zik.interface', 'parrot_zik.indicator'], + packages=['parrot_zik', 'parrot_zik.interface', 'parrot_zik.indicator', 'parrot_zik.model'], entry_points={ 'console_scripts': [ 'parrot_zik_tray=parrot_zik.parrot_zik_tray:ParrotZikIndicator.main', -- cgit v1.2.1 From 3d06315f862150a978ba3c8a7a5a3b1672b6e89d Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 14:06:02 +0200 Subject: Proper wrap. --- parrot_zik/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parrot_zik/utils.py b/parrot_zik/utils.py index 18b878d..86f52cd 100644 --- a/parrot_zik/utils.py +++ b/parrot_zik/utils.py @@ -1,3 +1,4 @@ +import functools from threading import Lock import gtk @@ -15,10 +16,10 @@ class repeat(object): def start(self, cls, frequency): self.lock.acquire() if not self.id: + @functools.wraps(self.f) def run(): self.f(cls) return True - self.id = gtk.timeout_add(frequency, run) self.lock.release() -- cgit v1.2.1 From 4573f9f3e95a0d79c576e3fe0f34023bbf6f0898 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 14:56:52 +0200 Subject: Implement head detection setting. --- parrot_zik/interface/version2.py | 17 +++++++++++++++++ parrot_zik/model/version2.py | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py index ff21004..c348bb4 100644 --- a/parrot_zik/interface/version2.py +++ b/parrot_zik/interface/version2.py @@ -98,14 +98,23 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, checkitem=True, visible=False) + self.settings = MenuItem("Settings", None, visible=False) + self.settings_submenu = Menu() + self.settings.set_submenu(self.settings_submenu) + + self.head_detection = MenuItem("Head Detection", self.toggle_head_detection, checkitem=True) + self.settings_submenu.append(self.head_detection) + self.indicator.menu.append(self.room_sound_effect) self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.flight_mode) + self.indicator.menu.append(self.settings) def activate(self, manager): self.noise_cancelation.show() self.flight_mode.show() self.room_sound_effect.show() + self.settings.show() super(ParrotZikVersion2Interface, self).activate(manager) self._read_noise_cancelation() self.flight_mode.set_active(self.parrot.flight_mode) @@ -130,6 +139,7 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_cancelation.hide() self.flight_mode.hide() self.room_sound_effect.hide() + self.settings.hide() super(ParrotZikVersion2Interface, self).deactivate() def toggle_flight_mode(self, widget): @@ -222,3 +232,10 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): ) for noise_control, menu_item in noise_control_to_menuitem_map: menu_item.set_active(active_noise_control == noise_control) + + def toggle_head_detection(self, widget): + try: + self.parrot.head_detection = self.head_detection.get_active() + self.head_detection.set_active(self.parrot.head_detection) + except resource_manager.DeviceDisconnected: + self.deactivate() \ No newline at end of file diff --git a/parrot_zik/model/version2.py b/parrot_zik/model/version2.py index 9ef6267..e0bce44 100644 --- a/parrot_zik/model/version2.py +++ b/parrot_zik/model/version2.py @@ -80,6 +80,15 @@ class ParrotZikVersion2(ParrotZikBase): answer = self.resource_manager.get('/api/audio/noise_control/enabled') return self._result_to_bool(answer.audio.noise_control['enabled']) + @property + def head_detection(self): + answer = self.resource_manager.get('/api/system/head_detection/enabled') + return self._result_to_bool(answer.system.head_detection['enabled']) + + @head_detection.setter + def head_detection(self, arg): + self.resource_manager.set('/api/system/head_detection/enabled', arg) + class NoiseControl(object): def __init__(self, type, value): -- cgit v1.2.1 From 814921eabbfb0cdc41baeb62e4b25da10c9e0212 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 15:11:43 +0200 Subject: Fix connection refused error. --- parrot_zik/bluetooth_paired_devices.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index 726731c..f06286a 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -88,7 +88,10 @@ def connect(): host = first_match["host"] sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM) - sock.connect((host, port)) + try: + sock.connect((host, port)) + except bluetooth.btcommon.BluetoothError: + raise ConnectionFailure sock.send('\x00\x03\x00') sock.recv(1024) -- cgit v1.2.1 From 2340cbd0291f6f0f64615a3ed0cb5cfc062ec4f5 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 15:32:31 +0200 Subject: Add more information to unknown response. --- parrot_zik/resource_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parrot_zik/resource_manager.py b/parrot_zik/resource_manager.py index 8a9cd46..4f90fb6 100644 --- a/parrot_zik/resource_manager.py +++ b/parrot_zik/resource_manager.py @@ -57,7 +57,8 @@ class ResourceManagerBase(object): if data.notify: notifications.append(data.notify) else: - raise AssertionError('Unknown response') + raise AssertionError('Unknown response "{}" for {}'.format( + data, message.request_string)) data = self.receive_message() self.handle_notifications(notifications, message.resource) return data.answer -- cgit v1.2.1 From 1e6c7b96695cb69de8655cbe20e8ddb5baa77a32 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 15:33:35 +0200 Subject: Add sound source model. --- parrot_zik/model/version2.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/parrot_zik/model/version2.py b/parrot_zik/model/version2.py index e0bce44..d90d79d 100644 --- a/parrot_zik/model/version2.py +++ b/parrot_zik/model/version2.py @@ -124,4 +124,8 @@ class Rooms: JAZZ_CLUB: 'Jazz Club', LIVING_ROOM: 'Living Room', SILENT_ROOM: 'Silent Room', - } \ No newline at end of file + } + +class SoundSource: + LINE_IN = 'line-in' + A2DP = 'a2dp' -- cgit v1.2.1 From 494e542c8eca97cb01f6e4495588a08136f482a0 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 17:37:54 +0200 Subject: Migrate to newer wersion of beatifulsop. --- parrot_zik/resource_manager.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parrot_zik/resource_manager.py b/parrot_zik/resource_manager.py index 4f90fb6..c2dae2f 100644 --- a/parrot_zik/resource_manager.py +++ b/parrot_zik/resource_manager.py @@ -2,7 +2,7 @@ import bluetooth from operator import itemgetter import sys -from BeautifulSoup import BeautifulSoup +from bs4 import BeautifulSoup from .message import Message diff --git a/setup.py b/setup.py index d1fd926..01fa2c2 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ setup( ], install_requires=[ - 'BeautifulSoup', 'pybluez' + 'beautifulsoup4', 'pybluez' ], packages=['parrot_zik', 'parrot_zik.interface', 'parrot_zik.indicator', 'parrot_zik.model'], -- cgit v1.2.1 From e7089b04e59ae1cf7a24649ec2ef64af56eb7dce Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 17:46:22 +0200 Subject: Use absolute package imports. --- parrot_zik/indicator/__init__.py | 25 ++++++++++--------------- parrot_zik/indicator/gtk_wrapping.py | 2 +- parrot_zik/indicator/linux.py | 2 +- parrot_zik/indicator/mac.py | 6 +++--- parrot_zik/indicator/windows.py | 2 +- parrot_zik/interface/base.py | 6 +++--- parrot_zik/interface/version1.py | 8 ++++---- parrot_zik/interface/version2.py | 12 ++++++------ parrot_zik/model/version1.py | 4 ++-- parrot_zik/model/version2.py | 4 ++-- 10 files changed, 33 insertions(+), 38 deletions(-) diff --git a/parrot_zik/indicator/__init__.py b/parrot_zik/indicator/__init__.py index aeda305..4194dde 100644 --- a/parrot_zik/indicator/__init__.py +++ b/parrot_zik/indicator/__init__.py @@ -2,22 +2,17 @@ __all__ = ('SysIndicator', 'Menu', 'MenuItem') import sys -if sys.platform == 'linux2': - import linux - import gtk_wrapping - SysIndicator = linux.LinuxIndicator - Menu = gtk_wrapping.GTKMenu - MenuItem = gtk_wrapping.GTKMenuItem +if sys.platform in ['linux', 'linux2']: + from parrot_zik.indicator.linux import LinuxIndicator as SysIndicator + from parrot_zik.indicator.gtk_wrapping import GTKMenuItem as MenuItem + from parrot_zik.indicator.gtk_wrapping import GTKMenu as Menu elif sys.platform == 'win32': - import gtk_wrapping - import windows - SysIndicator = windows.WindowsIndicator - Menu = gtk_wrapping.GTKMenu - MenuItem = gtk_wrapping.GTKMenuItem + from parrot_zik.indicator.windows import WindowsIndicator as SysIndicator + from parrot_zik.indicator.gtk_wrapping import GTKMenuItem as MenuItem + from parrot_zik.indicator.gtk_wrapping import GTKMenu as Menu elif sys.platform == 'darwin': - import mac - SysIndicator = mac.DarwinIndicator - Menu = mac.NSMenu - MenuItem = mac.NSMenuItem + from parrot_zik.indicator.mac import DarwinIndicator as SysIndicator + from parrot_zik.indicator.mac import NSMenuItem as MenuItem + from parrot_zik.indicator.mac import NSMenu as Menu else: raise Exception('Platform not supported') diff --git a/parrot_zik/indicator/gtk_wrapping.py b/parrot_zik/indicator/gtk_wrapping.py index 9494adc..ce78c1d 100644 --- a/parrot_zik/indicator/gtk_wrapping.py +++ b/parrot_zik/indicator/gtk_wrapping.py @@ -1,6 +1,6 @@ import gtk -from .base import MenuItemBase +from parrot_zik.indicator.base import MenuItemBase class GTKMenu(object): diff --git a/parrot_zik/indicator/linux.py b/parrot_zik/indicator/linux.py index fc0f425..278f781 100644 --- a/parrot_zik/indicator/linux.py +++ b/parrot_zik/indicator/linux.py @@ -2,7 +2,7 @@ import os import gtk -from .base import BaseIndicator +from parrot_zik.indicator.base import BaseIndicator class LinuxIndicator(BaseIndicator): diff --git a/parrot_zik/indicator/mac.py b/parrot_zik/indicator/mac.py index 232e010..ceeacb0 100644 --- a/parrot_zik/indicator/mac.py +++ b/parrot_zik/indicator/mac.py @@ -5,9 +5,9 @@ from Foundation import * from AppKit import * from PyObjCTools import AppHelper -from .base import BaseIndicator -from .base import MenuItemBase -from ..status_app_mac import StatusApp +from parrot_zik.indicator.base import BaseIndicator +from parrot_zik.indicator.base import MenuItemBase +from parrot_zik.status_app_mac import StatusApp class DarwinIndicator(BaseIndicator): diff --git a/parrot_zik/indicator/windows.py b/parrot_zik/indicator/windows.py index 79a4ef3..f10c91a 100644 --- a/parrot_zik/indicator/windows.py +++ b/parrot_zik/indicator/windows.py @@ -3,7 +3,7 @@ import tempfile import gtk import os -from .base import BaseIndicator +from parrot_zik.indicator.base import BaseIndicator class WindowsIndicator(BaseIndicator): diff --git a/parrot_zik/interface/base.py b/parrot_zik/interface/base.py index 1611874..225e53f 100644 --- a/parrot_zik/interface/base.py +++ b/parrot_zik/interface/base.py @@ -1,6 +1,6 @@ -from .. import resource_manager -from ..indicator import MenuItem -from ..model.base import BatteryStates +from parrot_zik import resource_manager +from parrot_zik.indicator import MenuItem +from parrot_zik.model.base import BatteryStates RECONNECT_FREQUENCY = 5000 diff --git a/parrot_zik/interface/version1.py b/parrot_zik/interface/version1.py index 1af71ec..6ddd1b5 100644 --- a/parrot_zik/interface/version1.py +++ b/parrot_zik/interface/version1.py @@ -1,7 +1,7 @@ -from .. import resource_manager -from ..indicator import MenuItem -from ..interface.base import ParrotZikBaseInterface -from ..model.version1 import ParrotZikVersion1 +from parrot_zik import resource_manager +from parrot_zik.indicator import MenuItem +from parrot_zik.interface.base import ParrotZikBaseInterface +from parrot_zik.model.version1 import ParrotZikVersion1 class ParrotZikVersion1Interface(ParrotZikBaseInterface): diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py index c348bb4..74fdcc9 100644 --- a/parrot_zik/interface/version2.py +++ b/parrot_zik/interface/version2.py @@ -1,11 +1,11 @@ import functools -from .. import resource_manager -from ..indicator import MenuItem, Menu -from .base import ParrotZikBaseInterface -from ..model.version2 import ParrotZikVersion2 -from ..model.version2 import NoiseControlTypes -from ..model.version2 import Rooms +from parrot_zik import resource_manager +from parrot_zik.indicator import MenuItem, Menu +from parrot_zik.interface.base import ParrotZikBaseInterface +from parrot_zik.model.version2 import ParrotZikVersion2 +from parrot_zik.model.version2 import NoiseControlTypes +from parrot_zik.model.version2 import Rooms class ParrotZikVersion2Interface(ParrotZikBaseInterface): diff --git a/parrot_zik/model/version1.py b/parrot_zik/model/version1.py index b39684f..f0197e9 100644 --- a/parrot_zik/model/version1.py +++ b/parrot_zik/model/version1.py @@ -1,5 +1,5 @@ -from .base import ParrotZikBase -from ..resource_manager import Version1ResourceManager +from parrot_zik.model.base import ParrotZikBase +from parrot_zik.resource_manager import Version1ResourceManager class ParrotZikVersion1(ParrotZikBase): diff --git a/parrot_zik/model/version2.py b/parrot_zik/model/version2.py index d90d79d..11b4d51 100644 --- a/parrot_zik/model/version2.py +++ b/parrot_zik/model/version2.py @@ -1,5 +1,5 @@ -from .base import ParrotZikBase -from ..resource_manager import Version2ResourceManager +from parrot_zik.model.base import ParrotZikBase +from parrot_zik.resource_manager import Version2ResourceManager class ParrotZikVersion2(ParrotZikBase): -- cgit v1.2.1 From 6049e5e3a9f77f4b784eeaf90ace6905feb1afd7 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 18:55:12 +0200 Subject: Move auto connection to setttings. --- parrot_zik/interface/base.py | 15 +++++++++++---- parrot_zik/interface/version2.py | 6 ------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/parrot_zik/interface/base.py b/parrot_zik/interface/base.py index 225e53f..b93c6c0 100644 --- a/parrot_zik/interface/base.py +++ b/parrot_zik/interface/base.py @@ -1,4 +1,5 @@ from parrot_zik import resource_manager +from parrot_zik.indicator import Menu from parrot_zik.indicator import MenuItem from parrot_zik.model.base import BatteryStates @@ -15,12 +16,18 @@ class ParrotZikBaseInterface(object): visible=False) self.firmware_version = MenuItem("Firmware Version:", None, sensitive=False, visible=False) + self.settings = MenuItem("Settings", None, visible=False) + self.settings_submenu = Menu() + self.settings.set_submenu(self.settings_submenu) + self.auto_connection = MenuItem("Auto Connection", self.toggle_auto_connection, - checkitem=True, visible=False) + checkitem=True) + self.settings_submenu.append(self.auto_connection) + 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) + self.indicator.menu.append(self.settings) def activate(self, manager): self.parrot = self.parrot_class(manager) @@ -32,7 +39,7 @@ class ParrotZikBaseInterface(object): self.battery_level.show() self.battery_state.show() self.firmware_version.show() - self.auto_connection.show() + self.settings.show() self.indicator.active_interface = self self.indicator.menu.reposition() @@ -45,7 +52,7 @@ class ParrotZikBaseInterface(object): self.battery_level.hide() self.battery_state.hide() self.firmware_version.hide() - self.auto_connection.hide() + self.settings.hide() self.indicator.menu.reposition() self.indicator.active_interface = None self.indicator.setIcon("zik-audio-headset") diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py index 74fdcc9..08af737 100644 --- a/parrot_zik/interface/version2.py +++ b/parrot_zik/interface/version2.py @@ -98,9 +98,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode, checkitem=True, visible=False) - self.settings = MenuItem("Settings", None, visible=False) - self.settings_submenu = Menu() - self.settings.set_submenu(self.settings_submenu) self.head_detection = MenuItem("Head Detection", self.toggle_head_detection, checkitem=True) self.settings_submenu.append(self.head_detection) @@ -108,13 +105,11 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.room_sound_effect) self.indicator.menu.append(self.noise_cancelation) self.indicator.menu.append(self.flight_mode) - self.indicator.menu.append(self.settings) def activate(self, manager): self.noise_cancelation.show() self.flight_mode.show() self.room_sound_effect.show() - self.settings.show() super(ParrotZikVersion2Interface, self).activate(manager) self._read_noise_cancelation() self.flight_mode.set_active(self.parrot.flight_mode) @@ -139,7 +134,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_cancelation.hide() self.flight_mode.hide() self.room_sound_effect.hide() - self.settings.hide() super(ParrotZikVersion2Interface, self).deactivate() def toggle_flight_mode(self, widget): -- cgit v1.2.1 From 48a0498d56e54e01b9eed06af00b5ba127fe9134 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 18:58:56 +0200 Subject: First get data from api then show. --- parrot_zik/interface/base.py | 1 - parrot_zik/interface/version1.py | 8 +++++--- parrot_zik/interface/version2.py | 8 +++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/parrot_zik/interface/base.py b/parrot_zik/interface/base.py index b93c6c0..90caa02 100644 --- a/parrot_zik/interface/base.py +++ b/parrot_zik/interface/base.py @@ -41,7 +41,6 @@ class ParrotZikBaseInterface(object): self.firmware_version.show() self.settings.show() self.indicator.active_interface = self - self.indicator.menu.reposition() @property def parrot_class(self): diff --git a/parrot_zik/interface/version1.py b/parrot_zik/interface/version1.py index 6ddd1b5..d0a1b2b 100644 --- a/parrot_zik/interface/version1.py +++ b/parrot_zik/interface/version1.py @@ -22,14 +22,16 @@ class ParrotZikVersion1Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.concert_hall_mode) def activate(self, manager): - self.noise_cancelation.show() - self.lou_reed_mode.show() - self.concert_hall_mode.show() super(ParrotZikVersion1Interface, self).activate(manager) self.noise_cancelation.set_active(self.parrot.cancel_noise) self.lou_reed_mode.set_active(self.parrot.lou_reed_mode) self.concert_hall_mode.set_active(self.parrot.concert_hall) + self.noise_cancelation.show() + self.lou_reed_mode.show() + self.concert_hall_mode.show() + self.indicator.menu.reposition() + def deactivate(self): self.noise_cancelation.hide() self.lou_reed_mode.hide() diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py index 08af737..b378a88 100644 --- a/parrot_zik/interface/version2.py +++ b/parrot_zik/interface/version2.py @@ -107,9 +107,6 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.indicator.menu.append(self.flight_mode) def activate(self, manager): - self.noise_cancelation.show() - self.flight_mode.show() - self.room_sound_effect.show() super(ParrotZikVersion2Interface, self).activate(manager) self._read_noise_cancelation() self.flight_mode.set_active(self.parrot.flight_mode) @@ -130,6 +127,11 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.angle_150.set_sensitive(sound_effect) self.angle_180.set_sensitive(sound_effect) + self.noise_cancelation.show() + self.flight_mode.show() + self.room_sound_effect.show() + self.indicator.menu.reposition() + def deactivate(self): self.noise_cancelation.hide() self.flight_mode.hide() -- cgit v1.2.1 From feac48c21e390cbf4e2ecf3b3c7a12d89c1e3436 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 20:39:17 +0200 Subject: Ignore dbus exception. --- parrot_zik/bluetooth_paired_devices.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index f06286a..cec6d8e 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -1,3 +1,4 @@ +import dbus import sys import re import os @@ -17,16 +18,24 @@ def get_parrot_zik_mac(): p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') if sys.platform == "linux2": - bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) - if bluetooth_on == 1: - out = os.popen("bluez-test-device list").read() - res = p.findall(out) - if len(res) > 0: - return res[0] - else: - raise DeviceNotConnected + try: + bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) + except dbus.exceptions.DBusException: + pass else: - raise BluetoothIsNotOn + if bluetooth_on == 1: + try: + out = os.popen("bluez-test-device list").read() + except dbus.exceptions.DBusException: + pass + else: + res = p.findall(out) + if len(res) > 0: + return res[0] + else: + raise DeviceNotConnected + else: + raise BluetoothIsNotOn elif sys.platform == "darwin": fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") plist = binplist.BinaryPlist(file_obj=fd) -- cgit v1.2.1 From deedbdca9564168460b24ee9549d084e2749fa1d Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Mon, 15 Jun 2015 20:49:11 +0200 Subject: Refactor. --- parrot_zik/bluetooth_paired_devices.py | 101 +++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index cec6d8e..e518161 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -14,57 +14,70 @@ else: import _winreg -def get_parrot_zik_mac(): - p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' - 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') - if sys.platform == "linux2": +p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' + 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') + +def get_parrot_zik_mac_linux(): + try: + bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) + except dbus.exceptions.DBusException: + pass + else: + if bluetooth_on == 1: try: - bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) + out = os.popen("bluez-test-device list").read() except dbus.exceptions.DBusException: pass else: - if bluetooth_on == 1: - try: - out = os.popen("bluez-test-device list").read() - except dbus.exceptions.DBusException: - pass - else: - res = p.findall(out) - if len(res) > 0: - return res[0] - else: - raise DeviceNotConnected - else: - raise BluetoothIsNotOn - elif sys.platform == "darwin": - fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") - plist = binplist.BinaryPlist(file_obj=fd) - parsed_plist = plist.Parse() - try: - for mac in parsed_plist['PairedDevices']: - if p.match(mac.replace("-", ":")): - return mac.replace("-", ":") + res = p.findall(out) + if len(res) > 0: + return res[0] else: raise DeviceNotConnected - except Exception: - pass + else: + raise BluetoothIsNotOn - elif sys.platform == "win32": - aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - aKey = _winreg.OpenKey( - aReg, 'SYSTEM\CurrentControlSet\Services\ - BTHPORT\Parameters\Devices') - for i in range(10): - try: - asubkey_name = _winreg.EnumKey(aKey, i) - mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) - res = p.findall(mac) - if len(res) > 0: - return res[0] - else: - raise DeviceNotConnected - except EnvironmentError: - pass + +def get_parrot_zik_mac_darwin(): + fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") + plist = binplist.BinaryPlist(file_obj=fd) + parsed_plist = plist.Parse() + try: + for mac in parsed_plist['PairedDevices']: + if p.match(mac.replace("-", ":")): + return mac.replace("-", ":") + else: + raise DeviceNotConnected + except Exception: + pass + + +def get_parrot_zik_mac_windows(): + aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + aKey = _winreg.OpenKey( + aReg, 'SYSTEM\CurrentControlSet\Services\ + BTHPORT\Parameters\Devices') + for i in range(10): + try: + asubkey_name = _winreg.EnumKey(aKey, i) + mac = ':'.join(asubkey_name[i:i+2] for i in range(0, 12, 2)) + res = p.findall(mac) + if len(res) > 0: + return res[0] + else: + raise DeviceNotConnected + except EnvironmentError: + pass + + +if sys.platform in ['linux', 'linux2']: + get_parrot_zik_mac = get_parrot_zik_mac_linux +elif sys.platform == 'darwin': + get_parrot_zik_mac = get_parrot_zik_mac_darwin +elif sys.platform == 'win32': + get_parrot_zik_mac = get_parrot_zik_mac_windows +else: + raise AssertionError('Platform not supported') def connect(): -- cgit v1.2.1 From 8236f6229e420406cfc64a55c8b358f7cb0357a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20S=C3=A1nchez?= Date: Fri, 3 Jul 2015 12:02:51 +0200 Subject: Fixed setter properties in version1 model --- parrot_zik/model/version1.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parrot_zik/model/version1.py b/parrot_zik/model/version1.py index f0197e9..324cc9f 100644 --- a/parrot_zik/model/version1.py +++ b/parrot_zik/model/version1.py @@ -25,7 +25,7 @@ class ParrotZikVersion1(ParrotZikBase): @lou_reed_mode.setter def lou_reed_mode(self, arg): - self.resource_manager.get("/api/audio/specific_mode/enabled", arg) + self.resource_manager.set("/api/audio/specific_mode/enabled", arg) @property def concert_hall(self): @@ -35,7 +35,7 @@ class ParrotZikVersion1(ParrotZikBase): @concert_hall.setter def concert_hall(self, arg): - self.resource_manager.get("/api/audio/sound_effect/enabled", arg) + self.resource_manager.set("/api/audio/sound_effect/enabled", arg) @property def cancel_noise(self): @@ -45,4 +45,4 @@ class ParrotZikVersion1(ParrotZikBase): @cancel_noise.setter def cancel_noise(self, arg): - self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) \ No newline at end of file + self.resource_manager.set("/api/audio/noise_cancellation/enabled", arg) -- cgit v1.2.1 From 0973bb1a2f8e46d7dffe67063f0d1415b3397619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20S=C3=A1nchez?= Date: Fri, 3 Jul 2015 12:07:31 +0200 Subject: Use other method to get bluetooth devices list in linux --- parrot_zik/bluetooth_paired_devices.py | 42 ++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index e518161..8eba2ce 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -1,7 +1,7 @@ import dbus import sys import re -import os +from subprocess import Popen, PIPE, STDOUT from .resource_manager import GenericResourceManager @@ -17,15 +17,28 @@ else: p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}|' 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') -def get_parrot_zik_mac_linux(): + +def get_parrot_zik_mac_linux_using_bluez_test(): try: - bluetooth_on = int(os.popen('bluez-test-adapter powered').read()) + pipe = Popen( + ['bluez-test-adapter', 'powered'], + stdout=PIPE, + stdin=PIPE, + stderr=STDOUT + ) + bluetooth_on = int(pipe.communicate()) except dbus.exceptions.DBusException: pass else: if bluetooth_on == 1: try: - out = os.popen("bluez-test-device list").read() + pipe = Popen( + ['bluez-test-device', 'list'], + stdout=PIPE, + stdin=PIPE, + stderr=STDOUT + ) + out = pipe.communicate() except dbus.exceptions.DBusException: pass else: @@ -38,6 +51,27 @@ def get_parrot_zik_mac_linux(): raise BluetoothIsNotOn +def get_parrot_zik_mac_linux_using_bluetoothcmd(): + pipe = Popen(['bluetoothctl'], stdout=PIPE, stdin=PIPE, stderr=STDOUT) + res = pipe.communicate("exit") + if len(res) > 0 and res[0]: + match = p.search(res[0]) + if match: + return match.group(0) + + raise DeviceNotConnected + + +def get_parrot_zik_mac_linux(): + try: + get_parrot_zik_mac_linux_using_bluez_test() + except OSError as e: + if e.errno == 2: + # File not found, probably it means that bluez utils are not + # installed + return get_parrot_zik_mac_linux_using_bluetoothcmd() + + def get_parrot_zik_mac_darwin(): fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb") plist = binplist.BinaryPlist(file_obj=fd) -- cgit v1.2.1 From 6eba736eb54ebecef14c4bd2b03df29b82f16f4b Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 3 Jul 2015 13:20:40 +0200 Subject: Fix mistakes and refactor. --- parrot_zik/bluetooth_paired_devices.py | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index 8eba2ce..0a40481 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -18,31 +18,24 @@ p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') -def get_parrot_zik_mac_linux_using_bluez_test(): +def get_parrot_zik_mac_bluez(): + pipe = Popen(['bluez-test-adapter', 'powered'], stdout=PIPE, stdin=PIPE, + stderr=STDOUT) try: - pipe = Popen( - ['bluez-test-adapter', 'powered'], - stdout=PIPE, - stdin=PIPE, - stderr=STDOUT - ) - bluetooth_on = int(pipe.communicate()) + stdout, stderr = pipe.communicate() except dbus.exceptions.DBusException: pass else: + bluetooth_on = int(stdout) if bluetooth_on == 1: + pipe = Popen(['bluez-test-device', 'list'], stdout=PIPE, stdin=PIPE, + stderr=STDOUT) try: - pipe = Popen( - ['bluez-test-device', 'list'], - stdout=PIPE, - stdin=PIPE, - stderr=STDOUT - ) - out = pipe.communicate() + stdout, stderr = pipe.communicate() except dbus.exceptions.DBusException: pass else: - res = p.findall(out) + res = p.findall(stdout) if len(res) > 0: return res[0] else: @@ -51,7 +44,7 @@ def get_parrot_zik_mac_linux_using_bluez_test(): raise BluetoothIsNotOn -def get_parrot_zik_mac_linux_using_bluetoothcmd(): +def get_parrot_zik_mac_bluetoothcmd(): pipe = Popen(['bluetoothctl'], stdout=PIPE, stdin=PIPE, stderr=STDOUT) res = pipe.communicate("exit") if len(res) > 0 and res[0]: @@ -64,12 +57,10 @@ def get_parrot_zik_mac_linux_using_bluetoothcmd(): def get_parrot_zik_mac_linux(): try: - get_parrot_zik_mac_linux_using_bluez_test() + return get_parrot_zik_mac_bluez() except OSError as e: if e.errno == 2: - # File not found, probably it means that bluez utils are not - # installed - return get_parrot_zik_mac_linux_using_bluetoothcmd() + return get_parrot_zik_mac_bluetoothcmd() def get_parrot_zik_mac_darwin(): -- cgit v1.2.1 From 3d455057798db862b5e1fb510d2f4aceaf71515a Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 3 Jul 2015 13:40:07 +0200 Subject: Refactor. --- parrot_zik/bluetooth_paired_devices.py | 80 ++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/parrot_zik/bluetooth_paired_devices.py b/parrot_zik/bluetooth_paired_devices.py index 0a40481..905819f 100644 --- a/parrot_zik/bluetooth_paired_devices.py +++ b/parrot_zik/bluetooth_paired_devices.py @@ -18,49 +18,63 @@ p = re.compile('90:03:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2 'A0:14:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}') -def get_parrot_zik_mac_bluez(): - pipe = Popen(['bluez-test-adapter', 'powered'], stdout=PIPE, stdin=PIPE, - stderr=STDOUT) - try: - stdout, stderr = pipe.communicate() - except dbus.exceptions.DBusException: - pass - else: - bluetooth_on = int(stdout) - if bluetooth_on == 1: - pipe = Popen(['bluez-test-device', 'list'], stdout=PIPE, stdin=PIPE, - stderr=STDOUT) - try: - stdout, stderr = pipe.communicate() - except dbus.exceptions.DBusException: - pass - else: - res = p.findall(stdout) - if len(res) > 0: - return res[0] - else: - raise DeviceNotConnected +class BluetoothDeviceManager(object): + def is_bluetooth_on(self): + raise NotImplementedError + + def get_mac(self): + raise NotImplementedError + + +class BluezBluetoothDeviceManager(BluetoothDeviceManager): + def is_bluetooth_on(self): + pipe = Popen(['bluez-test-adapter', 'powered'], stdout=PIPE, stdin=PIPE, + stderr=STDOUT) + try: + stdout, stderr = pipe.communicate() + except dbus.exceptions.DBusException: + pass + else: + return bool(stdout.strip()) + + def get_mac(self): + pipe = Popen(['bluez-test-device', 'list'], stdout=PIPE, stdin=PIPE, + stderr=STDOUT) + try: + stdout, stderr = pipe.communicate() + except dbus.exceptions.DBusException: + pass else: - raise BluetoothIsNotOn + res = p.findall(stdout) + if len(res) > 0: + return res[0] + else: + raise DeviceNotConnected -def get_parrot_zik_mac_bluetoothcmd(): - pipe = Popen(['bluetoothctl'], stdout=PIPE, stdin=PIPE, stderr=STDOUT) - res = pipe.communicate("exit") - if len(res) > 0 and res[0]: - match = p.search(res[0]) - if match: - return match.group(0) +class BluetoothCmdDeviceManager(BluetoothDeviceManager): + def is_bluetooth_on(self): + return True - raise DeviceNotConnected + def get_mac(self): + pipe = Popen(['bluetoothctl'], stdout=PIPE, stdin=PIPE, stderr=STDOUT) + res = pipe.communicate("exit") + if len(res) > 0 and res[0]: + match = p.search(res[0]) + if match: + return match.group(0) + raise DeviceNotConnected def get_parrot_zik_mac_linux(): + bluez_manager = BluezBluetoothDeviceManager() try: - return get_parrot_zik_mac_bluez() + bluez_manager.is_bluetooth_on() + return bluez_manager.get_mac() except OSError as e: if e.errno == 2: - return get_parrot_zik_mac_bluetoothcmd() + bluetoothcmd_manager = BluetoothCmdDeviceManager() + return bluetoothcmd_manager.get_mac() def get_parrot_zik_mac_darwin(): -- cgit v1.2.1 From 22e903f15887bff972ecd0f28c0ee485e918c3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20S=C3=A1nchez?= Date: Fri, 3 Jul 2015 13:33:26 +0200 Subject: Fixed cast when the value is an empty string --- parrot_zik/model/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parrot_zik/model/base.py b/parrot_zik/model/base.py index 0cd4652..d722788 100644 --- a/parrot_zik/model/base.py +++ b/parrot_zik/model/base.py @@ -16,7 +16,7 @@ class ParrotZikBase(object): def get_battery_level(self, field_name): answer = self.resource_manager.get("/api/system/battery") - return int(answer.system.battery[field_name]) + return int(answer.system.battery[field_name] or 0) @property def friendly_name(self): -- cgit v1.2.1 From 0200800656ff1add2df9c662ade6a52a2adb9f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20S=C3=A1nchez?= Date: Fri, 3 Jul 2015 13:22:02 +0200 Subject: Fixed _result_to_bool() assertion when a values has some strange status --- parrot_zik/model/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/parrot_zik/model/base.py b/parrot_zik/model/base.py index d722788..fdacde0 100644 --- a/parrot_zik/model/base.py +++ b/parrot_zik/model/base.py @@ -44,6 +44,8 @@ class ParrotZikBase(object): return True elif result == "false": return False + elif result == "invalid_on": + return True else: raise AssertionError(result) -- cgit v1.2.1 From 4098b681ca9bc4b57e8283f6f21d139fc1c9940b Mon Sep 17 00:00:00 2001 From: Max Grishkin Date: Tue, 8 Dec 2015 23:44:28 +0300 Subject: Use gtk on linux --- parrot_zik/indicator/__init__.py | 11 ++++++-- parrot_zik/indicator/gtk_wrapping.py | 6 +++++ parrot_zik/indicator/linux.py | 49 +++++++++++++++++++++++++----------- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/parrot_zik/indicator/__init__.py b/parrot_zik/indicator/__init__.py index 4194dde..156f7de 100644 --- a/parrot_zik/indicator/__init__.py +++ b/parrot_zik/indicator/__init__.py @@ -3,10 +3,17 @@ __all__ = ('SysIndicator', 'Menu', 'MenuItem') import sys if sys.platform in ['linux', 'linux2']: - from parrot_zik.indicator.linux import LinuxIndicator as SysIndicator + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("--gtk", action="store_true") + args = parser.parse_args() + if args.gtk: + from parrot_zik.indicator.linux import LinuxGtkIndicator as SysIndicator + else: + from parrot_zik.indicator.linux import LinuxAppIndicator as SysIndicator from parrot_zik.indicator.gtk_wrapping import GTKMenuItem as MenuItem from parrot_zik.indicator.gtk_wrapping import GTKMenu as Menu -elif sys.platform == 'win32': +elif sys.platform in ['win32']: from parrot_zik.indicator.windows import WindowsIndicator as SysIndicator from parrot_zik.indicator.gtk_wrapping import GTKMenuItem as MenuItem from parrot_zik.indicator.gtk_wrapping import GTKMenu as Menu diff --git a/parrot_zik/indicator/gtk_wrapping.py b/parrot_zik/indicator/gtk_wrapping.py index ce78c1d..6d4a5a8 100644 --- a/parrot_zik/indicator/gtk_wrapping.py +++ b/parrot_zik/indicator/gtk_wrapping.py @@ -13,6 +13,12 @@ class GTKMenu(object): def reposition(self): self.gtk_menu.reposition() + def popup(self, *args, **kwargs): + self.gtk_menu.popup(*args, **kwargs) + + def poVpdown(self, *args, **kwargs): + pass + class GTKMenuItem(MenuItemBase): def __init__(self, name, action, sensitive=True, checkitem=False, visible=True): diff --git a/parrot_zik/indicator/linux.py b/parrot_zik/indicator/linux.py index 278f781..f6f9cfc 100644 --- a/parrot_zik/indicator/linux.py +++ b/parrot_zik/indicator/linux.py @@ -6,17 +6,7 @@ from parrot_zik.indicator.base import BaseIndicator class LinuxIndicator(BaseIndicator): - def __init__(self, icon, menu): - import appindicator - self.icon_directory = os.path.join('/', 'usr', 'share', 'icons', 'zik') - if not os.path.isdir(self.icon_directory): - self.icon_directory = os.path.join('share', 'icons', 'zik') - statusicon = appindicator.Indicator( - "new-parrotzik-indicator", "indicator-messages", - appindicator.CATEGORY_APPLICATION_STATUS) - statusicon.set_status(appindicator.STATUS_ACTIVE) - statusicon.set_icon_theme_path(self.icon_directory) - statusicon.set_menu(menu.gtk_menu) + def __init__(self, icon, menu, statusicon): super(LinuxIndicator, self).__init__(icon, menu, statusicon) def gtk_right_click_event(self, icon, button, time): @@ -28,9 +18,6 @@ class LinuxIndicator(BaseIndicator): self.menu_shown = False self.menu.poVpdown() - def setIcon(self, name): - self.statusicon.set_icon(name) - @classmethod def main(cls): gtk.main() @@ -46,3 +33,37 @@ class LinuxIndicator(BaseIndicator): about_dialog.set_authors(["Dmitry Moiseev m0sia@m0sia.ru"]) about_dialog.run() about_dialog.destroy() + + +class LinuxAppIndicator(LinuxIndicator): + def __init__(self, icon, menu): + import appindicator + self.icon_directory = os.path.join('/', 'usr', 'share', 'icons', 'zik') + if not os.path.isdir(self.icon_directory): + self.icon_directory = os.path.join('share', 'icons', 'zik') + statusicon = appindicator.Indicator( + "new-parrotzik-indicator", "indicator-messages", + appindicator.CATEGORY_APPLICATION_STATUS) + statusicon.set_status(appindicator.STATUS_ACTIVE) + statusicon.set_icon_theme_path(self.icon_directory) + statusicon.set_menu(menu.gtk_menu) + super(LinuxIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_icon(name) + + + +class LinuxGtkIndicator(LinuxIndicator): + def __init__(self, icon, menu): + self.icon_directory = os.path.join( + '/usr', 'share', 'icons/') + self.menu_shown = False + statusicon = gtk.StatusIcon() + statusicon.connect("popup-menu", self.gtk_right_click_event) + statusicon.set_tooltip("Parrot Zik") + super(LinuxIndicator, self).__init__(icon, menu, statusicon) + + def setIcon(self, name): + self.statusicon.set_from_file(self.icon_directory + name + '.png') + -- cgit v1.2.1 From d6e3eb4ffb88959503cf41870dab72446ace6b46 Mon Sep 17 00:00:00 2001 From: Pavel Salomatov Date: Fri, 5 Feb 2016 15:41:47 +0300 Subject: Added functionality to change noise cancellation mode "Head detection" now initializes on startup --- parrot_zik/interface/version2.py | 14 ++++++++------ parrot_zik/model/version2.py | 4 ++-- parrot_zik/resource_manager.py | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py index b378a88..e6076ed 100644 --- a/parrot_zik/interface/version2.py +++ b/parrot_zik/interface/version2.py @@ -23,23 +23,23 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.noise_control_cancelation_max = MenuItem( "Max Calcelation", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True, sensitive=False) + NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True) self.noise_control_cancelation_on = MenuItem( "Normal Cancelation", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True, sensitive=False) + NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True) self.noise_control_off = MenuItem( "Off", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True, sensitive=False) + NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True) self.noise_control_street_mode = MenuItem( "Street Mode", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE), checkitem=True, sensitive=False) + NoiseControlTypes.STREET_MODE), checkitem=True) self.noise_control_street_mode_max = MenuItem( "Street Mode Max", functools.partial( self.toggle_noise_cancelation, - NoiseControlTypes.STREET_MODE_MAX), checkitem=True, sensitive=False) + NoiseControlTypes.STREET_MODE_MAX), checkitem=True) self.noise_cancelation_submenu.append(self.noise_control_cancelation_max) self.noise_cancelation_submenu.append(self.noise_control_cancelation_on) self.noise_cancelation_submenu.append(self.noise_control_off) @@ -112,6 +112,8 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.flight_mode.set_active(self.parrot.flight_mode) self._read_sound_effect_room() self._read_sound_effect_angle() + self.head_detection.set_active(self.parrot.head_detection) + sound_effect = self.parrot.sound_effect self.room_sound_effect_enabled.set_active(sound_effect) @@ -234,4 +236,4 @@ class ParrotZikVersion2Interface(ParrotZikBaseInterface): self.parrot.head_detection = self.head_detection.get_active() self.head_detection.set_active(self.parrot.head_detection) except resource_manager.DeviceDisconnected: - self.deactivate() \ No newline at end of file + self.deactivate() diff --git a/parrot_zik/model/version2.py b/parrot_zik/model/version2.py index 11b4d51..0cbdc1a 100644 --- a/parrot_zik/model/version2.py +++ b/parrot_zik/model/version2.py @@ -73,7 +73,7 @@ class ParrotZikVersion2(ParrotZikBase): @noise_control.setter def noise_control(self, arg): - pass + self.resource_manager.set('/api/audio/noise_control', arg) @property def noise_control_enabled(self): @@ -103,7 +103,7 @@ class NoiseControl(object): return self.type == other.type and self.value == other.value def __str__(self): - return '{}++{}'.format(self.type, self.value) + return '{}&value={}'.format(self.type, self.value) class NoiseControlTypes: diff --git a/parrot_zik/resource_manager.py b/parrot_zik/resource_manager.py index c2dae2f..aa141cb 100644 --- a/parrot_zik/resource_manager.py +++ b/parrot_zik/resource_manager.py @@ -132,7 +132,7 @@ class Version2ResourceManager(ResourceManagerBase): '/api/audio/equalizer/preset_value': ['set'], '/api/audio/noise_cancellation/enabled': ['get', 'set'], '/api/audio/noise_control/enabled': ['get', 'set'], - '/api/audio/noise_control': ['get'], + '/api/audio/noise_control': ['get', 'set'], '/api/audio/noise_control/phone_mode': ['get', 'set'], '/api/audio/noise': ['get'], '/api/audio/param_equalizer/value': ['set'], -- cgit v1.2.1