Permalink
Browse files

Genericise remote support

You can make p.py control a music app like so:

./p.py remote Spotify
  • Loading branch information...
1 parent ffd2824 commit ce40fba90de2fdbd85a491a202663e69a96de751 @Hexxeh committed Mar 15, 2013
Showing with 65 additions and 10 deletions.
  1. +45 −0 p.py
  2. +20 −10 pebble/pebble.py
View
45 p.py
@@ -1,7 +1,9 @@
#!/usr/bin/env python
import argparse
+import os
import pebble as libpebble
+import subprocess
import sys
import time
@@ -19,6 +21,44 @@ def cmd_load_fw(pebble, args):
print 'resetting to apply firmware update...'
pebble.reset()
+def cmd_remote(pebble, args):
+ def do_oscacript(command):
+ cmd = "osascript -e 'tell application \""+args.app_name+"\" to "+command+"'"
+ try:
+ return subprocess.check_output(cmd, shell=True)
+ except subprocess.CalledProcessError:
+ print "Failed to send message to "+args.app_name+", is it running?"
+ return False
+
+ def music_control_handler(endpoint, resp):
+ events = {
+ "PLAYPAUSE": "playpause",
+ "PREVIOUS": "previous track",
+ "NEXT": "next track"
+ }
+ do_oscacript(events[resp])
+ update_metadata()
+
+ def update_metadata():
+ artist = do_oscacript("artist of current track as string")
+ title = do_oscacript("name of current track as string")
+ album = do_oscacript("album of current track as string")
+
+ if not artist or not title or not album:
+ pebble.set_nowplaying_metadata("No Music Found", "", "")
+ else:
+ pebble.set_nowplaying_metadata(title, album, artist)
+
+ pebble.register_endpoint("MUSIC_CONTROL", music_control_handler)
+
+ print 'waiting for music control events'
+ try:
+ while True:
+ update_metadata()
+ time.sleep(5)
+ except KeyboardInterrupt:
+ return
+
def cmd_logcat(pebble, args):
print 'listening for logs...'
try:
@@ -102,6 +142,11 @@ def main():
set_time_parser.add_argument('timestamp', type=int, help='time stamp to be sent')
set_time_parser.set_defaults(func=cmd_set_time)
+ remote_parser = subparsers.add_parser('remote', help='control a music app on this PC using Pebble')
+ remote_parser.add_argument('app_name', type=str, help='title of application to be controlled')
+ remote_parser.set_defaults(func=cmd_remote)
+
+
args = parser.parse_args()
attempts = 0
View
@@ -156,6 +156,7 @@ def __init__(self, id = None):
self.endpoints["VERSION"]: self._version_response,
self.endpoints["PHONE_VERSION"]: self._phone_version_response,
self.endpoints["SYSTEM_MESSAGE"]: self._system_message_response,
+ self.endpoints["MUSIC_CONTROL"]: self._music_control_response,
self.endpoints["LOGS"]: self._log_response,
self.endpoints["PING"]: self._ping_response,
self.endpoints["APP_MANAGER"]: self._appbank_status_response
@@ -165,7 +166,6 @@ def __init__(self, id = None):
devicefile = "/dev/tty.Pebble"+id+"-SerialPortSe"
log.debug("Attempting to open %s as Pebble device %s" % (devicefile, id))
self._ser = serial.Serial(devicefile, 115200, timeout=1)
-
log.debug("Connected")
log.debug("Initializing reader thread")
@@ -196,7 +196,7 @@ def _reader(self):
if endpoint in self._internal_endpoint_handlers:
resp = self._internal_endpoint_handlers[endpoint](endpoint, resp)
- if endpoint in self._endpoint_handlers:
+ if endpoint in self._endpoint_handlers and resp:
self._endpoint_handlers[endpoint](endpoint, resp)
except:
traceback.print_exc()
@@ -260,8 +260,10 @@ def set_nowplaying_metadata(self, track, album, artist):
"""Update the song metadata displayed in Pebble's music app."""
parts = [artist, album, track]
+
data = pack("!b", 16)
for part in parts:
+ part = part[0:29] if len(part) > 30 else part
data += pack("!b", len(part))+part
self._send_message("MUSIC_CONTROL", data)
@@ -480,6 +482,7 @@ def _system_message_response(self, endpoint, data):
log.info("Got system message %s" % repr(unpack('!bb', data)))
else:
log.info("Got 'unknown' system message...")
+
def _log_response(self, endpoint, data):
if (len(data) < 8):
log.warn("Unable to decode log message (length %d is less than 8)" % len(data))
@@ -563,10 +566,6 @@ def _phone_version_response(self, endpoint, data):
"SMS" : 32,
"GPS" : 64,
"BTLE" : 128,
- # XXX: CAMERA_FRONT is 240 in the APK, but this can't
- # be right, as this will ruin the bitmask. Check
- # future app versions
- "CAMERA_FRONT" : 240,
"CAMERA_REAR" : 256,
"ACCEL" : 512,
"GYRO" : 1024,
@@ -580,17 +579,28 @@ def _phone_version_response(self, endpoint, data):
"LINUX" : 4,
"WINDOWS" : 5,
}
- # Magic prefix that the app adds
- prefix = "\x01\xff\xff\xff\xff"
+
# Then session capabilities, android adds GAMMA_RAY and it's
# the only session flag so far
session = session_cap["GAMMA_RAY"]
+
# Then phone capabilities, android app adds TELEPHONY and SMS,
# and the phone type (we know android works for now)
remote = remote_cap["TELEPHONY"] | remote_cap["SMS"] | os["ANDROID"]
- msg = prefix + pack("!II", session, remote)
+
+ msg = pack("!biII", 1, -1, session, remote)
self._send_message("PHONE_VERSION", msg);
- return data
+
+ def _music_control_response(self, endpoint, data):
+ event, = unpack("!b", data)
+
+ event_names = {
+ 1: "PLAYPAUSE",
+ 4: "NEXT",
+ 5: "PREVIOUS",
+ }
+
+ return event_names[event] if event in event_names else None
class PutBytesClient(object):
states = {

0 comments on commit ce40fba

Please sign in to comment.