diff --git a/EDMarketConnector.py b/EDMarketConnector.py
index 81242899..a2b605d9 100755
--- a/EDMarketConnector.py
+++ b/EDMarketConnector.py
@@ -23,6 +23,7 @@ import companion
 import bpc
 import td
 import eddn
+import edsm
 import loadout
 import coriolis
 import flightlog
@@ -34,6 +35,7 @@ l10n.Translations().install()
 EDDB = eddb.EDDB()
 
 SHIPYARD_RETRY = 5	# retry pause for shipyard data [s]
+EDSM_POLL = 0.1
 
 
 class HyperlinkLabel(ttk.Label):
@@ -75,6 +77,7 @@ class AppWindow:
 
         self.holdofftime = config.getint('querytime') + companion.holdoff
         self.session = companion.Session()
+        self.edsm = edsm.EDSM()
 
         self.w = master
         self.w.title(applongname)
@@ -110,7 +113,7 @@ class AppWindow:
         ttk.Label(frame, text=_('Station:')).grid(row=2, column=0, sticky=tk.W)	# Main window
 
         self.cmdr = ttk.Label(frame, width=-20)
-        self.system =  HyperlinkLabel(frame, width=-20, urlfn = self.system_url)
+        self.system =  HyperlinkLabel(frame, compound=tk.RIGHT, urlfn = self.system_url)
         self.station = HyperlinkLabel(frame, width=-20, urlfn = self.station_url)
         self.button = ttk.Button(frame, text=_('Update'), command=self.getandsend, default=tk.ACTIVE, state=tk.DISABLED)	# Update button in main window
         self.status = ttk.Label(frame, width=-25)
@@ -238,6 +241,7 @@ class AppWindow:
 
             self.cmdr['text'] = data.get('commander') and data.get('commander').get('name') or ''
             self.system['text'] = data.get('lastSystem') and data.get('lastSystem').get('name') or ''
+            self.system['image'] = None
             self.station['text'] = data.get('commander') and data.get('commander').get('docked') and data.get('lastStarport') and data.get('lastStarport').get('name') or (EDDB.system(self.system['text'] and '-' or ''))
 
             config.set('querytime', querytime)
@@ -253,9 +257,14 @@ class AppWindow:
 
             elif (config.getint('output') & config.OUT_EDDN) and data['commander'].get('docked') and not data['lastStarport'].get('ships') and not retrying:
                 # API is flakey about shipyard info - retry if missing (<1s is usually sufficient - 5s for margin).
-                self.w.after(SHIPYARD_RETRY * 1000, lambda:self.getandsend(retrying=True))
+                self.w.after(int(SHIPYARD_RETRY * 1000), lambda:self.getandsend(retrying=True))
 
                 # Stuff we can do while waiting for retry
+
+                self.edsm.start_lookup(self.system['text'])
+                self.system['image'] = self.edsm.result['img']
+                self.w.after(int(EDSM_POLL * 1000), self.edsmpoll)
+
                 if config.getint('output') & config.OUT_LOG:
                     flightlog.export(data)
                 if config.getint('output') & config.OUT_SHIP_EDS:
@@ -273,6 +282,10 @@ class AppWindow:
                         h.write(json.dumps(data, indent=2, sort_keys=True))
 
                 if not retrying:
+                    self.edsm.start_lookup(self.system['text'])
+                    self.system['image'] = self.edsm.result['img']
+                    self.w.after(int(EDSM_POLL * 1000), self.edsmpoll)
+
                     if config.getint('output') & config.OUT_LOG:
                         flightlog.export(data)
                     if config.getint('output') & config.OUT_SHIP_EDS:
@@ -332,8 +345,15 @@ class AppWindow:
 
         self.cooldown()
 
+    def edsmpoll(self):
+        result = self.edsm.result
+        if result['done']:
+            self.system['image'] = result['img']
+        else:
+            self.w.after(int(EDSM_POLL * 1000), self.edsmpoll)
+
     def system_url(self, text):
-        return text and 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(text)
+        return text and self.edsm.result['url']
 
     def station_url(self, text):
         if text:
