#!/usr/bin/gjs
/* jshint moz: true, multistr: true */
/* global imports */
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const AccuracyLevel = {
COUNTRY: 1,
CITY: 4,
NEIGHBORHOOD: 5,
STREET: 6,
EXACT: 8
};
const API_URL = 'http://api.open-notify.org/iss-now.json';
const ManagerIface = ' \
\
\
\
\
\
';
const ManagerProxy = Gio.DBusProxy.makeProxyWrapper(ManagerIface);
const ClientInterface = ' \
\
\
\
\
\
\
\
\
\
\
\
\
\
';
const ClientProxy = Gio.DBusProxy.makeProxyWrapper(ClientInterface);
const LocationInterface = ' \
\
\
\
\
\
\
';
const LocationProxy = Gio.DBusProxy.makeProxyWrapper(LocationInterface);
const ISS_Above = new GObject.Class({
Name: 'ISS_Above',
Extends: GObject.Object,
Signals: {
'processed_data': {
param_types: [
// GObject.TYPE_INT
]
}
},
_init: function(params) {
this.parent(params);
this.managerProxy = new ManagerProxy(Gio.DBus.system,
'org.freedesktop.GeoClue2', '/org/freedesktop/GeoClue2/Manager');
[this.clientAddr] = this.managerProxy.GetClientSync();
this.current_location = {};
this.iss_coords = null;
this.task_queue = 2; // number of async process to complete
this.clientProxy = new ClientProxy(Gio.DBus.system,
'org.freedesktop.GeoClue2', this.clientAddr);
this.clientProxy.DesktopId = 'gnome-shell-ISS_Above';
this.clientProxy.DistanceThreshold = 10000;
this.clientProxy.RequestedAccuracyLevel = AccuracyLevel.EXACT;
this.clientProxy.connectSignal('LocationUpdated',
Lang.bind(this, this.onLocationUpdated));
this.clientProxy.StartRemote();
this.connect('processed_data', Lang.bind(this, this.processResult));
},
run: function() {
this.getISScoords();
},
getISScoords: function () {
let self = this;
let iss_api = Gio.file_new_for_uri(API_URL);
iss_api.load_contents_async(null, function(iss_api, result) {
self.iss_coords = JSON.parse(iss_api.load_contents_finish(result)[1]);
// print(self.iss_coords.toSource());
self.emit('processed_data');
});
},
onLocationUpdated: function (proxy, sender, [oldPath, newPath]) {
let geoclueLocation = new LocationProxy(Gio.DBus.system,
"org.freedesktop.GeoClue2",
newPath);
this.current_location.Latitude = geoclueLocation.Latitude;
this.current_location.Longitude = geoclueLocation.Longitude;
this.current_location.Accuracy = geoclueLocation.Accuracy;
this.current_location.Description = geoclueLocation.Description;
this.emit('processed_data');
},
/**
* Calculate distance in km of two geographical points
*
* @param lat1 Number latitude of the first point
* @param long1 Number longitude of the first point
* @param lat2 Number latitude of the second point
* @param long2 Number longitude of the second point
* @return Number distance in km
*
* Described on https://en.wikipedia.org/wiki/Haversine_formula
*/
get_distance: function(lat1, long1, lat2, long2) {
// Mean radius of the Earth in km
const EARTH_R = 6371;
const PI_180 = Math.PI / 180;
function haversin(fi) {
return (1 - Math.cos(fi)) / 2;
}
lat1 = lat1 * PI_180;
long1 = long1 * PI_180;
lat2 = lat2 * PI_180;
long2 = long2 * PI_180;
let dist = 2 * EARTH_R *
Math.asin(Math.sqrt(haversin(lat2 - lat1) +
Math.cos(lat1) * Math.cos(lat2) * haversin(long2 - long1)));
let test_haversin = haversin(dist / EARTH_R);
if (test_haversin < 1) {
return dist.toFixed(3);
}
else {
throw new Error('haversine(d/r) cannot be over 1, but it is ' +
test_haversin);
}
},
processResult: function() {
this.task_queue--;
if (this.task_queue === 0) {
// print('our location: ' + this.current_location.toSource());
// print('iss coordinates: ' + this.iss_coords.toSource());
let dist = this.get_distance(this.current_location.Latitude,
this.current_location.Longitude,
this.iss_coords.iss_position.latitude,
this.iss_coords.iss_position.longitude)
print('ISS is ' + dist + ' km away.');
Mainloop.quit();
}
}
});
let client = new ISS_Above();
client.run();
Mainloop.run();