Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion p.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2

import argparse
import pebble as libpebble
Expand Down
92 changes: 80 additions & 12 deletions pebble/pebble.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2

import binascii
import serial
Expand Down Expand Up @@ -153,6 +153,7 @@ def __init__(self, id = None):
self._internal_endpoint_handlers = {
self.endpoints["TIME"]: self._get_time_response,
self.endpoints["VERSION"]: self._version_response,
self.endpoints["PHONE_VERSION"]: self._phone_version_response,
self.endpoints["SYSTEM_MESSAGE"]: self._system_message_response,
self.endpoints["LOGS"]: self._log_response,
self.endpoints["PING"]: self._ping_response,
Expand All @@ -164,13 +165,7 @@ def __init__(self, id = None):
log.debug("Attempting to open %s as Pebble device %s" % (devicefile, id))
self._ser = serial.Serial(devicefile, 115200, timeout=1)

log.debug("Connected, discarding null response")
# we get a null response when we connect, discard it
self._ser.read(5)

# Eat any cruft that might be sitting in the serial buffer...
while self._ser.read():
pass
log.debug("Connected")

log.debug("Initializing reader thread")
self._read_thread = threading.Thread(target=self._reader)
Expand All @@ -193,10 +188,6 @@ def _reader(self):
if resp == None:
continue

if DEBUG_PROTOCOL:
log.debug("Got message for endpoint %s of length %d" % (endpoint, len(resp)))
log.debug('<<< ' + resp.encode('hex'))

if endpoint in self._internal_endpoint_handlers:
resp = self._internal_endpoint_handlers[endpoint](endpoint, resp)

Expand Down Expand Up @@ -228,6 +219,11 @@ def _recv_message(self):
raise PebbleError(self.id, "Malformed response with length "+str(len(data)))
size, endpoint = unpack("!HH", data)
resp = self._ser.read(size)

if DEBUG_PROTOCOL:
log.debug("Got message for endpoint %s of length %d" % (endpoint, len(resp)))
log.debug('<<< ' + (data + resp).encode('hex'))

return (endpoint, resp)

def register_endpoint(self, endpoint_name, func):
Expand Down Expand Up @@ -454,6 +450,40 @@ def ping(self, cookie = 0, async = False):
if not async:
return EndpointSync(self, "PING").get_data()

phone_control_commands = {
"ANSWER" : 1,
"HANGUP" : 2,
"GET_STATE" : 3,
"INCOMING_CALL" : 4,
"OUTGOING_CALL" : 5,
"MISSED_CALL" : 6,
"RING" : 7,
"START" : 8,
"END" : 9,
}

def phone_incoming(self, number, name, cookie = 0, async = False):

"""Send a 'phone_control' notification for incoming call."""

fmt = "!bL" + str(1+len(number)) + "p" + str(1+len(name)) + "p"
data = pack(fmt, self.phone_control_commands["INCOMING_CALL"], cookie, number, name)
self._send_message("PHONE_CONTROL", data)

def phone_start(self, cookie = 0, async = False):

"""Send a 'phone_control' notification of start."""

data = pack("!bL", self.phone_control_commands["START"], cookie)
self._send_message("PHONE_CONTROL", data)

def phone_end(self, cookie = 0, async = False):

"""Send a 'phone_control' notification of end."""

data = pack("!bL", self.phone_control_commands["END"], cookie)
self._send_message("PHONE_CONTROL", data)

def reset(self):

"""Reset the watch remotely."""
Expand Down Expand Up @@ -558,6 +588,44 @@ def _version_response(self, endpoint, data):

return resp

def _phone_version_response(self, endpoint, data):
session_cap = {
"GAMMA_RAY" : 0x80000000,
}
remote_cap = {
"TELEPHONY" : 16,
"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,
"COMPASS" : 2048,
}
os = {
"UNKNOWN" : 0,
"IOS" : 1,
"ANDROID" : 2,
"OSX" : 3,
"LINUX" : 4,
"WINDOWS" : 5,
}
# Magic prefix that the app adds
prefix = "\x01\xff\xff\xff\xff"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comparing to the pebble app's source, I'd by far prefer the following:

pack('!bi', 1, -1)

It makes it clear the magic value consists of two values rather than a single string - hopefully we can get Team Pebble to tell us what/why those values are there :)

# 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)
self._send_message("PHONE_VERSION", msg);
return data

class PutBytesClient(object):
states = {
"NOT_STARTED": 0,
Expand Down
2 changes: 1 addition & 1 deletion repl.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2

import argparse
import pebble as libpebble
Expand Down