external prices added

This commit is contained in:
Mark Kors
2025-10-29 19:16:07 +01:00
parent 58409ba783
commit 6a722f6bf2
2 changed files with 337 additions and 44 deletions

View File

@@ -11,7 +11,8 @@ import sys
from typing import List, Dict, Optional
class SteVeReporter:
def __init__(self, host: str, database: str, user: str, password: str, port: int = 3306):
def __init__(self, host: str, database: str, user: str, password: str, port: int = 3306,
price_host: str = None, price_port: int = None, price_user: str = None, price_password: str = None):
"""Initialiseer database connectie"""
self.config = {
'host': host,
@@ -20,8 +21,17 @@ class SteVeReporter:
'password': password,
'port': port
}
# Prijzen database config (gebruik SteVe config als fallback)
self.price_config = {
'host': price_host or host,
'port': price_port or port,
'user': price_user or user,
'password': price_password or password
}
self.conn = None
self.cursor = None
self.price_conn = None
self.price_cursor = None
def connect(self):
"""Maak verbinding met de database"""
@@ -39,6 +49,10 @@ class SteVeReporter:
self.cursor.close()
if self.conn:
self.conn.close()
if hasattr(self, 'price_cursor') and self.price_cursor:
self.price_cursor.close()
if hasattr(self, 'price_conn') and self.price_conn:
self.price_conn.close()
def get_transactions(self, limit: Optional[int] = None, transaction_id: Optional[int] = None) -> List[Dict]:
"""Haal transacties op uit de database"""
@@ -114,6 +128,57 @@ class SteVeReporter:
self.cursor.execute(query, (id_tag,))
return self.cursor.fetchone()
def get_price(self, timestamp: datetime, provider: str, price_db: str) -> Optional[float]:
"""Haal prijs op voor een specifieke timestamp en provider"""
# Maak verbinding met prijzen database indien nodig
if not hasattr(self, 'price_conn') or self.price_conn is None:
try:
# Gebruik price_config met de juiste database naam
price_config = self.price_config.copy()
price_config['database'] = price_db
self.price_conn = mysql.connector.connect(**price_config)
self.price_cursor = self.price_conn.cursor(dictionary=True)
print(f"✓ Verbonden met prijzen database {price_db} op {price_config['host']}")
except mysql.connector.Error as err:
print(f"⚠ Waarschuwing: Kan geen verbinding maken met prijzen database: {err}")
return None
# Round timestamp naar het uur
hour_timestamp = timestamp.replace(minute=0, second=0, microsecond=0)
# Probeer eerst dynamic_price_data (voor historische en vandaag)
query = """
SELECT price
FROM dynamic_price_data
WHERE datetime = %s AND provider_code = %s
LIMIT 1
"""
try:
self.price_cursor.execute(query, (hour_timestamp, provider))
result = self.price_cursor.fetchone()
if result:
return float(result['price'])
except mysql.connector.Error:
pass
# Zo niet, probeer dynamic_price_data_tommorow (alleen NextEnergy)
if provider == 'NE':
query = """
SELECT price
FROM dynamic_price_data_tommorow
WHERE datetime = %s
LIMIT 1
"""
try:
self.price_cursor.execute(query, (hour_timestamp,))
result = self.price_cursor.fetchone()
if result:
return float(result['price'])
except mysql.connector.Error:
pass
return None
def analyze_hourly_consumption(self, meter_values: List[Dict]) -> List[Dict]:
"""Analyseer verbruik per uur"""
if not meter_values:
@@ -154,7 +219,7 @@ class SteVeReporter:
return result
def print_transaction_report(self, transaction: Dict, detailed: bool = True):
def print_transaction_report(self, transaction: Dict, detailed: bool = True, provider: str = 'NE', price_db: str = 'alfen'):
"""Print een geformatteerd rapport van een transactie"""
print("\n" + "=" * 80)
print(f"LAADSESSIE RAPPORT - Transactie #{transaction['transaction_pk']}")
@@ -210,23 +275,44 @@ class SteVeReporter:
hourly_data = self.analyze_hourly_consumption(meter_values)
if hourly_data:
print("\nVERBRUIK PER UUR:")
print("-" * 80)
print(f"{'Uur':<20} {'Start (kWh)':<15} {'Eind (kWh)':<15} {'Geladen (kWh)':<15}")
print("-" * 80)
print("\nVERBRUIK EN KOSTEN PER UUR:")
print("-" * 100)
print(f"{'Uur':<20} {'Start (kWh)':<15} {'Eind (kWh)':<15} {'Geladen (kWh)':<15} {'Prijs (€/kWh)':<15} {'Kosten (€)':<15}")
print("-" * 100)
total_detailed = 0
total_cost = 0
hours_with_price = 0
hours_without_price = 0
for hour in hourly_data:
hour_dt = datetime.strptime(hour['hour'], '%Y-%m-%d %H:00')
hour_display = hour_dt.strftime('%d-%m %H:%M')
# Haal prijs op voor dit uur
price = self.get_price(hour_dt, provider, price_db)
if price is not None:
cost = hour['consumption'] * price
total_cost += cost
hours_with_price += 1
price_str = f"{price:.5f}"
cost_str = f"{cost:.2f}"
else:
hours_without_price += 1
price_str = "n.v.t."
cost_str = "n.v.t."
print(f"{hour_display:<20} {hour['start_value']:<15.3f} "
f"{hour['end_value']:<15.3f} {hour['consumption']:<15.3f}")
f"{hour['end_value']:<15.3f} {hour['consumption']:<15.3f} "
f"{price_str:<15} {cost_str:<15}")
total_detailed += hour['consumption']
print("-" * 80)
print("-" * 100)
cost_total_str = f"{total_cost:.2f}" if hours_without_price == 0 else f"{total_cost:.2f}*"
print(f"{'TOTAAL':<20} {hourly_data[0]['start_value']:<15.3f} "
f"{hourly_data[-1]['end_value']:<15.3f} {total_detailed:<15.3f}")
f"{hourly_data[-1]['end_value']:<15.3f} {total_detailed:<15.3f} "
f"{'':15} {cost_total_str:<15}")
# Statistieken
active_hours = [h for h in hourly_data if h['consumption'] > 0.01]
@@ -235,18 +321,42 @@ class SteVeReporter:
print("STATISTIEKEN:")
print("-" * 80)
print(f"Actieve laaduren: {len(active_hours)}")
print(f"Provider: {provider}")
avg_per_hour = sum(h['consumption'] for h in active_hours) / len(active_hours)
print(f"Gemiddeld per actief uur: {avg_per_hour:.2f} kWh")
max_hour = max(hourly_data, key=lambda x: x['consumption'])
if max_hour['consumption'] > 0:
max_time = datetime.strptime(max_hour['hour'], '%Y-%m-%d %H:00')
print(f"Piekuur: {max_time.strftime('%d-%m %H:00')} "
print(f"Piekuur verbruik: {max_time.strftime('%d-%m %H:00')} "
f"({max_hour['consumption']:.2f} kWh)")
# Bereken geschatte kosten (indicatief) - nu met correcte total_detailed
print(f"\nGeschatte kosten (€0.30/kWh): €{total_detailed * 0.30:.2f}")
print(f"Geschatte kosten (€0.10/kWh): €{total_detailed * 0.10:.2f}")
# Vind duurste en goedkoopste uur
hours_with_costs = []
for hour in hourly_data:
if hour['consumption'] > 0.01:
hour_dt = datetime.strptime(hour['hour'], '%Y-%m-%d %H:00')
price = self.get_price(hour_dt, provider, price_db)
if price is not None:
hours_with_costs.append((hour_dt, price, hour['consumption']))
if hours_with_costs:
most_expensive = max(hours_with_costs, key=lambda x: x[1])
cheapest = min(hours_with_costs, key=lambda x: x[1])
print(f"Duurste uur: {most_expensive[0].strftime('%d-%m %H:00')} "
f"(€{most_expensive[1]:.5f}/kWh)")
print(f"Goedkoopste uur: {cheapest[0].strftime('%d-%m %H:00')} "
f"(€{cheapest[1]:.5f}/kWh)")
# Totale kosten
print(f"\n{'TOTALE KOSTEN:':<30} {cost_total_str}")
if hours_without_price > 0:
print(f"* Let op: Voor {hours_without_price} uur ontbreken prijsgegevens")
# Gemiddelde prijs
if hours_with_price > 0:
avg_price = total_cost / total_detailed if total_detailed > 0 else 0
print(f"{'Gemiddelde prijs:':<30}{avg_price:.5f}/kWh")
print("=" * 80)
@@ -297,17 +407,21 @@ Voorbeelden:
# Toon lijst van laatste 10 transacties
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim' --list
# Toon gedetailleerd rapport van transactie 1
# Toon gedetailleerd rapport van transactie 1 met NextEnergy prijzen
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim' --transaction 1
# Gebruik aparte credentials voor prijzen database
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim' \
--price-host 192.168.178.201 --price-port 3307 --price-user prijzen --price-password 'geheim2' --transaction 1
# Toon rapport met andere provider (bijv. 'AA' voor AllAbout)
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim' --transaction 1 --provider AA
# Toon laatste 20 transacties in lijst
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim' --list --limit 20
# Toon alle transacties gedetailleerd (laatste 10)
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim'
# Toon laatste 5 transacties gedetailleerd
python3 steve_transaction_report.py --host 192.168.178.201 --port 3307 --password 'geheim' --limit 5
"""
)
@@ -324,6 +438,14 @@ Voorbeelden:
parser.add_argument('--limit', type=int, default=10, help='Aantal transacties (default: 10)')
parser.add_argument('--simple', action='store_true', help='Eenvoudig rapport zonder uurdetails')
# Prijzen opties
parser.add_argument('--provider', default='NE', help='Energie provider code (default: NE voor NextEnergy)')
parser.add_argument('--price-db', default='alfen', help='Database naam voor prijzen (default: alfen)')
parser.add_argument('--price-host', default=None, help='Database host voor prijzen (default: zelfde als --host)')
parser.add_argument('--price-port', type=int, default=None, help='Database poort voor prijzen (default: zelfde als --port)')
parser.add_argument('--price-user', default=None, help='Database gebruiker voor prijzen (default: zelfde als --user)')
parser.add_argument('--price-password', default=None, help='Database wachtwoord voor prijzen (default: zelfde als --password)')
args = parser.parse_args()
# Maak reporter object
@@ -332,7 +454,11 @@ Voorbeelden:
database=args.database,
user=args.user,
password=args.password,
port=args.port
port=args.port,
price_host=args.price_host,
price_port=args.price_port,
price_user=args.price_user,
price_password=args.price_password
)
try:
@@ -342,7 +468,8 @@ Voorbeelden:
# Toon specifieke transactie
transactions = reporter.get_transactions(transaction_id=args.transaction)
if transactions:
reporter.print_transaction_report(transactions[0], detailed=not args.simple)
reporter.print_transaction_report(transactions[0], detailed=not args.simple,
provider=args.provider, price_db=args.price_db)
else:
print(f"✗ Transactie {args.transaction} niet gevonden")
sys.exit(1)
@@ -361,7 +488,8 @@ Voorbeelden:
for i, trans in enumerate(transactions):
if i > 0:
print("\n\n")
reporter.print_transaction_report(trans, detailed=not args.simple)
reporter.print_transaction_report(trans, detailed=not args.simple,
provider=args.provider, price_db=args.price_db)
except KeyboardInterrupt:
print("\n\nAfgebroken door gebruiker")