#!/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)