Package: asyncpushbullet
This is a python library for synchronous and asyncio-based
communication with the wonderfulPushbulletservice. It allows you to
send push notifications to your computer,Android,
andiOSdevices.In order to use the API you need an API key that can be obtainedhere. This is user specific and
is used instead of passwords.This is a fork of the synchronous-onlypushbullet.pyproject from randomchars, which uses thepushbulletnamespace.
This project usesasyncpushbullet.  I have made some changes to thepushbulletpackage, and you ought to be able to use the regular
synchronous functions alongside theasyncio-enabled versions.
Over time these have drifter further apart, so if you drop in theasyncpushbulletpackage in place of an olderpushbulletpackage,
you will probably need to make some changes to your code in terms of
function names and error handling.InstallationThe easiest way is to just open your favorite terminal and typepip install asyncpushbulletAlternatively you can clone this repo and install it withpython setup.py installRequirementsrequests: Used in synchronousPushbulletsuperclasspython-magic: Guesses at filetypes for uploading, optionalaiohttp: Foundational to theasyncio-enabledAsyncPushbulletclassestqdm: For some command line scriptspillow: Used in some example GUI codeUsageCommand Line (optional)Theasyncpushbulletpackage has some scripts that can be run from the
command line.  One is for sending pushes.  Two are for listening for and
responding to pushes.There are several ways to authenticate your Pushbullet.com API key when using
the command line:Set thePUSHBULLET_API_KEYenvironment variable.Use the--keycommand line option and include the key as an argument.Use the--key-filecommand line option and point to a text file
containing the API key.Use the--oauth2flag once to authenticate your command line tools using OAuth2.Pushing a Note from the Command LineYou can push a note from the command line and specify a title and body.$ pbpush --title "Hello World" --body "nothing to see"Uploading and Pushing a File from the Command LineYou can upload and push a file as well.$ pbpush --file homework.txt --title "Homework" --body "Avoid the dog."The flags available for thepbpushcommand line script:usage: pbpush [-h] [-k KEY] [--key-file KEY_FILE] [--proxy PROXY] [-t TITLE]
              [-b BODY] [-d DEVICE] [--list-devices] [-u URL] [-f FILE]
              [--transfer.sh] [-q] [--oauth2] [--debug] [-v] [--version]

optional arguments:
  -h, --help            show this help message and exit
  -k KEY, --key KEY     Your Pushbullet.com API key
  --key-file KEY_FILE   Text file containing your Pushbullet.com API key
  --proxy PROXY         Optional web proxy
  -t TITLE, --title TITLE
                        Title of your push
  -b BODY, --body BODY  Body of your push (- means read from stdin)
  -d DEVICE, --device DEVICE
                        Destination device nickname
  --list-devices        List registered device names
  -u URL, --url URL     URL of link being pushed
  -f FILE, --file FILE  Pathname to file to push
  --transfer.sh         Use www.transfer.sh website for uploading files (use
                        with --file)
  -q, --quiet           Suppress all output
  --oauth2              Register your command line tool using OAuth2
  --debug               Turn on debug logging
  -v, --verbose         Turn on verbose logging (INFO messages)
  --version             show program's version number and exitThere is also a variant ofpbpushcalledpbtransferthat makes it even
faster and easier to send off files using thehttp://transfer.shservice.$ pbtransfer somefile.jpg someotherfile.mp4The flags available for thepbtransfercommand line script:usage: pbtransfer [-h] [-k KEY] [--key-file KEY_FILE] [--proxy PROXY]
                  [-d DEVICE] [--list-devices] [-f FILE] [-q] [--oauth2]
                  [--debug] [-v] [--version]
                  [files [files ...]]

positional arguments:
  files                 Remaining arguments will be files to push

optional arguments:
  -h, --help            show this help message and exit
  -k KEY, --key KEY     Your Pushbullet.com API key
  --key-file KEY_FILE   Text file containing your Pushbullet.com API key
  --proxy PROXY         Optional web proxy
  -d DEVICE, --device DEVICE
                        Destination device nickname
  --list-devices        List registered device names
  -f FILE, --file FILE  Pathname to file to push
  -q, --quiet           Suppress all output
  --oauth2              Register your command line tool using OAuth2
  --debug               Turn on debug logging
  -v, --verbose         Turn on verbose logging (INFO messages)
  --version             show program's version number and exitListening for and Responding to PushesYou can listen for pushes and respond.  To simply echo pushes to the console:$ pblisten --echoYou can have a script called whenever a push arrives.  The--execflag takes its following
