update
This commit is contained in:
@@ -840,7 +840,7 @@ class AstmMessageService
|
||||
try {
|
||||
// Ambil pesan ASTM dari kolom 'message' atau yang relevan
|
||||
$response = $data->rawdt;
|
||||
if ($data->no_id != ''){
|
||||
if ($data->alat == 'MGIT' OR $data->alat == 'COM5' OR $data->alat == 'BACTEC'){
|
||||
$assembled = $this->reassembleAstmFrames($data->rawdt);
|
||||
$messages = $this->splitBDAstmMessages($assembled);
|
||||
foreach ($messages as $msg) {
|
||||
@@ -864,9 +864,14 @@ class AstmMessageService
|
||||
]
|
||||
);
|
||||
} else {
|
||||
DB::table('lis_phoenix')->where('id', $data->id)->update([
|
||||
'processed' => 9
|
||||
]);
|
||||
$result = $this->processAstmResponse($data->rawdt, $data->alat);
|
||||
if ($result) {
|
||||
DataListiner::where('urut', $data->urut)->update([
|
||||
'processed' => 1
|
||||
]);
|
||||
} else {
|
||||
Log::debug($result);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::critical($e->getMessage());
|
||||
|
||||
+88
-31
@@ -48,7 +48,9 @@ GENEXPERT_TEST_MAPPING = {
|
||||
"HCV VL": "HCV", # Xpert HCV Viral Load Version 1
|
||||
|
||||
# Mapping untuk IP 10.10.120.74 (Khusus)
|
||||
"HBV VL": "HBV", # Xpert HBV Viral Load Version 1
|
||||
# Catatan: Di dokumen Anda tertulis Assay 'HBV' tapi kodenya 'HCV'.
|
||||
# Pastikan ini benar, atau sesuaikan jika itu typo di dokumen.
|
||||
"HBV VL": "HCV",
|
||||
}
|
||||
|
||||
# Default code jika nama tes di database tidak dikenali
|
||||
@@ -72,16 +74,16 @@ app = Flask(__name__)
|
||||
active_genexpert_connections = {}
|
||||
connection_lock = threading.Lock()
|
||||
DEVICE_CONFIGS = [
|
||||
#{
|
||||
# 'port': 'COM6', 'baud_rate': 19200, 'device_type': 'vitek', 'alat_name': 'Vitek 1',
|
||||
# 'protocol': 'serial', 'flag_column': 'flg_vitek1'
|
||||
#},
|
||||
{
|
||||
'port': 'COM6', 'baud_rate': 19200, 'device_type': 'vitek', 'alat_name': 'Vitek 1',
|
||||
'protocol': 'serial', 'flag_column': 'flg_vitek1'
|
||||
},
|
||||
{
|
||||
'port': 'COM4', 'baud_rate': 9600, 'device_type': 'vitek', 'alat_name': 'Vitek 2',
|
||||
'protocol': 'serial', 'flag_column': 'flg_vitek2'
|
||||
},
|
||||
{
|
||||
'port': 'COM3', 'baud_rate': 19200, 'device_type': 'bd', 'alat_name': 'BACTEC',
|
||||
'port': 'COM5', 'baud_rate': 19200, 'device_type': 'bd', 'alat_name': 'BACTEC',
|
||||
'protocol': 'serial', 'flag_column': 'flg_bd1'
|
||||
},
|
||||
#BD_MGIT yang di dalam ruangan isolasi
|
||||
@@ -292,11 +294,12 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
||||
|
||||
# 4. Validasi Data Penting
|
||||
if not sample_id:
|
||||
logging.warning("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.")
|
||||
print("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.")
|
||||
return
|
||||
|
||||
logging.info(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}")
|
||||
print(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}")
|
||||
|
||||
# 5. Simpan ke Database (Tabel LisPhoenix)
|
||||
new_data = LisPhoenix(
|
||||
no_id=sample_id, # OBR-3
|
||||
@@ -310,9 +313,11 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
||||
|
||||
session.add(new_data)
|
||||
session.commit()
|
||||
logging.info(f"[DB] Berhasil simpan ke LisPhoenix: {sample_id}")
|
||||
print(f"[DB] Berhasil simpan ke LisPhoenix: {sample_id}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[HL7 Parser] Error menyimpan data: {e}")
|
||||
print(f"[HL7 Parser] Error menyimpan data: {e}")
|
||||
session.rollback()
|
||||
finally:
|
||||
@@ -329,6 +334,7 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"):
|
||||
# ==========================================
|
||||
def handle_tcp_client(client_socket, addr):
|
||||
"""Menangani satu koneksi client GeneXpert"""
|
||||
logging.info(f"[TCP] Koneksi diterima dari {addr}")
|
||||
print(f"[TCP] Koneksi diterima dari {addr}")
|
||||
try:
|
||||
# Loop baca data dari client ini
|
||||
@@ -341,19 +347,22 @@ def handle_tcp_client(client_socket, addr):
|
||||
# decode, parsing ASTM, save to DB
|
||||
try:
|
||||
msg = data.decode('latin-1', errors='ignore')
|
||||
print(f"[TCP] Data dari {addr}: {msg[:50]}...")
|
||||
logging.info(f"[TCP] Data dari {addr}: {msg[:50]}...")
|
||||
print(f"[TCP] Data dari {addr}: {msg[:50]}...")
|
||||
# Panggil fungsi parser GeneXpert Anda disini
|
||||
# parse_and_save_genexpert(msg)
|
||||
parse_hl7_result(msg, device_name=addr[0] if addr else "Unknown")
|
||||
|
||||
# Kirim ACK ASTM jika perlu (\x06)
|
||||
client_socket.send(b'\x06')
|
||||
except Exception as e:
|
||||
logging.error(f"[TCP] Error processing data: {e}")
|
||||
print(f"[TCP] Error processing data: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[TCP] Koneksi Error {addr}: {e}")
|
||||
print(f"[TCP] Koneksi Error {addr}: {e}")
|
||||
finally:
|
||||
client_socket.close()
|
||||
logging.info(f"[TCP] Koneksi ditutup {addr}")
|
||||
print(f"[TCP] Koneksi ditutup {addr}")
|
||||
|
||||
def manage_tcp_server():
|
||||
@@ -365,8 +374,8 @@ def manage_tcp_server():
|
||||
try:
|
||||
server.bind((SERVER_HOST, TCP_LISTENER_PORT))
|
||||
server.listen(5) # Bisa antri 5 koneksi
|
||||
logging.info(f"[TCP-SERVER] Listening GeneXpert di port {TCP_LISTENER_PORT}...")
|
||||
print(f"[TCP-SERVER] Listening GeneXpert di port {TCP_LISTENER_PORT}...")
|
||||
|
||||
while True:
|
||||
# Accept koneksi baru (Blocking, tapi aman karena di thread sendiri)
|
||||
client_sock, addr = server.accept()
|
||||
@@ -380,6 +389,7 @@ def manage_tcp_server():
|
||||
client_thread.start()
|
||||
|
||||
except Exception as e:
|
||||
logging.critical(f"[TCP-SERVER] Gagal Start: {e}")
|
||||
print(f"[TCP-SERVER] Gagal Start: {e}")
|
||||
|
||||
def run_flask():
|
||||
@@ -397,7 +407,7 @@ def send_mllp_message(sock, hl7_msg):
|
||||
def handle_genexpert_client(conn, addr):
|
||||
ip_sender = addr[0]
|
||||
logging.info(f"[CONNECT] GeneXpert terkoneksi dari IP: {ip_sender}")
|
||||
|
||||
print(f"[CONNECT] GeneXpert terkoneksi dari IP: {ip_sender}")
|
||||
with connection_lock:
|
||||
active_genexpert_connections[ip_sender] = conn
|
||||
|
||||
@@ -422,12 +432,13 @@ def handle_genexpert_client(conn, addr):
|
||||
hl7_str = raw_msg.decode('utf-8')
|
||||
|
||||
logging.info(f"[RECV] Dari {ip_sender}: {hl7_str[:50]}...") # Log 50 karakter awal
|
||||
|
||||
print(f"[RECV] Dari {ip_sender}: {hl7_str[:50]}...") # Print 50 karakter awal
|
||||
# Cek Tipe Pesan (MSH field 9)
|
||||
if "ORU^R01" in hl7_str:
|
||||
# Ini adalah Hasil
|
||||
hasil = parse_hl7_result(hl7_str)
|
||||
hasil = parse_hl7_result(hl7_str, device_name=addr[0] if addr else "GeneXpert")
|
||||
logging.info(f"[RESULT] {hasil}")
|
||||
print(f"[RESULT] {hasil}")
|
||||
# TODO: Simpan 'hasil' ke database berdasarkan Sample ID di HL7
|
||||
|
||||
# Kirim ACK (Terima Kasih) ke Alat
|
||||
@@ -459,7 +470,7 @@ def run_tcp_server():
|
||||
server.bind((SERVER_HOST, TCP_LISTENER_PORT))
|
||||
server.listen(5) # Backlog 5 koneksi
|
||||
logging.info(f"TCP Listener AKTIF di port {TCP_LISTENER_PORT}. Menunggu koneksi GeneXpert...")
|
||||
|
||||
print(f"TCP Listener AKTIF di port {TCP_LISTENER_PORT}. Menunggu koneksi GeneXpert...")
|
||||
while True:
|
||||
conn, addr = server.accept()
|
||||
# Buat thread baru untuk setiap alat yg konek
|
||||
@@ -468,6 +479,7 @@ def run_tcp_server():
|
||||
|
||||
except Exception as e:
|
||||
logging.critical(f"Gagal menjalankan TCP Server: {e}")
|
||||
print(f"Gagal menjalankan TCP Server: {e}")
|
||||
|
||||
def send_order_via_active_connection(target_ip, hl7_message):
|
||||
conn = None
|
||||
@@ -476,6 +488,7 @@ def send_order_via_active_connection(target_ip, hl7_message):
|
||||
|
||||
if not conn:
|
||||
logging.warning(f"Gagal kirim Order: GeneXpert dengan IP {target_ip} BELUM TERKONEKSI ke Python.")
|
||||
print(f"Gagal kirim Order: GeneXpert dengan IP {target_ip} BELUM TERKONEKSI ke Python.")
|
||||
return False # Indikasi gagal
|
||||
|
||||
try:
|
||||
@@ -494,6 +507,7 @@ def send_order_via_active_connection(target_ip, hl7_message):
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"Error mengirim ke {target_ip}: {e}")
|
||||
print(f"Error mengirim ke {target_ip}: {e}")
|
||||
# Jika error saat kirim, anggap koneksi rusak
|
||||
with connection_lock:
|
||||
if target_ip in active_genexpert_connections:
|
||||
@@ -507,19 +521,22 @@ def broadcast_order_to_all_machines(hl7_message, order_id):
|
||||
|
||||
if not connected_ips:
|
||||
logging.warning(f"Order {order_id} GAGAL dikirim: Tidak ada GeneXpert yang terkoneksi saat ini.")
|
||||
print(f"Order {order_id} GAGAL dikirim: Tidak ada GeneXpert yang terkoneksi saat ini.")
|
||||
return False
|
||||
|
||||
success_count = 0
|
||||
logging.info(f"Memulai broadcast Order {order_id} ke {len(connected_ips)} alat...")
|
||||
|
||||
print(f"Memulai broadcast Order {order_id} ke {len(connected_ips)} alat...")
|
||||
for target_ip in connected_ips:
|
||||
# Panggil fungsi kirim tunggal yang sudah kita buat sebelumnya
|
||||
# Note: Fungsi send_order_via_active_connection ada di kode sebelumnya
|
||||
if send_order_via_active_connection(target_ip, hl7_message):
|
||||
logging.info(f" -> Sukses kirim ke {target_ip}")
|
||||
print(f" -> Sukses kirim ke {target_ip}")
|
||||
success_count += 1
|
||||
else:
|
||||
logging.error(f" -> Gagal kirim ke {target_ip}")
|
||||
print(f" -> Gagal kirim ke {target_ip}")
|
||||
|
||||
# Logika bisnis: Dianggap sukses jika minimal terkirim ke SATU alat
|
||||
if success_count > 0:
|
||||
@@ -626,7 +643,7 @@ def parse_and_save_vitek_result(raw_data, port_name="VITEK"):
|
||||
final_res_string = "NEGATIVE / NO GROWTH"
|
||||
|
||||
logging.info(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Bakteri: {organism_name}")
|
||||
|
||||
print(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Bakteri: {organism_name}")
|
||||
new_entry = LisPhoenix(
|
||||
no_id=sample_id, # Menggunakan tag 'ci'
|
||||
seq_no=patient_id, # Menggunakan tag 'pi'
|
||||
@@ -641,11 +658,14 @@ def parse_and_save_vitek_result(raw_data, port_name="VITEK"):
|
||||
else:
|
||||
if msg_type != 'mtrsl':
|
||||
logging.info(f"[{port_name}] Mengabaikan pesan tipe {msg_type}")
|
||||
print(f"[{port_name}] Mengabaikan pesan tipe {msg_type}")
|
||||
else:
|
||||
logging.warning(f"[{port_name}] Data tidak lengkap (No Sample ID). Raw: {raw_data[:50]}...")
|
||||
print(f"[{port_name}] Data tidak lengkap (No Sample ID). Raw: {raw_data[:50]}...")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error Parsing Vitek: {e}")
|
||||
print(f"Error Parsing Vitek: {e}")
|
||||
session.rollback()
|
||||
finally:
|
||||
session.close()
|
||||
@@ -704,7 +724,7 @@ def manage_vitek_port(config):
|
||||
flag_col = config.get('flag_column')
|
||||
alat_name = config.get('alat_name', 'VITEK')
|
||||
logging.info(f"[{port_name}] Membuka port untuk alat {alat_name}...")
|
||||
|
||||
print(f"[{port_name}] Membuka port untuk alat {alat_name}...")
|
||||
# Buffer untuk menampung pecahan data
|
||||
rx_buffer = b""
|
||||
|
||||
@@ -730,6 +750,7 @@ def manage_vitek_port(config):
|
||||
# 1. Handle Handshake Awal (ENQ) - Alat minta izin kirim
|
||||
if b'\x05' in data_chunk:
|
||||
logging.info(f"[{port_name}] Terima ENQ. Kirim ACK.")
|
||||
print(f"[{port_name}] Terima ENQ. Kirim ACK.")
|
||||
ser.write(b'\x06') # ACK
|
||||
rx_buffer = b"" # Reset buffer bytes
|
||||
continue
|
||||
@@ -754,12 +775,13 @@ def manage_vitek_port(config):
|
||||
parse_and_save_vitek_result(full_str, alat_name)
|
||||
except Exception as e:
|
||||
logging.error(f"[{port_name}] Error Decoding/Parsing: {e}")
|
||||
|
||||
print(f"[{port_name}] Error Decoding/Parsing: {e}")
|
||||
rx_buffer = b"" # Bersihkan buffer
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{port_name}] Error Reading: {e}")
|
||||
print(f"[{port_name}] Error Reading: {e}")
|
||||
rx_buffer = b"" # Reset jika error parah
|
||||
|
||||
|
||||
@@ -778,7 +800,7 @@ def manage_vitek_port(config):
|
||||
if pending_order:
|
||||
has_activity = True # Jangan sleep lama-lama
|
||||
logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
||||
|
||||
print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
||||
# --- STEP 1: HANDSHAKE (ENQ) ---
|
||||
ser.reset_input_buffer()
|
||||
ser.write(b'\x05')
|
||||
@@ -789,6 +811,7 @@ def manage_vitek_port(config):
|
||||
|
||||
if ack_response == b'\x06':
|
||||
logging.info(f"[{port_name}] Handshake dengan {alat_name}Sukses. Kirim Data...")
|
||||
print(f"[{port_name}] Handshake dengan {alat_name} Sukses. Kirim Data...")
|
||||
time.sleep(1.0) # Jeda aman
|
||||
|
||||
frames = create_vitek_order_message(pending_order)
|
||||
@@ -799,7 +822,8 @@ def manage_vitek_port(config):
|
||||
retry = 0
|
||||
frame_sent = False
|
||||
while retry < 3:
|
||||
logging.info(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}") # Log apa yang dikirim
|
||||
logging.info(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}")
|
||||
print(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}")
|
||||
ser.write(frame)
|
||||
|
||||
# Tunggu ACK
|
||||
@@ -813,17 +837,21 @@ def manage_vitek_port(config):
|
||||
|
||||
if response == b'\x06': # ACK
|
||||
logging.info(f"[{port_name}] Frame ACK (OK).")
|
||||
print(f"[{port_name}] Frame ACK (OK).")
|
||||
frame_sent = True
|
||||
break
|
||||
elif response == b'\x15': # NAK
|
||||
logging.warning(f"[{port_name}] Dibalas NAK (Checksum/Format Salah).")
|
||||
print(f"[{port_name}] Dibalas NAK (Checksum/Format Salah).")
|
||||
time.sleep(1)
|
||||
retry += 1
|
||||
elif response is None: # TIMEOUT
|
||||
logging.warning(f"[{port_name}] Timeout (Alat tidak membalas). Cek Framing/Kabel.")
|
||||
print(f"[{port_name}] Timeout (Alat tidak membalas). Cek Framing/Kabel.")
|
||||
retry += 1
|
||||
else: # Respon Aneh
|
||||
logging.warning(f"[{port_name}] Respon aneh: {response}")
|
||||
print(f"[{port_name}] Respon aneh: {response}")
|
||||
retry += 1
|
||||
|
||||
if not frame_sent:
|
||||
@@ -835,20 +863,23 @@ def manage_vitek_port(config):
|
||||
|
||||
if all_success:
|
||||
logging.info(f"[{port_name}] Order {pending_order.rnoreg} SELESAI.")
|
||||
print(f"[{port_name}] Order {pending_order.rnoreg} SELESAI.")
|
||||
setattr(pending_order, flag_col, True)
|
||||
session.commit()
|
||||
else:
|
||||
logging.error(f"[{port_name}] Gagal kirim order {pending_order.rnoreg}.")
|
||||
|
||||
print(f"[{port_name}] Gagal kirim order {pending_order.rnoreg}.")
|
||||
else:
|
||||
# Handshake gagal (Alat sibuk/Mati)
|
||||
# logging.debug(f"[{port_name}] Alat sibuk/tidak balas ENQ.")
|
||||
print(f"[{port_name}] Alat sibuk/tidak balas ENQ.")
|
||||
pass
|
||||
|
||||
session.close()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{port_name}] Error Sending Logic: {e}")
|
||||
print(f"[{port_name}] Error Sending Logic: {e}")
|
||||
if 'session' in locals(): session.close()
|
||||
|
||||
# ==========================================
|
||||
@@ -861,6 +892,7 @@ def manage_vitek_port(config):
|
||||
|
||||
except Exception as e:
|
||||
logging.critical(f"[{port_name}] Gagal connect Serial: {e}")
|
||||
print(f"[{port_name}] Gagal connect Serial: {e}")
|
||||
time.sleep(5)
|
||||
|
||||
# ==========================================
|
||||
@@ -946,7 +978,7 @@ def parse_and_save_bd_result(raw_data, port_name="BD Bactec"):
|
||||
final_res_string += f" ({specimen_type})"
|
||||
|
||||
logging.info(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Hasil: {final_res_string}")
|
||||
|
||||
print(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Hasil: {final_res_string}")
|
||||
new_entry = LisPhoenix(
|
||||
no_id=sample_id,
|
||||
seq_no=patient_id,
|
||||
@@ -960,9 +992,11 @@ def parse_and_save_bd_result(raw_data, port_name="BD Bactec"):
|
||||
session.commit()
|
||||
else:
|
||||
logging.warning(f"[{port_name}] Data tidak lengkap. ID: {sample_id}, Res: {result_val}")
|
||||
print(f"[{port_name}] Data tidak lengkap. ID: {sample_id}, Res: {result_val}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error Parsing BD: {e}")
|
||||
print(f"Error Parsing BD: {e}")
|
||||
session.rollback()
|
||||
finally:
|
||||
session.close()
|
||||
@@ -1092,6 +1126,7 @@ def manage_bd_port(config):
|
||||
# 1. Handle Handshake Awal (ENQ)
|
||||
if b'\x05' in data_chunk:
|
||||
logging.info(f"[{port_name}] Terima ENQ (Alat mau kirim data). Kirim ACK.")
|
||||
print(f"[{port_name}] Terima ENQ (Alat mau kirim data). Kirim ACK.")
|
||||
ser.write(b'\x06') # ACK
|
||||
rx_buffer = "" # Reset buffer untuk data baru
|
||||
continue
|
||||
@@ -1099,6 +1134,7 @@ def manage_bd_port(config):
|
||||
# 2. Handle Akhir Transmisi (EOT)
|
||||
if b'\x04' in data_chunk:
|
||||
logging.info(f"[{port_name}] Terima EOT (Selesai). Memproses data...")
|
||||
print(f"[{port_name}] Terima EOT (Selesai). Memproses data...")
|
||||
# Proses semua data yang terkumpul di buffer
|
||||
parse_and_save_bd_result(rx_buffer, alat_name)
|
||||
rx_buffer = "" # Kosongkan buffer setelah save
|
||||
@@ -1118,11 +1154,13 @@ def manage_bd_port(config):
|
||||
# logging.debug(f"[{port_name}] Frame diterima, ACK dikirim.")
|
||||
except Exception as e:
|
||||
logging.error(f"Error decode frame: {e}")
|
||||
print(f"Error decode frame: {e}")
|
||||
|
||||
continue # Loop lagi untuk ambil sisa data
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{port_name}] Error Reading: {e}")
|
||||
print(f"[{port_name}] Error Reading: {e}")
|
||||
rx_buffer = b"" # Reset jika error parah
|
||||
|
||||
|
||||
@@ -1141,7 +1179,7 @@ def manage_bd_port(config):
|
||||
if pending_order:
|
||||
has_activity = True # Jangan sleep lama-lama
|
||||
logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
||||
|
||||
print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...")
|
||||
# --- STEP 1: HANDSHAKE (ENQ) ---
|
||||
ser.reset_input_buffer()
|
||||
ser.write(b'\x05')
|
||||
@@ -1151,7 +1189,7 @@ def manage_bd_port(config):
|
||||
|
||||
if ack_response == b'\x06':
|
||||
logging.info(f"[{port_name}] Handshake Sukses (Dapat ACK). Menunggu alat siap...")
|
||||
|
||||
print(f"[{port_name}] Handshake Sukses (Dapat ACK). Menunggu alat siap...")
|
||||
# --- PERBAIKAN 1: BERI JEDA SETELAH HANDSHAKE ---
|
||||
# Mesin butuh napas sebelum terima data panjang
|
||||
time.sleep(1.5) # Jeda 1.5 detik
|
||||
@@ -1171,6 +1209,7 @@ def manage_bd_port(config):
|
||||
ser.reset_input_buffer()
|
||||
|
||||
logging.info(f"[{port_name}] Kirim Frame {i+1} (Percobaan {retry_count+1})...")
|
||||
print(f"[{port_name}] Kirim Frame {i+1} (Percobaan {retry_count+1})...")
|
||||
ser.write(frame)
|
||||
|
||||
# Tunggu ACK
|
||||
@@ -1182,28 +1221,33 @@ def manage_bd_port(config):
|
||||
if frame_ack == b'\x06': # ACK (Sukses)
|
||||
frame_success = True
|
||||
logging.info(f"[{port_name}] Frame {i+1} ACK diterima.")
|
||||
print(f"[{port_name}] Frame {i+1} ACK diterima.")
|
||||
# Beri jeda dikit sebelum kirim frame berikutnya
|
||||
time.sleep(0.2)
|
||||
break
|
||||
|
||||
elif frame_ack == b'\x15': # NAK (Ditolak - Checksum Salah)
|
||||
logging.warning(f"[{port_name}] Frame ditolak (NAK). Checksum mungkin salah.")
|
||||
print(f"[{port_name}] Frame ditolak (NAK). Checksum mungkin salah.")
|
||||
time.sleep(2) # Tunggu 2 detik
|
||||
retry_count += 1
|
||||
|
||||
elif not frame_ack: # Timeout (Sepi)
|
||||
# --- PERBAIKAN 2: BERI JEDA SAAT TIMEOUT ---
|
||||
logging.warning(f"[{port_name}] Timeout (Alat diam). Menunggu sebelum retry...")
|
||||
print(f"[{port_name}] Timeout (Alat diam). Menunggu sebelum retry...")
|
||||
time.sleep(2) # Tunggu 2 detik agar alat recover
|
||||
retry_count += 1
|
||||
|
||||
else:
|
||||
logging.warning(f"[{port_name}] Respon aneh: {frame_ack}")
|
||||
print(f"[{port_name}] Respon aneh: {frame_ack}")
|
||||
time.sleep(1)
|
||||
retry_count += 1
|
||||
|
||||
if not frame_success:
|
||||
logging.error(f"[{port_name}] Gagal kirim frame ke-{i+1}. Batal.")
|
||||
print(f"[{port_name}] Gagal kirim frame ke-{i+1}. Batal.")
|
||||
all_frames_sent = False
|
||||
break
|
||||
# ---------------------------------------------------
|
||||
@@ -1212,17 +1256,18 @@ def manage_bd_port(config):
|
||||
if all_frames_sent:
|
||||
ser.write(b'\x04') # EOT (End of Transmission)
|
||||
logging.info(f"[{port_name}] Order {pending_order.rnoreg} SUKSES Terkirim.")
|
||||
|
||||
print(f"[{port_name}] Order {pending_order.rnoreg} SUKSES Terkirim.")
|
||||
# Update Database
|
||||
setattr(pending_order, flag_col, True)
|
||||
session.commit()
|
||||
else:
|
||||
ser.write(b'\x04') # EOT (Putus paksa karena error)
|
||||
logging.error(f"[{port_name}] Pengiriman Order GAGAL.")
|
||||
|
||||
print(f"[{port_name}] Pengiriman Order GAGAL.")
|
||||
else:
|
||||
# Jika Handshake gagal (Dibalas NAK, atau Timeout)
|
||||
logging.warning(f"[{port_name}] Handshake Gagal. Respon alat: {ack_response}")
|
||||
print(f"[{port_name}] Handshake Gagal. Respon alat: {ack_response}")
|
||||
# Jangan update flag DB, biarkan coba lagi nanti
|
||||
|
||||
|
||||
@@ -1230,6 +1275,7 @@ def manage_bd_port(config):
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"[{port_name}] Error Sending Logic: {e}")
|
||||
print(f"[{port_name}] Error Sending Logic: {e}")
|
||||
if 'session' in locals(): session.close()
|
||||
|
||||
# ==========================================
|
||||
@@ -1242,6 +1288,7 @@ def manage_bd_port(config):
|
||||
|
||||
except Exception as e:
|
||||
logging.critical(f"[{port_name}] Gagal connect Serial: {e}")
|
||||
print(f"[{port_name}] Gagal connect Serial: {e}")
|
||||
time.sleep(5)
|
||||
|
||||
# ==========================================
|
||||
@@ -1251,7 +1298,7 @@ def manage_bd_port(config):
|
||||
def order_poller(stop_event):
|
||||
"""Looping cek DB dan kirim order ke SEMUA alat"""
|
||||
logging.info("Order Poller Berjalan...")
|
||||
|
||||
print("Order Poller Berjalan...")
|
||||
while not stop_event.is_set():
|
||||
session = SessionLocal()
|
||||
try:
|
||||
@@ -1286,8 +1333,10 @@ def order_poller(stop_event):
|
||||
send_mllp_message(conn, hl7_msg)
|
||||
order.flg_gxp1 = True # Update Flag
|
||||
logging.info(f"[SENT] Order {order.rnoreg} dikirim ke GXP-1 ({target_ip})")
|
||||
print(f"[SENT] Order {order.rnoreg} dikirim ke GXP-1 ({target_ip})")
|
||||
except Exception as e:
|
||||
logging.error(f"[FAIL] Gagal kirim ke GXP-1: {e}")
|
||||
print(f"[FAIL] Gagal kirim ke GXP-1: {e}")
|
||||
else:
|
||||
# Alat 1 belum connect, biarkan False (pending)
|
||||
pass
|
||||
@@ -1301,8 +1350,10 @@ def order_poller(stop_event):
|
||||
send_mllp_message(conn, hl7_msg)
|
||||
order.flg_gxp2 = True
|
||||
logging.info(f"[SENT] Order {order.rnoreg} dikirim ke GXP-2 ({target_ip})")
|
||||
print(f"[SENT] Order {order.rnoreg} dikirim ke GXP-2 ({target_ip})")
|
||||
except Exception as e:
|
||||
logging.error(f"[FAIL] Gagal kirim ke GXP-2: {e}")
|
||||
print(f"[FAIL] Gagal kirim ke GXP-2: {e}")
|
||||
|
||||
# 3. Cek Target GXP 3
|
||||
if order.flg_gxp3 == False:
|
||||
@@ -1313,13 +1364,16 @@ def order_poller(stop_event):
|
||||
send_mllp_message(conn, hl7_msg)
|
||||
order.flg_gxp3 = True
|
||||
logging.info(f"[SENT] Order {order.rnoreg} dikirim ke GXP-3 ({target_ip})")
|
||||
print(f"[SENT] Order {order.rnoreg} dikirim ke GXP-3 ({target_ip})")
|
||||
except Exception as e:
|
||||
logging.error(f"[FAIL] Gagal kirim ke GXP-3: {e}")
|
||||
print(f"[FAIL] Gagal kirim ke GXP-3: {e}")
|
||||
|
||||
# Commit perubahan flag ke database
|
||||
session.commit()
|
||||
except Exception as e:
|
||||
logging.error(f"Error Poller: {e}")
|
||||
print(f"Error Poller: {e}")
|
||||
session.rollback()
|
||||
finally:
|
||||
session.close()
|
||||
@@ -1335,7 +1389,7 @@ def manage_serial_port(config):
|
||||
manage_bd_port(config)
|
||||
else:
|
||||
logging.error(f"Tipe alat tidak diketahui: '{device_type}' untuk port {config.get('port')}. Thread dihentikan.")
|
||||
|
||||
print(f"Tipe alat tidak diketahui: '{device_type}' untuk port {config.get('port')}. Thread dihentikan.")
|
||||
# ==========================================
|
||||
# 6. FLASK API (Opsional)
|
||||
# ==========================================
|
||||
@@ -1388,25 +1442,28 @@ if __name__ == "__main__":
|
||||
# Ini sekarang bisa berjalan karena Flask sudah dipindah ke thread
|
||||
try:
|
||||
while True:
|
||||
logging.debug(f"--- Monitoring {len(all_threads)} Threads ---")
|
||||
print(f"--- Monitoring {len(all_threads)} Threads ---")
|
||||
|
||||
# Cek status setiap thread
|
||||
alive_count = 0
|
||||
for t in all_threads:
|
||||
if t.is_alive():
|
||||
alive_count += 1
|
||||
else:
|
||||
logging.warning(f"!!! THREAD MATI: {t.name} !!!")
|
||||
print(f"!!! THREAD MATI: {t.name} !!!")
|
||||
# Disini Anda bisa menambahkan logika restart thread jika mati
|
||||
|
||||
# Jika semua mati, exit (atau restart service)
|
||||
if alive_count == 0:
|
||||
logging.critical("Semua thread mati. System Shutdown.")
|
||||
print("Semua thread mati. System Shutdown.")
|
||||
break
|
||||
|
||||
time.sleep(10) # Cek setiap 10 detik (Hemat CPU)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Mematikan Service (Ctrl+C)...")
|
||||
print("Mematikan Service (Ctrl+C)...")
|
||||
stop_event.set()
|
||||
# Thread daemon akan mati otomatis saat main exit
|
||||
# Thread daemon akan mati otomatis saat main exit
|
||||
|
||||
Reference in New Issue
Block a user