Skip to content

Commit

Permalink
A collection of patches to libpebble.
Browse files Browse the repository at this point in the history
* Adds improved support for new PebbleProtocol messages used by the Pebble Watchface SDK
* Includes experimental support for Bluetooth communication via lightblue on OS X and Linux.

Squashed commit of the following:

commit c6be3b3
Merge: ed215bb 80a371a
Author: Paul McInnis <[email protected]>
Date:   Thu Apr 11 12:36:42 2013 -0700

    Merge pull request #7 from pebble/launch-on-install

    User-side Improvements

commit 80a371a
Author: Paul McInnis <[email protected]>
Date:   Thu Apr 11 11:52:55 2013 -0700

    Give ping a default value as 0 doesn't get returned from LightBluePebble

commit ed215bb
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 10 19:39:53 2013 -0700

    Update README.md

commit 5ce56b8
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 10 19:12:55 2013 -0700

    Make launching on install an option in the arg parser

commit 74f983a
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 10 19:00:15 2013 -0700

    Added the launch on install feature and made the uuid usage more consistant

commit 0469d8f
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 10 16:54:08 2013 -0700

    Update README.md

commit 09f43a4
Author: follower <[email protected]>
Date:   Wed Apr 10 17:55:39 2013 +1200

    Fix typo.

commit 5f5bb0c
Author: follower <[email protected]>
Date:   Wed Apr 10 17:54:26 2013 +1200

    Fix typo.

commit 6b66262
Author: Martijn The <[email protected]>
Date:   Tue Apr 9 15:41:11 2013 -0700

    Update README.md

    Typo

commit 1196331
Merge: 662d199 939061e
Author: Paul McInnis <[email protected]>
Date:   Mon Apr 8 11:57:52 2013 -0700

    Merge pull request #5 from pebble/feature-launch-by-uuid

    Added missing endpoints for Application messages and Launcher messages

commit 939061e
Author: Paul McInnis <[email protected]>
Date:   Fri Apr 5 16:34:50 2013 -0700

    User itertools to flatten the tuple of tuples
    Use run_key correctly
    Other PR commentary

commit 662d199
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 3 19:20:10 2013 -0700

    Update README.md

commit 1b26286
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 3 17:41:57 2013 -0700

    Update README.md

commit 3eeb043
Merge: e6a63e0 2428e8a
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 3 12:59:01 2013 -0700

    Merge pull request #4 from pebble/feature-remove-app-by-uuid

    added app reinstallation with uuid feature

commit 2428e8a
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 3 12:58:29 2013 -0700

    Fixed segfault issue by overriding SIGINT to close the connection before exit(0)

commit 9937072
Author: Paul McInnis <[email protected]>
Date:   Wed Apr 3 12:18:05 2013 -0700

    Moved the tools to build an app message into their own class.

commit 53c4849
Author: Paul McInnis <[email protected]>
Date:   Tue Apr 2 20:43:19 2013 -0700

    Moved all message building into methods for use in building app_messages that may have more than one tuple.

commit 37008f5
Author: Paul McInnis <[email protected]>
Date:   Tue Apr 2 18:09:48 2013 -0700

    uuid_to_remove is string: --> uuid_is_string

commit 229f86a
Author: Paul McInnis <[email protected]>
Date:   Tue Apr 2 18:07:21 2013 -0700

    uuid --> app_uuid

commit e420d91
Author: Paul McInnis <[email protected]>
Date:   Tue Apr 2 18:04:26 2013 -0700

    improve uuid handling

commit 87c429c
Author: Paul McInnis <[email protected]>
Date:   Tue Apr 2 17:37:13 2013 -0700

    Added missing endpoints for Application messages and Launcher messages
    Added endpoint handler
    Added ability to launch an application over bluetooth
    * NEXT: make a put-bytes style client to parse messages to and from the application.

