Add PLC simulator
This commit is contained in:
Executable
+233
@@ -0,0 +1,233 @@
|
||||
#!/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)
|
||||
Reference in New Issue
Block a user