Generate live KML using ElementTree

pull/859/head
Clayton Smith 2024-01-30 20:12:56 -05:00
rodzic 0ea4558aa2
commit 58a183dffa
4 zmienionych plików z 119 dodań i 108 usunięć

Wyświetl plik

@ -564,7 +564,7 @@ def read_auto_rx_config(filename, no_sdr_test=False):
logging.warning(
"Config - Did not find kml_refresh_rate setting, using default (10 seconds)."
)
auto_rx_config["kml_refresh_rate"] = 11
auto_rx_config["kml_refresh_rate"] = 10
# New Sondehub db Settings
try:

Wyświetl plik

@ -522,17 +522,20 @@ def zip_log_files(serial_list=None):
return data
def _coordinates_to_kml_placemark(lat, lon, alt,
name="Placemark Name",
absolute=False,
icon="http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png",
scale=1.0):
def coordinates_to_kml_placemark(lat, lon, alt,
name="Placemark Name",
description="Placemark Description",
absolute=False,
icon="https://maps.google.com/mapfiles/kml/shapes/placemark_circle.png",
scale=1.0):
""" Generate a generic placemark object """
placemark = ET.Element("Placemark")
pm_name = ET.SubElement(placemark, "name")
pm_name.text = name
pm_desc = ET.SubElement(placemark, "description")
pm_desc.text = description
style = ET.SubElement(placemark, "Style")
icon_style = ET.SubElement(style, "IconStyle")
@ -552,13 +555,13 @@ def _coordinates_to_kml_placemark(lat, lon, alt,
return placemark
def _flight_path_to_kml_placemark(flight_path,
name="Flight Path Name",
track_color="aaffffff",
poly_color="20000000",
track_width=2.0,
absolute=True,
extrude=True):
def path_to_kml_placemark(flight_path,
name="Flight Path Name",
track_color="ff03bafc",
poly_color="8003bafc",
track_width=2.0,
absolute=True,
extrude=True):
''' Produce a placemark object from a flight path array '''
placemark = ET.Element("Placemark")
@ -572,13 +575,14 @@ def _flight_path_to_kml_placemark(flight_path,
color.text = track_color
width = ET.SubElement(line_style, "width")
width.text = str(track_width)
poly_style = ET.SubElement(style, "PolyStyle")
color = ET.SubElement(poly_style, "color")
color.text = poly_color
fill = ET.SubElement(poly_style, "fill")
fill.text = "1"
outline = ET.SubElement(poly_style, "outline")
outline.text = "1"
if extrude:
poly_style = ET.SubElement(style, "PolyStyle")
color = ET.SubElement(poly_style, "color")
color.text = poly_color
fill = ET.SubElement(poly_style, "fill")
fill.text = "1"
outline = ET.SubElement(poly_style, "outline")
outline.text = "1"
line_string = ET.SubElement(placemark, "LineString")
if absolute:
@ -603,26 +607,19 @@ def _log_file_to_kml_folder(filename, absolute=True, extrude=True, last_only=Fal
_flight_data = read_log_file(filename)
_flight_serial = _flight_data["serial"]
_launch_time = parse(_flight_data["first_time"]).strftime("%Y%m%d-%H%M%SZ")
# Generate a comment line to use in the folder and placemark descriptions
_track_comment = "%s %s" % (_launch_time, _flight_serial)
_landing_comment = "%s Last Position" % (_flight_serial)
# Grab last-seen position
_landing_time = _flight_data["last_time"]
_landing_pos = _flight_data["path"][-1]
_folder = ET.Element("Folder")
_name = ET.SubElement(_folder, "name")
_name.text = _track_comment
_description = ET.SubElement(_folder, "description")
_description.text = "Radiosonde Flight Path"
_name.text = _flight_serial
# Generate the placemark & flight track.
_folder.append(coordinates_to_kml_placemark(_landing_pos[0], _landing_pos[1], _landing_pos[2],
name=_flight_serial, description=_landing_time, absolute=absolute))
if not last_only:
_folder.append(_flight_path_to_kml_placemark(_flight_data["path"], name=_track_comment,
absolute=absolute, extrude=extrude))
_folder.append(_coordinates_to_kml_placemark(_landing_pos[0], _landing_pos[1], _landing_pos[2],
name=_landing_comment, absolute=absolute))
_folder.append(path_to_kml_placemark(_flight_data["path"], name="Track",
absolute=absolute, extrude=extrude))
return _folder
@ -630,7 +627,7 @@ def _log_file_to_kml_folder(filename, absolute=True, extrude=True, last_only=Fal
def log_files_to_kml(file_list, kml_file, absolute=True, extrude=True, last_only=False):
""" Convert a collection of log files to a KML file """
kml_root = ET.Element("kml", {"xmlns": "http://www.opengis.net/kml/2.2"})
kml_root = ET.Element("kml", xmlns="http://www.opengis.net/kml/2.2")
kml_doc = ET.SubElement(kml_root, "Document")
for file in file_list:

Wyświetl plik

@ -18,12 +18,20 @@ import requests
import time
import traceback
import sys
import xml.etree.ElementTree as ET
import autorx
import autorx.config
import autorx.scan
from autorx.geometry import GenericTrack
from autorx.utils import check_autorx_versions
from autorx.log_files import list_log_files, read_log_by_serial, zip_log_files, log_files_to_kml
from autorx.log_files import (
list_log_files,
read_log_by_serial,
zip_log_files,
log_files_to_kml,
coordinates_to_kml_placemark,
path_to_kml_placemark
)
from autorx.decode import SondeDecoder
from queue import Queue
from threading import Thread
@ -31,15 +39,6 @@ import flask
from flask import request, abort, make_response, send_file
from flask_socketio import SocketIO
from werkzeug.middleware.proxy_fix import ProxyFix
import re
try:
from simplekml import Kml, AltitudeMode
except ImportError:
print(
"Could not import simplekml! Try running: sudo pip3 install -r requirements.txt"
)
sys.exit(1)
# Inhibit Flask warning message about running a development server... (we know!)
@ -149,47 +148,60 @@ def flask_get_task_list():
def flask_get_kml():
""" Return KML with autorefresh """
_config = autorx.config.global_config
kml = Kml()
netlink = kml.newnetworklink(name="Radiosonde Auto-RX Live Telemetry")
netlink.open = 1
netlink.link.href = flask.request.url_root + "rs_feed.kml"
try:
netlink.link.refreshinterval = _config["kml_refresh_rate"]
except KeyError:
netlink.link.refreshinterval = 10
netlink.link.refreshmode = "onInterval"
return kml.kml(), 200, {"content-type": "application/vnd.google-earth.kml+xml"}
kml_root = ET.Element("kml", xmlns="http://www.opengis.net/kml/2.2")
kml_doc = ET.SubElement(kml_root, "Document")
network_link = ET.SubElement(kml_doc, "NetworkLink")
name = ET.SubElement(network_link, "name")
name.text = "Radiosonde Auto-RX Live Telemetry"
open = ET.SubElement(network_link, "open")
open.text = "1"
link = ET.SubElement(network_link, "Link")
href = ET.SubElement(link, "href")
href.text = flask.request.url_root + "rs_feed.kml"
refresh_mode = ET.SubElement(link, "refreshMode")
refresh_mode.text = "onInterval"
refresh_interval = ET.SubElement(link, "refreshInterval")
refresh_interval.text = str(autorx.config.global_config["kml_refresh_rate"])
kml_string = ET.tostring(kml_root, encoding="UTF-8", xml_declaration=True)
return kml_string, 200, {"content-type": "application/vnd.google-earth.kml+xml"}
@app.route("/rs_feed.kml")
def flask_get_kml_feed():
""" Return KML with RS telemetry """
kml = Kml()
kml.resetidcounter()
kml.document.name = "Track"
kml.document.open = 1
kml_root = ET.Element("kml", xmlns="http://www.opengis.net/kml/2.2")
kml_doc = ET.SubElement(kml_root, "Document")
name = ET.SubElement(kml_doc, "name")
name.text = "Track"
open = ET.SubElement(kml_doc, "open")
open.text = "1"
# Station Placemark
pnt = kml.newpoint(
name="Ground Station",
altitudemode=AltitudeMode.absolute,
kml_doc.append(coordinates_to_kml_placemark(
autorx.config.global_config["station_lat"],
autorx.config.global_config["station_lon"],
autorx.config.global_config["station_alt"],
name=autorx.config.global_config["habitat_uploader_callsign"],
description="AutoRX Ground Station",
)
pnt.open = 1
pnt.iconstyle.icon.href = flask.request.url_root + "static/img/antenna-green.png"
pnt.coords = [
(
autorx.config.global_config["station_lon"],
autorx.config.global_config["station_lat"],
autorx.config.global_config["station_alt"],
)
]
absolute=True,
icon=flask.request.url_root + "static/img/antenna-green.png"
))
for rs_id in flask_telemetry_store:
try:
coordinates = []
for tp in flask_telemetry_store[rs_id]["track"].track_history:
coordinates.append((tp[2], tp[1], tp[3]))
coordinates.append((tp[1], tp[2], tp[3]))
rs_data = """\
{type}/{subtype}
@ -208,56 +220,59 @@ def flask_get_kml_feed():
icon = flask.request.url_root + "static/img/parachute-green.png"
# Add folder
fol = kml.newfolder(name=rs_id)
folder = ET.SubElement(kml_doc, "Folder", id=f"folder_{rs_id}")
name = ET.SubElement(folder, "name")
name.text = rs_id
open = ET.SubElement(folder, "open")
open.text = "1"
# HAB Placemark
pnt = fol.newpoint(
folder.append(coordinates_to_kml_placemark(
flask_telemetry_store[rs_id]["latest_telem"]["lat"],
flask_telemetry_store[rs_id]["latest_telem"]["lon"],
flask_telemetry_store[rs_id]["latest_telem"]["alt"],
name=rs_id,
altitudemode=AltitudeMode.absolute,
description=rs_data.format(
**flask_telemetry_store[rs_id]["latest_telem"]
),
)
pnt.iconstyle.icon.href = icon
pnt.coords = [
description=rs_data.format(**flask_telemetry_store[rs_id]["latest_telem"]),
absolute=True,
icon=icon
))
# Track
folder.append(path_to_kml_placemark(
coordinates,
name="Track",
absolute=True,
extrude=True
))
# LOS line
coordinates = [
(
flask_telemetry_store[rs_id]["latest_telem"]["lon"],
flask_telemetry_store[rs_id]["latest_telem"]["lat"],
flask_telemetry_store[rs_id]["latest_telem"]["alt"],
)
]
linestring = fol.newlinestring(name="Track")
linestring.coords = coordinates
linestring.altitudemode = AltitudeMode.absolute
linestring.extrude = 1
linestring.stylemap.normalstyle.linestyle.color = "ff03bafc"
linestring.stylemap.highlightstyle.linestyle.color = "ff03bafc"
linestring.stylemap.normalstyle.polystyle.color = "AA03bafc"
linestring.stylemap.highlightstyle.polystyle.color = "CC03bafc"
# Add LOS line
linestring = fol.newlinestring(name="LOS")
linestring.altitudemode = AltitudeMode.absolute
linestring.coords = [
(
autorx.config.global_config["station_lon"],
autorx.config.global_config["station_lat"],
autorx.config.global_config["station_lon"],
autorx.config.global_config["station_alt"],
),
(
flask_telemetry_store[rs_id]["latest_telem"]["lon"],
flask_telemetry_store[rs_id]["latest_telem"]["lat"],
flask_telemetry_store[rs_id]["latest_telem"]["lon"],
flask_telemetry_store[rs_id]["latest_telem"]["alt"],
),
]
folder.append(path_to_kml_placemark(
coordinates,
name="LOS",
track_color="ffffffff",
absolute=True,
extrude=False
))
except Exception as e:
logging.error(
"KML - Could not parse data from RS %s - %s" % (rs_id, str(e))
)
return (
re.sub("<Document.*>", "<Document>", kml.kml()),
200,
{"content-type": "application/vnd.google-earth.kml+xml"},
)
kml_string = ET.tostring(kml_root, encoding="UTF-8", xml_declaration=True)
return kml_string, 200, {"content-type": "application/vnd.google-earth.kml+xml"}
@app.route("/get_config")

Wyświetl plik

@ -5,5 +5,4 @@ flask-socketio
numpy
requests
semver
simplekml
simple-websocket