arguments as a script to call and any parameters to pass that script.  The script will be
called with those parameters and with the push (json encoded) sent viastdin.$ pblisten --exec handle_new_push.shYou can even have multiple actions listed at one time:$ pblisten --exec handle_new_push.sh  --exec record_in_log.shYour script can respond via itsstdoutin order to send push(es) back.  An example response:[{"title":"Fish Food Served","body":"Your automated fish feeding gadget has fed your fish. "},{"title":"Second push","body":"Second body"}]Or if you only want to send one push, there is a simpler form for your response:{"title":"title here","body":"body here"}Finally instead of--exec, you can use--exec-simpleto skip json altogether.
Your script will receive the push viastdinexcept that the first line will be the
title of the push, and the subsequent lines will be the body.$ pblisten --exec-simple handle_new_push.shYou can throttle how many pushes are received in a period of time using
the--throttle-countand--throttle-secondsflags.If a device nickname is specified, and there is no device with that nickname,
a new device will be created with that nickname.The flags available for thepblistencommand line script:usage: pblisten [-h] [-k KEY] [--key-file KEY_FILE] [-e] [-x EXEC [EXEC ...]]
                [-s EXEC_SIMPLE [EXEC_SIMPLE ...]]
                [-p EXEC_PYTHON [EXEC_PYTHON ...]] [-t TIMEOUT]
                [--throttle-count THROTTLE_COUNT]
                [--throttle-seconds THROTTLE_SECONDS] [-d DEVICE]
                [--list-devices] [--proxy PROXY] [--debug] [-v] [-q]
                [--oauth2] [--clear-oauth2] [--version]

