1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-13 15:57:14 +03:00

Add support for saving a simple flight log.

This commit is contained in:
Jonathan Harris 2015-06-22 18:36:06 +01:00
parent 1af879ffae
commit 050aada1a2
5 changed files with 130 additions and 37 deletions

View File

@ -18,6 +18,7 @@ import bpc
import td
import eddn
import loadout
import flightlog
import stats
import prefs
from config import appname, applongname, config
@ -136,6 +137,15 @@ class AppWindow:
try:
self.session.login(config.get('username'), config.get('password'))
self.status['text'] = ''
# Try to obtain exclusive lock on flight log ASAP
if config.getint('output') & config.OUT_LOG:
try:
flightlog.openlog()
except Exception as e:
if __debug__: print_exc()
self.status['text'] = str(e)
except companion.VerificationRequired:
# don't worry about authentication now - prompt on query
self.status['text'] = ''
@ -178,31 +188,38 @@ class AppWindow:
# Validation
if not data.get('commander') or not data['commander'].get('name','').strip():
self.status['text'] = "Who are you?!" # Shouldn't happen
self.status['text'] = "Who are you?!" # Shouldn't happen
elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip():
self.status['text'] = "Where are you?!" # Shouldn't happen
self.status['text'] = "Where are you?!" # Shouldn't happen
elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip():
self.status['text'] = "What are you flying?!" # Shouldn't happen
elif not data['commander'].get('docked'):
if config.getint('output') & config.OUT_SHIP:
loadout.export(data) # do loadout even if not docked
self.status['text'] = "You're not docked at a station!"
elif not data['lastStarport'].get('commodities'):
self.status['text'] = "Station doesn't have a market!"
else:
# stuff we can do when not docked
if config.getint('output') & config.OUT_LOG:
flightlog.export(data)
if config.getint('output') & config.OUT_SHIP:
loadout.export(data)
if config.getint('output') & config.OUT_CSV:
bpc.export(data, True)
if config.getint('output') & config.OUT_TD:
td.export(data)
if config.getint('output') & config.OUT_BPC:
bpc.export(data, False)
if config.getint('output') & config.OUT_EDDN:
self.status['text'] = 'Sending data to EDDN...'
self.w.update_idletasks()
eddn.export(data)
self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))
if not (config.getint('output') & (config.OUT_CSV|config.OUT_TD|config.OUT_BPC|config.OUT_EDDN)):
# no further output requested
self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))
elif not data['commander'].get('docked'):
self.status['text'] = "You're not docked at a station!"
elif not data['lastStarport'].get('commodities'):
self.status['text'] = "Station doesn't have a market!"
else:
if config.getint('output') & config.OUT_CSV:
bpc.export(data, True)
if config.getint('output') & config.OUT_TD:
td.export(data)
if config.getint('output') & config.OUT_BPC:
bpc.export(data, False)
if config.getint('output') & config.OUT_EDDN:
self.status['text'] = 'Sending data to EDDN...'
self.w.update_idletasks()
eddn.export(data)
self.status['text'] = strftime('Last updated at %H:%M:%S', localtime(querytime))
except companion.VerificationRequired:
return prefs.AuthenticationDialog(self.w, self.verify)

View File

