def run(self): """Run the flight tracker. """ logging.info("Connecting to MQTT broker on %s:%s" % (self.__mqtt_broker, self.__mqtt_port)) self.__mqtt_bridge = mqtt_wrapper.bridge(host = self.__mqtt_broker, port = self.__mqtt_port, client_id = "FlightTracker-%d" % (os.getpid())) # TOOD: , user_id = args.mqtt_user, password = args.mqtt_password) threading.Thread(target = self.__publish_thread, daemon = True).start() while True: if not self.dump1090Connect(): continue for data in self.dump1090Read(): if data is None: continue self.cleanObservations() m = sbs1.parse(data) if m: icao24 = m["icao24"] if icao24 in self.__observations: self.__observations[icao24].update(m) else: self.__observations[icao24] = Observation(m) if self.__observations[icao24].isPresentable(): if not self.__tracking_icao24: self.__tracking_icao24 = icao24 self.updateTrackingDistance() logging.info("Tracking %s at %d" % (self.__tracking_icao24, self.__tracking_distance)) elif self.__tracking_icao24 == icao24: self.updateTrackingDistance() else: distance = utils.coordinate_distance(self.__latitude, self.__longitude, self.__observations[icao24].getLat(), self.__observations[icao24].getLon()) if distance < self.__tracking_distance: self.__tracking_icao24 = icao24 self.__tracking_distance = distance logging.info("Now tracking %s at %d" % (self.__tracking_icao24, self.__tracking_distance))
def __getObservationJson(self, observation): (lat, lon, alt) = utils.calc_travel_3d(observation.getLat(), observation.getLon(), observation.getAltitude(), observation.getLatLonTime(), observation.getAltitudeTime(), observation.getGroundSpeed(), observation.getTrack(), observation.getVerticalRate(), camera_lead) distance3d = utils.coordinate_distance_3d(camera_latitude, camera_longitude, camera_altitude, lat, lon, alt) #(latorig, lonorig) = utils.calc_travel(observation.getLat(), observation.getLon(), observation.getLatLonTime(), observation.getGroundSpeed(), observation.getTrack(), camera_lead) distance2d = utils.coordinate_distance(camera_latitude, camera_longitude, lat, lon) bearing = utils.bearingFromCoordinate( cameraPosition=[camera_latitude, camera_longitude], airplanePosition=[lat, lon], heading=observation.getTrack()) elevation = utils.elevation(distance2d, cameraAltitude=camera_altitude, airplaneAltitude=alt) cameraTilt = elevation cameraPan = utils.cameraPanFromCoordinate( cameraPosition=[camera_latitude, camera_longitude], airplanePosition=[lat, lon]) #elevationorig = utils.elevation(distance2d, observation.getAltitude(), camera_altitude) return observation.json()
def __publish_thread(self): """ MQTT publish closest observation every second, more often if the plane is closer """ while True: if not self.__tracking_icao24: time.sleep(1) else: if not self.__tracking_icao24 in self.__observations: self.__tracking_icao24 is None continue cur = self.__observations[self.__tracking_icao24] if cur is None: continue (lat, lon) = utils.calc_travel(cur.getLat(), cur.getLon(), cur.getLoggedDate(), cur.getGroundSpeed(), cur.getHeading()) distance = utils.coordinate_distance(self.__latitude, self.__longitude, lat, lon) # Round off to nearest 100 meters distance = round(distance/100) * 100 bearing = utils.bearing(self.__latitude, self.__longitude, lat, lon) # @todo: update altitude # altitude = sbs1["altitude"] retain = False self.__mqtt_bridge.publish(self.__prox_topic, cur.json(bearing, distance), 0, retain) logging.info("%s at %5d brg %3d alt %5d trk %3d spd %3d %s" % (cur.getIcao24(), distance, bearing, cur.getAltitude(), cur.getHeading(), cur.getGroundSpeed(), cur.getType())) if distance < 3000: time.sleep(0.25) elif distance < 6000: time.sleep(0.5) else: time.sleep(1)
def run(self): """Run the flight tracker. """ print("connecting to MQTT broker at " + self.__mqtt_broker + ", subcribing on channel '" + self.__plane_topic + "'publising on: " + self.__tracking_topic) self.__client = mqtt.Client("skyscan-tracker-" + ID) #create new instance self.__client.on_message = on_message #attach function to callback print("setup MQTT") self.__client.connect(self.__mqtt_broker) #connect to broker print("connected mqtt") self.__client.loop_start() #start the loop print("start MQTT") self.__client.subscribe(self.__plane_topic) self.__client.subscribe("skyscan/egi") self.__client.publish("skyscan/registration", "skyscan-tracker-" + ID + " Registration", 0, False) print("subscribe mqtt") threading.Thread(target=self.__publish_thread, daemon=True).start() while True: while not q.empty(): m = q.get() icao24 = m["icao24"] self.cleanObservations() if icao24 not in self.__observations: self.__observations[icao24] = Observation(m) self.__observations[icao24].update(m) if self.__observations[icao24].isPresentable(): if not self.__tracking_icao24: if self.__observations[icao24].getElevation( ) != None and self.__observations[icao24].getElevation( ) > min_elevation: self.__tracking_icao24 = icao24 self.updateTrackingDistance() logging.info( "Tracking %s at %d elevation: %d" % (self.__tracking_icao24, self.__tracking_distance, self.__observations[icao24].getElevation())) elif self.__tracking_icao24 == icao24: self.updateTrackingDistance() else: distance = utils.coordinate_distance( camera_latitude, camera_longitude, self.__observations[icao24].getLat(), self.__observations[icao24].getLon()) if distance < self.__tracking_distance and self.__observations[ icao24].getElevation() > min_elevation: self.__tracking_icao24 = icao24 self.__tracking_distance = distance logging.info( "Tracking %s at %d elevation: %d" % (self.__tracking_icao24, self.__tracking_distance, self.__observations[icao24].getElevation())) time.sleep(0.1)
def calculateCameraPosition(): global cameraPan global cameraTilt global distance2d global distance3d global bearing global angularVelocityHorizontal global angularVelocityVertical global elevation (lat, lon, alt) = utils.calc_travel_3d(currentPlane, camera_lead) distance3d = utils.coordinate_distance_3d(camera_latitude, camera_longitude, camera_altitude, lat, lon, alt) #(latorig, lonorig) = utils.calc_travel(observation.getLat(), observation.getLon(), observation.getLatLonTime(), observation.getGroundSpeed(), observation.getTrack(), camera_lead) distance2d = utils.coordinate_distance(camera_latitude, camera_longitude, lat, lon) bearing = utils.bearingFromCoordinate( cameraPosition=[camera_latitude, camera_longitude], airplanePosition=[lat, lon], heading=currentPlane["track"]) elevation = utils.elevation(distance2d, cameraAltitude=camera_altitude, airplaneAltitude=alt) (angularVelocityHorizontal, angularVelocityVertical) = utils.angular_velocity(currentPlane, camera_latitude, camera_longitude, camera_altitude) #logging.info("Angular Velocity - Horizontal: {} Vertical: {}".format(angularVelocityHorizontal, angularVelocityVertical)) cameraTilt = elevation cameraPan = utils.cameraPanFromCoordinate( cameraPosition=[camera_latitude, camera_longitude], airplanePosition=[lat, lon]) cameraPan = calculate_bearing_correction(cameraPan)
def test_coordinate_distance(): """Unit test for coordinate_distance().""" # Used this app to calculate distance: https://www.movable-type.co.uk/scripts/latlong.html lat1, long1 = 39.099912, -94.581213 lat2, long2 = 38.627089, -90.200203 expected_distance = 382900.05037560174 assert coordinate_distance(lat1, long1, lat2, long2) == expected_distance
def update(self, sbs1msg): oldData = dict(self.__dict__) #self.__loggedDate = datetime.utcnow() if sbs1msg["icao24"]: self.__icao24 = sbs1msg["icao24"] if sbs1msg["callsign"] and self.__callsign != sbs1msg["callsign"]: self.__callsign = sbs1msg["callsign"].rstrip() if sbs1msg["altitude"]: self.__altitude = sbs1msg["altitude"] self.__altitudeTime = datetime.utcnow() if sbs1msg["groundSpeed"]: self.__groundSpeed = sbs1msg["groundSpeed"] if sbs1msg["track"]: self.__track = sbs1msg["track"] if sbs1msg["lat"]: self.__lat = sbs1msg["lat"] self.__latLonTime = datetime.utcnow() if sbs1msg["lon"]: self.__lon = sbs1msg["lon"] self.__latLonTime = datetime.utcnow() if sbs1msg["verticalRate"]: self.__verticalRate = sbs1msg["verticalRate"] if not self.__verticalRate: self.__verticalRate = 0 if sbs1msg["loggedDate"]: self.__loggedDate = datetime.strptime(sbs1msg["loggedDate"], '%Y-%m-%d %H:%M:%S.%f') if sbs1msg["registration"]: self.__registration = sbs1msg["registration"] if sbs1msg["manufacturer"]: self.__manufacturer = sbs1msg["manufacturer"] if sbs1msg["model"]: self.__model = sbs1msg["model"] if sbs1msg["operator"]: self.__operator = sbs1msg["operator"] if sbs1msg["type"]: self.__type = sbs1msg["type"] # Calculates the distance from the cameras location to the airplane. The output is in METERS! distance = utils.coordinate_distance(camera_latitude, camera_longitude, self.__lat, self.__lon) #Not sure we want to... commented out for now -> Round off to nearest 100 meters self.__distance = distance = distance #round(distance/100) * 100 self.__bearing = utils.bearing(camera_latitude, camera_longitude, self.__lat, self.__lon) self.__elevation = utils.elevation( distance, self.__altitude, camera_altitude) # Distance and Altitude are both in meters # Check if observation was updated newData = dict(self.__dict__) #del oldData["_Observation__loggedDate"] #del newData["_Observation__loggedDate"] d = DictDiffer(oldData, newData) self.__updated = len(d.changed()) > 0
def __publish_thread(self): """ MQTT publish closest observation every second, more often if the plane is closer """ timeHeartbeat = 0 while True: if timeHeartbeat < time.mktime(time.gmtime()): timeHeartbeat = time.mktime(time.gmtime()) + 10 self.__client.publish("skyscan/heartbeat", "skyscan-tracker-" + ID + " Heartbeat", 0, False) if not self.__tracking_icao24: time.sleep(1) else: if not self.__tracking_icao24 in self.__observations: self.__tracking_icao24 is None continue cur = self.__observations[self.__tracking_icao24] if cur is None: continue (lat, lon) = utils.calc_travel(cur.getLat(), cur.getLon(), cur.getLoggedDate(), cur.getGroundSpeed(), cur.getTrack(), camera_lead) distance = utils.coordinate_distance(camera_latitude, camera_longitude, lat, lon) # Round off to nearest 100 meters #distance = round(distance/100) * 100 bearing = utils.bearing(camera_latitude, camera_longitude, lat, lon) elevation = utils.elevation( distance, cur.getAltitude(), camera_altitude ) # we need to convert to feet because the altitude is in feet retain = False self.__client.publish(self.__tracking_topic, cur.json(bearing, distance, elevation), 0, retain) logging.info( "%s at %5d brg %3d alt %5d trk %3d spd %3d %s" % (cur.getIcao24(), distance, bearing, cur.getAltitude(), cur.getTrack(), cur.getGroundSpeed(), cur.getType())) if distance < 3000: time.sleep(0.25) elif distance < 6000: time.sleep(0.5) else: time.sleep(1)
def selectNearestObservation(self): """Select nearest presentable aircraft """ self.__tracking_icao24 = None self.__tracking_distance = 999999999 for icao24 in self.__observations: if not self.__observations[icao24].isPresentable(): continue distance = utils.coordinate_distance(self.__latitude, self.__longitude, self.__observations[icao24].getLat(), self.__observations[icao24].getLon()) if distance < self.__tracking_distance: self.__tracking_icao24 = icao24 self.__tracking_distance = distance if self.__tracking_icao24 is None: logging.info("Found nothing to track") else: logging.info("Found new tracking %s at %d" % (self.__tracking_icao24, self.__tracking_distance))
def update(self, sbs1msg): """ Updates information about a plane from an SBS1 message """ oldData = dict( self.__dict__ ) # save existing data to determine if anything has changed self.__loggedDate = datetime.utcnow() if sbs1msg["icao24"]: self.__icao24 = sbs1msg["icao24"].lower( ) # Let's always keep icao24 in lower case if sbs1msg["callsign"] and self.__callsign != sbs1msg["callsign"]: self.__callsign = sbs1msg["callsign"].rstrip() if sbs1msg["altitude"] is not None: if self.__altitude != sbs1msg["altitude"]: self.__altitude = sbs1msg["altitude"] self.__altitudeTime = sbs1msg["generatedDate"] if sbs1msg["groundSpeed"] is not None: self.__groundSpeed = sbs1msg["groundSpeed"] if sbs1msg["track"] is not None: self.__track = sbs1msg["track"] if sbs1msg["onGround"] is not None: self.__onGround = sbs1msg["onGround"] if sbs1msg["lat"] is not None: self.__lat = sbs1msg["lat"] self.__latLonTime = sbs1msg["generatedDate"] if sbs1msg["lon"] is not None: self.__lon = sbs1msg["lon"] self.__latLonTime = sbs1msg["generatedDate"] if sbs1msg["verticalRate"] is not None: self.__verticalRate = sbs1msg["verticalRate"] if not self.__verticalRate: self.__verticalRate = 0 if self.__lat and self.__lon and self.__altitude and self.__track: # Calculates the distance from the cameras location to the airplane. The output is in METERS! distance3d = utils.coordinate_distance_3d(camera_latitude, camera_longitude, camera_altitude, self.__lat, self.__lon, self.__altitude) distance2d = utils.coordinate_distance(camera_latitude, camera_longitude, self.__lat, self.__lon) self.__distance = distance3d self.__bearing = utils.bearingFromCoordinate( cameraPosition=[camera_latitude, camera_longitude], airplanePosition=[self.__lat, self.__lon], heading=self.__track) self.__elevation = utils.elevation( distance2d, cameraAltitude=camera_altitude, airplaneAltitude=self.__altitude ) # Distance and Altitude are both in meters # Check if observation was updated newData = dict(self.__dict__) #del oldData["_Observation__loggedDate"] #del newData["_Observation__loggedDate"] d = DictDiffer(oldData, newData) self.__updated = len(d.changed()) > 0
def updateTrackingDistance(self): """Update distance to aircraft being tracked """ cur = self.__observations[self.__tracking_icao24] self.__tracking_distance = utils.coordinate_distance(self.__latitude, self.__longitude, cur.getLat(), cur.getLon())