commit 2302f39
Author: Paul McInnis <[email protected]>
Date:   Fri Mar 29 17:10:08 2013 -0700

    Added an endpoint for App_Manager so that app installation/reinstallation can be Asynchronous
    Improve uninstall behaviour
    Address matt's PR responses

commit 946f55c
Merge: a63325c e6a63e0
Author: Martijn The <[email protected]>
Date:   Fri Mar 29 16:55:09 2013 -0700

    Merge branch 'lightblue' into feature-remove-app-by-uuid

commit a63325c
Author: Paul McInnis <[email protected]>
Date:   Fri Mar 29 11:44:16 2013 -0700

    added app reinstallation with uuid feature

commit e6a63e0
Merge: 7dfb73e 5fff3b5
Author: Paul McInnis <[email protected]>
Date:   Thu Mar 28 17:32:50 2013 -0700

    Merge pull request #3 from pebble/lightblue-pebble-improval

    This is the working libpebble with lightblue

commit 5fff3b5
Author: Paul McInnis <[email protected]>
Date:   Thu Mar 28 16:21:55 2013 -0700

    Needed to remove the LightBlueSerial.py

commit f712434
Author: Paul McInnis <[email protected]>
Date:   Thu Mar 28 16:16:15 2013 -0700

    This is the working libpebble with lighblue which does not product a generic LightBlueSerial object in the style of PySerial, but instead has LightBluePebble which is designed to allow for pebble communications.

    in p.py
    - made p.py disconnect when it is done running the script
    - made p.py print "no apps" instead of throwing a non-scriptable TypeError when no apps are installed

    in LightBlueSerial a.k.a LightBluePebble:
    - simplified the IPC with a blocking call to read the rec_queue
    - renamed to LightBluePebble because the tool is not generic enough to be used for other LightBlue tasks
    - improved shutdown behaviour and debug behaviour

    in repl.py
    - added flags to support lightblue and to allow users to use PySerial instead

    in pebble.py
    - general cleaning up
    - handle the _ser.recv when lightblue is being used such that debugging prompts in the main process are still displayed nicely.

commit 7dfb73e
Merge: 3caec95 5a59afd
Author: Paul McInnis <[email protected]>
Date:   Wed Mar 27 13:14:15 2013 -0700

    Merge pull request #2 from pebble/improval-readability

    Improved readability and interface timeout. Fixed a buggy log in pebble.py read function.

commit 5a59afd
Author: Paul McInnis <[email protected]>
Date:   Tue Mar 26 23:15:25 2013 -0700

    refactored length to timeout, added verbose mac address to connection. pebble/lightblue-0.4#4

commit 1769111
Author: Paul McInnis <[email protected]>
Date:   Tue Mar 26 19:17:45 2013 -0700

    improved readability and interface. fixed buggy log in pebble.py

commit 3caec95
Merge: 1b5e04a 34e939b
Author: Paul McInnis <[email protected]>
Date:   Tue Mar 26 19:09:23 2013 -0700

    Merge pull request #1 from pebble/feature-remove-app-by-uuid

    Feature remove app by uuid

commit 34e939b
Author: Martijn The <[email protected]>
Date:   Tue Mar 26 18:41:46 2013 -0700

    Added "remove_app_by_uuid" function to libpebble / p.py

commit 1b5e04a
Author: Martijn The <[email protected]>
Date:   Tue Mar 26 17:25:17 2013 -0700

    non-editable dependency for lightblue in requirements.txt

commit b67d59a
Author: Martijn The <[email protected]>
Date:   Tue Mar 26 17:24:42 2013 -0700

    - Missing re import
    - 20 sec timout is too short when pairing
    - Fixed typo

commit 426a79a
Author: Martijn The <[email protected]>
Date:   Tue Mar 26 17:25:17 2013 -0700

    non-editable dependency for lightblue in requirements.txt

commit 4777457
Author: Martijn The <[email protected]>
Date:   Tue Mar 26 17:24:42 2013 -0700

    - Missing re import
    - 20 sec timout is too short when pairing
    - Fixed typo

