2 Commits
Author SHA1 Message Date
lorenz.stechauner 6f076919c7 Add XBE-24 key icons 2026-10-10 22:19:58 +02:00
lorenz.stechauner 947d581c11 Add PLC simulator 2026-10-10 22:19:40 +02:00
3 changed files with 449 additions and 0 deletions

No files matched your search

+233
View File
@@ -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)
BIN
View File
Binary file not shown.
+216
View File
@@ -0,0 +1,216 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="78mm" height="117mm" viewBox="0 0 780 1170">
<title>XBE-24 Key Legend Pamhagen</title>
<defs>
<path id="key" d="M 5,5 l 150,0 l 0,130 q -75,35 -150,0 Z"
stroke-width="10" stroke="#808080" paint-order="stroke"/>
<path id="start" d="M 0,-40 l 40,40 l -40,40 l -40,-40 Z M 0,-20 l 0,40 Z"
stroke-width="7" stroke="#004000" fill-opacity="0"
stroke-linejoin="round"/>
<path id="stop" d="M 0,40 a 40,40 180 0,0 0,-80 a 40,40 180 1,0 0,80 m 0,-5 l -30.310889,-52.5 l 60.621778,0 Z"
stroke-width="7" stroke="#400000" fill-opacity="0"/>
<path id="on-off" d="M 0,40 a 40,40 180 0,0 0,-80 a 40,40 180 1,0 0,80 Z M 0,-20 l 0,40 Z"
stroke-width="7" stroke="#000000" fill-opacity="0"
stroke-linejoin="round"/>
<path id="arrow-down" d="M 0,-35 l 15,0 l 0,50 l 10,0 l -25,25 l -25,-25 l 10,0 l 0,-50 Z"
fill="#000040"/>
<use id="arrow-left-down" href="#arrow-down" transform="rotate(30)"/>
<path id="arrow-from-mw1" d="M -70,-20 l 80,0 l 0,30 l 10,0 l -20,20 l -20,-20 l 10,0 l 0,-10 l -60,0 Z"
fill="#000040"/>
<use id="arrow-from-mw2" href="#arrow-from-mw1" transform="scale(-1,1)"/>
<path id="press" d="M 35,0 l 10,0 l 0,55 l -20,0 l 0,-10 l -50,0 l 0,10 l -20,0 l 0,-55 l 10,0 a 35,35 180 0,1 70,0 a 35,35 180 0,1 -70,0"
stroke-width="5" stroke="#000000" fill-opacity="0"/>
<!--path id="tank" d="M 35,-32 l 0,90 l -10,0 l 0,-23 l 10,-9 l -30,25 l -10,0 l -30,-25 l 10,9 l 0,23 l -10,0 l 0,-90 Z"
stroke-width="5" stroke="#000000" fill-opacity="0"/-->
<path id="tank" d="M 35,-32 l 0,90 l -10,0 l 0,-23 l -20,16 l -10,0 l -20,-16 l 0,23 l -10,0 l 0,-90 Z"
stroke-width="5" stroke="#000000" fill-opacity="0"/>
</defs>
<rect x="0" y="0" width="780" height="1170" stroke="#000000" fill="#FFFFFF" stroke-width="5"/>
<g id="k0">
<use href="#key" x="25" y="30" fill="#E8E8FF"/>
<use href="#press" x="105" y="110"/>
<text x="105" y="110" font-size="35" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">P1</text>
<use href="#arrow-from-mw2" x="105" y="60"/>
<text x="148" y="50" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k1">
<use href="#key" x="25" y="220" fill="#E8E8FF"/>
<use href="#press" x="105" y="300"/>
<text x="105" y="300" font-size="35" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">P2</text>
<use href="#arrow-from-mw2" x="105" y="250"/>
<text x="148" y="240" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k2">
<use href="#key" x="25" y="410" fill="#E8E8FF"/>
<use href="#tank" x="105" y="490"/>
<text x="105" y="490" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT1</text>
<use href="#arrow-from-mw2" x="105" y="440"/>
<text x="148" y="430" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k3">
<use href="#key" x="25" y="600" fill="#E8E8FF"/>
<use href="#tank" x="105" y="680"/>
<text x="105" y="680" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT2</text>
<use href="#arrow-from-mw2" x="105" y="630"/>
<text x="148" y="620" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k4">
<use href="#key" x="25" y="790" fill="#E8E8FF"/>
<use href="#tank" x="105" y="870"/>
<text x="105" y="870" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT3</text>
<use href="#arrow-from-mw2" x="105" y="820"/>
<text x="148" y="810" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k5">
<use href="#key" x="25" y="980" fill="#E8E8FF"/>
<use href="#tank" x="105" y="1060"/>
<text x="105" y="1060" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT4</text>
<use href="#arrow-from-mw2" x="105" y="1010"/>
<text x="148" y="1000" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k6">
<use href="#key" x="215" y="30" fill="#E8FFE8"/>
<use href="#start" x="295" y="85"/>
<text x="295" y="150" font-size="40" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">Rebler</text>
</g>
<g id="k7">
<use href="#key" x="215" y="220" fill="#FFE8E8"/>
<use href="#stop" x="295" y="275"/>
<text x="295" y="340" font-size="40" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">Rebler</text>
</g>
<g id="k8">
<use href="#key" x="215" y="410" fill="#E8E8FF"/>
<use href="#arrow-left-down" x="300" y="465"/>
<text x="295" y="530" font-size="45" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">MW2</text>
</g>
<g id="k9">
<use href="#key" x="215" y="600" fill="#FFFFFF"/>
<use href="#on-off" x="295" y="655"/>
<text x="295" y="710" font-size="25" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;"><tspan>Rührer</tspan><tspan font-size="30" dx="-2.5em" dy="0.875em">MW2</tspan></text>
</g>
<g id="k10">
<use href="#key" x="215" y="790" fill="#E8FFE8"/>
<use href="#start" x="295" y="845"/>
<text x="295" y="913" font-size="45" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">MP2</text>
</g>
<g id="k11">
<use href="#key" x="215" y="980" fill="#FFE8E8"/>
<use href="#stop" x="295" y="1035"/>
<text x="295" y="1103" font-size="45" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">MP2</text>
</g>
<g id="k12">
<use href="#key" x="405" y="30" fill="#E8FFE8"/>
<use href="#start" x="485" y="85"/>
<text x="485" y="140" font-size="25" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;"><tspan>Trog-</tspan><tspan dx="-3.5em" dy="0.875em">schnecke</tspan></text>
</g>
<g id="k13">
<use href="#key" x="405" y="220" fill="#FFE8E8"/>
<use href="#stop" x="485" y="275"/>
<text x="485" y="330" font-size="25" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;"><tspan>Trog-</tspan><tspan dx="-3.5em" dy="0.875em">schnecke</tspan></text>
</g>
<g id="k14">
<use href="#key" x="405" y="410" fill="#E8E8FF"/>
<use href="#arrow-down" x="485" y="465"/>
<text x="485" y="530" font-size="45" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
<g id="k15">
<use href="#key" x="405" y="600" fill="#FFFFFF"/>
<use href="#on-off" x="485" y="655"/>
<text x="485" y="710" font-size="25" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;"><tspan>Rührer</tspan><tspan font-size="30" dx="-2.5em" dy="0.875em">MW1</tspan></text>
</g>
<g id="k16">
<use href="#key" x="405" y="790" fill="#E8FFE8"/>
<use href="#start" x="485" y="845"/>
<text x="485" y="913" font-size="45" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">MP1</text>
</g>
<g id="k17">
<use href="#key" x="405" y="980" fill="#FFE8E8"/>
<use href="#stop" x="485" y="1035"/>
<text x="485" y="1103" font-size="45" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">MP1</text>
</g>
<g id="k18">
<use href="#key" x="595" y="30" fill="#E8E8FF"/>
<use href="#press" x="675" y="110"/>
<text x="675" y="110" font-size="35" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">P1</text>
<use href="#arrow-from-mw1" x="675" y="60"/>
<text x="632" y="50" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
<g id="k19">
<use href="#key" x="595" y="220" fill="#E8E8FF"/>
<use href="#press" x="675" y="300"/>
<text x="675" y="300" font-size="35" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">P2</text>
<use href="#arrow-from-mw1" x="675" y="250"/>
<text x="632" y="240" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
<g id="k20">
<use href="#key" x="595" y="410" fill="#E8E8FF"/>
<use href="#tank" x="675" y="490"/>
<text x="675" y="490" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT1</text>
<use href="#arrow-from-mw1" x="675" y="440"/>
<text x="632" y="430" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
<g id="k21">
<use href="#key" x="595" y="600" fill="#E8E8FF"/>
<use href="#tank" x="675" y="680"/>
<text x="675" y="680" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT2</text>
<use href="#arrow-from-mw1" x="675" y="630"/>
<text x="632" y="620" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
<g id="k22">
<use href="#key" x="595" y="790" fill="#E8E8FF"/>
<use href="#tank" x="675" y="870"/>
<text x="675" y="870" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT3</text>
<use href="#arrow-from-mw1" x="675" y="820"/>
<text x="632" y="810" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
<g id="k23">
<use href="#key" x="595" y="980" fill="#E8E8FF"/>
<use href="#tank" x="675" y="1060"/>
<text x="675" y="1060" font-size="30" text-anchor="middle" dominant-baseline="central"
style="font-family:Arial,sans-serif; font-weight:bold;">RT4</text>
<use href="#arrow-from-mw1" x="675" y="1010"/>
<text x="632" y="1000" font-size="20" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"
style="font-family:Arial,sans-serif; font-weight:bold;">MW1</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB