Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
GPS access -- Solved!!
-
UPDATE: The location issue was fixed quite elegantly with the location module added in Pythonista v1.4.
This problem of how to programmatically get GPS coordinates has been gnawing at me. @Westacular suggestion above is promising but I am not able to make it work...
theURL = 'http://www.w3schools.com/html/tryit.asp?filename=tryhtml5_geolocation' import webbrowser; webbrowser.open(theURL)
If I allow Pythonista access my current location when asked, the code above works as expected. However, I can find no way to programmatically get the resulting lat & lon values back into my Pythonista script. The webbrowser module provides no access to the results of the JavaScript execution. Similarly urllib2 and requests provide access to the source code of a webpage but not to the results of its execution.
import requests; print(requests.get(theURL).text)
Another approach would be to find an iOS app that supported sending GPS coordinates via x-callback-url Two Way Comminications (http://x-callback-url.com/examples) but no luck so far in finding such an app.
-
and with bs4?
-
Combined with the interactive form code it works (as you can see in the console right after running it)... But you have to press 'done' to get rid of the webbrowser once it has done its job.
<pre>
getGPS using html5 and interactive form
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
import cgi
import webbrowserHTML = ('<!DOCTYPE html>' +
'<html>'+
'<body>'+
'<form id="frm" action="/" method="POST" enctype="multipart/form-data">'+
'<input type="text" name="lat" id="lat" value="" />'+
'<input type="text" name="lng" id="lng" value="" />'+
'</form>'+
'<script>'+
'var frm=document.getElementById("frm");'+
'var lat=document.getElementById("lat");'+
'var lng=document.getElementById("lng");'+
'navigator.geolocation.getCurrentPosition(showPosition);'+
'function showPosition(position)'+
'{'+
' lat.value=position.coords.latitude;'+
' lng.value=position.coords.longitude;'+
' frm.submit();'
'}'+
'</script>'+
'</body>'+
'</html>')class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self): #load initial page
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(HTML)def do_POST(self): #process requests
#read form data
form = cgi.FieldStorage(fp = self.rfile, headers = self.headers,
environ = {'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type']})
#assign variables
lat = form.getfirst('lat')
lng = form.getfirst('lng')
print((lat,lng))if name == 'main': #start server and open browser
server = HTTPServer(('', 80), RequestHandler)
webbrowser.open('http://localhost', stop_when_done = True)
server.serve_forever()
</pre> -
UPDATE: The location issue was fixed quite elegantly with the location module added in Pythonista v1.4.
@hvmhvm This is a nice step forward... Thanks for that!
Now if we could only 1) get rid of the 'Done' button issue you mentioned that requires human intervention and 2) get the server.serve_forever() call to terminate once we have obtained the device's latLong.
For 1), I tried changing http:// to safari-http:// but to no effect.
For 2), I tried server.shutdown() but that seems to be a blackhole.
I also tried messing with Threads to solve both issues but to no avail.
My end goal is to create .gpx (GPS Exchange Format) files of hike, bike, and ski trips but that will require getting the device's GPS coordiantes without human intervention and having a main thread that is not blocked by a call to serve_forever().
-
Added some changes, including a response and a delayed submission, so it continuously samples your location. All you have to do now is write some GPX file generation. This even works while Pythonista is in the background (although you may need to add the keep alive code (found in another thread) to keep it going). The 'Done' button now ends the capture.
<pre>getGPS using html5 and interactive form
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
import cgi
import webbrowser
import timeHTML = ("""<!DOCTYPE html>
<html>
<body>
<p id="demo">Click the button to get your coordinates:</p>
<form id="frm" action="/" method="POST" enctype="multipart/form-data">
<input type="text" name="lat" id="lat" value="" />
<input type="text" name="lng" id="lng" value="" />
</form>
<script>
var frm=document.getElementById("frm");
var lat=document.getElementById("lat");
var lng=document.getElementById("lng");navigator.geolocation.getCurrentPosition(showPosition);
function showPosition(position)
{
lat.value=position.coords.latitude;
lng.value=position.coords.longitude;
window.setTimeout(submitPosition,2000)
}
function submitPosition()
{
frm.submit()
}
</script>
</body>
</html>""")class RequestHandler(BaseHTTPRequestHandler):
def do_GET(self): #load initial page
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(HTML)def do_POST(self): #process requests
#read form data
form = cgi.FieldStorage(fp = self.rfile, headers = self.headers,
environ = {'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type']})
#assign variables
lat = form.getfirst('lat')
lng = form.getfirst('lng')
print((lat,lng))
self.send_response(200)
self.send_header('Content-Type','text/html')
self.end_headers()
self.wfile.write(HTML)if name == 'main': #start server and open browser
server = HTTPServer(('', 80), RequestHandler)
webbrowser.open('http://localhost', stop_when_done = True)
server.serve_forever()
</pre> -
UPDATE: The location issue was fixed quite elegantly with the location module added in Pythonista v1.4.
Solved: gpsForPythonista.py delivers <b>getGPS()</b> and <b>getLatLong()</b>.
gpsForPythonista using html5 and interactive form
Source at https://gist.github.com/cclauss/6578926
Thanks to @hvmhvm of Pythonisa fourm for working codeTODO: Get rid of the user having to tap the 'Done' button
#usage: from gpsForPythonista import getGPS; print(getGPS()) # or... from gpsForPythonista import getLatLong; print(getLatLong()) # or... from gpsForPythonista import getGPS; print(getGPS().altitude)
I will give a <b>gold star</b> to anyone who can help with the TODO item above.<br>
Possible hint: why does post never get called if you change 'http://' to 'safari-http://' on line 102? -
Here is a new version.
-
We are closing the safari window, and going back to pythonista.
This looks not possible with the embedded webview, as the UIWebWiew ignores window.close() (this could be changed by omz). -
We are faking a (dumb and not compliant) web server, to bypass the heavy weight HTTPServer
-
To use, simply call get_lat_long. This should give you the latitude and longitude as float
-
The whole stuff needs better error checking...
<pre>
import socket
import webbrowser
import rehtml = """
<!DOCTYPE html>
<html>
<head>
<script>function returnToPythonista() { window.open('pythonista://', '_self', ''); window.close(); } function sendPosition(position) { var xhr = new XMLHttpRequest(); xhr.addEventListener("loadend", function () { window.setTimeout(returnToPythonista,0); }, false); var lat = position.coords.latitude; var lng = position.coords.longitude; xhr.open('HEAD', '/?lat=' + lat + '&lng=' + lng, true); xhr.send(""); } navigator.geolocation.getCurrentPosition(sendPosition);
</script>
</head><body>
<h1>Wait...</h1>
</body></html>
"""def get_lat_long(port=3050):
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind( ('127.0.0.1', port) )
s.listen(1)webbrowser.open('safari-http://localhost:3050/') def send(s, data): s2, addrinfo = s.accept() resp = s2.recv(4096) s2.send("\n".join(("HTTP/1.0 200 OK", "Content-Type: text/html", "Content-Length: {}".format(len(data)), "", data))) s2.close() return resp # Send html page on first connection send(s, html) # Send empty page data = send(s, "") s.close() result = re.search(r'lat=([\d.]*)&lng=([\d.]*)', data) if result: return [float(n) for n in result.groups()] return None, None
if name == 'main':
lat, lng = get_lat_long()
print ('lat {}, lng {}'.format(lat, lng))</pre>
-
-
Some small improvments and timing fixes in https://gist.github.com/6590539
-
UPDATE: The location issue was fixed quite elegantly with the location module added in Pythonista v1.4.
@anton2 I also made updates to https://gist.github.com/cclauss/6578926 based on your brilliant idea to use XMLHttpRequest which is much simpler than Forms! If we use the builtin webbrowser (http://) the user must click the Done button but at least we can make multiple calls to getGPS(). If we use Safari (safari-http://) the script will hang on the second call to getGPS(). We need the best of both worlds.
-
Latest version at https://gist.github.com/Anton-2/6599694, with error (like a user opting out of geolocation) and options handling. Still a big hack...