259 lines
9.1 KiB
Python
259 lines
9.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Import charging station transaction data from CSV to existing MySQL database
|
|
Aangepast voor bestaande 'transactions' tabel structuur
|
|
"""
|
|
|
|
import re
|
|
import mysql.connector
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
import sys
|
|
|
|
# Database configuration
|
|
DB_CONFIG = {
|
|
'host': '192.168.178.201',
|
|
'port': 3307,
|
|
'user': 'alfen_user',
|
|
'password': '5uVgr%f%s2P5GR@3q!',
|
|
'database': 'alfen', # Jouw database naam
|
|
'charset': 'utf8mb4'
|
|
}
|
|
|
|
class ChargingDataImporter:
|
|
def __init__(self, config):
|
|
self.config = config
|
|
self.conn = None
|
|
self.cursor = None
|
|
self.pending_transactions = {} # Track transactions waiting for stop
|
|
|
|
def connect(self):
|
|
"""Connect to MySQL database"""
|
|
try:
|
|
self.conn = mysql.connector.connect(**self.config)
|
|
self.cursor = self.conn.cursor()
|
|
print("✓ Database verbinding succesvol")
|
|
except mysql.connector.Error as err:
|
|
print(f"✗ Fout bij verbinden met database: {err}")
|
|
sys.exit(1)
|
|
|
|
def close(self):
|
|
"""Close database connection"""
|
|
if self.cursor:
|
|
self.cursor.close()
|
|
if self.conn:
|
|
self.conn.close()
|
|
|
|
def parse_txstart(self, line):
|
|
"""Parse transaction start line and store temporarily"""
|
|
# txstart2: id 0x0000000000000001, socket 1, 2025-10-28 18:27:42 5518.267kWh 04BB29EAFD0F94 3 2 Y
|
|
pattern = r'txstart2: id (0x[0-9a-fA-F]+), socket (\d+), ([\d-]+ [\d:]+) ([\d.]+)kWh (\w+)'
|
|
match = re.match(pattern, line)
|
|
|
|
if match:
|
|
tx_id = match.group(1) # Keep as hex string
|
|
socket_num = int(match.group(2))
|
|
timestamp = datetime.strptime(match.group(3), '%Y-%m-%d %H:%M:%S')
|
|
kwh = Decimal(match.group(4))
|
|
card = match.group(5)
|
|
|
|
# Store temporarily until we get the stop
|
|
self.pending_transactions[tx_id] = {
|
|
'transaction_id': tx_id,
|
|
'socket': socket_num,
|
|
'start_timestamp': timestamp,
|
|
'start_kWh': kwh,
|
|
'card': card
|
|
}
|
|
|
|
print(f" → Transactie {tx_id} gestart (wacht op stop...)")
|
|
return True
|
|
return False
|
|
|
|
def parse_txstop(self, line):
|
|
"""Parse transaction stop line and insert complete transaction"""
|
|
# txstop2: id 0x0000000000000001, socket 1, 2025-10-31 15:59:29 5540.316kWh 04BB29EAFD0F94 6 5 Y
|
|
pattern = r'txstop2: id (0x[0-9a-fA-F]+), socket (\d+), ([\d-]+ [\d:]+) ([\d.]+)kWh'
|
|
match = re.match(pattern, line)
|
|
|
|
if match:
|
|
tx_id = match.group(1)
|
|
socket_num = int(match.group(2))
|
|
timestamp = datetime.strptime(match.group(3), '%Y-%m-%d %H:%M:%S')
|
|
kwh = Decimal(match.group(4))
|
|
|
|
# Check if we have the start for this transaction
|
|
if tx_id not in self.pending_transactions:
|
|
print(f" ⚠ Stop gevonden voor {tx_id} maar geen start - overgeslagen")
|
|
return False
|
|
|
|
tx_data = self.pending_transactions[tx_id]
|
|
|
|
# Calculate total consumption
|
|
total_kwh = kwh - tx_data['start_kWh']
|
|
|
|
try:
|
|
# Check if transaction already exists
|
|
self.cursor.execute(
|
|
"SELECT id FROM transactions WHERE transaction_id = %s",
|
|
(tx_id,)
|
|
)
|
|
existing = self.cursor.fetchone()
|
|
|
|
if existing:
|
|
print(f" ⚠ Transactie {tx_id} bestaat al - overgeslagen")
|
|
del self.pending_transactions[tx_id]
|
|
return False
|
|
|
|
# Insert complete transaction
|
|
self.cursor.execute("""
|
|
INSERT INTO transactions
|
|
(transaction_id, socket, start_timestamp, start_kWh,
|
|
stop_timestamp, stop_kWh, total_kWh, card)
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
|
""", (
|
|
tx_id,
|
|
tx_data['socket'],
|
|
tx_data['start_timestamp'],
|
|
tx_data['start_kWh'],
|
|
timestamp,
|
|
kwh,
|
|
total_kwh,
|
|
tx_data['card']
|
|
))
|
|
|
|
self.conn.commit()
|
|
|
|
# Remove from pending
|
|
del self.pending_transactions[tx_id]
|
|
|
|
print(f" ✓ Transactie {tx_id} opgeslagen ({total_kwh:.3f} kWh)")
|
|
return True
|
|
|
|
except mysql.connector.Error as err:
|
|
print(f" ✗ Fout bij opslaan transactie {tx_id}: {err}")
|
|
return False
|
|
|
|
return False
|
|
|
|
def import_file(self, filepath):
|
|
"""Import CSV file into database"""
|
|
print(f"\n=== Import gestart: {filepath} ===\n")
|
|
|
|
line_count = 0
|
|
tx_start_count = 0
|
|
tx_stop_count = 0
|
|
tx_saved_count = 0
|
|
|
|
try:
|
|
with open(filepath, 'r') as file:
|
|
for line_num, line in enumerate(file, 1):
|
|
line = line.strip()
|
|
|
|
# Skip empty lines and comments
|
|
if not line or line.startswith('# Generated'):
|
|
continue
|
|
|
|
line_count += 1
|
|
|
|
# Parse transaction start
|
|
if line.startswith('txstart2:'):
|
|
if self.parse_txstart(line):
|
|
tx_start_count += 1
|
|
|
|
# Parse transaction stop
|
|
elif line.startswith('txstop2:'):
|
|
if self.parse_txstop(line):
|
|
tx_stop_count += 1
|
|
tx_saved_count += 1
|
|
|
|
# Skip meter values (mv:) - niet opgeslagen in deze tabel
|
|
elif line.startswith('mv:'):
|
|
continue
|
|
|
|
print(f"\n=== Import voltooid ===")
|
|
print(f"✓ Totaal regels verwerkt: {line_count}")
|
|
print(f"✓ Transacties gestart: {tx_start_count}")
|
|
print(f"✓ Transacties gestopt: {tx_stop_count}")
|
|
print(f"✓ Transacties opgeslagen: {tx_saved_count}")
|
|
|
|
# Check for incomplete transactions
|
|
if self.pending_transactions:
|
|
print(f"\n⚠ Let op: {len(self.pending_transactions)} transactie(s) nog actief (geen stop gevonden):")
|
|
for tx_id in self.pending_transactions:
|
|
print(f" - {tx_id}")
|
|
|
|
# Show summary statistics
|
|
self.show_statistics()
|
|
|
|
except FileNotFoundError:
|
|
print(f"✗ Bestand niet gevonden: {filepath}")
|
|
sys.exit(1)
|
|
except Exception as err:
|
|
print(f"✗ Onverwachte fout: {err}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
self.conn.rollback()
|
|
sys.exit(1)
|
|
|
|
def show_statistics(self):
|
|
"""Show database statistics after import"""
|
|
print("\n=== Database Statistieken ===")
|
|
|
|
# Total transactions
|
|
self.cursor.execute("SELECT COUNT(*) FROM transactions")
|
|
total_tx = self.cursor.fetchone()[0]
|
|
print(f"Totaal transacties in database: {total_tx}")
|
|
|
|
# Total consumption
|
|
self.cursor.execute("SELECT SUM(total_kWh) FROM transactions")
|
|
result = self.cursor.fetchone()
|
|
total_consumption = result[0] if result[0] else 0
|
|
print(f"Totaal verbruik: {total_consumption:.3f} kWh")
|
|
|
|
# Latest transaction
|
|
self.cursor.execute("""
|
|
SELECT transaction_id, start_timestamp, stop_timestamp, total_kWh
|
|
FROM transactions
|
|
ORDER BY stop_timestamp DESC
|
|
LIMIT 1
|
|
""")
|
|
latest = self.cursor.fetchone()
|
|
if latest:
|
|
print(f"\nLaatste transactie:")
|
|
print(f" ID: {latest[0]}")
|
|
print(f" Periode: {latest[1]} - {latest[2]}")
|
|
print(f" Verbruik: {latest[3]:.3f} kWh")
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Gebruik: python3 import_to_existing_db.py <csv_bestand>")
|
|
print("\nVoorbeeld: python3 import_to_existing_db.py VAN_01971_Transactions.csv")
|
|
sys.exit(1)
|
|
|
|
csv_file = sys.argv[1]
|
|
|
|
print("=" * 60)
|
|
print("Charging Station Data Importer")
|
|
print("Import naar bestaande 'transactions' tabel")
|
|
print("=" * 60)
|
|
|
|
# Create importer instance
|
|
importer = ChargingDataImporter(DB_CONFIG)
|
|
|
|
try:
|
|
# Connect to database
|
|
importer.connect()
|
|
|
|
# Import the file
|
|
importer.import_file(csv_file)
|
|
|
|
finally:
|
|
# Close connection
|
|
importer.close()
|
|
print("\n✓ Database verbinding gesloten")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |