#!/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();