csv logging added

This commit is contained in:
Adam 2025-03-15 22:46:42 +00:00
parent 87f0a7cc8c
commit 2e2792c913
3 changed files with 88 additions and 32 deletions

View File

@ -59,6 +59,8 @@ class RSICommandLineInterface:
self.adjust_speed(parts[1], parts[2])
elif cmd == "override" and len(parts) == 2:
self.override_safety(parts[1])
elif cmd == "log" and len(parts) >= 2:
self.handle_logging_command(parts)
elif cmd == "exit":
self.stop_rsi()
self.running = False
@ -161,6 +163,22 @@ class RSICommandLineInterface:
"""Override safety limits."""
print(f"⚠️ Overriding safety limit: {limit}")
def handle_logging_command(self, parts):
"""Handles logging-related commands."""
subcmd = parts[1]
if subcmd == "start" and len(parts) == 3:
filename = parts[2]
self.client.start_logging(filename)
print(f"✅ Logging started: {filename}")
elif subcmd == "stop":
self.client.stop_logging()
print("🛑 Logging stopped.")
elif subcmd == "status":
status = "ON" if self.client.is_logging_active() else "OFF"
print(f"📊 Logging Status: {status}")
else:
print("❌ Invalid log command. Use 'log start <file>.csv', 'log stop', or 'log status'.")
def show_help(self):
"""Displays the list of available commands."""
print("""
@ -170,6 +188,7 @@ Available Commands:
toggle <DiO/DiL> <0/1>, move_external <axis> <value>
correct <RKorr/AKorr> <X/Y/Z/A/B/C> <value>, speed <Tech.TX> <value>
override <limit>
log start <file>.csv, log stop, log status
""")
if __name__ == "__main__":

View File

@ -1,25 +1,15 @@
import multiprocessing
import socket
import time
import csv
import logging
from config_parser import ConfigParser
import sys
import os
import socket
import xml.etree.ElementTree as ET
import multiprocessing
from xml_handler import XMLGenerator # ✅ Import XML generator module
from config_parser import ConfigParser # ✅ Import the updated config parser
import multiprocessing
import socket
import logging
import xml.etree.ElementTree as ET # ✅ FIX: Import ElementTree
from config_parser import ConfigParser
from xml_handler import XMLGenerator
class NetworkProcess(multiprocessing.Process):
"""Handles UDP communication in a separate process."""
"""Handles UDP communication and optional CSV logging in a separate process."""
def __init__(self, ip, port, send_variables, receive_variables, stop_event, config_parser):
super().__init__()
@ -29,14 +19,17 @@ class NetworkProcess(multiprocessing.Process):
self.config_parser = config_parser
self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# ✅ Fallback IP handling
self.client_address = (ip, port)
if not self.is_valid_ip(ip):
logging.warning(f"Invalid IP address '{ip}' detected. Falling back to '0.0.0.0'.")
print(f"⚠️ Invalid IP '{ip}', falling back to '0.0.0.0'.")
self.client_address = ('0.0.0.0', port)
else:
self.client_address = (ip, port)
self.logging_active = multiprocessing.Value('b', False) # Shared flag for logging
self.log_filename = multiprocessing.Array('c', 256) # Shared memory for filename
self.csv_process = None
try:
self.udp_socket.bind(self.client_address)
@ -63,44 +56,74 @@ class NetworkProcess(multiprocessing.Process):
print("[DEBUG] Network process started.")
while not self.stop_event.is_set():
try:
print("[DEBUG] Waiting for incoming message...")
self.udp_socket.settimeout(5)
data_received, self.controller_ip_and_port = self.udp_socket.recvfrom(1024)
message = data_received.decode()
print(f"[DEBUG] Received message: {message}")
self.process_received_data(message)
# ✅ Generate the send XML using the updated XMLGenerator
send_xml = XMLGenerator.generate_send_xml(self.send_variables, self.config_parser.network_settings)
print(f"[DEBUG] Sending response: {send_xml}")
self.udp_socket.sendto(send_xml.encode(), self.controller_ip_and_port)
# ✅ If logging is active, write data to CSV
if self.logging_active.value:
self.log_to_csv()
except socket.timeout:
print("[WARNING] No message received within timeout period.")
except Exception as e:
print(f"[ERROR] Network process error: {e}")
def stop_network(self):
"""Safely stop the network process."""
if self.udp_socket:
self.udp_socket.close()
print("✅ Network socket closed.")
def process_received_data(self, xml_string):
"""Parse incoming XML and update shared variables."""
try:
root = ET.fromstring(xml_string)
for element in root:
if element.tag in self.receive_variables:
if len(element.attrib) > 0: # ✅ Handle structured data (dictionaries)
if len(element.attrib) > 0:
self.receive_variables[element.tag] = {k: float(v) for k, v in element.attrib.items()}
else:
self.receive_variables[element.tag] = element.text
print(f"[DEBUG] Updated received variables: {self.receive_variables}")
except Exception as e:
print(f"[ERROR] Error parsing received message: {e}")
def log_to_csv(self):
"""Write send/receive variables to the CSV log."""
filename = self.log_filename.value.decode().strip()
if not filename:
return
try:
with open(filename, mode="a", newline="") as file:
writer = csv.writer(file)
# Write header if the file is new
if file.tell() == 0:
headers = ["Timestamp", "IPOC"]
headers += [f"Send.{k}" for k in self.send_variables.keys()]
headers += [f"Receive.{k}" for k in self.receive_variables.keys()]
writer.writerow(headers)
# Write current data
timestamp = time.strftime("%d-%m-%Y %H:%M:%S")
ipoc = self.receive_variables.get("IPOC", 0)
send_data = [self.send_variables.get(k, "") for k in self.send_variables.keys()]
receive_data = [self.receive_variables.get(k, "") for k in self.receive_variables.keys()]
writer.writerow([timestamp, ipoc] + send_data + receive_data)
except Exception as e:
print(f"[ERROR] Failed to log data to CSV: {e}")
def start_logging(self, filename):
"""Start logging RSI data to CSV."""
self.logging_active.value = True
self.log_filename.value = filename.encode()
print(f"✅ CSV Logging started: {filename}")
def stop_logging(self):
"""Stop logging RSI data."""
self.logging_active.value = False
print("🛑 CSV Logging stopped.")
def is_logging_active(self):
"""Return logging status."""
return self.logging_active.value

View File

@ -77,3 +77,17 @@ class RSIAPI:
"send_variables": dict(self.client.send_variables),
"receive_variables": dict(self.client.receive_variables)
}
def start_logging(self, filename):
"""Start logging RSI data to CSV."""
self.client.start_logging(filename)
return f"✅ CSV Logging started: {filename}"
def stop_logging(self):
"""Stop logging RSI data."""
self.client.stop_logging()
return "🛑 CSV Logging stopped."
def is_logging_active(self):
"""Return logging status."""
return self.client.is_logging_active()