Files
pamhagen-sysctrl/Simulator/plc.py
T
2026-10-10 22:19:40 +02:00

234 lines
9.2 KiB
Python
Executable File

#!/bin/env python3
import socket
import time
import random
import argparse
mw1 = 0
mw2 = 0
t1 = 0
t2 = 0
t3 = 0
t4 = 0
t5 = 0
t6 = 0
t7 = 0
t8 = 0
t9 = 0
pr1 = 0
pr2 = 0
mw1_max = 5000
mw2_max = 5000
t_max = 35000
pr1_max = 20000
pr2_max = 15000
ENTRY_RATE = 20 / 20
PUMP_RATE = 5 / 20
rw = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
def are_valves_open(valves, *ns):
mask = 0
for n in ns:
mask |= 1 << (n - 1)
return (~valves & mask) == mask
def send_cmd(cmd: str, data: str) -> None:
msg = f'(A01{cmd}{data}&'
chk = sum(c for c in msg.encode('ascii')) & 0xFF
msg += f'{chk:02X})\r'
time.sleep(len(msg) * 8 / 9600 * 2)
print(f'-> {msg}')
client.send(msg.encode('ascii'))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('socket')
args = parser.parse_args()
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client.connect(args.socket)
while True:
line = b''
while b'\r' not in line:
line += client.recv(256)
cmds = line.split(b'\r')
line = cmds[-1]
cmds = [c.decode('ascii') for c in cmds[:-1]]
for cmd in cmds:
print(f'<- {cmd}')
time.sleep(len(cmd) * 8 / 9600 * 2)
if not cmd.startswith('(A01') or not cmd.endswith(')') or len(cmd) < 7:
send_cmd('CE', '02')
continue
c, d = cmd[4:6], cmd[6:-1]
if cmd[-4] == '&':
chk1 = int(cmd[-3:-1], 16)
chk2 = sum(c for c in cmd[:-3].encode('ascii')) & 0xFF
if chk1 != chk2:
send_cmd('CE', '03')
continue
d = d[:-3]
if c == 'TS':
send_cmd('TS', d)
elif c == 'ST':
send_cmd('ST', '0002')
elif c == 'DR':
# FIXME
d = d.split(',')
s = int(d[0][2:])
l = int(d[1])
send_cmd('DR', ''.join(f'{r:04X}' for r in rw[s:s+l]))
elif c == 'DW':
# FIXME
d = d.split(',')
s = int(d[0][2:])
l = int(d[1])
for i in range(l):
rw[s + i] = int(d[2 + i], 16)
send_cmd('ST', '0002')
else:
send_cmd('CE', '01')
# tick - valves
for i in range(0, 60):
want_open = rw[i // 16] & (1 << (i % 16)) == 0
is_open = rw[10 + i // 16] & (1 << (i % 16)) != 0
if want_open and not is_open:
if random.random() > 0.875:
rw[10 + i // 16] |= 1 << (i % 16)
elif not want_open and is_open:
if random.random() > 0.875:
rw[10 + i // 16] &= ~(1 << (i % 16))
# tick - wannen
want_a1_selected = (rw[5] & 0x0004) != 0
want_a2_selected = not want_a1_selected
is_a1_selected = (rw[14] & 0x0200) != 0
is_a2_selected = (rw[14] & 0x0100) != 0
if is_a1_selected and not want_a1_selected:
rw[14] &= 0xFDFF
elif not is_a1_selected and want_a1_selected:
if random.random() > 0.875:
rw[14] |= 0x0200
if is_a2_selected and not want_a2_selected:
rw[14] &= 0xFEFF
elif not is_a2_selected and want_a2_selected:
if random.random() > 0.875:
rw[14] |= 0x0100
# tick - pipeline
valves = (rw[13] << 48) | (rw[12] << 32) | (rw[11] << 16) | rw[10]
wannen_schnecke = (rw[5] & 0x1) != 0
mp1 = (rw[4] & 0x002) != 0
mp2 = (rw[4] & 0x004) != 0
p12 = (rw[4] & 0x010) != 0
p3 = (rw[4] & 0x020) != 0
p4 = (rw[4] & 0x040) != 0
p5 = (rw[4] & 0x080) != 0
p6 = (rw[4] & 0x100) != 0
if wannen_schnecke and is_a1_selected:
mw1 += ENTRY_RATE
elif wannen_schnecke and is_a2_selected:
mw2 += ENTRY_RATE
if mp1 and mw1 > 0:
mw1 -= PUMP_RATE
if are_valves_open(valves, 1, 6, 51) or are_valves_open(valves, 4, 8, 52):
pr1 += PUMP_RATE
elif are_valves_open(valves, 1, 6, 55) or are_valves_open(valves, 4, 8, 56):
pr2 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 22) or are_valves_open(valves, 4, 7, 9, 13, 23):
t1 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 24) or are_valves_open(valves, 4, 7, 9, 13, 25):
t2 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 26) or are_valves_open(valves, 4, 7, 9, 13, 27):
t3 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 28, 30) or are_valves_open(valves, 4, 7, 9, 13, 29, 31):
t4 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 28, 32) or are_valves_open(valves, 4, 7, 9, 13, 29, 33):
t5 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 28, 34, 37) or are_valves_open(valves, 4, 7, 9, 13, 29, 35, 36):
t6 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 28, 34, 39) or are_valves_open(valves, 4, 7, 9, 13, 29, 35, 38):
t7 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 28, 34, 41) or are_valves_open(valves, 4, 7, 9, 13, 29, 35, 40):
t8 += PUMP_RATE
elif are_valves_open(valves, 1, 5, 12, 28, 34, 43) or are_valves_open(valves, 4, 7, 9, 13, 29, 35, 42):
t9 += PUMP_RATE
if mp2 and mw2 > 0:
mw2 -= PUMP_RATE
if are_valves_open(valves, 2, 8, 52) or are_valves_open(valves, 3, 6, 51):
pr1 += PUMP_RATE
elif are_valves_open(valves, 2, 8, 56) or are_valves_open(valves, 3, 6, 55):
pr2 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 22) or are_valves_open(valves, 2, 7, 9, 13, 23):
t1 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 24) or are_valves_open(valves, 2, 7, 9, 13, 25):
t2 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 26) or are_valves_open(valves, 2, 7, 9, 13, 27):
t3 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 28, 30) or are_valves_open(valves, 2, 7, 9, 13, 29, 31):
t4 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 28, 32) or are_valves_open(valves, 2, 7, 9, 13, 29, 33):
t5 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 28, 34, 37) or are_valves_open(valves, 2, 7, 9, 13, 29, 35, 36):
t6 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 28, 34, 39) or are_valves_open(valves, 2, 7, 9, 13, 29, 35, 38):
t7 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 28, 34, 41) or are_valves_open(valves, 2, 7, 9, 13, 29, 35, 40):
t8 += PUMP_RATE
elif are_valves_open(valves, 3, 5, 12, 28, 34, 43) or are_valves_open(valves, 2, 7, 9, 13, 29, 35, 42):
t9 += PUMP_RATE
if p6 and (t6 > 0 or t7 > 0 or t8 > 0 or t9 > 0):
if t6 > 0:
t6 -= PUMP_RATE
if t7 > 0:
t7 -= PUMP_RATE
if t8 > 0:
t8 -= PUMP_RATE
if t9 > 0:
t9 -= PUMP_RATE
if are_valves_open(valves, 53):
pr1 += PUMP_RATE
elif are_valves_open(valves, 57):
pr2 += PUMP_RATE
# tick - fill levels
rw[14] &= 0xFF00
rw[14] |= 0x0004 if mw1 > 50 else 0
rw[14] |= 0x0002 if mw1 > mw1_max / 2 else 0
rw[14] |= 0x0001 if mw1 > mw1_max * 0.875 else 0
rw[14] |= 0x0020 if mw2 > 50 else 0
rw[14] |= 0x0010 if mw2 > mw2_max / 2 else 0
rw[14] |= 0x0008 if mw2 > mw2_max * 0.875 else 0
rw[14] |= 0x0040 if pr1 > pr1_max * 0.875 else 0
rw[14] |= 0x0080 if pr2 > pr2_max * 0.875 else 0
rw[16] &= 0xC000
rw[16] |= 0x0001 if t1 > 50 else 0
rw[16] |= 0x0002 if t1 > t_max * 0.875 else 0
rw[16] |= 0x0004 if t2 > 50 else 0
rw[16] |= 0x0008 if t2 > t_max * 0.875 else 0
rw[16] |= 0x0010 if t3 > 50 else 0
rw[16] |= 0x0020 if t3 > t_max * 0.875 else 0
rw[16] |= 0x0040 if t4 > 50 else 0
rw[16] |= 0x0080 if t4 > t_max * 0.875 else 0
rw[16] |= 0x0100 if t5 > 50 else 0
rw[16] |= 0x0200 if t5 > t_max * 0.875 else 0
rw[16] |= 0x0400 if t6 > t_max * 0.875 else 0
rw[16] |= 0x0800 if t7 > t_max * 0.875 else 0
rw[16] |= 0x1000 if t8 > t_max * 0.875 else 0
rw[16] |= 0x2000 if t9 > t_max * 0.875 else 0
print(mw1, mw2, t1, t2, t3, t4, t5, t6, t7, t8, t9, pr1, pr2)