Fix PEP8 styling issues

merge-requests/1/head
Cees Bassa 2018-11-30 15:40:18 +01:00
parent a762e1147a
commit 5b36c23855
1 changed files with 202 additions and 92 deletions

View File

@ -13,6 +13,7 @@ import glob
import lxml.html import lxml.html
import argparse import argparse
class twolineelement: class twolineelement:
"""TLE class""" """TLE class"""
@ -22,11 +23,11 @@ class twolineelement:
self.tle0 = tle0 self.tle0 = tle0
self.tle1 = tle1 self.tle1 = tle1
self.tle2 = tle2 self.tle2 = tle2
if tle0[:2]=="0 ": if tle0[:2] == "0 ":
self.name = tle0[2:] self.name = tle0[2:]
else: else:
self.name = tle0 self.name = tle0
if tle1.split(" ")[1]=="": if tle1.split(" ")[1] == "":
self.id = int(tle1.split(" ")[2][:4]) self.id = int(tle1.split(" ")[2][:4])
else: else:
self.id = int(tle1.split(" ")[1][:5]) self.id = int(tle1.split(" ")[1][:5])
@ -48,6 +49,7 @@ class satellite:
self.good_count = good_count self.good_count = good_count
self.data_count = data_count self.data_count = data_count
def get_scheduled_passes_from_network(ground_station, tmin, tmax): def get_scheduled_passes_from_network(ground_station, tmin, tmax):
# Get first page # Get first page
client = requests.session() client = requests.session()
@ -55,61 +57,75 @@ def get_scheduled_passes_from_network(ground_station, tmin, tmax):
# Loop # Loop
start = True start = True
scheduledpasses = [] scheduledpasses = []
while True: while True:
if start: if start:
r = client.get("https://network.satnogs.org/api/observations/?ground_station=%d"%ground_station) r = client.get(
"https://network.satnogs.org/api/observations/?ground_station=%d" %
ground_station)
start = False start = False
else: else:
nextpage = r.links.get("next") nextpage = r.links.get("next")
r = client.get(nextpage["url"]) r = client.get(nextpage["url"])
# r.json() is a list of dicts # r.json() is a list of dicts
for o in r.json(): for o in r.json():
satpass = {"id": o['norad_cat_id'], satpass = {
"tr": datetime.strptime(o['start'].replace("Z", ""), "%Y-%m-%dT%H:%M:%S"), "id": o['norad_cat_id'],
"ts": datetime.strptime(o['end'].replace("Z", ""), "%Y-%m-%dT%H:%M:%S"), "tr": datetime.strptime(
"scheduled": True} o['start'].replace(
"Z",
""),
"%Y-%m-%dT%H:%M:%S"),
"ts": datetime.strptime(
o['end'].replace(
"Z",
""),
"%Y-%m-%dT%H:%M:%S"),
"scheduled": True}
if satpass['ts']>tmin and satpass['tr']<tmax: if satpass['ts'] > tmin and satpass['tr'] < tmax:
scheduledpasses.append(satpass) scheduledpasses.append(satpass)
if satpass['ts']<tmin: if satpass['ts'] < tmin:
break break
return scheduledpasses return scheduledpasses
def overlap(satpass, scheduledpasses): def overlap(satpass, scheduledpasses):
# No overlap # No overlap
overlap = False overlap = False
# Loop over scheduled passes # Loop over scheduled passes
for scheduledpass in scheduledpasses: for scheduledpass in scheduledpasses:
# Test pass falls within scheduled pass # Test pass falls within scheduled pass
if satpass['tr']>=scheduledpass['tr'] and satpass['ts']<scheduledpass['ts']: if satpass['tr'] >= scheduledpass['tr'] and satpass['ts'] < scheduledpass['ts']:
overlap = True overlap = True
# Scheduled pass falls within test pass # Scheduled pass falls within test pass
elif scheduledpass['tr']>=satpass['tr'] and scheduledpass['ts']<satpass['ts']: elif scheduledpass['tr'] >= satpass['tr'] and scheduledpass['ts'] < satpass['ts']:
overlap = True overlap = True
# Pass start falls within pass # Pass start falls within pass
elif satpass['tr']>=scheduledpass['tr'] and satpass['tr']<scheduledpass['ts']: elif satpass['tr'] >= scheduledpass['tr'] and satpass['tr'] < scheduledpass['ts']:
overlap = True overlap = True
# Pass end falls within end # Pass end falls within end
elif satpass['ts']>=scheduledpass['tr'] and satpass['ts']<scheduledpass['ts']: elif satpass['ts'] >= scheduledpass['tr'] and satpass['ts'] < scheduledpass['ts']:
overlap = True overlap = True
if overlap == True: if overlap:
break break
return overlap return overlap
def ordered_scheduler(passes, scheduledpasses): def ordered_scheduler(passes, scheduledpasses):
"""Loop through a list of ordered passes and schedule each next one that fits""" """Loop through a list of ordered passes and schedule each next one that fits"""
# Loop over passes # Loop over passes
for satpass in passes: for satpass in passes:
# Schedule if there is no overlap with already scheduled passes # Schedule if there is no overlap with already scheduled passes
if overlap(satpass, scheduledpasses)==False: if not overlap(satpass, scheduledpasses):
scheduledpasses.append(satpass) scheduledpasses.append(satpass)
return scheduledpasses return scheduledpasses
def random_scheduler(passes, scheduledpasses): def random_scheduler(passes, scheduledpasses):
"""Schedule passes based on random ordering""" """Schedule passes based on random ordering"""
# Shuffle passes # Shuffle passes
@ -117,24 +133,29 @@ def random_scheduler(passes, scheduledpasses):
return ordered_scheduler(passes, scheduledpasses) return ordered_scheduler(passes, scheduledpasses)
def efficiency(passes): def efficiency(passes):
# Loop over passes # Loop over passes
start = False start = False
for satpass in passes: for satpass in passes:
if start==False: if not start:
dt = satpass['ts']-satpass['tr'] dt = satpass['ts'] - satpass['tr']
tmin = satpass['tr'] tmin = satpass['tr']
tmax = satpass['ts'] tmax = satpass['ts']
start = True start = True
else: else:
dt += satpass['ts']-satpass['tr'] dt += satpass['ts'] - satpass['tr']
if satpass['tr']<tmin: tmin=satpass['tr'] if satpass['tr'] < tmin:
if satpass['ts']>tmax: tmax=satpass['ts'] tmin = satpass['tr']
if satpass['ts'] > tmax:
tmax = satpass['ts']
# Total time covered # Total time covered
dttot = tmax-tmin dttot = tmax - tmin
return dt.total_seconds(),dttot.total_seconds(), dt.total_seconds()/dttot.total_seconds() return dt.total_seconds(), dttot.total_seconds(
), dt.total_seconds() / dttot.total_seconds()
def find_passes(satellites, observer, tmin, tmax, minimum_altitude): def find_passes(satellites, observer, tmin, tmax, minimum_altitude):
# Loop over satellites # Loop over satellites
@ -143,7 +164,7 @@ def find_passes(satellites, observer, tmin, tmax, minimum_altitude):
for satellite in satellites: for satellite in satellites:
# Set start time # Set start time
observer.date = ephem.date(tmin) observer.date = ephem.date(tmin)
# Load TLE # Load TLE
try: try:
sat_ephem = ephem.readtle(str(satellite.tle0), sat_ephem = ephem.readtle(str(satellite.tle0),
@ -204,12 +225,14 @@ def find_passes(satellites, observer, tmin, tmax, minimum_altitude):
'data_count': satellite.data_count, 'data_count': satellite.data_count,
'scheduled': False} 'scheduled': False}
passes.append(satpass) passes.append(satpass)
observer.date = ephem.Date(ts).datetime() + timedelta(minutes=1) observer.date = ephem.Date(
ts).datetime() + timedelta(minutes=1)
else: else:
keep_digging = False keep_digging = False
return passes return passes
def get_groundstation_info(ground_station_id): def get_groundstation_info(ground_station_id):
# Get first page # Get first page
client = requests.session() client = requests.session()
@ -242,6 +265,7 @@ def get_groundstation_info(ground_station_id):
else: else:
return {} return {}
def get_active_transmitter_info(fmin, fmax): def get_active_transmitter_info(fmin, fmax):
# Open session # Open session
client = requests.session() client = requests.session()
@ -250,13 +274,14 @@ def get_active_transmitter_info(fmin, fmax):
# Loop # Loop
transmitters = [] transmitters = []
for o in r.json(): for o in r.json():
if o["alive"] and o["downlink_low"]>fmin and o["downlink_low"]<=fmax: if o["alive"] and o["downlink_low"] > fmin and o["downlink_low"] <= fmax:
transmitter = {"norad_cat_id": o["norad_cat_id"], transmitter = {"norad_cat_id": o["norad_cat_id"],
"uuid": o["uuid"]} "uuid": o["uuid"]}
transmitters.append(transmitter) transmitters.append(transmitter)
return transmitters return transmitters
def get_last_update(fname): def get_last_update(fname):
try: try:
fp = open(fname, "r") fp = open(fname, "r")
@ -267,22 +292,31 @@ def get_last_update(fname):
return None return None
def schedule_observation(username, password, norad_cat_id, uuid, ground_station_id, starttime, endtime): def schedule_observation(
loginUrl = "https://network.satnogs.org/accounts/login/" #login URL username,
password,
norad_cat_id,
uuid,
ground_station_id,
starttime,
endtime):
loginUrl = "https://network.satnogs.org/accounts/login/" # login URL
session = requests.session() session = requests.session()
login = session.get(loginUrl) #Get login page for CSFR token login = session.get(loginUrl) # Get login page for CSFR token
login_html = lxml.html.fromstring(login.text) login_html = lxml.html.fromstring(login.text)
login_hidden_inputs = login_html.xpath(r'//form//input[@type="hidden"]') #Get CSFR token login_hidden_inputs = login_html.xpath(
r'//form//input[@type="hidden"]') # Get CSFR token
form = {x.attrib["name"]: x.attrib["value"] for x in login_hidden_inputs} form = {x.attrib["name"]: x.attrib["value"] for x in login_hidden_inputs}
form["login"] = username form["login"] = username
form["password"] = password form["password"] = password
session.post(loginUrl, data=form, headers={'referer':loginUrl}) #Login session.post(loginUrl, data=form, headers={'referer': loginUrl}) # Login
obsURL = "https://network.satnogs.org/observations/new/" #Observation URL obsURL = "https://network.satnogs.org/observations/new/" # Observation URL
obs = session.get(obsURL) #Get the observation/new/ page to get the CSFR token # Get the observation/new/ page to get the CSFR token
obs_html = lxml.html.fromstring(obs.text) obs = session.get(obsURL)
obs_html = lxml.html.fromstring(obs.text)
hidden_inputs = obs_html.xpath(r'//form//input[@type="hidden"]') hidden_inputs = obs_html.xpath(r'//form//input[@type="hidden"]')
form = {x.attrib["name"]: x.attrib["value"] for x in hidden_inputs} form = {x.attrib["name"]: x.attrib["value"] for x in hidden_inputs}
form["satellite"] = norad_cat_id form["satellite"] = norad_cat_id
form["transmitter"] = uuid form["transmitter"] = uuid
form["start-time"] = starttime form["start-time"] = starttime
@ -291,34 +325,51 @@ def schedule_observation(username, password, norad_cat_id, uuid, ground_station_
form["0-ending_time"] = endtime form["0-ending_time"] = endtime
form["0-station"] = ground_station_id form["0-station"] = ground_station_id
form["total"] = str(1) form["total"] = str(1)
session.post(obsURL, data=form, headers={'referer':obsURL}) session.post(obsURL, data=form, headers={'referer': obsURL})
def get_transmitter_success_rate(norad, uuid): def get_transmitter_success_rate(norad, uuid):
transmitters = requests.get("https://network.satnogs.org/transmitters/"+str(norad)).json()["transmitters"] transmitters = requests.get(
"https://network.satnogs.org/transmitters/" +
str(norad)).json()["transmitters"]
success_rate = 0 success_rate = 0
good_count = 0 good_count = 0
data_count = 0 data_count = 0
for transmitter in transmitters: for transmitter in transmitters:
if transmitter["uuid"]==uuid: if transmitter["uuid"] == uuid:
success_rate = transmitter["success_rate"] success_rate = transmitter["success_rate"]
good_count = transmitter["good_count"] good_count = transmitter["good_count"]
data_count = transmitter["data_count"] data_count = transmitter["data_count"]
break break
return success_rate, good_count, data_count return success_rate, good_count, data_count
if __name__ == "__main__": if __name__ == "__main__":
# Parse arguments # Parse arguments
parser = argparse.ArgumentParser(description="Automatically schedule observations on a SatNOGS station.") parser = argparse.ArgumentParser(
description="Automatically schedule observations on a SatNOGS station.")
parser.add_argument("-s", "--station", help="Ground station ID", type=int) parser.add_argument("-s", "--station", help="Ground station ID", type=int)
parser.add_argument("-t", "--starttime", help="Start time (YYYY-MM-DD HH:MM:SS) [default: now]", parser.add_argument(
default=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")) "-t",
parser.add_argument("-d", "--duration", help="Duration to schedule [hours]", type=int, default=1) "--starttime",
help="Start time (YYYY-MM-DD HH:MM:SS) [default: now]",
default=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S"))
parser.add_argument(
"-d",
"--duration",
help="Duration to schedule [hours]",
type=int,
default=1)
parser.add_argument("-u", "--username", help="SatNOGS username") parser.add_argument("-u", "--username", help="SatNOGS username")
parser.add_argument("-p", "--password", help="SatNOGS password") parser.add_argument("-p", "--password", help="SatNOGS password")
parser.add_argument("-n", "--dryrun", help="Dry run (do not schedule passes)", action="store_true") parser.add_argument(
"-n",
"--dryrun",
help="Dry run (do not schedule passes)",
action="store_true")
args = parser.parse_args() args = parser.parse_args()
# Settings # Settings
ground_station_id = args.station ground_station_id = args.station
length_hours = args.duration length_hours = args.duration
@ -331,7 +382,7 @@ if __name__ == "__main__":
# Set time range # Set time range
tnow = datetime.strptime(args.starttime, "%Y-%m-%dT%H:%M:%S") tnow = datetime.strptime(args.starttime, "%Y-%m-%dT%H:%M:%S")
tmin = tnow tmin = tnow
tmax = tnow+timedelta(hours=length_hours) tmax = tnow + timedelta(hours=length_hours)
# Get ground station information # Get ground station information
ground_station = get_groundstation_info(ground_station_id) ground_station = get_groundstation_info(ground_station_id)
@ -341,49 +392,81 @@ if __name__ == "__main__":
os.mkdir(cache_dir) os.mkdir(cache_dir)
# Get last update # Get last update
tlast = get_last_update(os.path.join(cache_dir, "last_update_%d.txt"%ground_station_id)) tlast = get_last_update(
os.path.join(
cache_dir,
"last_update_%d.txt" %
ground_station_id))
# Update logic # Update logic
update = False update = False
if tlast==None or (tnow-tlast).total_seconds()>data_age_hours*3600: if tlast is None or (tnow - tlast).total_seconds() > data_age_hours * 3600:
update = True update = True
if not os.path.isfile(os.path.join(cache_dir, "transmitters_%d.txt"%ground_station_id)): if not os.path.isfile(
os.path.join(
cache_dir,
"transmitters_%d.txt" %
ground_station_id)):
update = True update = True
if not os.path.isfile(os.path.join(cache_dir, "tles_%d.txt"%ground_station_id)): if not os.path.isfile(
os.path.join(
cache_dir,
"tles_%d.txt" %
ground_station_id)):
update = True update = True
# Update # Update
if update: if update:
# Store current time # Store current time
with open(os.path.join(cache_dir, "last_update_%d.txt"%ground_station_id), "w") as fp: with open(os.path.join(cache_dir, "last_update_%d.txt" % ground_station_id), "w") as fp:
fp.write(tnow.strftime("%Y-%m-%dT%H:%M:%S")+"\n") fp.write(tnow.strftime("%Y-%m-%dT%H:%M:%S") + "\n")
# Get active transmitters in frequency range of each antenna # Get active transmitters in frequency range of each antenna
transmitters = [] transmitters = []
for antenna in ground_station['antenna']: for antenna in ground_station['antenna']:
transmitters.append(get_active_transmitter_info(antenna["frequency"], antenna["frequency_max"])) transmitters.append(
get_active_transmitter_info(
antenna["frequency"],
antenna["frequency_max"]))
transmitters = list(itertools.chain.from_iterable(transmitters)) transmitters = list(itertools.chain.from_iterable(transmitters))
# Store transmitters # Store transmitters
fp = open(os.path.join(cache_dir, "transmitters_%d.txt"%ground_station_id), "w") fp = open(
os.path.join(
cache_dir,
"transmitters_%d.txt" %
ground_station_id),
"w")
for transmitter in transmitters: for transmitter in transmitters:
success_rate, good_count, data_count = get_transmitter_success_rate( success_rate, good_count, data_count = get_transmitter_success_rate(
transmitter["norad_cat_id"], transmitter["uuid"]) transmitter["norad_cat_id"], transmitter["uuid"])
fp.write("%05d %s %d %d %d\n"%(transmitter["norad_cat_id"], transmitter["uuid"], success_rate, good_count, data_count)) fp.write(
"%05d %s %d %d %d\n" %
(transmitter["norad_cat_id"],
transmitter["uuid"],
success_rate,
good_count,
data_count))
fp.close() fp.close()
# Get NORAD IDs # Get NORAD IDs
norad_cat_ids = sorted(set([transmitter["norad_cat_id"] for transmitter in transmitters])) norad_cat_ids = sorted(
set([transmitter["norad_cat_id"] for transmitter in transmitters]))
# Get TLEs # Get TLEs
tles = fetch_tles(norad_cat_ids) tles = fetch_tles(norad_cat_ids)
# Store TLEs # Store TLEs
fp = open(os.path.join(cache_dir, "tles_%d.txt"%ground_station_id), "w") fp = open(
os.path.join(
cache_dir,
"tles_%d.txt" %
ground_station_id),
"w")
for norad_cat_id, (source, tle) in tles.items(): for norad_cat_id, (source, tle) in tles.items():
fp.write("%s\n%s\n%s\n"%(tle[0], tle[1], tle[2])) fp.write("%s\n%s\n%s\n" % (tle[0], tle[1], tle[2]))
fp.close() fp.close()
# Set observer # Set observer
observer = ephem.Observer() observer = ephem.Observer()
observer.lon = str(ground_station['lng']) observer.lon = str(ground_station['lng'])
@ -392,21 +475,28 @@ if __name__ == "__main__":
minimum_altitude = ground_station['min_horizon'] minimum_altitude = ground_station['min_horizon']
# Read tles # Read tles
with open(os.path.join(cache_dir, "tles_%d.txt"%ground_station_id), "r") as f: with open(os.path.join(cache_dir, "tles_%d.txt" % ground_station_id), "r") as f:
lines = f.readlines() lines = f.readlines()
tles = [twolineelement(lines[i], lines[i+1], lines[i+2]) tles = [twolineelement(lines[i], lines[i + 1], lines[i + 2])
for i in range(0, len(lines), 3)] for i in range(0, len(lines), 3)]
# Read transmitters # Read transmitters
satellites = [] satellites = []
with open(os.path.join(cache_dir, "transmitters_%d.txt"%ground_station_id), "r") as f: with open(os.path.join(cache_dir, "transmitters_%d.txt" % ground_station_id), "r") as f:
lines = f.readlines() lines = f.readlines()
for line in lines: for line in lines:
item = line.split() item = line.split()
norad_cat_id, uuid, success_rate, good_count, data_count = int(item[0]), item[1], float(item[2])/100.0, int(item[3]), int(item[4]) norad_cat_id, uuid, success_rate, good_count, data_count = int(
item[0]), item[1], float(item[2]) / 100.0, int(item[3]), int(item[4])
for tle in tles: for tle in tles:
if tle.id == norad_cat_id: if tle.id == norad_cat_id:
satellites.append(satellite(tle, uuid, success_rate, good_count, data_count)) satellites.append(
satellite(
tle,
uuid,
success_rate,
good_count,
data_count))
# Find passes # Find passes
passes = find_passes(satellites, observer, tmin, tmax, minimum_altitude) passes = find_passes(satellites, observer, tmin, tmax, minimum_altitude)
@ -414,11 +504,14 @@ if __name__ == "__main__":
# Priorities # Priorities
# priorities = {"40069": 1.000, "25338": 0.990, "28654": 0.990, "33591": 0.990} # priorities = {"40069": 1.000, "25338": 0.990, "28654": 0.990, "33591": 0.990}
priorities = {} priorities = {}
# List of scheduled passes # List of scheduled passes
scheduledpasses = get_scheduled_passes_from_network(ground_station_id, tmin, tmax) scheduledpasses = get_scheduled_passes_from_network(
print("Found %d scheduled passes between %s and %s on ground station %d\n"%(len(scheduledpasses), tmin, tmax, ground_station_id)) ground_station_id, tmin, tmax)
print(
"Found %d scheduled passes between %s and %s on ground station %d\n" %
(len(scheduledpasses), tmin, tmax, ground_station_id))
# Get passes of priority objects # Get passes of priority objects
prioritypasses = [] prioritypasses = []
normalpasses = [] normalpasses = []
@ -428,37 +521,54 @@ if __name__ == "__main__":
satpass['priority'] = priorities[satpass['id']] satpass['priority'] = priorities[satpass['id']]
prioritypasses.append(satpass) prioritypasses.append(satpass)
else: else:
satpass['priority'] = (float(satpass['altt'])/90.0)*satpass['success_rate'] satpass['priority'] = (
float(satpass['altt']) / 90.0) * satpass['success_rate']
normalpasses.append(satpass) normalpasses.append(satpass)
# Priority scheduler # Priority scheduler
prioritypasses = sorted(prioritypasses, key=lambda satpass: -satpass['priority']) prioritypasses = sorted(
prioritypasses,
key=lambda satpass: -
satpass['priority'])
scheduledpasses = ordered_scheduler(prioritypasses, scheduledpasses) scheduledpasses = ordered_scheduler(prioritypasses, scheduledpasses)
# Random scheduler # Random scheduler
normalpasses = sorted(normalpasses, key=lambda satpass: -satpass['priority']) normalpasses = sorted(
normalpasses,
key=lambda satpass: -
satpass['priority'])
scheduledpasses = ordered_scheduler(normalpasses, scheduledpasses) scheduledpasses = ordered_scheduler(normalpasses, scheduledpasses)
dt, dttot, eff = efficiency(scheduledpasses) dt, dttot, eff = efficiency(scheduledpasses)
print("%d passes scheduled out of %d, %.0f s out of %.0f s at %.3f%% efficiency"%(len(scheduledpasses), len(passes), dt, dttot, 100*eff)) print(
"%d passes scheduled out of %d, %.0f s out of %.0f s at %.3f%% efficiency" %
(len(scheduledpasses), len(passes), dt, dttot, 100 * eff))
# Find unique objects # Find unique objects
satids = sorted(set([satpass['id'] for satpass in passes])) satids = sorted(set([satpass['id'] for satpass in passes]))
for satpass in sorted(scheduledpasses, key=lambda satpass: satpass['tr']): for satpass in sorted(scheduledpasses, key=lambda satpass: satpass['tr']):
if satpass['scheduled']==False: if not satpass['scheduled']:
print("%05d %s %s %3.0f %4.3f %s %s"%(int(satpass['id']), satpass['tr'].strftime("%Y-%m-%dT%H:%M:%S"), satpass['ts'].strftime("%Y-%m-%dT%H:%M:%S"), float(satpass['altt']), satpass['priority'], satpass['uuid'], satpass['name'].rstrip())) print(
"%05d %s %s %3.0f %4.3f %s %s" %
(int(
satpass['id']),
satpass['tr'].strftime("%Y-%m-%dT%H:%M:%S"),
satpass['ts'].strftime("%Y-%m-%dT%H:%M:%S"),
float(
satpass['altt']),
satpass['priority'],
satpass['uuid'],
satpass['name'].rstrip()))
# Schedule passes # Schedule passes
for satpass in sorted(scheduledpasses, key=lambda satpass: satpass['tr']): for satpass in sorted(scheduledpasses, key=lambda satpass: satpass['tr']):
if satpass['scheduled']==False: if not satpass['scheduled']:
if schedule: if schedule:
schedule_observation(username, schedule_observation(username,
password, password,
int(satpass['id']), int(satpass['id']),
satpass['uuid'], satpass['uuid'],
ground_station_id, ground_station_id,
satpass['tr'].strftime("%Y-%m-%d %H:%M:%S")+".000", satpass['tr'].strftime("%Y-%m-%d %H:%M:%S") + ".000",
satpass['ts'].strftime("%Y-%m-%d %H:%M:%S")+".000") satpass['ts'].strftime("%Y-%m-%d %H:%M:%S") + ".000")