diff --git a/hardware/pcb/CybICS.kicad_pcb b/hardware/pcb/CybICS.kicad_pcb
index 3d78131..2f4245d 100644
--- a/hardware/pcb/CybICS.kicad_pcb
+++ b/hardware/pcb/CybICS.kicad_pcb
@@ -14711,7 +14711,7 @@
)
(fp_arc
(start 64.20104 22.49932)
- (mid 64.054479 22.85315)
+ (mid 64.054473 22.853115)
(end 63.70066 22.9997)
(stroke
(width 0.12)
diff --git a/hardware/pcb/README.md b/hardware/pcb/README.md
new file mode 100644
index 0000000..185feb4
--- /dev/null
+++ b/hardware/pcb/README.md
@@ -0,0 +1,23 @@
+### Ordering PCB at JLCPCB
+
+Open KiCad and under "Tools" → "Plugin and Content Manager":
+
+
+ |
+
+Install the "Fabrication Toolkit":
+
+
+ |
+
+Open the "PCB Editor" and click on the icon of "Fabrication Toolkit":
+
+
+ |
+
+Generate the fabrication data:
+
+
+ |
+
+Now you have a folder "production", with all the file to upload to JLCPCB.
diff --git a/hardware/pcb/doc/fabricationToolkit.png b/hardware/pcb/doc/fabricationToolkit.png
new file mode 100644
index 0000000..7728eb1
Binary files /dev/null and b/hardware/pcb/doc/fabricationToolkit.png differ
diff --git a/hardware/pcb/doc/generate.png b/hardware/pcb/doc/generate.png
new file mode 100644
index 0000000..c990f38
Binary files /dev/null and b/hardware/pcb/doc/generate.png differ
diff --git a/hardware/pcb/doc/pcbEditor.png b/hardware/pcb/doc/pcbEditor.png
new file mode 100644
index 0000000..e5c3ee7
Binary files /dev/null and b/hardware/pcb/doc/pcbEditor.png differ
diff --git a/hardware/pcb/doc/pluginManager.png b/hardware/pcb/doc/pluginManager.png
new file mode 100644
index 0000000..c0c7290
Binary files /dev/null and b/hardware/pcb/doc/pluginManager.png differ
diff --git a/hardware/pcb/docs/CybICS-board_bottom.pdf b/hardware/pcb/docs/CybICS-board_bottom.pdf
index 1e79986..1f64360 100644
Binary files a/hardware/pcb/docs/CybICS-board_bottom.pdf and b/hardware/pcb/docs/CybICS-board_bottom.pdf differ
diff --git a/hardware/pcb/docs/CybICS-board_top.pdf b/hardware/pcb/docs/CybICS-board_top.pdf
index 2bbec8a..f440462 100644
Binary files a/hardware/pcb/docs/CybICS-board_top.pdf and b/hardware/pcb/docs/CybICS-board_top.pdf differ
diff --git a/hardware/pcb/docs/CybICS-schematic.pdf b/hardware/pcb/docs/CybICS-schematic.pdf
index 13851a4..077a2af 100644
Binary files a/hardware/pcb/docs/CybICS-schematic.pdf and b/hardware/pcb/docs/CybICS-schematic.pdf differ
diff --git a/hardware/pcb/pcb/CybICS-top.svg b/hardware/pcb/pcb/CybICS-top.svg
index 03899b9..5c7957f 100644
--- a/hardware/pcb/pcb/CybICS-top.svg
+++ b/hardware/pcb/pcb/CybICS-top.svg
@@ -8959,7 +8959,7 @@
-
+
diff --git a/hardware/pcb/pcb/CybICS_top.png b/hardware/pcb/pcb/CybICS_top.png
index 4cb8ae6..e80e0cc 100644
Binary files a/hardware/pcb/pcb/CybICS_top.png and b/hardware/pcb/pcb/CybICS_top.png differ
diff --git a/software/FUXA/Dockerfile b/software/FUXA/Dockerfile
index ecbcf85..479622c 100644
--- a/software/FUXA/Dockerfile
+++ b/software/FUXA/Dockerfile
@@ -3,6 +3,7 @@ FROM debian:12
RUN apt-get update && apt-get install -y \
npm \
curl \
+ unixodbc-dev \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g --unsafe-perm @frangoteam/fuxa
diff --git a/software/hwio-virtual/Dockerfile b/software/hwio-virtual/Dockerfile
index 6fc1099..7c65d53 100644
--- a/software/hwio-virtual/Dockerfile
+++ b/software/hwio-virtual/Dockerfile
@@ -3,8 +3,10 @@ FROM python:3
WORKDIR /CybICS
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
+RUN mkdir -p pics
COPY hardwareAbstraction.py ./
-COPY CybICS_logo.png ./
-COPY favicon.ico ./
+COPY pics/CybICS_logo.png pics/CybICS_logo.png
+COPY pics/favicon.ico pics/favicon.ico
+COPY pics/pcb.png pics/pcb.png
CMD [ "python", "./hardwareAbstraction.py" ]
diff --git a/software/hwio-virtual/hardwareAbstraction.py b/software/hwio-virtual/hardwareAbstraction.py
index cf3530e..62ae47e 100644
--- a/software/hwio-virtual/hardwareAbstraction.py
+++ b/software/hwio-virtual/hardwareAbstraction.py
@@ -11,10 +11,32 @@
client = ModbusTcpClient(host="openplc",port=502) # Create client object
client.connect() # connect to device, reconnect automatically
-def thread_nicegui():
- ui.run(port=8090,reload=False,show=False,dark=True,favicon="favicon.ico",title="CybICS VIRT")
+# Global variables
+gst=0
+hpt=0
+sysSen=0
+boSen=0
+heartbeat=0
+compressor=0
+systemValve=0
+gstSig=0
+delay=0
+timer=0
-if __name__ == "__main__":
+# definiton for button reset
+def button_reset():
+ # use global variables
+ global gst
+ global hpt
+ global sysSen
+ global boSen
+ global heartbeat
+ global compressor
+ global systemValve
+ global gstSig
+ global delay
+ global timer
+ logging.info("button_rest: clicked")
gst=0
hpt=0
sysSen=0
@@ -24,6 +46,15 @@ def thread_nicegui():
systemValve=0
gstSig=0
delay=0
+ timer=0
+ logging.info("button_rest: all reseted")
+
+# thread for nicegui
+def thread_nicegui():
+ ui.run(port=8090,reload=False,show=False,dark=True,favicon="pics/favicon.ico",title="CybICS VIRT")
+
+# main function
+if __name__ == "__main__":
flag = [17273, 25161, 17235, 10349, 12388, 25205, 9257]
format = "%(asctime)s: %(message)s"
@@ -37,54 +68,186 @@ def thread_nicegui():
logging.info("Main : before running thread")
x.start()
- # NiceGUI setup
- with ui.row():
- ui.spinner('dots', size='lg', color='red')
- ui.image('CybICS_logo.png').classes('w-64')
- ui.spinner('dots', size='lg', color='red')
-
- columns = [
- {'name': 'variable', 'label': 'Variable', 'field': 'variable', 'required': True, 'align': 'left'},
- {'name': 'value', 'label': 'Value', 'field': 'value', 'sortable': True},
- ]
- rows = [
- {'variable': 'GST', 'value': gst},
- {'variable': 'HPT', 'value': hpt},
- {'variable': 'boSen', 'value': boSen},
- {'variable': 'heartbeat', 'value': heartbeat},
- {'variable': 'compressor', 'value': compressor},
- {'variable': 'systemValve', 'value': systemValve},
- {'variable': 'gstSig', 'value': gstSig},
- {'variable': 'System', 'value': sysSen},
- ]
+ # Create container for the content
+ with ui.element('div').style('text-align: center; min-width: 1024; width: 1024;'):
+
+ # NiceGUI setup
+ with ui.row().style('width: 900px; text-align: center; align-items: center; justify-content: center;'):
+ ui.spinner('dots', size='lg', color='red')
+ ui.image('pics/CybICS_logo.png').classes('w-64')
+ ui.spinner('dots', size='lg', color='red')
+
+ columns = [
+ {'name': 'variable', 'label': 'Variable', 'field': 'variable', 'required': True, 'align': 'left'},
+ {'name': 'value', 'label': 'Value', 'field': 'value', 'sortable': True},
+ ]
+ rows = [
+ {'variable': 'GST', 'value': gst},
+ {'variable': 'HPT', 'value': hpt},
+ {'variable': 'boSen', 'value': boSen},
+ {'variable': 'heartbeat', 'value': heartbeat},
+ {'variable': 'compressor', 'value': compressor},
+ {'variable': 'systemValve', 'value': systemValve},
+ {'variable': 'gstSig', 'value': gstSig},
+ {'variable': 'System', 'value': sysSen},
+ ]
+ # add horizontal line
+ with ui.element('div').style('display: flex; justify-content: center;'):
+ ui.element('div').style(
+ 'height: 1px; background-color: white; width: 80%; margin: 20px 0;'
+ )
+
+ # Add PCB as a PNG image
+ with ui.element('div').style('position: relative; display: inline-block;'):
+ # Display the PNG image
+ ui.image('pics/pcb.png').style('width: 100%; height: auto; display: block; width: 800px; height: 500px; margin: auto;')
+
+ # Reset button
+ ui.button('reset', on_click=button_reset).style(
+ 'position: absolute; top: 240px; left: 0px;'
+ 'background-color: red; color: white; width: 40px; height: 5px;'
+ 'display: block;'
+ )
+
+ # Overlay Display
+ DISPLAYoverlay1 = ui.label('CybICS v1.0.0').style(
+ 'position: absolute; top: 370px; left: 430px; border-radius: 50%; color=black'
+ 'background-color: transparent; font-size: 40px;'
+ 'display: block;'
+ )
+ DISPLAYoverlay2 = ui.label('0').style(
+ 'position: absolute; top: 415px; left: 430px; border-radius: 50%; color=black'
+ 'background-color: transparent; font-size: 40px; width:330px; text-align: right;'
+ 'display: block;'
+ )
- # Build a visual representation of the process
- with ui.row():
- with ui.column():
- variableTable = ui.table(columns=columns, rows=rows, row_key='name')
- with ui.column():
- ui.label('Gas Storage Tank (GST)')
- with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as gstCard:
- gstLabel = ui.label(str(gst)).style('color: black;')
- ui.label('System Valve ')
- with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as systemValveCard:
- systemValveLabel = ui.label(str(systemValve)).style('color: black;')
- with ui.column():
- ui.label('Compressor (C)')
- with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as cCard:
- cLabel = ui.label(str(compressor)).style('color: black;')
- ui.label('System (Sys)')
- with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as sysCard:
- sysLabel = ui.label(str(sysSen)).style('color: black;')
- with ui.column():
- ui.label('High Pressure Tank (HPT)')
- with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as hptCard:
- hptLabel = ui.label(str(hpt)).style('color: black;')
- ui.label('Blow Out (BO)')
- with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as boCard:
- boLabel = ui.label(str(boSen)).style('color: black;')
+ # Overlay GST
+ GSToverlayLow=ui.card().style(
+ 'position: absolute; top: 140px; left: 115px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ GSToverlayNormal=ui.card().style(
+ 'position: absolute; top: 110px; left: 115px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ GSToverlayHigh=ui.card().style(
+ 'position: absolute; top: 80px; left: 115px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ # Overlay Compressor
+ CoverlayOn=ui.card().style(
+ 'position: absolute; top: 95px; left: 355px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ CoverlayOff=ui.card().style(
+ 'position: absolute; top: 125px; left: 355px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+
+ # Overlay HPT
+ HPToverlayEmpty=ui.card().style(
+ 'position: absolute; top: 210px; left: 495px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayLow=ui.card().style(
+ 'position: absolute; top: 184px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayNormal=ui.card().style(
+ 'position: absolute; top: 158px; left: 495px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayHigh=ui.card().style(
+ 'position: absolute; top: 132px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayCritical=ui.card().style(
+ 'position: absolute; top: 106px; left: 495px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+
+ # Overlay Blow Out
+ BOoverlayOpen=ui.card().style(
+ 'position: absolute; top: 55px; left: 680px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ BOoverlayClosed=ui.card().style(
+ 'position: absolute; top: 80px; left: 680px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+
+ # Overlay System
+ SoverlayWorking=ui.card().style(
+ 'position: absolute; top: 140px; left: 680px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ SoverlayError=ui.card().style(
+ 'position: absolute; top: 165px; left: 680px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+
+ # Overlay System Valve
+ SVoverlayOpen=ui.card().style(
+ 'position: absolute; top: 245px; left: 620px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ SVoverlayClosed=ui.card().style(
+ 'position: absolute; top: 270px; left: 620px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+
+ # add horizontal line
+ with ui.element('div').style('display: flex; justify-content: center;'):
+ ui.element('div').style(
+ 'height: 1px; background-color: white; width: 80%; margin: 20px 0;'
+ )
+
+ # Build a visual representation of the process
+ with ui.row().style('width: 900px; text-align: center; align-items: center; justify-content: center;'):
+ with ui.column():
+ variableTable = ui.table(columns=columns, rows=rows, row_key='name')
+ with ui.column():
+ ui.label('Gas Storage Tank (GST)')
+ with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as gstCard:
+ gstLabel = ui.label(str(gst)).style('color: black;')
+ ui.label('System Valve ')
+ with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as systemValveCard:
+ systemValveLabel = ui.label(str(systemValve)).style('color: black;')
+ with ui.column():
+ ui.label('Compressor (C)')
+ with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as cCard:
+ cLabel = ui.label(str(compressor)).style('color: black;')
+ ui.label('System (Sys)')
+ with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as sysCard:
+ sysLabel = ui.label(str(sysSen)).style('color: black;')
+ with ui.column():
+ ui.label('High Pressure Tank (HPT)')
+ with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as hptCard:
+ hptLabel = ui.label(str(hpt)).style('color: black;')
+ ui.label('Blow Out (BO)')
+ with ui.card().style(f'background-color: grey; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;') as boCard:
+ boLabel = ui.label(str(boSen)).style('color: black;')
+
+
+
while True:
# read coils from OpenPLC
@@ -98,8 +261,10 @@ def thread_nicegui():
logging.error("Main : Read from OpenPLC failed - " + str(e))
# get roughly one second
- if delay > 1000:
+ if delay > 50:
delay = 0
+ timer = timer + 1
+ DISPLAYoverlay2.set_text(str(timer))
if gstSig > 0:
gst = gst+random.randint(0, 5)
if compressor > 0:
@@ -107,6 +272,8 @@ def thread_nicegui():
hpt = hpt+1
if systemValve > 0:
hpt = hpt-random.randint(0, 1)
+ if boSen > 0:
+ hpt=hpt-random.randint(0, 5)
delay = delay+1
# System Valve
@@ -122,22 +289,85 @@ def thread_nicegui():
sysSen=1
sysCard.style(f'background-color: green; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
sysLabel.set_text("Operational: " + str(sysSen))
+ SoverlayWorking.style(
+ 'position: absolute; top: 140px; left: 680px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ SoverlayError.style(
+ 'position: absolute; top: 165px; left: 680px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
else:
sysSen=0
sysCard.style(f'background-color: red; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
sysLabel.set_text("Non operational: " + str(sysSen))
+ SoverlayWorking.style(
+ 'position: absolute; top: 140px; left: 680px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ SoverlayError.style(
+ 'position: absolute; top: 165px; left: 680px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+
+ # Control System Valve Overlay
+ if systemValve>0:
+ SVoverlayOpen.style(
+ 'position: absolute; top: 245px; left: 620px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ SVoverlayClosed.style(
+ 'position: absolute; top: 270px; left: 620px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ else:
+ SVoverlayOpen.style(
+ 'position: absolute; top: 245px; left: 620px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ SVoverlayClosed.style(
+ 'position: absolute; top: 270px; left: 620px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
# Blowout if the HPTpressure if over 220 until HTP pressure < 201
if hpt>220 or (boSen==1 and hpt>200):
boSen=1
boCard.style(f'background-color: red; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
- boLabel.set_text("Open: " + str(boSen))
- hpt=hpt-random.randint(0, 5)
+ boLabel.set_text("Open: " + str(boSen))
+ BOoverlayOpen.style(
+ 'position: absolute; top: 55px; left: 680px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ BOoverlayClosed.style(
+ 'position: absolute; top: 80px; left: 680px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
else:
boSen=0
boCard.style(f'background-color: green; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
boLabel.set_text("Closed: " + str(boSen))
+ BOoverlayOpen.style(
+ 'position: absolute; top: 55px; left: 680px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ BOoverlayClosed.style(
+ 'position: absolute; top: 80px; left: 680px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
if gst>255:
gst=255
@@ -176,38 +406,231 @@ def thread_nicegui():
cLabel.set_text(str(compressor))
hptLabel.set_text(str(hpt))
+ # HPT status
if hpt == 0:
hptCard.style(f'background-color: blue; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
hptLabel.set_text("Empty: " + str(hpt))
+ HPToverlayEmpty.style(
+ 'position: absolute; top: 210px; left: 495px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayLow.style(
+ 'position: absolute; top: 184px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayNormal.style(
+ 'position: absolute; top: 158px; left: 495px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayHigh.style(
+ 'position: absolute; top: 132px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayCritical.style(
+ 'position: absolute; top: 106px; left: 495px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
elif hpt < 50:
hptCard.style(f'background-color: white; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
hptLabel.set_text("Low: " + str(hpt))
+ HPToverlayEmpty.style(
+ 'position: absolute; top: 210px; left: 495px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayLow.style(
+ 'position: absolute; top: 184px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayNormal.style(
+ 'position: absolute; top: 158px; left: 495px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayHigh.style(
+ 'position: absolute; top: 132px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayCritical.style(
+ 'position: absolute; top: 106px; left: 495px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
elif hpt < 100:
hptCard.style(f'background-color: green; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
hptLabel.set_text("Normal: " + str(hpt))
+ HPToverlayEmpty.style(
+ 'position: absolute; top: 210px; left: 495px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayLow.style(
+ 'position: absolute; top: 184px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayNormal.style(
+ 'position: absolute; top: 158px; left: 495px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayHigh.style(
+ 'position: absolute; top: 132px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayCritical.style(
+ 'position: absolute; top: 106px; left: 495px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
elif hpt < 150:
hptCard.style(f'background-color: orange; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
hptLabel.set_text("High: " + str(hpt))
+ HPToverlayEmpty.style(
+ 'position: absolute; top: 210px; left: 495px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayLow.style(
+ 'position: absolute; top: 184px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayNormal.style(
+ 'position: absolute; top: 158px; left: 495px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayHigh.style(
+ 'position: absolute; top: 132px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ HPToverlayCritical.style(
+ 'position: absolute; top: 106px; left: 495px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
else:
hptCard.style(f'background-color: red; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
hptLabel.set_text("Critical: " + str(hpt))
+ HPToverlayEmpty.style(
+ 'position: absolute; top: 210px; left: 495px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayLow.style(
+ 'position: absolute; top: 184px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayNormal.style(
+ 'position: absolute; top: 158px; left: 495px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayHigh.style(
+ 'position: absolute; top: 132px; left: 495px; border-radius: 50%;'
+ 'background-color: white; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ HPToverlayCritical.style(
+ 'position: absolute; top: 106px; left: 495px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ # Display for compressor
if compressor:
cCard.style(f'background-color: green; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
cLabel.set_text("ON: " + str(compressor))
+ CoverlayOn.style(
+ 'position: absolute; top: 95px; left: 355px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ CoverlayOff.style(
+ 'position: absolute; top: 125px; left: 355px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
else:
cCard.style(f'background-color: red; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
cLabel.set_text("OFF: " + str(compressor))
+ CoverlayOn.style(
+ 'position: absolute; top: 95px; left: 355px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ CoverlayOff.style(
+ 'position: absolute; top: 125px; left: 355px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ # Display style for GST
if gst < 50:
gstCard.style(f'background-color: red; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
gstLabel.set_text("Low: " + str(gst))
+ GSToverlayLow.style(
+ 'position: absolute; top: 140px; left: 115px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ GSToverlayNormal.style(
+ 'position: absolute; top: 110px; left: 115px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ GSToverlayHigh.style(
+ 'position: absolute; top: 80px; left: 115px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: none;'
+ )
elif gst < 150:
gstCard.style(f'background-color: green; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
gstLabel.set_text("Normal: " + str(gst))
+ GSToverlayLow.style(
+ 'position: absolute; top: 140px; left: 115px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ GSToverlayNormal.style(
+ 'position: absolute; top: 110px; left: 115px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: block;'
+ )
+ GSToverlayHigh.style(
+ 'position: absolute; top: 80px; left: 115px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: none;'
+ )
else:
gstCard.style(f'background-color: blue; width: 200px; height: 100px; display: flex; justify-content: center; align-items: center;')
gstLabel.set_text("Full: " + str(gst))
+ GSToverlayLow.style(
+ 'position: absolute; top: 140px; left: 115px; border-radius: 50%;'
+ 'background-color: red; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ GSToverlayNormal.style(
+ 'position: absolute; top: 110px; left: 115px; border-radius: 50%;'
+ 'background-color: green; width: 5px; height: 5px;'
+ 'display: none;'
+ )
+ GSToverlayHigh.style(
+ 'position: absolute; top: 80px; left: 115px; border-radius: 50%;'
+ 'background-color: blue; width: 5px; height: 5px;'
+ 'display: block;'
+ )
- time.sleep(0.001) # OpenPLC has a Cycle time of 50ms
+ time.sleep(0.02) # OpenPLC has a Cycle time of 50ms
diff --git a/software/hwio-virtual/CybICS_logo.png b/software/hwio-virtual/pics/CybICS_logo.png
similarity index 100%
rename from software/hwio-virtual/CybICS_logo.png
rename to software/hwio-virtual/pics/CybICS_logo.png
diff --git a/software/hwio-virtual/favicon.ico b/software/hwio-virtual/pics/favicon.ico
similarity index 100%
rename from software/hwio-virtual/favicon.ico
rename to software/hwio-virtual/pics/favicon.ico
diff --git a/software/hwio-virtual/pics/pcb.png b/software/hwio-virtual/pics/pcb.png
new file mode 100644
index 0000000..88a54e4
Binary files /dev/null and b/software/hwio-virtual/pics/pcb.png differ