I am using Azure notification hub to send push notifications from Raspberry pi to android application.
I am using python client app using REST API as per this post How to use Notification Hubs from Python
Everything works fine but there is, almost 2 seconds of delay in every notification from Raspberry pi to Android application!! How to avoid this delay and get the notification on Android device within same second.
My python script
import time
import hmac
import base64
import hashlib
import json
import urllib.parse
import http.client
class Notification:
def __init__(self, notification_format=None, payload=None, debug=0):
valid_formats = ['template', 'apple', 'gcm', 'windows', 'windowsphone', "adm", "baidu"]
if not any(x in notification_format for x in valid_formats):
raise Exception(
"Invalid Notification format. " +
"Must be one of the following - 'template', 'apple', 'gcm', 'windows', 'windowsphone', 'adm', 'baidu'")
self.format = notification_format
self.payload = payload
# array with keynames for headers
# Note: Some headers are mandatory: Windows: X-WNS-Type, WindowsPhone: X-NotificationType
# Note: For Apple you can set Expiry with header: ServiceBusNotification-ApnsExpiry
# in W3C DTF, YYYY-MM-DDThh:mmTZD (for example, 1997-07-16T19:20+01:00).
self.headers = None
class NotificationHub:
API_VERSION = "?api-version=2013-10"
DEBUG_SEND = "&test"
def __init__(self, connection_string=None, hub_name=None, debug=0):
self.HubName = hub_name
self.Debug = debug
# Parse connection string
parts = connection_string.split(';')
if len(parts) != 3:
raise Exception("Invalid ConnectionString.")
for part in parts:
if part.startswith('Endpoint'):
self.Endpoint = 'https' + part[11:]
if part.startswith('SharedAccessKeyName'):
self.SasKeyName = part[20:]
if part.startswith('SharedAccessKey'):
self.SasKeyValue = part[16:]
@staticmethod
def get_expiry():
# By default returns an expiration of 5 minutes (=300 seconds) from now
return int(round(time.time() + 300))
@staticmethod
def encode_base64(data):
return base64.b64encode(data)
def sign_string(self, to_sign):
key = self.SasKeyValue.encode('utf-8')
to_sign = to_sign.encode('utf-8')
signed_hmac_sha256 = hmac.HMAC(key, to_sign, hashlib.sha256)
digest = signed_hmac_sha256.digest()
encoded_digest = self.encode_base64(digest)
return encoded_digest
def generate_sas_token(self):
target_uri = self.Endpoint + self.HubName
my_uri = urllib.parse.quote(target_uri, '').lower()
expiry = str(self.get_expiry())
to_sign = my_uri + '\n' + expiry
signature = urllib.parse.quote(self.sign_string(to_sign))
auth_format = 'SharedAccessSignature sig={0}&se={1}&skn={2}&sr={3}'
sas_token = auth_format.format(signature, expiry, self.SasKeyName, my_uri)
return sas_token
def make_http_request(self, url, payload, headers):
parsed_url = urllib.parse.urlparse(url)
connection = http.client.HTTPSConnection(parsed_url.hostname, parsed_url.port)
if self.Debug > 0:
connection.set_debuglevel(self.Debug)
# adding this querystring parameter gets detailed information about the PNS send notification outcome
url += self.DEBUG_SEND
print("--- REQUEST ---")
print("URI: " + url)
print("Headers: " + json.dumps(headers, sort_keys=True, indent=4, separators=(' ', ': ')))
print("--- END REQUEST ---\n")
connection.request('POST', url, payload, headers)
response = connection.getresponse()
if self.Debug > 0:
# print out detailed response information for debugging purpose
print("\n\n--- RESPONSE ---")
print(str(response.status) + " " + response.reason)
print(response.msg)
print(response.read())
print("--- END RESPONSE ---")
elif response.status != 201:
# Successful outcome of send message is HTTP 201 - Created
raise Exception(
"Error sending notification. Received HTTP code " + str(response.status) + " " + response.reason)
connection.close()
def send_notification(self, notification, tag_or_tag_expression=None):
url = self.Endpoint + self.HubName + '/messages' + self.API_VERSION
json_platforms = ['template', 'apple', 'gcm', 'adm', 'baidu']
if any(x in notification.format for x in json_platforms):
content_type = "application/json"
payload_to_send = json.dumps(notification.payload)
else:
content_type = "application/xml"
payload_to_send = notification.payload
headers = {
'Content-type': content_type,
'Authorization': self.generate_sas_token(),
'ServiceBusNotification-Format': notification.format
}
if isinstance(tag_or_tag_expression, set):
tag_list = ' || '.join(tag_or_tag_expression)
else:
tag_list = tag_or_tag_expression
# add the tags/tag expressions to the headers collection
if tag_list != "":
headers.update({'ServiceBusNotification-Tags': tag_list})
# add any custom headers to the headers collection that the user may have added
if notification.headers is not None:
headers.update(notification.headers)
self.make_http_request(url, payload_to_send, headers)
def send_apple_notification(self, payload, tags=""):
nh = Notification("apple", payload)
self.send_notification(nh, tags)
def send_gcm_notification(self, payload, tags=""):
nh = Notification("gcm", payload)
self.send_notification(nh, tags)
def send_adm_notification(self, payload, tags=""):
nh = Notification("adm", payload)
self.send_notification(nh, tags)
def send_baidu_notification(self, payload, tags=""):
nh = Notification("baidu", payload)
self.send_notification(nh, tags)
def send_mpns_notification(self, payload, tags=""):
nh = Notification("windowsphone", payload)
if "<wp:Toast>" in payload:
nh.headers = {'X-WindowsPhone-Target': 'toast', 'X-NotificationClass': '2'}
elif "<wp:Tile>" in payload:
nh.headers = {'X-WindowsPhone-Target': 'tile', 'X-NotificationClass': '1'}
self.send_notification(nh, tags)
def send_windows_notification(self, payload, tags=""):
nh = Notification("windows", payload)
if "<toast>" in payload:
nh.headers = {'X-WNS-Type': 'wns/toast'}
elif "<tile>" in payload:
nh.headers = {'X-WNS-Type': 'wns/tile'}
elif "<badge>" in payload:
nh.headers = {'X-WNS-Type': 'wns/badge'}
self.send_notification(nh, tags)
def send_template_notification(self, properties, tags=""):
nh = Notification("template", properties)
self.send_notification(nh, tags)
isDebug = True
myConnectionString = "connection string"
hub = NotificationHub(myConnectionString, "cavenotificationhub", isDebug)
data = {}
data['response'] = 'data: R1|X1|S1,1|$'
json_data = json.dumps(data,separators=(',',':'))
print(json_data)
#gcm_payload = {"response":R1|X1|S1,1}
val= "R1|X1|S1,1|$"
gcm_payload = { 'data' : {'response': ''+val+''}}
hub.send_gcm_notification(gcm_payload)
Attached logs:
Windows 10 Surface Pro 3 - Python 3.4 script
**** Send GCM Notitification START> 2016-05-08 10:42:07.883226
*** make_http_request connection OPEN> 2016-05-08 10:42:08.139328
--- REQUEST ---
#Request header
--- END REQUEST ---
*** make_http_request START> 2016-05-08 10:42:08.165356
#Sending request to Azure
*** make_http_request END> 2016-05-08 10:42:09.016024
--- RESPONSE ---
#Response received from Azure
--- END RESPONSE ---
*** make_http_request connection CLOSE> 2016-05-08 10:42:09.184785
**** Send GCM Notitification END> 2016-05-08 10:42:09.188788
################################################################################################################################ Raspberry Pi Model B+ V1.2 - Python 2.7 script
('*** Send GCM Notitification START> ', '2016-05-08 10:46:32.692844') ('*** make_http_request connection OPEN> ', '2016-05-08 10:46:32.698456')
--- REQUEST ---
#Request header
--- END REQUEST ---
('*** make_http_request START> ', '2016-05-08 10:46:32.705946')
#Sending request to Azure ('*** make_http_request END> ', '2016-05-08 10:46:39.557759')
--- RESPONSE ---
#Response received from Azure
--- END RESPONSE ---
('*** make_http_request connection CLOSE> ', '2016-05-08 10:46:39.569713') ('*** Send GCM Notitification END> ', '2016-05-08 10:46:39.570986')
################################################################################################################################ Raspberry Pi 2 Model B V1.1 - Python 2.7 script
('*** Send GCM Notitification START> ', '2016-05-08 05:36:49.721024') ('*** make_http_request connection OPEN> ', '2016-05-08 05:36:49.732056')
--- REQUEST ---
#Request header
--- END REQUEST ---
('*** make_http_request START> ', '2016-05-08 05:36:49.733069')
#Sending request to Azure ('*** make_http_request END> ', '2016-05-08 05:36:50.741605')
--- RESPONSE ---
#Response received from Azure
--- END RESPONSE ---
('*** make_http_request connection CLOSE> ', '2016-05-08 05:36:50.746248') ('*** Send GCM Notitification END> ', '2016-05-08 05:36:50.747000')