Update
This commit is contained in:
80
glory.py
80
glory.py
@ -10,7 +10,6 @@ import logging
|
||||
import random
|
||||
import time
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
import serial
|
||||
|
||||
@ -29,7 +28,7 @@ STATE_MESSAGE_PENDING = "PRN"
|
||||
|
||||
|
||||
class GlorySimulator:
|
||||
def __init__(self, port: str, baudrate: int = 9600):
|
||||
def __init__(self, logger: logging.Logger, port: str, baudrate: int = 9600):
|
||||
self.port = port
|
||||
self.baudrate = baudrate
|
||||
self.serial_conn: Optional[serial.Serial] = None
|
||||
@ -77,10 +76,7 @@ class GlorySimulator:
|
||||
# Message buffer
|
||||
self.pending_message = None
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.logger = logger
|
||||
|
||||
def get_status(self) -> str:
|
||||
"""Get current machine status"""
|
||||
@ -116,7 +112,7 @@ class GlorySimulator:
|
||||
|
||||
def handle_clear_command(self, data: bytes) -> bytes:
|
||||
"""Handle clear commands (CC, CB, CS, CG)"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if cmd == "CB":
|
||||
# Clear batch
|
||||
@ -146,27 +142,32 @@ class GlorySimulator:
|
||||
|
||||
def handle_get_data_command(self, data: bytes) -> bytes:
|
||||
"""Handle get data commands (GD, GT, GS, GG, GI, GV)"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if cmd == "GT":
|
||||
# Get batch total
|
||||
# If no counts, generate random simulation data
|
||||
# if not self.batch_counts and self.motor_has_run:
|
||||
if True:
|
||||
self._simulate_counting()
|
||||
|
||||
total = sum(self.batch_counts.values())
|
||||
response = f"BT{total:08d}"
|
||||
self.logger.info(f"Get batch total: {total}")
|
||||
self.logger.info(f"Get batch total: {total} coins")
|
||||
return self.create_message(response)
|
||||
|
||||
elif cmd == "GS":
|
||||
# Get subtotal
|
||||
total = sum(self.sub_counts.values())
|
||||
response = f"BS{total:08d}"
|
||||
self.logger.info(f"Get subtotal: {total}")
|
||||
self.logger.info(f"Get subtotal: {total} coins")
|
||||
return self.create_message(response)
|
||||
|
||||
elif cmd == "GG":
|
||||
# Get grand total
|
||||
total = sum(self.grand_counts.values())
|
||||
response = f"BG{total:08d}"
|
||||
self.logger.info(f"Get grand total: {total}")
|
||||
self.logger.info(f"Get grand total: {total} coins")
|
||||
return self.create_message(response)
|
||||
|
||||
elif cmd.startswith("GD"):
|
||||
@ -174,7 +175,7 @@ class GlorySimulator:
|
||||
denom_str = cmd[2:]
|
||||
count = self.partial_counts.get(denom_str, 0)
|
||||
response = f"BD{count:08d}"
|
||||
self.logger.info(f"Get partial count for {denom_str}: {count}")
|
||||
self.logger.info(f"Get partial count for {denom_str}: {count} coins")
|
||||
return self.create_message(response)
|
||||
|
||||
elif cmd.startswith("GT") and len(cmd) > 2:
|
||||
@ -182,7 +183,7 @@ class GlorySimulator:
|
||||
denom_str = cmd[2:]
|
||||
count = self.batch_counts.get(denom_str, 0)
|
||||
response = f"BT{count:08d}"
|
||||
self.logger.info(f"Get batch count for {denom_str}: {count}")
|
||||
self.logger.info(f"Get batch count for {denom_str}: {count} coins")
|
||||
return self.create_message(response)
|
||||
|
||||
elif cmd == "GI":
|
||||
@ -205,7 +206,7 @@ class GlorySimulator:
|
||||
|
||||
def handle_bag_stop_command(self, data: bytes) -> bytes:
|
||||
"""Handle SV - Set bag stop command"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if len(cmd) >= 13 and cmd.startswith("SV"):
|
||||
denom_str = cmd[2:5]
|
||||
@ -224,7 +225,7 @@ class GlorySimulator:
|
||||
|
||||
def handle_motor_command(self, data: bytes) -> bytes:
|
||||
"""Handle MG/MS - Motor control commands"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if cmd == "MG":
|
||||
# Start motor
|
||||
@ -251,7 +252,7 @@ class GlorySimulator:
|
||||
|
||||
def handle_accept_command(self, data: bytes) -> bytes:
|
||||
"""Handle AB/AS/AG - Accept commands"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if cmd == "AB" or cmd == "Ab":
|
||||
# Accept batch
|
||||
@ -281,7 +282,7 @@ class GlorySimulator:
|
||||
|
||||
def handle_partial_count_command(self, data: bytes) -> bytes:
|
||||
"""Handle PC - Set partial count command"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if len(cmd) >= 13 and cmd.startswith("PC"):
|
||||
denom_str = cmd[2:5]
|
||||
@ -300,7 +301,7 @@ class GlorySimulator:
|
||||
|
||||
def handle_id_command(self, data: bytes) -> bytes:
|
||||
"""Handle ID/IS/IG - Set ID number commands"""
|
||||
cmd = data.decode('ascii', errors='ignore').strip()
|
||||
cmd = data.decode("ascii", errors="ignore").strip()
|
||||
|
||||
if cmd.startswith("ID"):
|
||||
self.batch_id = cmd[2:14] if len(cmd) >= 14 else cmd[2:]
|
||||
@ -319,15 +320,40 @@ class GlorySimulator:
|
||||
def _simulate_counting(self):
|
||||
"""Simulate coin counting when motor runs"""
|
||||
# Generate random counts for simulation
|
||||
denominations = ["005", "010", "025", "050", "100"]
|
||||
for denom in denominations:
|
||||
count = random.randint(10, 100)
|
||||
self.batch_counts[denom] = self.batch_counts.get(denom, 0) + count
|
||||
self.partial_counts[denom] = self.partial_counts.get(denom, 0) + count
|
||||
# Standard denominations with realistic count distributions
|
||||
denominations = {
|
||||
"001": (20, 150), # Pennies - high count
|
||||
"005": (10, 100), # Nickels
|
||||
"010": (10, 80), # Dimes
|
||||
"025": (5, 60), # Quarters
|
||||
"050": (0, 20), # Half dollars - rare
|
||||
"100": (0, 10), # Dollar coins - rare
|
||||
}
|
||||
|
||||
for denom, (min_count, max_count) in denominations.items():
|
||||
count = random.randint(min_count, max_count)
|
||||
if count > 0:
|
||||
# Update batch counts
|
||||
self.batch_counts[denom] = self.batch_counts.get(denom, 0) + count
|
||||
# Update partial counts
|
||||
self.partial_counts[denom] = self.partial_counts.get(denom, 0) + count
|
||||
# Update subtotal
|
||||
self.sub_counts[denom] = self.sub_counts.get(denom, 0) + count
|
||||
# Update grand total
|
||||
self.grand_counts[denom] = self.grand_counts.get(denom, 0) + count
|
||||
|
||||
self.logger.info(f"Counted {count} coins of denomination {denom}")
|
||||
|
||||
# Log total value counted
|
||||
total_value = sum(
|
||||
self.batch_counts.get(denom, 0) * int(denom)
|
||||
for denom in denominations.keys()
|
||||
)
|
||||
self.logger.info(f"Total value counted in this batch: ${total_value/100:.2f}")
|
||||
|
||||
def create_message(self, data: str) -> bytes:
|
||||
"""Create a message with STX and ETX"""
|
||||
return bytes([STX]) + data.encode('ascii') + bytes([ETX])
|
||||
return bytes([STX]) + data.encode("ascii") + bytes([ETX])
|
||||
|
||||
def parse_message(self, message: bytes) -> Optional[bytes]:
|
||||
"""Parse and validate a received message"""
|
||||
@ -352,7 +378,7 @@ class GlorySimulator:
|
||||
return None
|
||||
|
||||
try:
|
||||
cmd_str = data.decode('ascii', errors='ignore').strip()
|
||||
cmd_str = data.decode("ascii", errors="ignore").strip()
|
||||
cmd = cmd_str[:2]
|
||||
|
||||
self.logger.info(f"Received command: {cmd_str}")
|
||||
@ -435,14 +461,14 @@ class GlorySimulator:
|
||||
message = bytes(buffer[stx_idx : etx_idx + 1])
|
||||
buffer = buffer[etx_idx + 1 :]
|
||||
|
||||
self.logger.debug(f"RX: {message.hex()}")
|
||||
self.logger.debug(f"RX: {' '.join(f'{b:02X}' for b in message)}")
|
||||
|
||||
# Parse and handle message
|
||||
parsed_data = self.parse_message(message)
|
||||
if parsed_data:
|
||||
response = self.handle_command(parsed_data)
|
||||
if response:
|
||||
self.logger.debug(f"TX: {response.hex()}")
|
||||
self.logger.debug(f"TX: {' '.join(f'{b:02X}' for b in response)}")
|
||||
self.serial_conn.write(response)
|
||||
except ValueError:
|
||||
pass # ETX not found yet
|
||||
|
||||
Reference in New Issue
Block a user