@ -3,10 +3,11 @@ Elite: Dangerous Market Connector
This app downloads commodity market data from the game [Elite: Dangerous](https://www.elitedangerous.com/) and, at your choice, either:
* transmits the data to the [Elite Dangerous Data Network](http://eddn.ed-td.space/) ("EDDN") from where you and others can use it via online trading tools such as [eddb](http://eddb.io/).
* sends the data to the [Elite Dangerous Data Network](http://eddn.ed-td.space/) ("EDDN") from where you and others can use it via online trading tools such as [eddb](http://eddb.io/) or [Elite Trade Net](http://etn.io/).
* saves the data to files on your computer that you can load into trading tools such as [Slopey's BPC Market Tool](https://forums.frontier.co.uk/showthread.php?t=76081), [Trade Dangerous](https://bitbucket.org/kfsone/tradedangerous/wiki/Home) and [Thrudd's Trading Tools](http://www.elitetradingtool.co.uk/).
* saves a record of your ship loadout and/or flight log.
The user-interface is deliberately minimal - when you land at a station just switch to the app and press the "Update" button or press Enter to automatically download and transmit and/or save the station's commodity market data:
The user-interface is deliberately minimal - when you land at a station just switch to the app and press the "Update" button or press Enter to automatically download and transmit and/or save your choice of data.
![Windows screenshot](img/win.png) ![Mac screenshot](img/mac.png)
@ -32,11 +33,9 @@ Windows:
Setup
--------
The first time that you run the app you are prompted for your username and password. This is the same username and password
combination that you use to log into the Elite: Dangerous launcher, and is required so that the Frontier servers can send the app the market data for the station that *you* are docked at.
combination that you use to log into the Elite: Dangerous launcher, and is required so that the Frontier servers can send the app *your* data and the market data for the station that *you* are docked at.
You can also choose here whether to send the market data that you download to EDDN or to save it locally,
whether to attach your Cmdr name or a [pseudo-anonymized](http://en.wikipedia.org/wiki/Pseudonymity) ID to the data,
and whether to save a record of your ship loadout in a form that you can import into [E:D Shipyard](http://www.edshipyard.com) after every outfitting change.
You can also choose here what data to save (refer to the next section for details) and whether to attach your Cmdr name or a [pseudo-anonymized](http://en.wikipedia.org/wiki/Pseudonymity) ID to the data.
You are next prompted to authenticate with a "verification code", which you will shortly receive by email from Frontier.
Note that each "verification code" is one-time only - if you enter the code incorrectly or quit the app before
@ -45,6 +44,24 @@ authenticating you will need to wait for Frontier to send you a new code.
If you are not prompted to authenticate, but instead see the message "Error: Invalid Credentials" then choose the menu
option EDMarketConnector → Preferences (Mac) or File → Settings (Windows) and double-check your username and password.
Output
--------
This app can save a variety of data in a variety of formats:
* Market data
* Elite Dangerous Data Network - sends the market data to the "[EDDN](http://eddn.ed-td.space/)" from where you and others can use it via online trading tools such as [eddb](http://eddb.io/) or [Elite Trade Net](http://etn.io/).
* Slopey's BPC format - saves the market data as files that you can load into [Slopey's BPC Market Tool](https://forums.frontier.co.uk/showthread.php?t=76081).
* Trade Dangerous format - saves the market data as files that you can load into [Trade Dangerous](https://bitbucket.org/kfsone/tradedangerous/wiki/Home).
* CSV format - saves the market data as files that you can upload to [Thrudd's Trading Tools](http://www.elitetradingtool.co.uk/).
* Ship loadout
* After every outfitting change saves a record of your ship loadout as a file that you can open in a text editor and that you can import into [E:D Shipyard](http://www.edshipyard.com).
* Flight log
* Adds a record of your location, ship and cargo to a file that you can open in a text editor or a spreadsheet program such as Excel.
By default these files will be placed in your Documents folder. Since this app will create a lot of files if you use it for a while you may wish to create a separate folder for the files and tell the app to place them there.
Statistics
--------
Choose the "Statistics" item from the menu to view your Cmdrs's statistics. The statistics shown are largely the same
@ -61,6 +78,7 @@ Windows:
* Uninstall **Elite Dangerous Market Connector** from Control Panel → Programs.
Note: Uninstalling the app does not delete any output files that it has previously written.
Running from source
--------

View File

@ -70,6 +70,7 @@ class Config:
OUT_TD = 4
OUT_CSV = 8
OUT_SHIP = 16
OUT_LOG = 32
if platform=='darwin':

55
flightlog.py Normal file
View File

@ -0,0 +1,55 @@
# Export poor man's flight log
import errno
import os
from os.path import join
from sys import platform
import time
from config import config
from companion import ship_map, commodity_map
logfile = None
def openlog():
global logfile
if logfile: return
try:
logfile = open(join(config.get('outdir'), 'Flight Log.csv'), 'a+')
if platform != 'win32': # open for writing is automatically exclusive on Windows
from fcntl import lockf, LOCK_SH, LOCK_NB
lockf(logfile, LOCK_SH|LOCK_NB)
logfile.seek(0, os.SEEK_END)
if not logfile.tell():
logfile.write('Date,Time,System,Station,Ship,Cargo\r\n')
except EnvironmentError as e:
logfile = None
if e.errno in [errno.EACCES, errno.EAGAIN]:
raise Exception('Can\'t write "Flight Log.csv". Are you editing it in another app?')
else:
raise
except:
logfile = None
raise
def export(data):
def elapsed(game_time):
return '%3d:%02d:%02d' % ((game_time // 3600) % 3600, (game_time // 60) % 60, game_time % 60)
querytime = config.getint('querytime') or int(time.time())
openlog()
logfile.write('%s,%s,%s,%s,%s,%s\r\n' % (
time.strftime('%Y-%m-%d', time.localtime(querytime)),
time.strftime('%H:%M:%S', time.localtime(querytime)),
data['lastSystem']['name'],
data['commander']['docked'] and data['lastStarport']['name'] or '',
data['ship']['name'],
','.join([('%d %s' % (x['qty'], commodity_map.get(x['commodity'],x['commodity']))) for x in data['ship']['cargo']['items'] if x['commodity']!='drones'])))
logfile.flush()

View File

@ -57,7 +57,7 @@ class PreferencesDialog(tk.Toplevel):
credframe.grid(padx=10, pady=10, sticky=tk.NSEW)
credframe.columnconfigure(1, weight=1)
ttk.Label(credframe, text="Please log in with your Elite:Dangerous account details").grid(row=0, columnspan=2, sticky=tk.W)
ttk.Label(credframe, text="Please log in with your Elite: Dangerous account details").grid(row=0, columnspan=2, sticky=tk.W)
ttk.Label(credframe, text="Username (Email)").grid(row=1, sticky=tk.W)
ttk.Label(credframe, text="Password").grid(row=2, sticky=tk.W)
@ -77,23 +77,25 @@ class PreferencesDialog(tk.Toplevel):
outframe.columnconfigure(0, weight=1)
output = config.getint('output') or (config.OUT_EDDN | config.OUT_SHIP)
ttk.Label(outframe, text="Please choose how you want the data saved").grid(row=0, columnspan=2, padx=5, pady=3, sticky=tk.W)
ttk.Label(outframe, text="Please choose what data to save").grid(row=0, columnspan=2, padx=5, pady=3, sticky=tk.W)
self.out_eddn= tk.IntVar(value = (output & config.OUT_EDDN) and 1 or 0)
ttk.Checkbutton(outframe, text="Online to the Elite Dangerous Data Network (EDDN)", variable=self.out_eddn).grid(row=1, columnspan=2, padx=5, sticky=tk.W)
ttk.Checkbutton(outframe, text="Send market data to the Elite Dangerous Data Network", variable=self.out_eddn).grid(row=1, columnspan=2, padx=5, sticky=tk.W)
self.out_bpc = tk.IntVar(value = (output & config.OUT_BPC ) and 1 or 0)
ttk.Checkbutton(outframe, text="Offline in Slopey's BPC format", variable=self.out_bpc, command=self.outvarchanged).grid(row=2, columnspan=2, padx=5, sticky=tk.W)
ttk.Checkbutton(outframe, text="Market data in Slopey's BPC format", variable=self.out_bpc, command=self.outvarchanged).grid(row=2, columnspan=2, padx=5, sticky=tk.W)
self.out_td = tk.IntVar(value = (output & config.OUT_TD ) and 1 or 0)
ttk.Checkbutton(outframe, text="Offline in Trade Dangerous format", variable=self.out_td, command=self.outvarchanged).grid(row=3, columnspan=2, padx=5, sticky=tk.W)
ttk.Checkbutton(outframe, text="Market data in Trade Dangerous format", variable=self.out_td, command=self.outvarchanged).grid(row=3, columnspan=2, padx=5, sticky=tk.W)
self.out_csv = tk.IntVar(value = (output & config.OUT_CSV ) and 1 or 0)
ttk.Checkbutton(outframe, text="Offline in CSV format", variable=self.out_csv, command=self.outvarchanged).grid(row=4, columnspan=2, padx=5, sticky=tk.W)
ttk.Checkbutton(outframe, text="Market data in CSV format", variable=self.out_csv, command=self.outvarchanged).grid(row=4, columnspan=2, padx=5, sticky=tk.W)
self.out_ship= tk.IntVar(value = (output & config.OUT_SHIP) and 1 or 0)
ttk.Checkbutton(outframe, text="Offline ship loadout in E:D Shipyard format", variable=self.out_ship, command=self.outvarchanged).grid(row=5, columnspan=2, padx=5, sticky=tk.W)
ttk.Label(outframe, text=(platform=='darwin' and 'Where:' or 'File location:')).grid(row=6, padx=5, pady=(5,0), sticky=tk.NSEW)
ttk.Checkbutton(outframe, text="Ship loadout in E:D Shipyard format", variable=self.out_ship, command=self.outvarchanged).grid(row=5, columnspan=2, padx=5, sticky=tk.W)
self.out_log = tk.IntVar(value = (output & config.OUT_LOG) and 1 or 0)
ttk.Checkbutton(outframe, text="Flight log", variable=self.out_log, command=self.outvarchanged).grid(row=6, columnspan=2, padx=5, sticky=tk.W)
ttk.Label(outframe, text=(platform=='darwin' and 'Where:' or 'File location:')).grid(row=7, padx=5, pady=(5,0), sticky=tk.NSEW)
self.outbutton = ttk.Button(outframe, text=(platform=='darwin' and 'Change...' or 'Browse...'), command=self.outbrowse)
self.outbutton.grid(row=6, column=1, padx=5, pady=(5,0), sticky=tk.NSEW)
self.outbutton.grid(row=7, column=1, padx=5, pady=(5,0), sticky=tk.NSEW)
self.outdir = ttk.Entry(outframe)
self.outdir.insert(0, config.get('outdir'))
self.outdir.grid(row=7, columnspan=2, padx=5, pady=5, sticky=tk.EW)
self.outdir.grid(row=8, columnspan=2, padx=5, pady=5, sticky=tk.EW)
self.outvarchanged()
privacyframe = ttk.LabelFrame(frame, text='Privacy')
@ -120,7 +122,7 @@ class PreferencesDialog(tk.Toplevel):
#self.wait_window(self) # causes duplicate events on OSX
def outvarchanged(self):
local = self.out_bpc.get() or self.out_td.get() or self.out_csv.get() or self.out_ship.get()
local = self.out_bpc.get() or self.out_td.get() or self.out_csv.get() or self.out_ship.get() or self.out_log.get()
self.outbutton['state'] = local and tk.NORMAL or tk.DISABLED
self.outdir['state'] = local and 'readonly' or tk.DISABLED
@ -159,7 +161,7 @@ class PreferencesDialog(tk.Toplevel):
credentials = (config.get('username'), config.get('password'))
config.set('username', self.username.get().strip())
config.set('password', self.password.get().strip())
config.set('output', (self.out_eddn.get() and config.OUT_EDDN or 0) + (self.out_bpc.get() and config.OUT_BPC or 0) + (self.out_td.get() and config.OUT_TD or 0) + (self.out_csv.get() and config.OUT_CSV or 0) + (self.out_ship.get() and config.OUT_SHIP or 0))
config.set('output', (self.out_eddn.get() and config.OUT_EDDN or 0) + (self.out_bpc.get() and config.OUT_BPC or 0) + (self.out_td.get() and config.OUT_TD or 0) + (self.out_csv.get() and config.OUT_CSV or 0) + (self.out_ship.get() and config.OUT_SHIP or 0) + (self.out_log.get() and config.OUT_LOG or 0))
config.set('outdir', self.outdir.get().strip())
config.set('anonymous', self.out_anon.get())
self.destroy()