{"id":1813,"date":"2011-10-02T21:30:52","date_gmt":"2011-10-02T21:30:52","guid":{"rendered":"http:\/\/dalelane.co.uk\/blog\/?p=1813"},"modified":"2011-10-02T21:38:47","modified_gmt":"2011-10-02T21:38:47","slug":"using-bluevia-apis","status":"publish","type":"post","link":"https:\/\/dalelane.co.uk\/blog\/?p=1813","title":{"rendered":"My first experience using BlueVia APIs"},"content":{"rendered":"<p>I wrote yesterday about a <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=1800\">quick hack I did at Over The Air using the BlueVia API<\/a>. I thought it was worth a quick post to show just how simple it was. <\/p>\n<p>Read yesterday&#8217;s post for background to the idea behind the hack, but in essence, what I wanted was:<\/p>\n<ul>\n<li>monitor the location of my mobile phone\n<\/li>\n<li>send an SMS to a different mobile number when my phone goes into a predefined known area\n<\/li>\n<\/ul>\n<p><a href=\"http:\/\/bluevia.com\/\">BlueVia<\/a> provides an API that let me doing this using network operator data. In other words, nothing needs to run on my phone itself as location data is obtained from where O2 thinks my phone is. <\/p>\n<p>This means there is no battery-life impact on the phone for this monitoring. <\/p>\n<p>It also means this will work with any phone &#8211; from iPhones and Androids to cheap feature phones. <\/p>\n<p>The whole thing took me less than an hour and needed only 90 lines of Python. <\/p>\n<p>This is how I did it.<\/p>\n<p><!--more--><strong>1.<\/strong> Downloaded the zip file from <a href=\"https:\/\/github.com\/BlueVia\/BlueVia\">BlueVia&#8217;s github page<\/a><\/p>\n<p><strong>2.<\/strong> Opened the Readme.html file in the <code>examples\/python\/Sample Code<\/code> folder<\/p>\n<p><strong>3.<\/strong> Installed the Python prereqs listed in the Readme.html file using easy_install<\/p>\n<p><strong>4.<\/strong> Created an app at <a href=\"https:\/\/bluevia.com\/en\/my-apps\/api-keys\">bluevia.com<\/a> requesting the Send SMS and the Location API<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/dalelane.co.uk\/blog\/post-images\/111002-bluevia-1.gif\" alt=\"screenshot\"\/><\/p>\n<p>I got keys and IDs immediately.<\/p>\n<p><strong>5.<\/strong> The Readme.html contained enough sample code to show me how to do their OAuth process:<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em; font-size: 1.1em; overflow: auto;\"># overtheair-auth.py\r\n\r\nimport bluevia\r\n\r\nconsumer = 'XXXXXXXXXXXXXX'\r\nsecret = 'XXXXXXXXXXXXX'\r\n\r\no3 = bluevia.BlueViaOauth(consumer, secret)\r\nurlobj = o3.fetch_request_token()\r\n\r\ncode = urlobj[0]\r\nurl = urlobj[1]\r\n\r\nif code == 200:\r\n    access_token = raw_input('go to ' + url + ' then come back here and enter the verifier\\n\\nverifier: ')\r\n    o3.fetch_access_token(access_token)\r\n    o3.saveAccessToken(\"blueviaauthtok.pkl\")\r\nelse:\r\n    print 'fail ' + code<\/pre>\n<p><strong>6.<\/strong> The Readme.html file also contained enough sample code to show me how to get my mobile&#8217;s current location<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em; font-size: 1.1em; overflow: auto;\"># overtheair-location-attempt1.py\r\n\r\nimport bluevia\r\nimport pprint\r\n\r\nl = bluevia.BlueViaLocation()\r\nl.loadAccessToken(\"blueviaauthtok.pkl\")\r\nlocation = l.locateTerminal()\r\n\r\npprint.pprint(location)<\/pre>\n<p><strong>7.<\/strong> That wasn&#8217;t very accurate. <\/p>\n<p>It gave me a location somewhere in Slough, which was nowhere near me in Bletchley Park. That confused me for a minute until I remembered that O2 are in Slough. <\/p>\n<p>Comparing the location I got out of the BlueVia API with the O2 UK Head Office&#8230;<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/dalelane.co.uk\/blog\/post-images\/111002-bluevia-2.gif\" alt=\"map\"\/><\/p>\n<p>Ah&#8230; I guessed it wasn&#8217;t returning me inaccurate location data. It was returning me canned data, which they&#8217;ve set to their head office location. <\/p>\n<p>Which is when I remembered that in <a href=\"http:\/\/overtheair.org\/blog\/2011-schedule\/bluevia-apis\/\">the BlueVia APIs talk I went to<\/a>, they mentioned that the REST API included a sandbox endpoint for testing and development. <\/p>\n<p>I took a quick peek at the source code of the Python bluevia library I downloaded from github, and spotted that the BlueViaLocation function had an optional sandbox parameter which defaulted to &#8216;sandbox&#8217;. <\/p>\n<p>A quick tweak:<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em; font-size: 1.1em; overflow: auto;\"># overtheair-location-attempt2.py\r\n\r\nimport bluevia\r\nimport pprint\r\n\r\nl = bluevia.BlueViaLocation(sandbox=\"\")\r\nl.loadAccessToken(\"blueviaauthtok.pkl\")\r\nlocation = l.locateTerminal()\r\n\r\npprint.pprint(location)<\/pre>\n<p>Bingo &#8211; I had the latitude\/longitude of my location in Bletchley Park. <\/p>\n<p><strong>8.<\/strong> I needed to know how to see how far this location was from the predefined known area. A quick Google turned some public domain Python for doing this at <a href=\"http:\/\/www.johndcook.com\/python_longitude_latitude.html\">johndcook.com<\/a> &#8211; so big thanks to John D. Cook for saving me having to do any complicated maths.<\/p>\n<p><strong>9.<\/strong> Back to the Readme.html file, to get sample code for sending an SMS:<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em; font-size: 1.1em; overflow: auto;\"># overtheair-sendsms.py\r\n\r\nimport bluevia\r\nimport pprint\r\n\r\ntargetMobileNumber = \"447654123456\"\r\n\r\ns = bluevia.BlueViaOutboundSms(sandbox=\"\")\r\ns.loadAccessToken(\"blueviaauthtok.pkl\")\r\nr = s.sendSMS([targetMobileNumber], \"message to send\")\r\npprint.pprint(s.deliveryStatus(r[1]))<\/pre>\n<p><strong>10.<\/strong> I did a little tinkering to dynamically set a polling frequency based on my distance from the target<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em; font-size: 1.1em; overflow: auto;\"># 1 miles per hour = 0.44704 metres per second\r\n# my max speed = 70 mph\r\n# my max speed = (70 * 0.44704) metres per second\r\npollinterval = ((70 * 0.44704) \/ distanceInMetres)\r\n# lower limit - don't poll more frequently than once a minute\r\nif pollinterval < 60:\r\n    return 60\r\nelse:\r\n    return pollinterval<\/pre>\n<p><strong>11.<\/strong> Putting it all together, I had this:<\/p>\n<pre style=\"border: thin solid silver; background-color: #eeeeee; padding: 0.7em; font-size: 1.1em; overflow: auto;\"># overtheair.py\r\n\r\nimport bluevia\r\nimport pprint\r\nimport math\r\nimport time\r\n\r\n# borrowed with thanks from http:\/\/www.johndcook.com\/python_longitude_latitude.html\r\ndef distance_on_unit_sphere(lat1, long1, lat2, long2):\r\n\r\n    # Convert latitude and longitude to \r\n    # spherical coordinates in radians.\r\n    degrees_to_radians = math.pi\/180.0\r\n        \r\n    # phi = 90 - latitude\r\n    phi1 = (90.0 - lat1)*degrees_to_radians\r\n    phi2 = (90.0 - lat2)*degrees_to_radians\r\n        \r\n    # theta = longitude\r\n    theta1 = long1*degrees_to_radians\r\n    theta2 = long2*degrees_to_radians\r\n        \r\n    # Compute spherical distance from spherical coordinates.\r\n        \r\n    cos = (math.sin(phi1)*math.sin(phi2)*math.cos(theta1 - theta2) + \r\n           math.cos(phi1)*math.cos(phi2))\r\n    arc = math.acos( cos )\r\n\r\n    # return in metres\r\n    return arc * 6373 * 1000\r\n\r\ndef getlocationtoken():\r\n    l = bluevia.BlueViaLocation(sandbox=\"\")\r\n    l.loadAccessToken(\"blueviaauthtok.pkl\")\r\n    return l\r\n\r\ndef getlocation(l):\r\n    loc = l.locateTerminal()\r\n    return loc\r\n\r\ndef getdistanceinmetres(loc, target):\r\n    currentlat = float(loc[1]['terminalLocation']['currentLocation']['coordinates']['latitude'])\r\n    currentlon = float(loc[1]['terminalLocation']['currentLocation']['coordinates']['longitude'])\r\n    return distance_on_unit_sphere(target['latitude'], target['longitude'], currentlat, currentlon)\r\n\r\ndef sendsms(place):\r\n    s = bluevia.BlueViaOutboundSms(sandbox=\"\")\r\n    s.loadAccessToken(\"blueviaauthtok.pkl\")\r\n    r = s.sendSMS([\"447654123456\"], \"I'm near \" + place['name'] + \" now. Do you need me to get you anything?\")\r\n    pprint.pprint(s.deliveryStatus(r[1]))\r\n\r\ndef choosesleeptime(metres):\r\n    # 1 miles per hour = 0.44704 metres per second\r\n    # my max speed = 70 mph\r\n    # my max speed = (70 * 0.44704) metres per second\r\n    quickesttraveltime = ((70 * 0.44704) \/ metres)\r\n    # fix lower limit - don't poll more frequently than once a minute\r\n    if quickesttraveltime < 60:\r\n        return 60\r\n    else:\r\n        return quickesttraveltime\r\n\r\nloctok = getlocationtoken()\r\n\r\nwhile True:\r\n    loc = getlocation(loctok)\r\n\r\n    closestPlace = None\r\n\r\n    places = [ { 'latitude' : 51.99684, 'longitude' : -0.7384, 'name' : 'Bletchley Park' },\r\n               { 'latitude' : 50.96948, 'longitude' : -1.35246, 'name' : 'Sainsburys' },\r\n               { 'latitude' : 50.97966, 'longitude' : -1.34928, 'name' : 'Tesco Express' } ]\r\n\r\n    for place in places:\r\n        place['distance'] = getdistanceinmetres(loc, place)\r\n        if closestPlace is None:\r\n            closestPlace = place\r\n        elif closestPlace['distance'] > place['distance']:\r\n            closestPlace = place\r\n    \r\n    if closestPlace is None:\r\n        print \"something went wrong. fail.\"\r\n        exit()\r\n\r\n    # network location wont be precise, so tolerate anything within 500 metres\r\n    goodenough = 500\r\n    \r\n    if closestPlace['distance'] < goodenough:\r\n        sendsms(closestPlace)\r\n        print \"finished - don't do this again for at least 12 hours\"\r\n        time.sleep(12 * 60 * 60) # 12 hours\r\n    else:\r\n        seconds = choosesleeptime(closestPlace['distance'])\r\n        print str(closestPlace['distance']) + \" from nearest place. waiting for \" + str(seconds) + \" seconds before checking again\"\r\n        time.sleep(seconds)<\/pre>\n<p><strong>12.<\/strong> It worked. :-)<\/p>\n<p><a href=\"http:\/\/www.flickr.com\/photos\/dalelane\/6201225253\/\" title=\"photo of a hack by dalelane, on Flickr\"><img loading=\"lazy\" decoding=\"async\" style=\"border: thin black solid\" src=\"http:\/\/farm7.static.flickr.com\/6010\/6201225253_df47828f9e.jpg\" width=\"450\" height=\"338\" alt=\"photo of a hack\"\/><\/a><\/p>\n<p>Okay, so it was a silly idea. <\/p>\n<p>But the point is - it was amazingly easy to get this working. To do this by writing a native mobile app would have needed much more effort, and would have only worked on one platform. <\/p>\n<p>The downside? You need to be on a mobile network that supports BlueVia - which in the UK means O2. I couldn't have done this if I was on Vodafone. Which restricts the usability a little. <\/p>\n<p>But still. It is pretty cool. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote yesterday about a quick hack I did at Over The Air using the BlueVia API. I thought it was worth a quick post to show just how simple it was. Read yesterday&#8217;s post for background to the idea behind the hack, but in essence, what I wanted was: monitor the location of my [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[501,384,137,46,503,500,146,212],"class_list":["post-1813","post","type-post","status-publish","format-standard","hentry","category-code","tag-bluevia","tag-geolocation","tag-location","tag-mobile","tag-o2","tag-ota11","tag-overtheair","tag-python"],"_links":{"self":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1813"}],"version-history":[{"count":0,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1813\/revisions"}],"wp:attachment":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}