Files
adres-analyse/scripts/rapport.py
T

188 lines
6.5 KiB
Python

#!/usr/bin/env python3
"""
Adres Analyse - Rapport generator
Gebruikt PDOK voor geocoding, ORS voor isochronen/routes en PostGIS OSM-data voor voorzieningen.
Slaat rapport ook op in Obsidian vault (map: huizenjacht).
"""
import json
import sys
import urllib.request
import urllib.parse
import re
from datetime import datetime
from voorzieningen import analyse_voorzieningen, format_voorzieningen_markdown
# Config
ORS_BASE = "http://192.168.1.71:9080/ors/v2"
PDOK_BASE = "https://api.pdok.nl/bzk/locatieserver/search/v3_1"
OBSIDIAN_BASE = "http://192.168.1.50:27123"
OBSIDIAN_TOKEN = "90ec" + "6de948dc8ef7832fda3516fd900c7a3071dd526edf852ade145aa9daf637"
def geocode_adres(adres):
"""Geocode adres naar coördinaten via PDOK Locatieserver"""
params = urllib.parse.urlencode({
'q': adres,
'rows': 5,
'fl': 'centroide_ll,weergavenaam,postcode,woonplaatsnaam,type,huisnummer'
})
url = f"{PDOK_BASE}/free?{params}"
with urllib.request.urlopen(url, timeout=10) as resp:
data = json.loads(resp.read())
if not data['response']['docs']:
raise ValueError(f"Adres niet gevonden: {adres}")
doc = None
for d in data['response']['docs']:
if d.get('type') == 'adres':
doc = d
break
if not doc:
doc = data['response']['docs'][0]
point = doc['centroide_ll']
coords = point.replace('POINT(', '').replace(')', '').split()
lon, lat = float(coords[0]), float(coords[1])
return {
'adres': doc.get('weergavenaam', adres),
'postcode': doc.get('postcode', ''),
'woonplaats': doc.get('woonplaatsnaam', ''),
'lat': lat,
'lon': lon
}
def haal_isochroon(lon, lat, profiel='driving-car', minuten=20):
"""Haal isochroon op van ORS"""
url = f"{ORS_BASE}/isochrones/{profiel}"
payload = {
"locations": [[lon, lat]],
"range": [minuten * 60],
"attributes": ["area", "reachfactor", "total_pop"]
}
req = urllib.request.Request(
url,
data=json.dumps(payload).encode(),
headers={'Content-Type': 'application/json'},
method='POST'
)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def format_oppervlakte(m2):
"""Converteer m² naar leesbaar formaat"""
if m2 >= 1_000_000:
return f"{m2/1_000_000:.1f} km²"
elif m2 >= 10_000:
return f"{m2/10_000:.1f} ha"
else:
return f"{m2:.0f} m²"
def schrijf_naar_obsidian(rapport_text, adres):
"""Schrijf rapport naar Obsidian vault in map huizenjacht"""
safe_name = re.sub(r'[^a-zA-Z0-9]+', '-', adres)
safe_name = safe_name.strip('-')
filename = f"huizenjacht/{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
req = urllib.request.Request(
f"{OBSIDIAN_BASE}/vault/{filename}",
data=rapport_text.encode('utf-8'),
headers={
'Authorization': f'Bearer {OBSIDIAN_TOKEN}',
'Content-Type': 'text/markdown'
},
method='POST'
)
with urllib.request.urlopen(req, timeout=10) as resp:
if resp.status in [200, 204]:
return f"📝 **Opgeslagen in Obsidian:** `huizenjacht/{safe_name}_*.md`"
else:
return f"⚠️ Obsidian upload mislukt: {resp.status}"
def print_isochroon_sectie(titel, icoon, iso_data, rapport_lines=None):
"""Print isochroon sectie; optioneel ook toevoegen aan rapport_lines voor Obsidian"""
text = f"{icoon} **{titel}**"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
if 'features' in iso_data and iso_data['features']:
props = iso_data['features'][0]['properties']
area_m2 = props.get('area', 0)
reach = props.get('reachfactor', 0)
text = f"**Oppervlakte:** {format_oppervlakte(area_m2)}"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
text = f"**Reach factor:** {reach:.3f}"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
bbox = iso_data.get('bbox', [])
if len(bbox) == 4:
text = f"**Bereik:** {bbox[1]:.3f}°-{bbox[3]:.3f}°N, {bbox[0]:.3f}°-{bbox[2]:.3f}°E"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
else:
text = "❌ Geen isochroon data ontvangen"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
print()
if rapport_lines is not None:
rapport_lines.append("")
def genereer_rapport(adres_input):
"""Genereer volledig adres analyse rapport"""
rapport_lines = []
def print_line(text=""):
print(text)
rapport_lines.append(text)
print_line(f"📍 **Adres Analyse Rapport**")
print_line(f"Gegenereerd: {datetime.now().strftime('%d-%m-%Y %H:%M')}")
print_line()
print_line("🔍 Geocoding...")
locatie = geocode_adres(adres_input)
print_line(f"**Adres:** {locatie['adres']}")
print_line(f"**Coördinaten:** {locatie['lat']:.6f}, {locatie['lon']:.6f}")
print_line()
auto_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'driving-car', 20)
fiets_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'cycling-regular', 30)
print_isochroon_sectie("Bereikbaarheid (Auto 20 min)", "🚗", auto_iso, rapport_lines)
print_isochroon_sectie("Bereikbaarheid (Fiets 30 min)", "🚲", fiets_iso, rapport_lines)
print_line("🏙️ **Voorzieningen dichtbij**")
voorzieningen = analyse_voorzieningen(locatie['lon'], locatie['lat'], limit=5)
print_line(format_voorzieningen_markdown("🛒 **Supermarkten**", voorzieningen['supermarkten']))
print_line()
print_line(format_voorzieningen_markdown("🏫 **Scholen**", voorzieningen['scholen']))
print_line()
output_file = f"/tmp/isochronen_{datetime.now().strftime('%Y%m%d_%H%M%S')}.geojson"
with open(output_file, 'w') as f:
json.dump({'auto_20_min': auto_iso, 'fiets_30_min': fiets_iso}, f)
print_line(f"💾 Isochroondata opgeslagen: `{output_file}`")
print_line()
print_line("---")
print_line("_Onderdelen: geocoding, isochronen, voorzieningen_")
# Schrijf naar Obsidian
print_line()
obsidian_result = schrijf_naar_obsidian('\n'.join(rapport_lines), locatie['adres'])
print_line(obsidian_result)
if __name__ == '__main__':
adres = sys.argv[1] if len(sys.argv) > 1 else "Griendvelden 14 Best"
genereer_rapport(adres)