commit 87e8c3f
Author: Martijn The <[email protected]>
Date:   Tue Mar 26 15:02:31 2013 -0700

    Added lightblue dependency to requirements.txt

commit 4e1b84e
Author: Paul McInnis <[email protected]>
Date:   Tue Mar 26 14:21:14 2013 -0700

    Moved LightBlueProcess into its own file, wrapped in PySerial style read, write and close.

commit 19b5b22
Author: Paul McInnis <[email protected]>
Date:   Mon Mar 25 20:30:33 2013 -0700

    improved the behaviour of the child process (lightblue) by making it Daemonic. Also added a timeout for waiting on the setup process.

commit 336b76b
Author: Paul McInnis <[email protected]>
Date:   Mon Mar 25 18:39:24 2013 -0700

    Usability improvements and some readability improvements

commit 1381d38
Author: Paul McInnis <[email protected]>
Date:   Mon Mar 25 16:15:27 2013 -0700

    general improvements to formatting and autodetection.

commit 0cd60ca
Author: Paul McInnis <[email protected]>
Date:   Mon Mar 25 11:58:10 2013 -0700

    further improved autodetection. Catching correct exception thrown from _bluetoothsocket.py (socket.timeout())

commit 6719e39
Author: Paul McInnis <[email protected]>
Date:   Mon Mar 25 11:19:38 2013 -0700

    bigfixes for cases within autodetect

commit 2e1769f
Author: Paul McInnis <[email protected]>
Date:   Mon Mar 25 10:52:31 2013 -0700

    This is the initial feature commit for libpebble with lightblue.

    -lightblue runs inside it's own process, there are issues with shutting it down when it's parent process dies.

    -example command line call:
    ./p.py --pebble_id DC93 --lightblue --pair ping
    --> this will pair to the mac-address obtained by searching for .*DC:93 and then will ping it. --lightblue indicates use of lightblue library
  • Loading branch information
zulak committed Apr 12, 2013
1 parent 0028d8e commit 7471ce2
Show file tree
Hide file tree
Showing 6 changed files with 614 additions and 84 deletions.
126 changes: 92 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,118 @@
libpebble
=========
Interact with your Pebble from OSX, Ubuntu or Debian operating systems.

Interact with your Pebble from any device.
## Warning and Complications

Getting started
---------------
* Supported OS's are `OSX 10.8`, `Ubuntu`, `Debian`
* OS's which can utilize a faster bluetooth library, Lightblue-0.4, are `OSX 10.8` and `Ubuntu`
* Detailed Lightblue-0.4 installation instructions for earlier version of OSX (10.6) and other OS's can be found [here](http://lightblue.sourceforge.net/#downloads)

I've only tested this on OS X 10.8. Things will be a little different on other platforms. Firstly make sure you have Python and PySerial installed.

Next, pair your Pebble to your computer and make sure it's setup as a serial port. For me, it gets exposed as /dev/tty.Pebble402F-SerialPortSe. If this is different for you anywhere but in 402F, you'll need to edit pebble.py. The 402F bit is my Pebble's ID. You can just run pebble.py with your ID as an argument if the rest of that path matches.
##1. Install Dependancies

Once you're paired and the serial port is setup, try running `p.py ping`. You should get a notification on your Pebble to test that it works properly. It sometimes helps to tell the Pebble App to disconnect from the Pebble first.
All supported OS's will require `python 2.7` to operate libpebble. It can be installed [here](http://www.python.org/download/releases/2.7/)

Join #pebble on Freenode IRC to let me know how you get on and share your creations!
###a. OSX Additional Dependencies

