import paramiko import base64 def run(): client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect('192.168.192.96', username='jetson', password='jetson', timeout=10) # 1. Backup DB first backup_cmd = "cp /opt/jetson-counter/jetson_counter.db /opt/jetson-counter/jetson_counter.db.bak_$(date +%Y%m%d_%H%M%S)" stdin, stdout, stderr = client.exec_command(backup_cmd) print("Backup output:", stdout.read().decode(), stderr.read().decode()) # 2. Python migration script on Jetson code = """ import sqlite3 import shutil from datetime import datetime db_path = '/opt/jetson-counter/jetson_counter.db' conn = sqlite3.connect(db_path) conn.row_factory = sqlite3.Row cur = conn.cursor() def process_date_2026_08_21(): print("=== Processing 2026-08-21 ===") # Fetch all batches rows = cur.execute("SELECT * FROM batches WHERE counting_date = '2026-08-21' ORDER BY batch_number ASC").fetchall() batches = [dict(r) for r in rows] print(f"Initial batches count: {len(batches)}") # Rules: # 1. Batch 15 & 16 merge -> start_time = batch 15 start_time, end_time = batch 16 end_time, count = count15 + count16 # 2. Batch 20 hapus new_batches = [] i = 0 while i < len(batches): b = batches[i] b_num = b['batch_number'] if b_num == 15: # Look for batch 16 b_next = batches[i+1] if i+1 < len(batches) and batches[i+1]['batch_number'] == 16 else None if b_next: merged = { 'camera_name': b['camera_name'], 'object_label': b['object_label'], 'count': b['count'] + b_next['count'], 'start_time': b['start_time'], 'end_time': b_next['end_time'] } new_batches.append(merged) i += 2 continue else: new_batches.append(b) i += 1 continue elif b_num == 20: # Delete / skip print(f"Deleting batch 20 (count: {b['count']})") i += 1 continue else: new_batches.append({ 'camera_name': b['camera_name'], 'object_label': b['object_label'], 'count': b['count'], 'start_time': b['start_time'], 'end_time': b['end_time'] }) i += 1 # Delete existing batches for 2026-08-21 cur.execute("DELETE FROM batches WHERE counting_date = '2026-08-21'") # Re-insert with renumbered batch_number (1 to N) total_count = 0 for idx, b in enumerate(new_batches, start=1): total_count += b['count'] cur.execute(\"\"\" INSERT INTO batches (counting_date, batch_number, camera_name, object_label, count, start_time, end_time) VALUES ('2026-08-21', ?, ?, ?, ?, ?, ?) \"\"\", (idx, b['camera_name'], b['object_label'], b['count'], b['start_time'], b['end_time'])) total_batches = len(new_batches) print(f"New total batches for 2026-08-21: {total_batches}, total count: {total_count}") # Update daily_summaries cur.execute(\"\"\" INSERT INTO daily_summaries (counting_date, camera_name, object_label, total_count, total_batches, updated_at) VALUES ('2026-08-21', 'CC1', 'karung-pakan', ?, ?, CURRENT_TIMESTAMP) ON CONFLICT(counting_date, camera_name, object_label) DO UPDATE SET total_count = excluded.total_count, total_batches = excluded.total_batches, updated_at = CURRENT_TIMESTAMP \"\"\", (total_count, total_batches)) def process_date_2026_08_22(): print("=== Processing 2026-08-22 ===") # Fetch all batches rows = cur.execute("SELECT * FROM batches WHERE counting_date = '2026-08-22' ORDER BY batch_number ASC").fetchall() batches = [dict(r) for r in rows] print(f"Initial batches count: {len(batches)}") # Rules: # 1. Batch 5 & batch 6 gabungkan # 2. Batch 27 hapus # 3. Batch 28 & batch 29 gabungkan new_batches = [] i = 0 while i < len(batches): b = batches[i] b_num = b['batch_number'] if b_num == 5: # merge with 6 b_next = batches[i+1] if i+1 < len(batches) and batches[i+1]['batch_number'] == 6 else None if b_next: merged = { 'camera_name': b['camera_name'], 'object_label': b['object_label'], 'count': b['count'] + b_next['count'], 'start_time': b['start_time'], 'end_time': b_next['end_time'] } new_batches.append(merged) i += 2 continue else: new_batches.append(b) i += 1 continue elif b_num == 27: # Delete / skip print(f"Deleting batch 27 (count: {b['count']})") i += 1 continue elif b_num == 28: # merge with 29 b_next = batches[i+1] if i+1 < len(batches) and batches[i+1]['batch_number'] == 29 else None if b_next: merged = { 'camera_name': b['camera_name'], 'object_label': b['object_label'], 'count': b['count'] + b_next['count'], 'start_time': b['start_time'], 'end_time': b_next['end_time'] } new_batches.append(merged) i += 2 continue else: new_batches.append(b) i += 1 continue else: new_batches.append({ 'camera_name': b['camera_name'], 'object_label': b['object_label'], 'count': b['count'], 'start_time': b['start_time'], 'end_time': b['end_time'] }) i += 1 # Delete existing batches for 2026-08-22 cur.execute("DELETE FROM batches WHERE counting_date = '2026-08-22'") # Re-insert with renumbered batch_number (1 to N) total_count = 0 for idx, b in enumerate(new_batches, start=1): total_count += b['count'] cur.execute(\"\"\" INSERT INTO batches (counting_date, batch_number, camera_name, object_label, count, start_time, end_time) VALUES ('2026-08-22', ?, ?, ?, ?, ?, ?) \"\"\", (idx, b['camera_name'], b['object_label'], b['count'], b['start_time'], b['end_time'])) total_batches = len(new_batches) print(f"New total batches for 2026-08-22: {total_batches}, total count: {total_count}") # Update daily_summaries cur.execute(\"\"\" INSERT INTO daily_summaries (counting_date, camera_name, object_label, total_count, total_batches, updated_at) VALUES ('2026-08-22', 'CC1', 'karung-pakan', ?, ?, CURRENT_TIMESTAMP) ON CONFLICT(counting_date, camera_name, object_label) DO UPDATE SET total_count = excluded.total_count, total_batches = excluded.total_batches, updated_at = CURRENT_TIMESTAMP \"\"\", (total_count, total_batches)) process_date_2026_08_21() process_date_2026_08_22() conn.commit() conn.close() print("Migration completed successfully!") """ b64 = base64.b64encode(code.encode()).decode() stdin, stdout, stderr = client.exec_command(f"python3 -c \"import base64; exec(base64.b64decode('{b64}'))\"") print("Migration stdout:\n", stdout.read().decode()) print("Migration stderr:\n", stderr.read().decode()) client.close() if __name__ == '__main__': run()