2018-07-19 12:44:01 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Project Horus - Browser-Based Chase Mapper - Config Reader
|
|
|
|
#
|
|
|
|
# Copyright (C) 2018 Mark Jessop <vk5qi@rfhead.net>
|
|
|
|
# Released under GNU GPL v3 or later
|
|
|
|
#
|
|
|
|
import logging
|
2018-08-02 11:19:36 +00:00
|
|
|
import os
|
2018-07-19 12:44:01 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
# Python 2
|
|
|
|
from ConfigParser import RawConfigParser
|
|
|
|
except ImportError:
|
|
|
|
# Python 3
|
|
|
|
from configparser import RawConfigParser
|
|
|
|
|
|
|
|
|
|
|
|
default_config = {
|
|
|
|
# Start location for the map (until either a chase car position, or balloon position is available.)
|
2021-01-16 04:48:27 +00:00
|
|
|
"default_lat": -34.9,
|
|
|
|
"default_lon": 138.6,
|
2021-03-20 05:32:04 +00:00
|
|
|
"default_alt": 0,
|
2021-01-16 04:48:27 +00:00
|
|
|
"payload_max_age": 180,
|
|
|
|
"thunderforest_api_key": "none",
|
2021-04-18 05:32:57 +00:00
|
|
|
"stadia_api_key": "none",
|
2018-07-19 12:44:01 +00:00
|
|
|
# Predictor settings
|
2021-01-16 04:48:27 +00:00
|
|
|
"pred_enabled": True, # Enable running and display of predicted flight paths.
|
|
|
|
"offline_predictions": False, # Use an offline GFS model and predictor instead of Tawhiri.
|
2018-07-19 12:44:01 +00:00
|
|
|
# Default prediction settings (actual values will be used once the flight is underway)
|
2021-01-16 04:48:27 +00:00
|
|
|
"pred_model": "Disabled",
|
|
|
|
"pred_desc_rate": 6.0,
|
|
|
|
"pred_burst": 28000,
|
|
|
|
"show_abort": True, # Show a prediction of an 'abort' paths (i.e. if the balloon bursts *now*)
|
|
|
|
"pred_update_rate": 15, # Update predictor every 15 seconds.
|
2019-04-27 05:26:49 +00:00
|
|
|
# Range Rings
|
2021-01-16 04:48:27 +00:00
|
|
|
"range_rings_enabled": False,
|
|
|
|
"range_ring_quantity": 5,
|
|
|
|
"range_ring_spacing": 1000,
|
|
|
|
"range_ring_weight": 1.5,
|
|
|
|
"range_ring_color": "red",
|
|
|
|
"range_ring_custom_color": "#FF0000",
|
|
|
|
# Chase Car Speedometer
|
|
|
|
"chase_car_speed": True,
|
2019-08-10 12:10:40 +00:00
|
|
|
# Bearing processing
|
2021-01-16 04:48:27 +00:00
|
|
|
"max_bearings": 300,
|
|
|
|
"max_bearing_age": 30 * 60,
|
|
|
|
"car_speed_gate": 10,
|
|
|
|
"bearing_length": 10,
|
|
|
|
"bearing_weight": 1.0,
|
|
|
|
"bearing_color": "black",
|
|
|
|
"bearing_custom_color": "#FF0000",
|
2021-01-11 04:32:28 +00:00
|
|
|
# History
|
2021-01-16 04:48:27 +00:00
|
|
|
"reload_last_position": False,
|
|
|
|
}
|
2018-07-19 12:44:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
def parse_config_file(filename):
|
2021-01-16 04:48:27 +00:00
|
|
|
""" Parse a Configuration File """
|
|
|
|
|
|
|
|
chase_config = default_config.copy()
|
|
|
|
|
|
|
|
config = RawConfigParser()
|
|
|
|
config.read(filename)
|
|
|
|
|
|
|
|
# Map Defaults
|
|
|
|
chase_config["flask_host"] = config.get("map", "flask_host")
|
|
|
|
chase_config["flask_port"] = config.getint("map", "flask_port")
|
2021-03-20 05:32:04 +00:00
|
|
|
chase_config["default_lat"] = config.getfloat("map", "default_lat")
|
|
|
|
chase_config["default_lon"] = config.getfloat("map", "default_lon")
|
2021-01-16 04:48:27 +00:00
|
|
|
chase_config["payload_max_age"] = config.getint("map", "payload_max_age")
|
|
|
|
chase_config["thunderforest_api_key"] = config.get("map", "thunderforest_api_key")
|
|
|
|
|
|
|
|
# GPSD Settings
|
|
|
|
chase_config["car_gpsd_host"] = config.get("gpsd", "gpsd_host")
|
|
|
|
chase_config["car_gpsd_port"] = config.getint("gpsd", "gpsd_port")
|
|
|
|
|
|
|
|
# Serial GPS Settings
|
|
|
|
chase_config["car_serial_port"] = config.get("gps_serial", "gps_port")
|
|
|
|
chase_config["car_serial_baud"] = config.getint("gps_serial", "gps_baud")
|
|
|
|
|
|
|
|
# Habitat Settings
|
|
|
|
chase_config["habitat_upload_enabled"] = config.getboolean(
|
|
|
|
"habitat", "habitat_upload_enabled"
|
|
|
|
)
|
|
|
|
chase_config["habitat_call"] = config.get("habitat", "habitat_call")
|
|
|
|
chase_config["habitat_update_rate"] = config.getint(
|
|
|
|
"habitat", "habitat_update_rate"
|
|
|
|
)
|
|
|
|
|
|
|
|
# Predictor
|
|
|
|
chase_config["pred_enabled"] = config.getboolean("predictor", "predictor_enabled")
|
|
|
|
chase_config["offline_predictions"] = config.getboolean(
|
|
|
|
"predictor", "offline_predictions"
|
|
|
|
)
|
|
|
|
chase_config["pred_burst"] = config.getfloat("predictor", "default_burst")
|
|
|
|
chase_config["pred_desc_rate"] = config.getfloat(
|
|
|
|
"predictor", "default_descent_rate"
|
|
|
|
)
|
|
|
|
chase_config["pred_binary"] = config.get("predictor", "pred_binary")
|
|
|
|
chase_config["pred_gfs_directory"] = config.get("predictor", "gfs_directory")
|
|
|
|
chase_config["pred_model_download"] = config.get("predictor", "model_download")
|
|
|
|
|
|
|
|
# Range Ring Settings
|
|
|
|
chase_config["range_rings_enabled"] = config.getboolean(
|
|
|
|
"range_rings", "range_rings_enabled"
|
|
|
|
)
|
|
|
|
chase_config["range_ring_quantity"] = config.getint(
|
|
|
|
"range_rings", "range_ring_quantity"
|
|
|
|
)
|
|
|
|
chase_config["range_ring_spacing"] = config.getint(
|
|
|
|
"range_rings", "range_ring_spacing"
|
|
|
|
)
|
|
|
|
chase_config["range_ring_weight"] = config.getfloat(
|
|
|
|
"range_rings", "range_ring_weight"
|
|
|
|
)
|
|
|
|
chase_config["range_ring_color"] = config.get("range_rings", "range_ring_color")
|
|
|
|
chase_config["range_ring_custom_color"] = config.get(
|
|
|
|
"range_rings", "range_ring_custom_color"
|
|
|
|
)
|
|
|
|
|
|
|
|
# Bearing Processing
|
|
|
|
chase_config["max_bearings"] = config.getint("bearings", "max_bearings")
|
|
|
|
chase_config["max_bearing_age"] = (
|
|
|
|
config.getint("bearings", "max_bearing_age") * 60
|
|
|
|
) # Convert to seconds
|
|
|
|
if chase_config["max_bearing_age"] < 60:
|
|
|
|
chase_config[
|
|
|
|
"max_bearing_age"
|
|
|
|
] = 60 # Make sure this number is something sane, otherwise things will break
|
|
|
|
chase_config["car_speed_gate"] = (
|
|
|
|
config.getfloat("bearings", "car_speed_gate") / 3.6
|
|
|
|
) # Convert to m/s
|
|
|
|
chase_config["bearing_length"] = config.getfloat("bearings", "bearing_length")
|
|
|
|
chase_config["bearing_weight"] = config.getfloat("bearings", "bearing_weight")
|
|
|
|
chase_config["bearing_color"] = config.get("bearings", "bearing_color")
|
|
|
|
chase_config["bearing_custom_color"] = config.get(
|
|
|
|
"bearings", "bearing_custom_color"
|
|
|
|
)
|
|
|
|
|
|
|
|
# Offline Map Settings
|
|
|
|
chase_config["tile_server_enabled"] = config.getboolean(
|
|
|
|
"offline_maps", "tile_server_enabled"
|
|
|
|
)
|
|
|
|
chase_config["tile_server_path"] = config.get("offline_maps", "tile_server_path")
|
|
|
|
|
|
|
|
# Determine valid offline map layers.
|
|
|
|
chase_config["offline_tile_layers"] = []
|
|
|
|
if chase_config["tile_server_enabled"]:
|
|
|
|
for _dir in os.listdir(chase_config["tile_server_path"]):
|
|
|
|
if os.path.isdir(os.path.join(chase_config["tile_server_path"], _dir)):
|
|
|
|
chase_config["offline_tile_layers"].append(_dir)
|
|
|
|
logging.info("Found Map Layers: %s" % str(chase_config["offline_tile_layers"]))
|
|
|
|
|
|
|
|
try:
|
|
|
|
chase_config["chase_car_speed"] = config.getboolean("speedo", "chase_car_speed")
|
|
|
|
except:
|
|
|
|
logging.info("Missing Chase Car Speedo Setting, using default (disabled)")
|
|
|
|
chase_config["chase_car_speed"] = False
|
|
|
|
|
2021-03-20 05:32:04 +00:00
|
|
|
try:
|
|
|
|
chase_config["default_alt"] = config.getfloat("map", "default_alt")
|
|
|
|
except:
|
|
|
|
logging.info("Missing default_alt setting, using default (0m)")
|
|
|
|
chase_config["default_alt"] = 0
|
|
|
|
|
2021-04-18 05:32:57 +00:00
|
|
|
try:
|
|
|
|
chase_config["stadia_api_key"] = config.get("map", "stadia_api_key")
|
|
|
|
except:
|
|
|
|
logging.info("Missing Stadia API Key setting, using default (none)")
|
|
|
|
chase_config["stadia_api_key"] = "none"
|
|
|
|
|
2021-04-26 07:13:13 +00:00
|
|
|
try:
|
|
|
|
chase_config["turn_rate_threshold"] = config.getfloat("bearings", "turn_rate_threshold")
|
|
|
|
except:
|
|
|
|
logging.info("Missing turn rate gate setting, using default (4m/s)")
|
|
|
|
chase_config["turn_rate_threshold"] = 4.0
|
|
|
|
|
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
# Telemetry Source Profiles
|
|
|
|
|
|
|
|
_profile_count = config.getint("profile_selection", "profile_count")
|
|
|
|
_default_profile = config.getint("profile_selection", "default_profile")
|
|
|
|
|
|
|
|
chase_config["selected_profile"] = ""
|
|
|
|
chase_config["profiles"] = {}
|
|
|
|
|
|
|
|
# Unit Selection
|
|
|
|
|
|
|
|
chase_config["unitselection"] = config.get(
|
|
|
|
"units", "unitselection", fallback="metric"
|
|
|
|
)
|
|
|
|
if chase_config["unitselection"] != "imperial":
|
|
|
|
chase_config[
|
|
|
|
"unitselection"
|
|
|
|
] = "metric" # unless imperial is explicitly requested do metric
|
|
|
|
chase_config["switch_miles_feet"] = config.get(
|
|
|
|
"units", "switch_miles_feet", fallback="400"
|
|
|
|
)
|
|
|
|
|
|
|
|
for i in range(1, _profile_count + 1):
|
|
|
|
_profile_section = "profile_%d" % i
|
|
|
|
try:
|
|
|
|
_profile_name = config.get(_profile_section, "profile_name")
|
|
|
|
_profile_telem_source_type = config.get(
|
|
|
|
_profile_section, "telemetry_source_type"
|
|
|
|
)
|
|
|
|
_profile_telem_source_port = config.getint(
|
|
|
|
_profile_section, "telemetry_source_port"
|
|
|
|
)
|
|
|
|
_profile_car_source_type = config.get(_profile_section, "car_source_type")
|
|
|
|
_profile_car_source_port = config.getint(
|
|
|
|
_profile_section, "car_source_port"
|
|
|
|
)
|
|
|
|
|
2021-04-10 01:20:00 +00:00
|
|
|
_profile_online_tracker = config.get(_profile_section, "online_tracker")
|
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
chase_config["profiles"][_profile_name] = {
|
|
|
|
"name": _profile_name,
|
|
|
|
"telemetry_source_type": _profile_telem_source_type,
|
|
|
|
"telemetry_source_port": _profile_telem_source_port,
|
|
|
|
"car_source_type": _profile_car_source_type,
|
|
|
|
"car_source_port": _profile_car_source_port,
|
2021-04-10 01:20:00 +00:00
|
|
|
"online_tracker": _profile_online_tracker,
|
2021-01-16 04:48:27 +00:00
|
|
|
}
|
|
|
|
if _default_profile == i:
|
|
|
|
chase_config["selected_profile"] = _profile_name
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
logging.error("Error reading profile section %d - %s" % (i, str(e)))
|
|
|
|
|
|
|
|
if len(chase_config["profiles"].keys()) == 0:
|
|
|
|
logging.critical("Could not read any profile data!")
|
|
|
|
return None
|
|
|
|
|
|
|
|
if chase_config["selected_profile"] not in chase_config["profiles"]:
|
|
|
|
logging.critical("Default profile selection does not exist.")
|
|
|
|
return None
|
2018-07-27 12:17:17 +00:00
|
|
|
|
2021-01-10 03:28:45 +00:00
|
|
|
# History
|
2021-01-10 03:39:52 +00:00
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
chase_config["reload_last_position"] = config.getboolean(
|
|
|
|
"history", "reload_last_position", fallback=False
|
|
|
|
)
|
2018-07-19 12:44:01 +00:00
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
return chase_config
|
2018-07-19 12:44:01 +00:00
|
|
|
|
2021-01-10 03:28:45 +00:00
|
|
|
|
2018-07-19 12:44:01 +00:00
|
|
|
def read_config(filename, default_cfg="horusmapper.cfg.example"):
|
2021-01-16 04:48:27 +00:00
|
|
|
""" Read in a Horus Mapper configuration file,and return as a dict. """
|
2018-07-19 12:44:01 +00:00
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
try:
|
|
|
|
config_dict = parse_config_file(filename)
|
|
|
|
except Exception as e:
|
|
|
|
logging.error("Could not parse %s, trying default: %s" % (filename, str(e)))
|
|
|
|
try:
|
|
|
|
config_dict = parse_config_file(default_cfg)
|
|
|
|
except Exception as e:
|
|
|
|
logging.critical("Could not parse example config file! - %s" % str(e))
|
|
|
|
config_dict = None
|
2018-07-19 12:44:01 +00:00
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
return config_dict
|
2018-07-19 12:44:01 +00:00
|
|
|
|
|
|
|
|
2021-01-16 04:48:27 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
import sys
|
|
|
|
|
|
|
|
logging.basicConfig(
|
|
|
|
format="%(asctime)s %(levelname)s:%(message)s",
|
|
|
|
stream=sys.stdout,
|
|
|
|
level=logging.DEBUG,
|
|
|
|
)
|
|
|
|
print(read_config(sys.argv[1]))
|