diff --git a/README.md b/README.md
index e2990e21..00e88c24 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ Click on the system name to go to its [Elite: Dangerous Star Map](http://www.eds
 
 Click on the station name to go to its [Elite: Dangerous Database](http://eddb.io/) (“eddb”) entry in your web broswer.
 
-![Windows screenshot](img/win.png) ![Mac screenshot](img/mac.png)
+![Windows screenshot](img/win.png) &nbsp; ![Mac screenshot](img/mac.png)
 
 
 Installation
diff --git a/edsm.py b/edsm.py
new file mode 100644
index 00000000..f69b17e8
--- /dev/null
+++ b/edsm.py
@@ -0,0 +1,62 @@
+import requests
+import threading
+from sys import platform
+import urllib
+
+import Tkinter as tk
+
+if __debug__:
+    from traceback import print_exc
+
+class EDSM:
+
+    _TIMEOUT = 10
+
+    def __init__(self):
+        self.result = { 'img': None, 'url': None, 'done': True }
+        EDSM._IMG_WAIT_MAC = tk.PhotoImage(data = 'R0lGODlhDgAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAOABAAAAIrlAWpx6jZzoPRvQqC3qBlzjGfNnbSFpQmQibcOqKpKIe0vIpTZS3Y/rscCgA7')	# wristwatch
+        EDSM._IMG_WAIT_WIN = tk.PhotoImage(data = 'R0lGODlhDgAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAOABAAAAIuFI4JwurcgpxhQUOnhUD2Xl1R5YmcZl5fqoYsVqYgKs527ZHu+ZGb4UhwgghGAQA7')	# hourglass
+        EDSM._IMG_KNOWN    = tk.PhotoImage(data = 'R0lGODlhDgAOAMIEAFWjVVWkVWS/ZGfFZwAAAAAAAAAAAAAAACH5BAEKAAQALAAAAAAOAA4AAAMsSLrcHEIEp8C4GDSLu15dOCyB2E2EYGKCoq5DS5QwSsDjwomfzlOziA0ITAAAOw==')	# green circle
+        EDSM._IMG_UNKNOWN  = tk.PhotoImage(data = 'R0lGODlhDgAOAMIEAM16BM57BfCPBfiUBgAAAAAAAAAAAAAAACH5BAEKAAQALAAAAAAOAA4AAAMsSLrcHEIEp8C4GDSLu15dOCyB2E2EYGKCoq5DS5QwSsDjwomfzlOziA0ITAAAOw==')	# orange circle
+        EDSM._IMG_NOTFOUND = tk.PhotoImage(data = 'R0lGODlhDgAOAKECAGVLJ+ddWO5fW+5fWyH5BAEKAAMALAAAAAAOAA4AAAImnI+JEAFqgJj0LYqFNTkf2VVGEFLBWE7nAJZbKlzhFnX00twQVAAAOw==')	# red circle
+        EDSM._IMG_ERROR    = tk.PhotoImage(data = 'R0lGODlhDgAOAIABAAAAAP///yH5BAEKAAEALAAAAAAOAA4AAAIcjAOpx+rAUGrzVHujWRrDvmWdOH5geKZqSmpkAQA7')	  # BBC Mode 7 '?'
+
+    def start_lookup(self, system_name):
+        self.cancel_lookup()
+        self.result = { 'img': None, 'url': 'http://www.edsm.net/needed-distances?systemName=%s' % urllib.quote(system_name), 'done': False }	# default URL
+        self.thread = threading.Thread(target = self.worker, name = 'EDSM worker', args = (system_name, self.result))
+        self.thread.daemon = True
+        self.thread.start()
+
+    def cancel_lookup(self):
+        self.thread = None	# orphan any existing thread
+        self.result = { 'img': None, 'url': None, 'done': True }	# orphan existing thread's results
+
+    def worker(self, system_name, result):
+        try:
+            r = requests.get('http://www.edsm.net/api-v1/system?sysname=%s&coords=1' % urllib.quote(system_name), timeout=EDSM._TIMEOUT)
+            r.raise_for_status()
+            data = r.json()
+
+            if data == -1:
+                # System not present - create it
+                result['img'] = EDSM._IMG_NOTFOUND
+                result['done'] = True	# give feedback immediately
+                requests.get('http://www.edsm.net/api-v1/url?sysname=%s' % urllib.quote(system_name), timeout=EDSM._TIMEOUT)	# creates system
+            elif data.get('coords'):
+                # Prefer to send user to "Show distances" page for systems with known coordinates
+                result['img'] = EDSM._IMG_KNOWN
+                result['done'] = True	# give feedback immediately
+                try:
+                    r = requests.get('http://www.edsm.net/api-v1/url?sysname=%s' % urllib.quote(system_name), timeout=EDSM._TIMEOUT)
+                    r.raise_for_status()
+                    data = r.json()
+                    result['url'] = data['url']['show-system'].replace('\\','')
+                except:
+                    if __debug__: print_exc()
+            else:
+                result['img'] = EDSM._IMG_UNKNOWN
+        except:
+            if __debug__: print_exc()
+            result['img'] = EDSM._IMG_ERROR
+        result['done'] = True
diff --git a/img/mac.png b/img/mac.png
index 73f3f429..69f8622b 100644
Binary files a/img/mac.png and b/img/mac.png differ