commit aac69b38ddecbf4024a227395d6fd09a28496fa2 Author: CarstenArend Date: Wed Sep 3 12:23:27 2025 +0200 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..dfe97db --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +#zeroPLC installer \ No newline at end of file diff --git a/dtoverlay/mcp23017_0x20_zeroplc.dtbo b/dtoverlay/mcp23017_0x20_zeroplc.dtbo new file mode 100644 index 0000000..1ec5d22 Binary files /dev/null and b/dtoverlay/mcp23017_0x20_zeroplc.dtbo differ diff --git a/dtoverlay/mcp23017_0x20_zeroplc.dts b/dtoverlay/mcp23017_0x20_zeroplc.dts new file mode 100644 index 0000000..c881779 --- /dev/null +++ b/dtoverlay/mcp23017_0x20_zeroplc.dts @@ -0,0 +1,156 @@ +/dts-v1/; + +/ { + compatible = "brcm,bcm2835"; + + fragment@100 { + target = <0xffffffff>; + phandle = <0x01>; + + __overlay__ { + status = "okay"; + phandle = <0x05>; + }; + }; + + fragment@101 { + target = <0xffffffff>; + + __dormant__ { + status = "okay"; + }; + }; + + fragment@102 { + target = <0xffffffff>; + + __dormant__ { + status = "okay"; + }; + }; + + __overrides__ { + i2c0 = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2b 31 30 31 2b 31 30 32 00]; + i2c_csi_dsi = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2b 31 30 31 2b 31 30 32 00]; + i2c_csi_dsi0 = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2b 31 30 31 2b 31 30 32 00]; + i2c1 = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2d 31 30 31 2d 31 30 32 00]; + i2c2 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63320000 0x2d 0x3130312d 0x31303200>; + i2c3 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63330000 0x2d 0x3130312d 0x31303200>; + i2c4 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63340000 0x2d 0x3130312d 0x31303200>; + i2c5 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63350000 0x2d 0x3130312d 0x31303200>; + i2c6 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63360000 0x2d 0x3130312d 0x31303200>; + i2c-path = [00 00 00 01 74 61 72 67 65 74 3f 3d 30 00 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 00 00 00 00 00 2d 31 30 31 2d 31 30 32 00]; + gpiopin = [00 00 00 02 62 72 63 6d 2c 70 69 6e 73 3a 30 00 00 00 00 03 69 6e 74 65 72 72 75 70 74 73 3a 30 00]; + addr = <0x04 0x7265673a 0x30000000 0x27265 0x673a3000>; + mcp23008 = [00 00 00 00 3d 32 00]; + noints = [00 00 00 00 21 31 21 33 00]; + }; + + fragment@1 { + target = <0xffffffff>; + + __overlay__ { + + mcp23017_pins@20 { + brcm,pins = <0x04>; + brcm,function = <0x00>; + phandle = <0x02>; + }; + }; + }; + + fragment@2 { + target = <0x04>; + + __dormant__ { + compatible = "microchip,mcp23008"; + }; + }; + + fragment@3 { + target = <0x04>; + + __overlay__ { + #interrupt-cells = <0x02>; + pinctrl-names = "default"; + pinctrl-0 = <0x02>; + interrupt-parent = <0xffffffff>; + interrupts = <0x04 0x02>; + interrupt-controller; + microchip,irq-mirror; + phandle = <0x03>; + }; + }; + + fragment@4 { + target = <0x05>; + + __overlay__ { + #address-cells = <0x01>; + #size-cells = <0x00>; + + mcp@20 { + compatible = "microchip,mcp23017"; + reg = <0x20>; + gpio-line-names = "AIN1_SWITCH_I/V","AIN2_SWITCH_I/V","AIN3_SWITCH_I/V","AIN4_SWITCH_I/V","AIN5_SWITCH_I/V","AIN6_SWITCH_I/V","AIN7_SWITCH_I/V","AIN8_SWITCH_I/V","NC","IN7","IN8","DIS_24VOUT_POE","5V_EXT_FAULT","5V_EXT_EN","RS485_120R","DIS_24VOUTPUTS"; + gpio-controller; + #gpio-cells = <0x02>; + status = "okay"; + phandle = <0x04>; + }; + }; + }; + + __symbols__ { + busfrag = "/fragment@100"; + i2cbus = "/fragment@100/__overlay__"; + mcp23017_pins = "/fragment@1/__overlay__/mcp23017_pins@20"; + mcp23017_irq = "/fragment@3/__overlay__"; + mcp23017 = "/fragment@4/__overlay__/mcp@20"; + }; + + __fixups__ { + i2c_arm = "/fragment@100:target:0"; + i2c0if = "/fragment@101:target:0"; + i2c0mux = "/fragment@102:target:0"; + i2c0 = "/__overrides__:i2c0:14"; + i2c_csi_dsi = "/__overrides__:i2c_csi_dsi:14"; + i2c_csi_dsi0 = "/__overrides__:i2c_csi_dsi0:14"; + i2c1 = "/__overrides__:i2c1:14"; + gpio = "/fragment@1:target:0\0/fragment@3/__overlay__:interrupt-parent:0"; + }; + + __local_fixups__ { + + __overrides__ { + i2c0 = <0x00 0x12>; + i2c_csi_dsi = <0x00 0x12>; + i2c_csi_dsi0 = <0x00 0x12>; + i2c1 = <0x00 0x12>; + i2c2 = <0x00 0x0e>; + i2c3 = <0x00 0x0e>; + i2c4 = <0x00 0x0e>; + i2c5 = <0x00 0x0e>; + i2c6 = <0x00 0x0e>; + i2c-path = <0x00 0x0e>; + gpiopin = <0x00 0x10>; + addr = <0x00 0x0a>; + }; + + fragment@2 { + target = <0x00>; + }; + + fragment@3 { + target = <0x00>; + + __overlay__ { + pinctrl-0 = <0x00>; + }; + }; + + fragment@4 { + target = <0x00>; + }; + }; +}; diff --git a/dtoverlay/mcp23017_0x21_zeroplc.dtbo b/dtoverlay/mcp23017_0x21_zeroplc.dtbo new file mode 100644 index 0000000..dcb6195 Binary files /dev/null and b/dtoverlay/mcp23017_0x21_zeroplc.dtbo differ diff --git a/dtoverlay/mcp23017_0x21_zeroplc.dts b/dtoverlay/mcp23017_0x21_zeroplc.dts new file mode 100644 index 0000000..b0f2245 --- /dev/null +++ b/dtoverlay/mcp23017_0x21_zeroplc.dts @@ -0,0 +1,156 @@ +/dts-v1/; + +/ { + compatible = "brcm,bcm2835"; + + fragment@100 { + target = <0xffffffff>; + phandle = <0x01>; + + __overlay__ { + status = "okay"; + phandle = <0x05>; + }; + }; + + fragment@101 { + target = <0xffffffff>; + + __dormant__ { + status = "okay"; + }; + }; + + fragment@102 { + target = <0xffffffff>; + + __dormant__ { + status = "okay"; + }; + }; + + __overrides__ { + i2c0 = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2b 31 30 31 2b 31 30 32 00]; + i2c_csi_dsi = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2b 31 30 31 2b 31 30 32 00]; + i2c_csi_dsi0 = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2b 31 30 31 2b 31 30 32 00]; + i2c1 = [00 00 00 01 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 3f 3d 30 00 00 00 00 00 2d 31 30 31 2d 31 30 32 00]; + i2c2 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63320000 0x2d 0x3130312d 0x31303200>; + i2c3 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63330000 0x2d 0x3130312d 0x31303200>; + i2c4 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63340000 0x2d 0x3130312d 0x31303200>; + i2c5 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63350000 0x2d 0x3130312d 0x31303200>; + i2c6 = <0x01 0x74617267 0x65743f3d 0x30000000 0x17461 0x72676574 0x2d706174 0x683d6932 0x63360000 0x2d 0x3130312d 0x31303200>; + i2c-path = [00 00 00 01 74 61 72 67 65 74 3f 3d 30 00 00 00 00 01 74 61 72 67 65 74 2d 70 61 74 68 00 00 00 00 00 2d 31 30 31 2d 31 30 32 00]; + gpiopin = [00 00 00 02 62 72 63 6d 2c 70 69 6e 73 3a 30 00 00 00 00 03 69 6e 74 65 72 72 75 70 74 73 3a 30 00]; + addr = <0x04 0x7265673a 0x30000000 0x27265 0x673a3000>; + mcp23008 = [00 00 00 00 3d 32 00]; + noints = [00 00 00 00 21 31 21 33 00]; + }; + + fragment@1 { + target = <0xffffffff>; + + __overlay__ { + + mcp23017_pins@20 { + brcm,pins = <0x04>; + brcm,function = <0x00>; + phandle = <0x02>; + }; + }; + }; + + fragment@2 { + target = <0x04>; + + __dormant__ { + compatible = "microchip,mcp23008"; + }; + }; + + fragment@3 { + target = <0x04>; + + __overlay__ { + #interrupt-cells = <0x02>; + pinctrl-names = "default"; + pinctrl-0 = <0x02>; + interrupt-parent = <0xffffffff>; + interrupts = <0x04 0x02>; + interrupt-controller; + microchip,irq-mirror; + phandle = <0x03>; + }; + }; + + fragment@4 { + target = <0x05>; + + __overlay__ { + #address-cells = <0x01>; + #size-cells = <0x00>; + + mcp@20 { + compatible = "microchip,mcp23017"; + reg = <0x21>; + gpio-line-names = "IN_FAULT","BUS_IO1","BUS_IO2","TFT_BACKLIGHT","NC","NC","NC","NC","NC","NC","NC","NC","OUT_DIAG","TFT_RST","TFT_RS","TOUCHT_RST"; + gpio-controller; + #gpio-cells = <0x02>; + status = "okay"; + phandle = <0x04>; + }; + }; + }; + + __symbols__ { + busfrag = "/fragment@100"; + i2cbus = "/fragment@100/__overlay__"; + mcp23017_pins = "/fragment@1/__overlay__/mcp23017_pins@20"; + mcp23017_irq = "/fragment@3/__overlay__"; + mcp23017 = "/fragment@4/__overlay__/mcp@20"; + }; + + __fixups__ { + i2c_arm = "/fragment@100:target:0"; + i2c0if = "/fragment@101:target:0"; + i2c0mux = "/fragment@102:target:0"; + i2c0 = "/__overrides__:i2c0:14"; + i2c_csi_dsi = "/__overrides__:i2c_csi_dsi:14"; + i2c_csi_dsi0 = "/__overrides__:i2c_csi_dsi0:14"; + i2c1 = "/__overrides__:i2c1:14"; + gpio = "/fragment@1:target:0\0/fragment@3/__overlay__:interrupt-parent:0"; + }; + + __local_fixups__ { + + __overrides__ { + i2c0 = <0x00 0x12>; + i2c_csi_dsi = <0x00 0x12>; + i2c_csi_dsi0 = <0x00 0x12>; + i2c1 = <0x00 0x12>; + i2c2 = <0x00 0x0e>; + i2c3 = <0x00 0x0e>; + i2c4 = <0x00 0x0e>; + i2c5 = <0x00 0x0e>; + i2c6 = <0x00 0x0e>; + i2c-path = <0x00 0x0e>; + gpiopin = <0x00 0x10>; + addr = <0x00 0x0a>; + }; + + fragment@2 { + target = <0x00>; + }; + + fragment@3 { + target = <0x00>; + + __overlay__ { + pinctrl-0 = <0x00>; + }; + }; + + fragment@4 { + target = <0x00>; + }; + }; +}; diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..d816adb --- /dev/null +++ b/install.sh @@ -0,0 +1,139 @@ +#/bin/bash + +#test for root privilege +if [ $(id -u) -ne 0 ] + then echo "Please run this script using sudo!" + exit +fi + +echo +echo "#################################################################" +echo "#### Welcome! ####" +echo "#### zeroPLC Installer v1.0 ####" +echo "#################################################################" +echo +echo +sleep 1 + +echo "#################################################################" +echo "#### Downloading files ####" +echo "#################################################################" +sleep 1 + +cd /home/$SUDO_USER +wget https://git.sqegmbh.de/zeroPLC/zeroPLC-installer/archive/master.zip +#check wget exit code +if [ $? -ne 0 ] + then echo "Error downloading files, exiting" + exit +fi +unzip -q master.zip +cd zeroplc-installer +sleep 1 + +echo +echo +echo "#################################################################" +echo "#### Activating device tree overlays ####" +echo "#################################################################" +sleep 1 + +echo "Copying overlay files" +cp ./dtoverlay/mcp23017_0x20_zeroplc.dtbo /boot/overlays/ +cp ./dtoverlay/mcp23017_0x21_zeroplc.dtbo /boot/overlays/ + +echo "Activating overlays in /boot/firmware/config.txt" +cat <> /boot/firmware/config.txt +dtparam=i2c_arm=on +dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=23,i2c_gpio_scl=24 + +dtoverlay=w1-gpio + +enable_uart=1 + +dtparam=spi=on +dtoverlay=spi0-0cs + +dtoverlay=mcp23017_0x20_zeroplc,noints=1 +dtoverlay=mcp23017_0x21_zeroplc,addr=0x21,noints=1 + +dtoverlay=i2c-rtc,pcf8523 + +dtoverlay=ads1015,addr=0x4b +dtparam=cha_enable=true,cha_cfg=4,cha_gain=0 +dtparam=chb_enable=true,chb_cfg=5,chb_gain=0 +dtparam=chc_enable=true,chc_cfg=6,chc_gain=0 +dtparam=chd_enable=true,chd_cfg=7,chd_gain=0 + +dtoverlay=ads1015,addr=0x49 +dtparam=cha_enable=true,cha_cfg=4,cha_gain=0 +dtparam=chb_enable=true,chb_cfg=5,chb_gain=0 +dtparam=chc_enable=true,chc_cfg=6,chc_gain=0 +dtparam=chd_enable=true,chd_cfg=7,chd_gain=0 +EOF + +#load i2c-dev module, done by raspi-config when enabling i2c there +echo i2c-dev >> /etc/modules +#disable console on serial (will change /boot/firmware/cmdline.txt) +echo "Disabling console on serial" +raspi-config nonint do_serial_cons 1 + +echo "Done!" +sleep 1 + +echo +echo +echo "#################################################################" +echo "#### Activating RTC ####" +echo "#################################################################" +sleep 1 + +apt -y remove fake-hwclock +update-rc.d -f fake-hwclock remove +systemctl disable fake-hwclock + +#GUI +echo +echo +echo "#################################################################" +echo "#### zeroPLC testing gui ####" +echo "#################################################################" +sleep 1 + +while true; do +read -p "Do you want to intall the zeroPLCgui for simple testing of hardware functions? (yes/no) " yn +case $yn in + yes ) echo Starting zeroPLCgui installation to zeroPLCgui folder in home directory; + break;; + no ) cd ..; + rm -r /home/$SUDO_USER/zeroplc-installer; + echo Exiting installer, please reboot the system; + exit;; + * ) echo invalid response;; +esac +done + +apt update +apt -y install python3-pip python3-picamera2 + +mv /home/$SUDO_USER/zeroplc-installer/zeroPLCgui /home/$SUDO_USER/ +cd /home/$SUDO_USER/zeroPLCgui + +chmod +x gui.py + +echo "Creating python venv" +sleep 1 +python3 -m venv --system-site-packages .venv +. /home/$SUDO_USER/zeroPLCgui/.venv/bin/activate + +echo "Installing python packages" +sleep 1 +pip3 install nicegui adafruit-circuitpython-tmp117 adafruit-circuitpython-sht4x adafruit-extended-bus +deactivate + +chown -R $SUDO_USER:$SUDO_USER /home/$SUDO_USER/zeroPLCgui +rm -r /home/$SUDO_USER/zeroplc-installer +echo +echo "Installation finished, start gui with ./gui.py" +sleep 1 +echo "Exiting installer" diff --git a/zeroPLCgui/gui.py b/zeroPLCgui/gui.py new file mode 100644 index 0000000..7303d24 --- /dev/null +++ b/zeroPLCgui/gui.py @@ -0,0 +1,388 @@ +#!/usr/bin/env bash +'''exec' "$HOME/zeroPLCgui/.venv/bin/python3" "$0" "$@" +' ''' + +from nicegui import ui,app +import os,sys +import gpiod +import atexit +import board +import adafruit_tmp117 +import adafruit_sht4x +from adafruit_extended_bus import ExtendedI2C as I2C + +from picamera2 import Picamera2 +from fastapi.responses import StreamingResponse +import io +from PIL import Image +import time + +picam2 = None +camera_connected = 0 + +def init_camera(): + global picam2 + picam2 = Picamera2() + picam2.configure(picam2.create_preview_configuration(main={"format": 'XRGB8888', "size": (640, 480)})) + picam2.start() + + +def generate_mjpeg(): + while True: + img = picam2.capture_array() + pil_img = Image.fromarray(img) + if pil_img.mode == 'RGBA': + pil_img = pil_img.convert('RGB') + buf = io.BytesIO() + pil_img.save(buf, format='JPEG') + frame = buf.getvalue() + + yield ( + b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n' + ) + time.sleep(0.1) + +@app.get('/video_feed') +def video_feed(): + return StreamingResponse(generate_mjpeg(), media_type='multipart/x-mixed-replace; boundary=frame') + +i2c = board.I2C() # uses board.SCL and board.SDA +tmp117 = adafruit_tmp117.TMP117(i2c) + +i2c3=I2C(3) +try: + sht = adafruit_sht4x.SHT4x(i2c3,0x46) +except: + sht = 0 + +# Do not request the line upfront; request and release on demand +chip = gpiod.Chip('gpiochip0') +chip2 = gpiod.Chip('gpiochip2') +output1 = chip.get_line(12) +output2 = chip.get_line(13) +output3 = chip.get_line(18) +output4 = chip.get_line(19) +output5 = chip.get_line(20) +output6 = chip.get_line(21) +output7 = chip.get_line(22) +output8 = chip.get_line(26) +input1 = chip.get_line(5) +input2 = chip.get_line(6) +input3 = chip.get_line(7) +input4 = chip.get_line(8) +input5 = chip.get_line(27) +input6 = chip.get_line(25) +input7 = chip2.get_line(9) +input8 = chip2.get_line(10) + +def set_output1(): + try: + output1.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output1.set_value(switch_1.value) + output1.release() + except OSError as e: + print(f"Output1 error: {e}") + +def set_output2(): + try: + output2.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output2.set_value(switch_2.value) + output2.release() + except OSError as e: + print(f"Output2 error: {e}") + +def set_output3(): + try: + output3.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output3.set_value(switch_3.value) + output3.release() + except OSError as e: + print(f"Output3 error: {e}") + +def set_output4(): + try: + output4.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output4.set_value(switch_4.value) + output4.release() + except OSError as e: + print(f"Output4 error: {e}") + +def set_output5(): + try: + output5.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output5.set_value(switch_5.value) + output5.release() + except OSError as e: + print(f"Output5 error: {e}") + +def set_output6(): + try: + output6.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output6.set_value(switch_6.value) + output6.release() + except OSError as e: + print(f"Output6 error: {e}") + +def set_output7(): + try: + output7.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output7.set_value(switch_7.value) + output7.release() + except OSError as e: + print(f"Output7 error: {e}") + +def set_output8(): + try: + output8.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_OUT) + output8.set_value(switch_8.value) + output8.release() + except OSError as e: + print(f"Output8 error: {e}") + +def get_input1(): + try: + input1.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input1.get_value(): + input1_indicator.classes('text-green', remove='text-red') + else: + input1_indicator.classes('text-red', remove='text-green') + input1.release() + except OSError as e: + print(f"Input1 error: {e}") + +def get_input2(): + try: + input2.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input2.get_value(): + input2_indicator.classes('text-green', remove='text-red') + else: + input2_indicator.classes('text-red', remove='text-green') + input2.release() + except OSError as e: + print(f"Input2 error: {e}") + +def get_input3(): + try: + input3.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input3.get_value(): + input3_indicator.classes('text-green', remove='text-red') + else: + input3_indicator.classes('text-red', remove='text-green') + input3.release() + except OSError as e: + print(f"Input3 error: {e}") + +def get_input4(): + try: + input4.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input4.get_value(): + input4_indicator.classes('text-green', remove='text-red') + else: + input4_indicator.classes('text-red', remove='text-green') + input4.release() + except OSError as e: + print(f"Input4 error: {e}") + +def get_input5(): + try: + input5.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input5.get_value(): + input5_indicator.classes('text-green', remove='text-red') + else: + input5_indicator.classes('text-red', remove='text-green') + input5.release() + except OSError as e: + print(f"Input5 error: {e}") + +def get_input6(): + try: + input6.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input6.get_value(): + input6_indicator.classes('text-green', remove='text-red') + else: + input6_indicator.classes('text-red', remove='text-green') + input6.release() + except OSError as e: + print(f"Input6 error: {e}") + +def get_input7(): + try: + input7.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input7.get_value(): + input7_indicator.classes('text-green', remove='text-red') + else: + input7_indicator.classes('text-red', remove='text-green') + input7.release() + except OSError as e: + print(f"Input7 error: {e}") + +def get_input8(): + try: + input8.request(consumer='nicegui', type=gpiod.LINE_REQ_DIR_IN) + if input8.get_value(): + input8_indicator.classes('text-green', remove='text-red') + else: + input8_indicator.classes('text-red', remove='text-green') + input8.release() + except OSError as e: + print(f"Input8 error: {e}") + +atexit.register(lambda: output1.release()) +atexit.register(lambda: output2.release()) +atexit.register(lambda: output3.release()) +atexit.register(lambda: output4.release()) +atexit.register(lambda: output5.release()) +atexit.register(lambda: output6.release()) +atexit.register(lambda: output7.release()) +atexit.register(lambda: output8.release()) +atexit.register(lambda: input1.release()) +atexit.register(lambda: input2.release()) +atexit.register(lambda: input3.release()) +atexit.register(lambda: input4.release()) +atexit.register(lambda: input5.release()) +atexit.register(lambda: input6.release()) +atexit.register(lambda: input7.release()) +atexit.register(lambda: input8.release()) + +ui.markdown('#zeroPLC') +ui.markdown('##24V Outputs') +with ui.row(): + switch_1 = ui.switch('Output 1', on_change=set_output1) + switch_2 = ui.switch('Output 2', on_change=set_output2) + switch_3 = ui.switch('Output 3', on_change=set_output3) + switch_4 = ui.switch('Output 4', on_change=set_output4) + switch_5 = ui.switch('Output 5', on_change=set_output5) + switch_6 = ui.switch('Output 6', on_change=set_output6) + switch_7 = ui.switch('Output 7', on_change=set_output7) + switch_8 = ui.switch('Output 8', on_change=set_output8) + +ui.markdown('##24V Digital Inputs') +with ui.row(): + input1_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 1') + input2_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 2') + input3_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 3') + input4_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 4') + input5_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 5') + input6_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 6') + input7_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 7') + input8_indicator = ui.icon('fiber_manual_record', size='2em').classes('drop-shadow text-red') + ui.label('Input 8') + ui.timer(0.5, get_input1) + ui.timer(0.5, get_input2) + ui.timer(0.5, get_input3) + ui.timer(0.5, get_input4) + ui.timer(0.5, get_input5) + ui.timer(0.5, get_input6) + ui.timer(0.5, get_input7) + ui.timer(0.5, get_input8) + +table_rows = [ + {'Input': str(i + 1), 'Voltage': 0.0} for i in range(8) +] + +# Example function to update voltages +def get_analog_inputs(): + value = [0] * 8 + with open('/sys/bus/iio/devices/iio:device1/in_voltage0_raw', 'r') as f: + value[0]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device1/in_voltage1_raw', 'r') as f: + value[1]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device1/in_voltage2_raw', 'r') as f: + value[2]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device1/in_voltage3_raw', 'r') as f: + value[3]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device0/in_voltage0_raw', 'r') as f: + value[4]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device0/in_voltage1_raw', 'r') as f: + value[5]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device0/in_voltage2_raw', 'r') as f: + value[6]=int(f.read())*3/500 + with open('/sys/bus/iio/devices/iio:device0/in_voltage3_raw', 'r') as f: + value[7]=int(f.read())*3/500 + for i in range(8): + table_rows[i]['Voltage'] = value[i] + table.rows = table_rows + table.update() + +ui.markdown('##10V Analog Inputs') +with ui.row(): + # Create the table + table = ui.table( + columns=[ + {'name': 'Input', 'label': 'Input', 'field': 'Input'}, + {'name': 'Voltage', 'label': 'Voltage', 'field': 'Voltage'}, + ], + rows=table_rows, +) + ui.timer(0.5, get_analog_inputs) + +ui.markdown('##Communication') +ui.markdown('####Onewire') +def get_onewire(): + try: + with open('/sys/bus/w1/devices/28-ca795e1e64ff/temperature', 'r') as f: + value=int(f.read())/1000 + onewirelabel.set_text("DS18B20 onewire sensor: %.2f °C"%value) + except: + onewirelabel.set_text("not connected") + +with ui.row(): + onewirelabel = ui.label() + ui.timer(1, get_onewire) + +ui.markdown('####I2C') +with ui.row(): + tmp117label = ui.label() + ui.timer(1, lambda: tmp117label.set_text("Onboard TMP117 temperature: %.2f °C"%tmp117.temperature)) + +ui.markdown('####Differential I2C') +def get_diffi2c(): + if sht == 0: + sht40label.set_text("not connected") + else: + temperature, relative_humidity = sht.measurements + sht40label.set_text("SHT40 sensor: %.2f °C %0.1f %%"%(temperature, relative_humidity)) + + +with ui.row(): + sht40label = ui.label() + ui.timer(1, get_diffi2c) + +app.add_static_files('/static', 'static') + +ui.query("body").style( + "background-image: url('/static/zeroplc.jpg');" + "background-size: contain;" + "background-position: center;" + "background-repeat: no-repeat;" +) + +def main(): + try: + init_camera() + camera_connected = 1 + except: + camera_connected = 0 + ui.markdown('####Camera') + with ui.row().classes('w-full justify-left'): + if camera_connected != 0: + ui.html(''' +
+ +
+ ''') + else: + ui.html('

No camera connected

') + ui.run(reload=False) + +if __name__ == '__main__': + main() + diff --git a/zeroPLCgui/static/zeroplc.jpg b/zeroPLCgui/static/zeroplc.jpg new file mode 100644 index 0000000..e088565 Binary files /dev/null and b/zeroPLCgui/static/zeroplc.jpg differ