added datasim and kmz tools
This commit is contained in:
133
Code Snippets/dataSim.py
Normal file
133
Code Snippets/dataSim.py
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
mqtt_counter_publish.py
|
||||
-----------------------
|
||||
|
||||
* Uses `paho.mqtt.client` to connect to a broker.
|
||||
* Publishes a list of *static* payloads to a topic.
|
||||
* Measures bytes sent/received by the **process** with `psutil`.
|
||||
* Prints a neat summary at the end.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
import psutil
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Helper: return write_bytes / read_bytes of the current process
|
||||
# ------------------------------------------------------------------
|
||||
def get_io_counters():
|
||||
"""Return (write_bytes, read_bytes) for the current process."""
|
||||
proc = psutil.Process(os.getpid())
|
||||
io = proc.io_counters() # .write_bytes, .read_bytes
|
||||
return io.write_bytes, io.read_bytes #io.write_chars, io.read_chars #io.write_bytes, io.read_bytes
|
||||
|
||||
def print_io_delta(start, end):
|
||||
"""Print the difference between two (write, read) tuples."""
|
||||
sent = end[0] - start[0]
|
||||
recv = end[1] - start[1]
|
||||
print(f"\nΔ sent: {sent:,} bytes")
|
||||
print(f"Δ received: {recv:,} bytes\n")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# MQTT callbacks (minimal – we don't care about incoming messages)
|
||||
# ------------------------------------------------------------------
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
if rc == 0:
|
||||
print("✅ Connected to broker")
|
||||
else:
|
||||
print(f"❌ Connect failed (rc={rc})")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Publish static payloads
|
||||
# ------------------------------------------------------------------
|
||||
def publish_static_payloads(client, topic, payloads, delay=0.1):
|
||||
"""
|
||||
Publish each payload in `payloads` to `topic`.
|
||||
`delay` (seconds) can be used to throttle the rate.
|
||||
"""
|
||||
for i, payload in enumerate(payloads, 1):
|
||||
result = client.publish(topic, json.dumps(payload))
|
||||
# Wait for the network loop to actually send it
|
||||
client.loop(timeout=0.1)
|
||||
if result.rc != mqtt.MQTT_ERR_SUCCESS:
|
||||
print(f"⚠️ Publish {i} failed with rc={result.rc}")
|
||||
else:
|
||||
print(f"→ Sent msg #{i} ({len(json.dumps(payload))} bytes)")
|
||||
time.sleep(delay)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Main routine
|
||||
# ------------------------------------------------------------------
|
||||
def main():
|
||||
broker = "hp.henrypump.cloud" # change if needed
|
||||
port = 1883 # default MQTT
|
||||
topic = "v1/devices/me/telemetry"
|
||||
|
||||
# Static payloads – feel free to replace with your own data
|
||||
payloads = []
|
||||
now = time.time() * 1000
|
||||
for x in range(25):
|
||||
values = {}
|
||||
for y in range(20):
|
||||
values[f"my_telemetry_{x+y}"] = random.random()
|
||||
payloads.append({"ts": now, "values": values})
|
||||
|
||||
payloads = [{"test1k": "A" * 1024}]
|
||||
# ------------------------------------------------------------------
|
||||
# Create MQTT client, connect
|
||||
# ------------------------------------------------------------------
|
||||
client = mqtt.Client()
|
||||
client.username_pw_set("e5xv3wfi1oa44ty2ydv2")
|
||||
client.on_connect = on_connect
|
||||
client.connect(broker, port, keepalive=60)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 1️⃣ Capture baseline I/O counters **before** any traffic
|
||||
# -------------------------------------------------------------
|
||||
baseline = get_io_counters()
|
||||
print("\n📊 Baseline I/O counters:")
|
||||
print(f" Written: {baseline[0]:,} bytes")
|
||||
print(f" Read: {baseline[1]:,} bytes")
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 2️⃣ Start network loop in a background thread
|
||||
# -------------------------------------------------------------
|
||||
client.loop_start()
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 3️⃣ Publish the static payloads
|
||||
# -------------------------------------------------------------
|
||||
print("\n📤 Publishing static payloads …")
|
||||
for _ in range(1):
|
||||
publish_static_payloads(client, topic, payloads, delay=0.2)
|
||||
|
||||
# Give the broker a moment to ack / reply (if any)
|
||||
time.sleep(10)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 4️⃣ Capture I/O counters **after** traffic
|
||||
# -------------------------------------------------------------
|
||||
final = get_io_counters()
|
||||
print("\n📊 Final I/O counters:")
|
||||
print(f" Written: {final[0]:,} bytes")
|
||||
print(f" Read: {final[1]:,} bytes")
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 5️⃣ Report the delta
|
||||
# -------------------------------------------------------------
|
||||
print_io_delta(baseline, final)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Clean‑up
|
||||
# -------------------------------------------------------------
|
||||
client.loop_stop()
|
||||
client.disconnect()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
Code Snippets/data_estimation_calculator.xlsx
Normal file
BIN
Code Snippets/data_estimation_calculator.xlsx
Normal file
Binary file not shown.
153
Code Snippets/network_usage_per_process.py
Normal file
153
Code Snippets/network_usage_per_process.py
Normal file
@@ -0,0 +1,153 @@
|
||||
from scapy.all import *
|
||||
import psutil
|
||||
from collections import defaultdict
|
||||
import os, time
|
||||
from datetime import datetime
|
||||
from threading import Thread
|
||||
import pandas as pd
|
||||
|
||||
# get the all network adapter's MAC addresses
|
||||
all_macs = {iface.mac for iface in ifaces.values()}
|
||||
# A dictionary to map each connection to its correponding process ID (PID)
|
||||
connection2pid = {}
|
||||
# A dictionary to map each process ID (PID) to total Upload (0) and Download (1) traffic
|
||||
pid2traffic = defaultdict(lambda: [0, 0])
|
||||
# the global Pandas DataFrame that's used to track previous traffic stats
|
||||
global_df = None
|
||||
# global boolean for status of the program
|
||||
is_program_running = True
|
||||
|
||||
def get_size(bytes):
|
||||
"""
|
||||
Returns size of bytes in a nice format
|
||||
"""
|
||||
for unit in ['', 'K', 'M', 'G', 'T', 'P']:
|
||||
if bytes < 1024:
|
||||
return f"{bytes:.2f}{unit}B"
|
||||
bytes /= 1024
|
||||
|
||||
|
||||
def process_packet(packet):
|
||||
global pid2traffic
|
||||
try:
|
||||
# get the packet source & destination IP addresses and ports
|
||||
packet_connection = (packet.sport, packet.dport)
|
||||
except (AttributeError, IndexError):
|
||||
# sometimes the packet does not have TCP/UDP layers, we just ignore these packets
|
||||
pass
|
||||
else:
|
||||
# get the PID responsible for this connection from our `connection2pid` global dictionary
|
||||
packet_pid = connection2pid.get(packet_connection)
|
||||
if packet_pid:
|
||||
if packet.src in all_macs:
|
||||
# the source MAC address of the packet is our MAC address
|
||||
# so it's an outgoing packet, meaning it's upload
|
||||
pid2traffic[packet_pid][0] += len(packet)
|
||||
else:
|
||||
# incoming packet, download
|
||||
pid2traffic[packet_pid][1] += len(packet)
|
||||
|
||||
|
||||
def get_connections():
|
||||
"""A function that keeps listening for connections on this machine
|
||||
and adds them to `connection2pid` global variable"""
|
||||
global connection2pid
|
||||
while is_program_running:
|
||||
# using psutil, we can grab each connection's source and destination ports
|
||||
# and their process ID
|
||||
for c in psutil.net_connections():
|
||||
if c.laddr and c.raddr and c.pid:
|
||||
# if local address, remote address and PID are in the connection
|
||||
# add them to our global dictionary
|
||||
connection2pid[(c.laddr.port, c.raddr.port)] = c.pid
|
||||
connection2pid[(c.raddr.port, c.laddr.port)] = c.pid
|
||||
# sleep for a second, feel free to adjust this
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def print_pid2traffic():
|
||||
global global_df
|
||||
# initialize the list of processes
|
||||
processes = []
|
||||
for pid, traffic in pid2traffic.items():
|
||||
# `pid` is an integer that represents the process ID
|
||||
# `traffic` is a list of two values: total Upload and Download size in bytes
|
||||
try:
|
||||
# get the process object from psutil
|
||||
p = psutil.Process(pid)
|
||||
except psutil.NoSuchProcess:
|
||||
# if process is not found, simply continue to the next PID for now
|
||||
continue
|
||||
# get the name of the process, such as chrome.exe, etc.
|
||||
name = p.name()
|
||||
# get the time the process was spawned
|
||||
try:
|
||||
create_time = datetime.fromtimestamp(p.create_time())
|
||||
except OSError:
|
||||
# system processes, using boot time instead
|
||||
create_time = datetime.fromtimestamp(psutil.boot_time())
|
||||
# construct our dictionary that stores process info
|
||||
process = {
|
||||
"pid": pid, "name": name, "create_time": create_time, "Upload": traffic[0],
|
||||
"Download": traffic[1],
|
||||
}
|
||||
try:
|
||||
# calculate the upload and download speeds by simply subtracting the old stats from the new stats
|
||||
process["Upload Speed"] = traffic[0] - global_df.at[pid, "Upload"]
|
||||
process["Download Speed"] = traffic[1] - global_df.at[pid, "Download"]
|
||||
except (KeyError, AttributeError):
|
||||
# If it's the first time running this function, then the speed is the current traffic
|
||||
# You can think of it as if old traffic is 0
|
||||
process["Upload Speed"] = traffic[0]
|
||||
process["Download Speed"] = traffic[1]
|
||||
# append the process to our processes list
|
||||
processes.append(process)
|
||||
# construct our Pandas DataFrame
|
||||
df = pd.DataFrame(processes)
|
||||
try:
|
||||
# set the PID as the index of the dataframe
|
||||
df = df.set_index("pid")
|
||||
# sort by column, feel free to edit this column
|
||||
df.sort_values("Download", inplace=True, ascending=False)
|
||||
except KeyError as e:
|
||||
# when dataframe is empty
|
||||
pass
|
||||
# make another copy of the dataframe just for fancy printing
|
||||
printing_df = df.copy()
|
||||
try:
|
||||
# apply the function get_size to scale the stats like '532.6KB/s', etc.
|
||||
printing_df["Download"] = printing_df["Download"].apply(get_size)
|
||||
printing_df["Upload"] = printing_df["Upload"].apply(get_size)
|
||||
printing_df["Download Speed"] = printing_df["Download Speed"].apply(get_size).apply(lambda s: f"{s}/s")
|
||||
printing_df["Upload Speed"] = printing_df["Upload Speed"].apply(get_size).apply(lambda s: f"{s}/s")
|
||||
except KeyError as e:
|
||||
# when dataframe is empty again
|
||||
pass
|
||||
# clear the screen based on your OS
|
||||
os.system("cls") if "nt" in os.name else os.system("clear")
|
||||
# print our dataframe
|
||||
print(printing_df.to_string())
|
||||
# update the global df to our dataframe
|
||||
global_df = df
|
||||
|
||||
|
||||
def print_stats():
|
||||
"""Simple function that keeps printing the stats"""
|
||||
while is_program_running:
|
||||
time.sleep(1)
|
||||
print_pid2traffic()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# start the printing thread
|
||||
printing_thread = Thread(target=print_stats)
|
||||
printing_thread.start()
|
||||
# start the get_connections() function to update the current connections of this machine
|
||||
connections_thread = Thread(target=get_connections)
|
||||
connections_thread.start()
|
||||
# start sniffing
|
||||
print("Started sniffing")
|
||||
sniff(prn=process_packet, store=False)
|
||||
# setting the global variable to False to exit the program
|
||||
is_program_running = False
|
||||
142
Code Snippets/rrig_kmz/breakout_kml.py
Normal file
142
Code Snippets/rrig_kmz/breakout_kml.py
Normal file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
KML coordinate extractor
|
||||
------------------------
|
||||
|
||||
* Every <Polygon> element → list of [lat, lon] pairs, written to *output_polygons*.
|
||||
* Every <LineString> element → list of [lat, lon] pairs, written to *output_linestrings*.
|
||||
* Every <Placemark> that contains a <name> and a <Point> → “Marker Name: lat, lon”
|
||||
written to *output_markers*.
|
||||
|
||||
The coordinates in a KML file are stored as `lon,lat[,alt]`.
|
||||
The script converts them to `lat,lon` because that’s the format you asked for.
|
||||
"""
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ----------------------------------------------------------------------
|
||||
def parse_kml(file_path: Path) -> ET.ElementTree:
|
||||
"""Parse the KML file; exit with a message on failure."""
|
||||
try:
|
||||
return ET.parse(file_path)
|
||||
except ET.ParseError as exc:
|
||||
print(f"ERROR: Failed to parse {file_path}: {exc}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def _lon_lat_to_list(coord_str: str) -> list[list[float]]:
|
||||
"""
|
||||
Convert a KML coordinate string (lon,lat[,alt] …) into a list of [lat, lon].
|
||||
Ignores malformed entries.
|
||||
"""
|
||||
coords = []
|
||||
for pair in coord_str.strip().split():
|
||||
parts = pair.split(',')
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
lon, lat = float(parts[0]), float(parts[1])
|
||||
coords.append([lat, lon])
|
||||
return coords
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Main extraction routine
|
||||
# ----------------------------------------------------------------------
|
||||
def extract_kml(
|
||||
kml_file: Path,
|
||||
out_polygons: Path,
|
||||
out_linestrings: Path,
|
||||
out_markers: Path,
|
||||
) -> None:
|
||||
tree = parse_kml(kml_file)
|
||||
root = tree.getroot()
|
||||
|
||||
# Namespace handling (most KML files use the same namespace)
|
||||
ns = {'kml': root.tag.split('}')[0].strip('{')}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 1) Polygons
|
||||
# ------------------------------------------------------------------
|
||||
polygons = [] # List[ List[ [lat, lon] ] ]
|
||||
for poly in root.findall('.//kml:Polygon', ns):
|
||||
coord_el = poly.find('.//kml:coordinates', ns)
|
||||
if coord_el is None or not coord_el.text:
|
||||
continue
|
||||
polygons.append(_lon_lat_to_list(coord_el.text))
|
||||
|
||||
# Write polygons
|
||||
with out_polygons.open('w', encoding='utf-8') as fp:
|
||||
for i, poly in enumerate(polygons, start=1):
|
||||
fp.write(f"Polygon {i}:\n")
|
||||
fp.write(str(poly) + "\n\n")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 2) LineStrings
|
||||
# ------------------------------------------------------------------
|
||||
linestrings = [] # List[ List[ [lat, lon] ] ]
|
||||
for ls in root.findall('.//kml:LineString', ns):
|
||||
coord_el = ls.find('.//kml:coordinates', ns)
|
||||
if coord_el is None or not coord_el.text:
|
||||
continue
|
||||
linestrings.append(_lon_lat_to_list(coord_el.text))
|
||||
|
||||
# Write LineStrings
|
||||
with out_linestrings.open('w', encoding='utf-8') as fp:
|
||||
for i, ls in enumerate(linestrings, start=1):
|
||||
fp.write(f"LineString {i}:\n")
|
||||
fp.write(str(ls) + "\n\n")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 3) Markers (Point placemarks with a name)
|
||||
# ------------------------------------------------------------------
|
||||
markers = [] # List[ (name, [lat, lon]) ]
|
||||
for pm in root.findall('.//kml:Placemark', ns):
|
||||
name_el = pm.find('kml:name', ns)
|
||||
point_el = pm.find('.//kml:Point/kml:coordinates', ns)
|
||||
if name_el is None or point_el is None:
|
||||
continue
|
||||
|
||||
name = name_el.text.strip()
|
||||
coord_list = _lon_lat_to_list(point_el.text)
|
||||
if not coord_list:
|
||||
continue
|
||||
markers.append((name, coord_list[0])) # a point has exactly one pair
|
||||
|
||||
# Write markers
|
||||
with out_markers.open('w', encoding='utf-8') as fp:
|
||||
for name, (lat, lon) in markers:
|
||||
fp.write(f"{name}: {lat}, {lon}\n")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Summary
|
||||
# ------------------------------------------------------------------
|
||||
print(f"Polygons written to: {out_polygons}")
|
||||
print(f"LineStrings written to: {out_linestrings}")
|
||||
print(f"Markers written to: {out_markers}")
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Entry‑point
|
||||
# ----------------------------------------------------------------------
|
||||
def main() -> None:
|
||||
if len(sys.argv) != 5:
|
||||
print(
|
||||
"Usage: python breakout_kml.py <input_file> "
|
||||
"<output_polygons> <output_linestrings> <output_markers>"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
input_file = Path(sys.argv[1]).expanduser().resolve()
|
||||
out_polygons = Path(sys.argv[2]).expanduser().resolve()
|
||||
out_linestrings = Path(sys.argv[3]).expanduser().resolve()
|
||||
out_markers = Path(sys.argv[4]).expanduser().resolve()
|
||||
|
||||
if not input_file.exists():
|
||||
print(f"ERROR: Input file not found: {input_file}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
extract_kml(input_file, out_polygons, out_linestrings, out_markers)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
Code Snippets/rrig_kmz/kmz/Node C Monahans Booster Station.kmz
Normal file
BIN
Code Snippets/rrig_kmz/kmz/Node C Monahans Booster Station.kmz
Normal file
Binary file not shown.
Binary file not shown.
BIN
Code Snippets/rrig_kmz/kmz/Node F US Silica.kmz
Normal file
BIN
Code Snippets/rrig_kmz/kmz/Node F US Silica.kmz
Normal file
Binary file not shown.
BIN
Code Snippets/rrig_kmz/kmz/Node X Cipher Interconnect.kmz
Normal file
BIN
Code Snippets/rrig_kmz/kmz/Node X Cipher Interconnect.kmz
Normal file
Binary file not shown.
Binary file not shown.
BIN
Code Snippets/rrig_kmz/kmz/RRIG Water Pump Station.kmz
Normal file
BIN
Code Snippets/rrig_kmz/kmz/RRIG Water Pump Station.kmz
Normal file
Binary file not shown.
120
Code Snippets/rrig_kmz/kmz_combine.py
Normal file
120
Code Snippets/rrig_kmz/kmz_combine.py
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
combine_kmz_to_kml.py
|
||||
|
||||
Combine all KMZ files in a folder into a single KML file.
|
||||
|
||||
Usage:
|
||||
python combine_kmz_to_kml.py <input_folder> <output_kml>
|
||||
|
||||
Example:
|
||||
python combine_kmz_to_kml.py ./kmz_files all_points.kml
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Helper functions
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def find_kmz_files(folder: Path) -> List[Path]:
|
||||
"""Return a list of .kmz files in the given folder (non‑recursive)."""
|
||||
return list(folder.rglob("*.kmz"))
|
||||
|
||||
def extract_kml_from_kmz(kmz_path: Path) -> ET.ElementTree:
|
||||
"""
|
||||
Extract the first KML file found inside a KMZ archive.
|
||||
Returns an ElementTree of the extracted KML.
|
||||
"""
|
||||
with zipfile.ZipFile(kmz_path, "r") as z:
|
||||
# Find the first file ending with .kml (case‑insensitive)
|
||||
kml_name = next((n for n in z.namelist()
|
||||
if n.lower().endswith(".kml")), None)
|
||||
if not kml_name:
|
||||
raise ValueError(f"No KML file found inside {kmz_path}")
|
||||
with z.open(kml_name) as kml_file:
|
||||
return ET.parse(kml_file)
|
||||
|
||||
def get_top_level_elements(kml_tree: ET.ElementTree) -> List[ET.Element]:
|
||||
"""
|
||||
Return a list of the top‑level elements that contain placemarks.
|
||||
Common patterns are:
|
||||
<Document>
|
||||
<Folder>
|
||||
<Placemark>
|
||||
"""
|
||||
root = kml_tree.getroot()
|
||||
# KML namespace handling (most KMLs use the same namespace)
|
||||
ns = {"kml": "http://www.opengis.net/kml/2.2"}
|
||||
# Find <Document> or <Folder> or <Placemark> elements directly under root
|
||||
elements = []
|
||||
for tag in ["Document", "Folder", "Placemark"]:
|
||||
elements.extend(root.findall(f"kml:{tag}", ns))
|
||||
return elements
|
||||
|
||||
def build_merged_kml(elements_by_file: List[List[ET.Element]]) -> ET.ElementTree:
|
||||
"""
|
||||
Build a new KML ElementTree that contains a single <Document>
|
||||
wrapping all collected elements.
|
||||
"""
|
||||
kml_ns = "http://www.opengis.net/kml/2.2"
|
||||
ET.register_namespace("", kml_ns) # ensure no prefix in output
|
||||
|
||||
kml_root = ET.Element(f"{{{kml_ns}}}kml")
|
||||
doc = ET.SubElement(kml_root, "Document")
|
||||
|
||||
for elems in elements_by_file:
|
||||
for elem in elems:
|
||||
doc.append(elem)
|
||||
|
||||
return ET.ElementTree(kml_root)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Main logic
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def main(input_folder: Path, output_file: Path):
|
||||
kmz_files = find_kmz_files(input_folder)
|
||||
if not kmz_files:
|
||||
print(f"No .kmz files found in {input_folder}")
|
||||
sys.exit(1)
|
||||
|
||||
all_elements = []
|
||||
|
||||
for kmz in kmz_files:
|
||||
try:
|
||||
kml_tree = extract_kml_from_kmz(kmz)
|
||||
elems = get_top_level_elements(kml_tree)
|
||||
if not elems:
|
||||
print(f"WARNING: No placemark elements found in {kmz}")
|
||||
else:
|
||||
all_elements.append(elems)
|
||||
except Exception as e:
|
||||
print(f"ERROR processing {kmz}: {e}")
|
||||
|
||||
if not any(all_elements):
|
||||
print("No placemark data to write.")
|
||||
sys.exit(1)
|
||||
|
||||
merged_tree = build_merged_kml(all_elements)
|
||||
merged_tree.write(output_file, encoding="utf-8", xml_declaration=True)
|
||||
print(f"Combined KML written to {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: python combine_kmz_to_kml.py <input_folder> <output_kml>")
|
||||
sys.exit(1)
|
||||
|
||||
input_dir = Path(sys.argv[1]).expanduser().resolve()
|
||||
output_kml = Path(sys.argv[2]).expanduser().resolve()
|
||||
|
||||
if not input_dir.is_dir():
|
||||
print(f"Input path {input_dir} is not a directory.")
|
||||
sys.exit(1)
|
||||
|
||||
main(input_dir, output_kml)
|
||||
3
Code Snippets/rrig_kmz/linestring.txt
Normal file
3
Code Snippets/rrig_kmz/linestring.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
LineString 1:
|
||||
[[31.65053381256015, -103.1381372489133], [31.65078110147886, -103.1371939568141], [31.65137766837301, -103.135379572764], [31.65501734857683, -103.1216582043267], [31.66820232963991, -103.1267090001346], [31.66857428692562, -103.1254217441416], [31.68730649748832, -103.097869762411], [31.69401658057209, -103.0880082019376], [31.71262120882616, -103.0201699677156], [31.71246042343891, -103.0199628293717], [31.71229701578655, -103.0197573453124], [31.71245394748738, -103.0195184188874], [31.63091832800928, -102.9041726111906], [31.6165910414367, -102.8944523887092], [31.59718777074555, -102.8811494904473], [31.58231202839571, -102.8680137394599], [31.56931339800882, -102.8516886598823], [31.48448961907497, -102.7180735327187], [31.51503752317085, -102.7283930769256], [31.51898260340799, -102.7117114856601], [31.5330847136263, -102.7165257753119], [31.53686069788628, -102.7003948024066], [31.56540947523578, -102.7095293371793], [31.58496921843023, -102.6901307183483], [31.60301750051444, -102.6955769601148]]
|
||||
|
||||
5
Code Snippets/rrig_kmz/marker.txt
Normal file
5
Code Snippets/rrig_kmz/marker.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Node X: Cipher Interconnect: 31.69772151150734, -103.0755810899755
|
||||
Node D: 10" to 12" Transition - Wadell Valve: 31.48528462529936, -102.7191228273435
|
||||
Node F: US Silica: 31.60330030384848, -102.6955825380853
|
||||
RRIG Water Pump Station: 31.65239911273985, -103.1419105981684
|
||||
Node C: Monahans Booster Station: 31.59192479909473, -102.8767681214162
|
||||
352
Code Snippets/rrig_kmz/out.kml
Normal file
352
Code Snippets/rrig_kmz/out.kml
Normal file
@@ -0,0 +1,352 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:ns1="http://www.google.com/kml/ext/2.2" xmlns:ns2="http://www.w3.org/2005/Atom"><Document><Document>
|
||||
<name>Node X Cipher Interconnect.kmz</name>
|
||||
<StyleMap id="msn_X">
|
||||
<Pair>
|
||||
<key>normal</key>
|
||||
<styleUrl>#sn_X</styleUrl>
|
||||
</Pair>
|
||||
<Pair>
|
||||
<key>highlight</key>
|
||||
<styleUrl>#sh_X</styleUrl>
|
||||
</Pair>
|
||||
</StyleMap>
|
||||
<Style id="sh_X">
|
||||
<IconStyle>
|
||||
<scale>1.3</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/X.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/X-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Style id="sn_X">
|
||||
<IconStyle>
|
||||
<scale>1.1</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/X.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/X-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Placemark>
|
||||
<name>Node X: Cipher Interconnect</name>
|
||||
<LookAt>
|
||||
<longitude>-103.0664786491922</longitude>
|
||||
<latitude>31.67995227525221</latitude>
|
||||
<altitude>0</altitude>
|
||||
<heading>-20.19425301511447</heading>
|
||||
<tilt>0.3113470562703879</tilt>
|
||||
<range>19074.24725536319</range>
|
||||
<ns1:altitudeMode>relativeToSeaFloor</ns1:altitudeMode>
|
||||
</LookAt>
|
||||
<styleUrl>#msn_X</styleUrl>
|
||||
<Point>
|
||||
<ns1:drawOrder>1</ns1:drawOrder>
|
||||
<coordinates>-103.0755810899755,31.69772151150734,0</coordinates>
|
||||
</Point>
|
||||
<ns2:link rel="app" href="https://www.google.com/earth/about/versions/#earth-pro" title="Google Earth Pro 7.3.6.10441" />
|
||||
</Placemark>
|
||||
</Document>
|
||||
<Document>
|
||||
<name>Node D 10 to 12 Transition - Wadell Valve.kmz</name>
|
||||
<StyleMap id="msn_D">
|
||||
<Pair>
|
||||
<key>normal</key>
|
||||
<styleUrl>#sn_D</styleUrl>
|
||||
</Pair>
|
||||
<Pair>
|
||||
<key>highlight</key>
|
||||
<styleUrl>#sh_D</styleUrl>
|
||||
</Pair>
|
||||
</StyleMap>
|
||||
<Style id="sh_D">
|
||||
<IconStyle>
|
||||
<scale>1.3</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/D.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/D-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Style id="sn_D">
|
||||
<IconStyle>
|
||||
<scale>1.1</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/D.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/D-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Placemark>
|
||||
<name>Node D: 10" to 12" Transition - Wadell Valve</name>
|
||||
<description>This is a proposed booster station location.
|
||||
|
||||
Before this proposed booster station is NEW 10" CS SCH/40 and after the pump it transitions to the existing 12" CS SCH/STD.</description>
|
||||
<LookAt>
|
||||
<longitude>-102.714901153744</longitude>
|
||||
<latitude>31.49028973104173</latitude>
|
||||
<altitude>0</altitude>
|
||||
<heading>0.2075710380470465</heading>
|
||||
<tilt>34.53924441923252</tilt>
|
||||
<range>3707.334765680453</range>
|
||||
<ns1:altitudeMode>relativeToSeaFloor</ns1:altitudeMode>
|
||||
</LookAt>
|
||||
<styleUrl>#msn_D</styleUrl>
|
||||
<Point>
|
||||
<ns1:drawOrder>1</ns1:drawOrder>
|
||||
<coordinates>-102.7191228273435,31.48528462529936,0</coordinates>
|
||||
</Point>
|
||||
<ns2:link rel="app" href="https://www.google.com/earth/about/versions/#earth-pro" title="Google Earth Pro 7.3.6.10441" />
|
||||
</Placemark>
|
||||
</Document>
|
||||
<Document>
|
||||
<name>Node F US Silica.kmz</name>
|
||||
<StyleMap id="msn_F">
|
||||
<Pair>
|
||||
<key>normal</key>
|
||||
<styleUrl>#sn_F</styleUrl>
|
||||
</Pair>
|
||||
<Pair>
|
||||
<key>highlight</key>
|
||||
<styleUrl>#sh_F</styleUrl>
|
||||
</Pair>
|
||||
</StyleMap>
|
||||
<Style id="sh_F">
|
||||
<IconStyle>
|
||||
<scale>1.3</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/F.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/F-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Style id="sn_F">
|
||||
<IconStyle>
|
||||
<scale>1.1</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/F.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/F-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Placemark>
|
||||
<name>Node F: US Silica</name>
|
||||
<description>This is the final destination (US Silica).</description>
|
||||
<LookAt>
|
||||
<longitude>-102.7057483945038</longitude>
|
||||
<latitude>31.58085164971466</latitude>
|
||||
<altitude>0</altitude>
|
||||
<heading>0.1391520682125403</heading>
|
||||
<tilt>14.07815682751618</tilt>
|
||||
<range>9472.365324672779</range>
|
||||
<ns1:altitudeMode>relativeToSeaFloor</ns1:altitudeMode>
|
||||
</LookAt>
|
||||
<styleUrl>#msn_F</styleUrl>
|
||||
<ns1:balloonVisibility>1</ns1:balloonVisibility>
|
||||
<Point>
|
||||
<ns1:drawOrder>1</ns1:drawOrder>
|
||||
<coordinates>-102.6955825380853,31.60330030384848,0</coordinates>
|
||||
</Point>
|
||||
<ns2:link rel="app" href="https://www.google.com/earth/about/versions/#earth-pro" title="Google Earth Pro 7.3.6.10441" />
|
||||
</Placemark>
|
||||
</Document>
|
||||
<Document>
|
||||
<name>RRIG Water Pump Station.kmz</name>
|
||||
<StyleMap id="msn_ylw-pushpin">
|
||||
<Pair>
|
||||
<key>normal</key>
|
||||
<styleUrl>#sn_ylw-pushpin</styleUrl>
|
||||
</Pair>
|
||||
<Pair>
|
||||
<key>highlight</key>
|
||||
<styleUrl>#sh_ylw-pushpin</styleUrl>
|
||||
</Pair>
|
||||
</StyleMap>
|
||||
<Style id="sh_ylw-pushpin">
|
||||
<IconStyle>
|
||||
<scale>1.3</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<BalloonStyle>
|
||||
</BalloonStyle>
|
||||
</Style>
|
||||
<Style id="sn_ylw-pushpin">
|
||||
<IconStyle>
|
||||
<scale>1.1</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<BalloonStyle>
|
||||
</BalloonStyle>
|
||||
</Style>
|
||||
<Placemark>
|
||||
<name>RRIG Water Pump Station</name>
|
||||
<LookAt>
|
||||
<longitude>-103.1424336640816</longitude>
|
||||
<latitude>31.65637246137589</latitude>
|
||||
<altitude>0</altitude>
|
||||
<heading>-0.01350029730544429</heading>
|
||||
<tilt>33.60918004711282</tilt>
|
||||
<range>3855.687513264544</range>
|
||||
<ns1:altitudeMode>relativeToSeaFloor</ns1:altitudeMode>
|
||||
</LookAt>
|
||||
<styleUrl>#msn_ylw-pushpin</styleUrl>
|
||||
<Point>
|
||||
<ns1:drawOrder>1</ns1:drawOrder>
|
||||
<coordinates>-103.1419105981684,31.65239911273985,0</coordinates>
|
||||
</Point>
|
||||
<ns2:link rel="app" href="https://www.google.com/earth/about/versions/#earth-pro" title="Google Earth Pro 7.3.6.10441" />
|
||||
</Placemark>
|
||||
</Document>
|
||||
<Document>
|
||||
<name>Node C Monahans Booster Station.kmz</name>
|
||||
<StyleMap id="msn_C">
|
||||
<Pair>
|
||||
<key>normal</key>
|
||||
<styleUrl>#sn_C</styleUrl>
|
||||
</Pair>
|
||||
<Pair>
|
||||
<key>highlight</key>
|
||||
<styleUrl>#sh_C</styleUrl>
|
||||
</Pair>
|
||||
</StyleMap>
|
||||
<Style id="sh_C">
|
||||
<IconStyle>
|
||||
<scale>1.3</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/C.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<BalloonStyle>
|
||||
</BalloonStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/C-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Style id="sn_C">
|
||||
<IconStyle>
|
||||
<scale>1.1</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/C.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<BalloonStyle>
|
||||
</BalloonStyle>
|
||||
<ListStyle>
|
||||
<ItemIcon>
|
||||
<href>http://maps.google.com/mapfiles/kml/paddle/C-lv.png</href>
|
||||
</ItemIcon>
|
||||
</ListStyle>
|
||||
</Style>
|
||||
<Placemark>
|
||||
<name>Node C: Monahans Booster Station</name>
|
||||
<description>Here is an exisiting booster station. The pumps here will require an upgrade/new pumps.
|
||||
Before the booster station is 16" SDR-11 HDPE and after the pump it transitions to the existing worn 10" CS SCH/40.</description>
|
||||
<LookAt>
|
||||
<longitude>-102.8754448804377</longitude>
|
||||
<latitude>31.59216413663673</latitude>
|
||||
<altitude>0</altitude>
|
||||
<heading>0.02738240047835951</heading>
|
||||
<tilt>19.33959001588264</tilt>
|
||||
<range>589.3935585480306</range>
|
||||
<ns1:altitudeMode>relativeToSeaFloor</ns1:altitudeMode>
|
||||
</LookAt>
|
||||
<styleUrl>#msn_C</styleUrl>
|
||||
<Point>
|
||||
<ns1:drawOrder>1</ns1:drawOrder>
|
||||
<coordinates>-102.8767681214162,31.59192479909473,0</coordinates>
|
||||
</Point>
|
||||
<ns2:link rel="app" href="https://www.google.com/earth/about/versions/#earth-pro" title="Google Earth Pro 7.3.6.10441" />
|
||||
</Placemark>
|
||||
</Document>
|
||||
<Document>
|
||||
<name>Original - Rig PL wilth existing Azul PL.kmz</name>
|
||||
<StyleMap id="msn_ylw-pushpin89">
|
||||
<Pair>
|
||||
<key>normal</key>
|
||||
<styleUrl>#sn_ylw-pushpin96</styleUrl>
|
||||
</Pair>
|
||||
<Pair>
|
||||
<key>highlight</key>
|
||||
<styleUrl>#sh_ylw-pushpin94</styleUrl>
|
||||
</Pair>
|
||||
</StyleMap>
|
||||
<Style id="sh_ylw-pushpin94">
|
||||
<IconStyle>
|
||||
<scale>1.3</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<LineStyle>
|
||||
<color>ff0000ff</color>
|
||||
<width>3</width>
|
||||
</LineStyle>
|
||||
</Style>
|
||||
<Style id="sn_ylw-pushpin96">
|
||||
<IconStyle>
|
||||
<scale>1.1</scale>
|
||||
<Icon>
|
||||
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
|
||||
</Icon>
|
||||
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels" />
|
||||
</IconStyle>
|
||||
<LineStyle>
|
||||
<color>ff0000ff</color>
|
||||
<width>3</width>
|
||||
</LineStyle>
|
||||
</Style>
|
||||
<Placemark>
|
||||
<name>Original - Rig PL wilth existing Azul PL</name>
|
||||
<styleUrl>#msn_ylw-pushpin89</styleUrl>
|
||||
<LineString>
|
||||
<tessellate>1</tessellate>
|
||||
<coordinates>
|
||||
-103.1381372489133,31.65053381256015,0 -103.1371939568141,31.65078110147886,0 -103.135379572764,31.65137766837301,0 -103.1216582043267,31.65501734857683,0 -103.1267090001346,31.66820232963991,0 -103.1254217441416,31.66857428692562,0 -103.097869762411,31.68730649748832,0 -103.0880082019376,31.69401658057209,0 -103.0201699677156,31.71262120882616,0 -103.0199628293717,31.71246042343891,0 -103.0197573453124,31.71229701578655,0 -103.0195184188874,31.71245394748738,0 -102.9041726111906,31.63091832800928,0 -102.8944523887092,31.6165910414367,0 -102.8811494904473,31.59718777074555,0 -102.8680137394599,31.58231202839571,0 -102.8516886598823,31.56931339800882,0 -102.7180735327187,31.48448961907497,0 -102.7283930769256,31.51503752317085,0 -102.7117114856601,31.51898260340799,0 -102.7165257753119,31.5330847136263,0 -102.7003948024066,31.53686069788628,0 -102.7095293371793,31.56540947523578,0 -102.6901307183483,31.58496921843023,0 -102.6955769601148,31.60301750051444,0
|
||||
</coordinates>
|
||||
</LineString>
|
||||
<ns2:link rel="app" href="https://www.google.com/earth/about/versions/#earth-pro" title="Google Earth Pro 7.3.6.10441" />
|
||||
</Placemark>
|
||||
</Document>
|
||||
</Document></kml>
|
||||
0
Code Snippets/rrig_kmz/polygon.txt
Normal file
0
Code Snippets/rrig_kmz/polygon.txt
Normal file
Reference in New Issue
Block a user