###Linux Notes
Installing Lightblue-0.4 in OSX will require the following be installed:
* `PyObjC` which can be installed via [pip](https://pypi.python.org/pypi/pip)
* `Xcode 2.1 or later` to build LightAquaBlue framework

**Please note the following was tested on Linux Mint 13, but should be valid for any Debian based distro**
###b. Ubuntu Additional Dependencies

* Install rfcomm `sudo apt-get install rfcomm`
* Bind the device `sudo rfcomm bind 0 PEBBLE_BLUETOOTH_ADDRESS 1`
* make the following code change:
Installing Lightblue-0.4 in Ubuntu requires some extra dependancies be installed via `apt-get install`:
* `python-dev`
* `libopenobex1-dev`
* `python-tk` if you wish to use the GUI selection tool

Change:
###c. Debian Additional Dependencies

self._ser = serial.Serial("/dev/tty.Pebble"+id+"-SerialPortSe", 115200, timeout=2)
Support for lightblue is untested in Debian, however the following should be installed/completed for use with PySerial:
* Install rfcomm `sudo apt-get install rfcomm`
* Bind the device `sudo rfcomm bind 0 PEBBLE_BLUETOOTH_ADDRESS 1`
* Make the following code change to `pebble/pebble.py`:
Change:

to:
self._ser = serial.Serial("/dev/tty.Pebble"+id+"-SerialPortSe", 115200, timeout=2)

self._ser = serial.Serial("/dev/rfcomm0", 115200, timeout=2)
to:

You can run the application as normal now. You may have to run it as root with `sudo python pebble.py`
self._ser = serial.Serial("/dev/rfcomm0", 115200, timeout=2)

Status
------
* Note that you may have to run libpebble as root with `sudo python pebble.py` in Debian


##2. Install Libpebble and Lightblue

* To install libpebble, clone the current libpebble with lightblue support from `[email protected]:pebble/libpebble.git` to a location of your choosing
* To install lightblue clone `lightblue-0.4` from `https://github.com/pebble/lightblue-0.4` and then:
* `cd lightblue-0.4`
* `sudo python setup.py install`


##3. Testing the Connection
Note: you should have your bluetooth module enabled before continuing

###a. OSX
When using libpebble on OSX, it is recommended that `--lightblue` be utilized.

#####Using libpebble with --lightblue on OSX
* First install the OSX dependancies, general dependancies and lightblue
* From the `libpebble-dev` folder, execute the following: `./p.py --lightblue --pair get_time`
* Note that if no `--pebble_id` is specified before the command, you are provided with a GUI selection tool.
* Note that if a MAC address is supplied, initialization time is reduced.
* For example: `./p.py --pebble_id 00:11:22:33:44:55:66 --lightblue get_time`
where `00:11:22:33:44:55:66` is the Pebble's MAC Address, viewable on the Pebble from `settings`-->`about`
* You can obtain your pebble's MAC address after a successful connection in the libpebble stdout debug logs
* The `--pebble_id` can also be the 4 letter friendly name of your pebble but this will require that the Pebble is broadcasting.

#####Using libpebble without --lightblue on OSX (MAY CAUSE KERNEL PANICS)

* Pair your Pebble to your computer and make sure it's setup as a serial port. For example it could be exposed as `/dev/tty.Pebble123A-SerialPortSe`. You can accomplish this by using OSX's pairing utility in `System Preferences` --> `Bluetooth` -> `+` --> selecting your pebble `Pebble XXXX` then confirming the pairing code on the Pebble.
* Once you're paired and the serial port is setup, you can execute commands without the `--lightblue` flag, just ensure that the `--pebble_id` is the 4 letter friendly name of your Pebble, `123A` for example.
* A command to get the time might be: `./p.py --pebble_id 123A get_time`

### b. Ubuntu

_Automated pairing via `--pair` is not currently supported in Ubuntu_

* First install the Ubuntu dependancies, general dependancies and lightblue
* In Ubuntu's `Menu`-->`Settings`-->`Connectivity`-->`Bluetooth` dialog, pair with your Pebble
* From the `libpebble-dev` folder, execute the following: `./p.py --lightblue get_time`
* Note that if no `--pebble_id` is specified before the command, you are provided with a GUI selection tool.
* For example: `./p.py --pebble_id 00:11:22:33:44:55:66 --lightblue get_time`
* The `--pebble_id` can also be the 4 letter friendly name of your pebble but this require that the Pebble is broadcasting.

## Applications
* Note that applications each have a unique UUID which is used to launch on install/re-install, it should be visible in the source for your application.
* Once an application is installed or re-installed it will be launched automatically. Disable this with `--nolaunch`
* for example `./p.py --pebble_id 00:11:22:33:44:55:66 --lightblue reinstall brains.pbw --nolaunch`

#####Installing:
* From your libpebble directory, execute `p.py` with the argument `load <path-to-valid-app>`
* for example: `./p.py --pebble_id 00:11:22:33:44:55:66 --lightblue load brains.pbw`

#####Re-installing
* To re-install an application, execute `p.py` with the argument `reinstall <path-to-valid-app>`. This will attempt to remove the application by its UUID or, if that fails, the name of the application before installing it once more.
* for example: `./p.py --pebble_id 00:11:22:33:44:55:66 --lightblue reinstall brains.pbw`

Functionality
-------------

The following are currently supported:

* Pinging device
* Sending email, sms and ping notifications
* Installing, reinstalling and uninstalling applications
* Installing firmwares
* Launching applications by UUID
* Sending application messages
* Resetting device
* Setting/getting time
* Sending notifications
* Setting the currently playing track
* Listing installed apps
* Installing apps
* Deleting apps
* Getting the installed firmware versions
* Installing firmware
* Getting device data (serial, BT MAC etc)
* Getting the installed firmware version
* Getting and setting the pebble's time

REPL
----
Expand All @@ -56,11 +121,4 @@ A basic REPL is available, it is best used with ipython:

`sudo ipython repl.py`

The variable pebble refers the watch connection. You can for example do `pebble.ping()` to perform a ping.

Thanks
------

* Pebble for making an awesome watch.
* RaYmAn for helping me figure out how the PutBytesClient worked.
* Overv for helping me pick apart the Android different message factories in the Android app.
The variable pebble refers the watch connection. You can for example perform `pebble.get_time()` to get the time of the watch
71 changes: 57 additions & 14 deletions p.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ def cmd_ping(pebble, args):
pebble.ping(cookie=0xDEADBEEF)

def cmd_load(pebble, args):
pebble.install_app(args.app_bundle)
pebble.install_app(args.app_bundle, args.nolaunch)

def cmd_load_fw(pebble, args):
pebble.install_firmware(args.fw_bundle)
time.sleep(5)
print 'resetting to apply firmware update...'
pebble.reset()

def cmd_launch_app(pebble, args):
pebble.launcher_message(args.app_uuid, "RUNNING")

def cmd_remote(pebble, args):
def do_oscacript(command):
cmd = "osascript -e 'tell application \""+args.app_name+"\" to "+command+"'"
Expand Down Expand Up @@ -68,16 +71,34 @@ def cmd_logcat(pebble, args):
return

def cmd_list_apps(pebble, args):
for app in pebble.get_appbank_status()['apps']:
print '[{}] {}'.format(app['index'], app['name'])
apps = pebble.get_appbank_status()
if apps is not False:
for app in apps['apps']:
print '[{}] {}'.format(app['index'], app['name'])
else:
print "no apps"

def cmd_rm_app(pebble, args):
for app in pebble.get_appbank_status()['apps']:
if app['index'] == args.app_index:
pebble.remove_app(app["id"], app["index"])

try:
uuid = args.app_index_or_hex_uuid.decode('hex')
if len(uuid) == 16:
pebble.remove_app_by_uuid(uuid, uuid_is_string=False)
print 'removed app'
return
return 0
except:
pass
try:
idx = int(args.app_index_or_hex_uuid)
for app in pebble.get_appbank_status()['apps']:
if app['index'] == idx:
pebble.remove_app(app["id"], app["index"])
print 'removed app'
return 0
except:
print 'Invalid arguments. Use bank index or hex app UUID (16 bytes / 32 hex digits)'

def cmd_reinstall_app(pebble, args):
pebble.reinstall_app(args.app_bundle, args.nolaunch)

def cmd_reset(pebble, args):
pebble.reset()
Expand All @@ -99,14 +120,24 @@ def cmd_set_time(pebble, args):

def main():
parser = argparse.ArgumentParser(description='a utility belt for pebble development')
parser.add_argument('--pebble_id', type=str, help='the last 4 digits of the target Pebble\'s MAC address')
parser.add_argument('--pebble_id', type=str, help='the last 4 digits of the target Pebble\'s MAC address. \nNOTE: if \
--lightblue is set, providing a full MAC address (ex: "A0:1B:C0:D3:DC:93") won\'t require the pebble \
to be discoverable and will be faster')

parser.add_argument('--lightblue', action="store_true", help='use LightBlue bluetooth API')
parser.add_argument('--pair', action="store_true", help='pair to the pebble from LightBlue bluetooth API before connecting.')

subparsers = parser.add_subparsers(help='commands', dest='which')

ping_parser = subparsers.add_parser('ping', help='send a ping message')
ping_parser.set_defaults(func=cmd_ping)

launch_parser = subparsers.add_parser('launch_app', help='launch an app on the watch by its UUID')
launch_parser.add_argument('app_uuid', metavar='UUID', type=str, help='a valid UUID in the form of: 54D3008F0E46462C995C0D0B4E01148C')
launch_parser.set_defaults(func=cmd_launch_app)

load_parser = subparsers.add_parser('load', help='load an app onto a connected watch')
load_parser.add_argument('--nolaunch', action="store_false", help='do not launch the application after install')
load_parser.add_argument('app_bundle', metavar='FILE', type=str, help='a compiled app bundle')
load_parser.set_defaults(func=cmd_load)

Expand All @@ -120,10 +151,15 @@ def main():
list_apps_parser = subparsers.add_parser('list', help='list installed apps')
list_apps_parser.set_defaults(func=cmd_list_apps)

rm_app_parser = subparsers.add_parser('rm', help='remove installed apps')
rm_app_parser.add_argument('app_index', metavar='IDX', type=int, help='the app index to delete')
rm_app_parser = subparsers.add_parser('rm', help='remove installed app')
rm_app_parser.add_argument('app_index_or_hex_uuid', metavar='IDX or UUID in the form of: 54D3008F0E46462C995C0D0B4E01148C', type=str, help='the app index or UUID to delete')
rm_app_parser.set_defaults(func=cmd_rm_app)

reinstall_app_parser = subparsers.add_parser('reinstall', help='reinstall then launch an installed app')
reinstall_app_parser.add_argument('app_bundle', metavar='FILE', type=str, help='a compiled app bundle')
reinstall_app_parser.add_argument('--nolaunch', action="store_false", help='do not launch the application after install')
reinstall_app_parser.set_defaults(func=cmd_reinstall_app)

reset_parser = subparsers.add_parser('reset', help='reset the watch remotely')
reset_parser.set_defaults(func=cmd_reset)

Expand Down Expand Up @@ -163,13 +199,20 @@ def main():
if attempts > MAX_ATTEMPTS:
raise 'Could not connect to Pebble'
try:
pebble = libpebble.Pebble(args.pebble_id)
pebble = libpebble.Pebble(args.pebble_id, args.lightblue, args.pair)
break
except libpebble.PebbleError:
except:
time.sleep(5)
attempts += 1

args.func(pebble, args)
try:
args.func(pebble, args)
except Exception as e:
pebble.disconnect()
raise e
return

pebble.disconnect()

if __name__ == '__main__':
main()
Loading

1 comment on commit 7471ce2

@Hexxeh
Copy link

@Hexxeh Hexxeh commented on 7471ce2 Apr 12, 2013

Choose a reason for hiding this comment

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

Best.

Pull request.

Ever.

Please sign in to comment.