optional arguments:
  -h, --help            show this help message and exit
  -k KEY, --key KEY     Your Pushbullet.com API key
  --key-file KEY_FILE   Text file containing your Pushbullet.com API key
  -e, --echo            ACTION: Echo push as json to stdout
  -x EXEC [EXEC ...], --exec EXEC [EXEC ...]
                        ACTION: Execute a script to receive push as json via
                        stdin. Your script can write json to stdout to send
                        pushes back. [ { "title" : "Fish Food Served", "body"
                        : "Your automated fish feeding gadget has fed your
                        fish. " }, { "title" : "Second push", "body" : "Second
                        body" } ] Or simpler form for a single push: { "title"
                        : "title here", "body" : "body here"}
  -s EXEC_SIMPLE [EXEC_SIMPLE ...], --exec-simple EXEC_SIMPLE [EXEC_SIMPLE ...]
                        ACTION: Execute a script to receive push in simplified
                        form via stdin. The first line of stdin will be the
                        title, and subsequent lines will be the body. Your
                        script can write lines back to stdout to send a single
                        push back. The first line of stdout will be the title,
                        and subsequent lines will be the body.
  -p EXEC_PYTHON [EXEC_PYTHON ...], --exec-python EXEC_PYTHON [EXEC_PYTHON ...]
                        ACTION: Load the given python file and execute it by
                        calling its on_push(p, pb) function with 2 arguments:
                        the push that was received and a live/connected
                        AsyncPushbullet object with which responses may be
                        sent.
  -t TIMEOUT, --timeout TIMEOUT
                        Timeout in seconds to use for actions being called
                        (default 30).
  --throttle-count THROTTLE_COUNT
                        Pushes will be throttled to this many pushes (default
                        10) in a certain number of seconds (default 10)
  --throttle-seconds THROTTLE_SECONDS
                        Pushes will be throttled to a certain number of pushes
                        (default 10) in this many seconds (default 10)
  -d DEVICE, --device DEVICE
                        Only listen for pushes targeted at given device name
  --list-devices        List registered device names
  --proxy PROXY         Optional web proxy
  --debug               Turn on debug logging
  -v, --verbose         Turn on verbose logging (INFO messages)
  -q, --quiet           Suppress all output
  --oauth2              Register your command line tool using OAuth2
  --clear-oauth2        Clears/unregisters the oauth2 token
  --version             show program's version number and exitDeveloper DocsThe following instructions relate to usingasyncpushbulletwithin
your own Python code.Quick StartHere is a well-behaved example right off the bat to take a look at:# !/usr/bin/env python3# -*- coding: utf-8 -*-"""
A basic, complete example of using AsyncPushbullet to interact with the Pushbullet.com service.
"""importasyncioimportosimportsysimporttracebacksys.path.append("..")# Since examples are buried one level into source treefromasyncpushbulletimportAsyncPushbullet,InvalidKeyError,PushbulletError,LiveStreamListenerAPI_KEY=""# YOUR API KEYPROXY=os.environ.get("https_proxy")oros.environ.get("http_proxy")EXIT_INVALID_KEY=1EXIT_PUSHBULLET_ERROR=2EXIT_OTHER=3defmain():asyncdef_run():try:asyncwithAsyncPushbullet(API_KEY,proxy=PROXY)aspb:# List devicesdevices=awaitpb.async_get_devices()print("Devices:")fordevindevices:print("\t",dev)# Send a pushpush=awaitpb.async_push_note(title="Success",body="I did it!")print("Push sent:",push)# Ways to listen for pushesasyncwithLiveStreamListener(pb)aslsl:# This will retrieve the previous push because it occurred# after the enclosing AsyncPushbullet connection was madepush=awaitlsl.next_push()print("Previous push, now received:",push)# Alternately get pushes with a 3 second inter-push timeoutprint("Awaiting pushes with 3 second inter-push timeout...")asyncforpushinlsl.timeout(3):print("Push received:",push)# Alternately get pushes foreverprint("Awaiting pushes forever...")asyncforpushinlsl:print("Push received:",push)exceptInvalidKeyErroraske:print(ke,file=sys.stderr)returnEXIT_INVALID_KEYexceptPushbulletErroraspe:print(pe,file=sys.stderr)returnEXIT_PUSHBULLET_ERRORexceptExceptionasex:print(ex,file=sys.stderr)traceback.print_tb(sys.exc_info()[2])returnEXIT_OTHERloop=asyncio.get_event_loop()returnloop.run_until_complete(_run())if__name__=="__main__":ifAPI_KEY=="":withopen("../api_key.txt")asf:API_KEY=f.read().strip()sys.exit(main())AuthenticationTo create anAsyncPushbulletobject:fromasyncpushbulletimportAsyncPushbulletpb=AsyncPushbullet(api_key)If your key is invalid (that is, the Pushbullet API returns a401),
anInvalidKeyErroris raised the first time communication is made.
To check right away for the validity of your key, you can use theverify_key()orasync_verify_key()functions,
in synchronous or asynchronous mode as appropriate.fromasyncpushbulletimportAsyncPushbullet...pb=AsyncPushbullet(api_key)awaitpb.async_verify_key()...awaitpb.async_close()or even better –this is preferredbecause it neatly closes sessions using
theasync withcontext manager.fromasyncpushbulletimportAsyncPushbullet...asyncdef_run():asyncwithAsyncPushbullet(api_key)aspb:# Do stuffloop.create_task(_run())Event LoopsAsyncPushbulletexpects its async functions to operate on only one event loop.
Create a newAsyncPushbulletobject if you need to operate on multiple
event loops.  If you need to close anAsyncPushbulletfrom another loop
or thread, use theclose_all_threadsafe().Using a proxyWhen specified, all requests to the API will be made through the proxy.fromasyncpushbulletimportAsyncPushbulletpb=AsyncPushbullet(api_key,proxy="https://user:pass@10.10.1.10:3128/")Pushing a text notepush=awaitpb.async_push_note("This is the title","This is the body")pushis a dictionary containing the data returned by the Pushbullet API.Pushing an addressPushing addresses is no longer supported by pushbullet.com and has been dropped inasyncpushbullet.Pushing a listPushing lists is no longer supported by pushbullet.com and has been dropped inasyncpushbullet.Pushing a linkpush=awaitpb.async_push_link("Cool site","https://github.com")Pushing a filePushing files is a two part process.  First you need to upload the file, and after that
you can push it like you would anything else.asyncdefupload_my_file(pb:AsyncPushbullet,filename:str):# The actual uploadinfo=awaitpb.async_upload_file(filename)# Push as a file:awaitpb.async_push_file(info["file_name"],info["file_url"],info["file_type"],title="File Arrived!",body="Please enjoy your file")# or Push as a link:awaitpb.async_push_link("Link to File Arrived!",info["file_url"],body="Please enjoy your file")async_upload_file()returns a dictionary containingfile_type,file_urlandfile_namekeys,
which are the same parameters thatasync_push_file()requires.You can also upload a file to thehttps://transfer.shservice usingasync_upload_file_to_transfer_sh.
Thehttps://transfer.shservice allows file uploads up to 10GB in size, and links last only two weeks....info=awaitpb.async_upload_file_to_transfer_sh(filename)...Working with pushesYou can also view all previous pushes:pushes=awaitpb.async_get_pushes()Pushes is a list containing dictionaries that have push data.
You can use this data to dismiss notifications or delete pushes.latest=pushes[0]# We already read it, so let's dismiss itawaitpb.async_dismiss_push(latest.get("iden"))# And you can delete itawaitpb.async_delete_push(latest.get("iden"))Both of these raise aPushbulletErrorif there’s an error.You can also delete all of your pushes (be careful):awaitpb.async_delete_pushes()Pushing to specific devicesSo far all our pushes went to all connected devices, but there’s a way to limit that.First we need to get hold of some devices.# Get all devices that the current user has access to.devices=awaitpb.async_get_devices()print(devices)# [Device('Motorola Moto G'), Device('N7'), Device('Chrome')]# Or retrieve a device by its name. Returns None if not found.motog=awaitpb.async_get_device(nickname='Motorola Moto G')We can pass the device to push methods:push=awaitpb.async_push_note("Hello world!","We're using the api.",device=motog)Creating new devicesCreating a new device is easy too, you only need to specify a name for it.
Though you can also specify manufacturer, model and icon too.coffee=awaitpb.async_new_device("MyCoffeePotGadget")# ormotog=awaitpb.async_new_device("MotoG",manufacturer="Motorola",model="G",icon="android")Now you can use it like any other device.Editing devicesYou can change the nickname, the manufacturer, model and icon of the device.  The newDeviceobject is returned.coffee=awaitpb.async_new_device("MyCoffeePotGadget")coffee2=awaitpb.async_edit_device(coffee,manufacturer="Me!")Deleting devicesOf course, you can also delete devices, even those not added by your code.awaitpb.async_remove_device(coffee)ChannelsYou can also send pushes to channels. First, create a channel on the Pushbullet
website (also make sure to subscribe to that channel). All channels which
belong to the current user can be retrieved as follows:# Get all channels created by the current userchannels=awaitpb.async_get_channels()print(channels)# [Channel('My Channel' 'channel_identifier')]# Or retrieve a channel by its name. Returns None if not found.mychannel=awaitpb.async_get_channel('My Channel')Then you can send a push to all subscribers of this channel like so:push=awaitpb.async_push_note("Hello Channel!",channel=mychannel)ContactsContacts, which are known as “Chats” in Pushbullet’s terminilogy, work just like devices:# Get all chats that the current user has access to.chats=awaitpb.async_get_chats()print(chats)# [Chat('Pushbullet Team' < pushbullet - team @ pushbullet.com >:# {'active': True,#  'created': 1484549777.2763588,#  'modified': 1484549777.276366,#  'muted': None,#  'with': {'email': 'pushbullet-team@pushbullet.com',#           'email_normalized': 'pushbullet-team@pushbullet.com',#           'iden': 'ujzob6qgcYm',#           'image_url': 'https://static.pushbullet.com/google-user/4308fcd45302c1dde28c5d86d7654da31bd32e70e9c28cac4a29d7f35c193e51',#           'name': 'Pushbullet Team',#           'type': 'user'}})]# How to access propertiesprint("Active:",chats[0].active)print("Email:",chats[0].with_email)# Or retrieve a chat by its email. Returns None if not found.peter=awaitpb.async_get_chat('peter@gmail.com')Now we can use the chat objects like we did withpbor with the devices.:push=awaitpb.async_push_note("Hello world!","We're using the api.",chat=peter)Adding new chatsbob=awaitpb.async_new_chat("Bob","bob@gmail.com")Sending SMS messagesThe author (Robert Harder) does not have any Android devices, so he has not
been able to test theasyncioversions of the sms functions.  In theory
they should work. :-/motog=awaitpb.async_get_device(nickname='Motorola Moto G')push=awaitpb.async_push_sms(motog,"+3615555678","Wowza!")Sending EphemeralsThe Pushbullet service has ephemeral messages that are not stored and are used
for, wait for it, ephemeral or transient messaging such as the universal clipboard
functionality.  You can send these messages as well.msg={"body":"something I copied","type":"clip"}awaitpb.async_push_ephemeral(msg)msg={"foobar":"Some control message you use for your IoT devices."}awaitpb.async_push_ephemerals(msg)End-To-End encryptionThe End-to-End notes are from the originalPushbulletproject.You activate end-to-end encryption by specifying your encryption key during the construction of thePushbulletinstance:frompushbulletimportPushbulletpb=Pushbullet(api_key,"My secret password")When specified, all sent SMS will be encrypted. Note that the use of end-to-end encryption requires thecryptographypackage. Since end-to-end encryption is only supported for SMS at the moment, thecryptographylibrary is not specified as a dependency ofpushbullet.pyand should be installed seperatly by runningpip install cryptography.Note that Pushbullet supportes End-To-End encryption only in SMS, notification mirroring and universal copy & paste. Your pushes will not be end-to-end encrypted.Error checkingIf the Pushbullet api returns an error code an __InvalidKeyErroror aPushbulletErroris raised. The first __
two are both subclasses ofPushbulletErrorThepushbullet api documetationcontains a list of possible status codes.Listening for PushesTo listen for pushes, use theLiveStreamListenerclass in anasync forloop:asyncdef_run():asyncwithAsyncPushbullet(api_key)aspb:asyncwithLiveStreamListener(pb)aspl:print("Awaiting pushes...")asyncforpushinpl:print("Got a push:",push)loop=asyncio.get_event_loop()loop.run_until_complete(_run())TODOMore tests. Write them all.LicenseMIT license. See LICENSE for full text.