From 7b35ad4a28c2c030c205ef7a6c2bb488194b4f4d Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Mon, 11 Jul 2016 12:01:58 -0400 Subject: [PATCH 001/239] hmi --- plants/oil-refinery/Display_Oil.py | 84 +++++++++++++ plants/oil-refinery/hmi_oil.py | 187 +++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100755 plants/oil-refinery/Display_Oil.py create mode 100755 plants/oil-refinery/hmi_oil.py diff --git a/plants/oil-refinery/Display_Oil.py b/plants/oil-refinery/Display_Oil.py new file mode 100755 index 0000000..96bd964 --- /dev/null +++ b/plants/oil-refinery/Display_Oil.py @@ -0,0 +1,84 @@ +# for logging events +import logging + +# imports the twisted software and uses the reactor function to drive the inferace +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +# Log Information +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Utility Functions +def PLCSetTag(addr, value): + context[0x0].setValues(3, addr, [value]) + +def PLCGetTag(addr): + return context[0x0].getValues(3, addr, count=1)[0] + +# "Constants" +SCREEN_WIDTH = 600 +SCREEN_HEIGHT = 350 +FPS=50.0 + +MODBUS_SERVER_PORT=5020 + +PLC_TAG_LEVEL_SENSOR = 0x1 +PLC_TAG_LIMIT_SWITCH = 0x2 +PLC_TAG_OIL_BARREL = 0x4 +PLC_TAG_RUN = 0x10 + +#Global Variable +#global boiler + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +def add_oil(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(181,182) + body.position = x, 410 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = 0x5 #liquid + space.add(body, shape) + return shape + +def draw_oil(screen, ball, color=THECOLORS['brown4']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +def oil_barrel(space): + body = pymunk.Body() + body.position = (100, 480) + shape = pymunk.Poly.create_box(body, (80, 100), (0, 0), 0) + space.add(shape) + return shape + +def boiler(space): + mass = 100 + inertia = 0xFFFFFFFFF + body = pymunk.Body(mass, inertia) + body.position = (130,300) + l1 = pymunk.Segment(body, (-150, 0), (-100, 0), 2.0) + l2 = pymunk.Segment(body, (-150, 0), (-150, 100), 2.0) + l3 = pymunk.Segment(body, (-100, 0), (-100, 100), 2.0) \ No newline at end of file diff --git a/plants/oil-refinery/hmi_oil.py b/plants/oil-refinery/hmi_oil.py new file mode 100755 index 0000000..dba16f1 --- /dev/null +++ b/plants/oil-refinery/hmi_oil.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python + +from gi.repository import GLib, Gtk, GObject +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import pygtk +import socket + +s = socket.socket() +host = '192.168.228.143' +port = 5020 +s.connect((host, port)) +#print s.recv(1024) + +MODBUS_SLEEP=1 + +class HMIWindow(Gtk.Window): + + def initModbus(self): + + self.modbusClient = ModbusClient('localhost', port=5020) + + def resetLabels(self): + self.crudeOilValue.set_markup("STOPPED") + self.boilerValveValue.set_markup("CLOSED") + self.boilerTempValue.set_markup("NORMAL") + self.processStatusValue.set_markup("STOPPED") + self.connectionStatusValue.set_markup("OFFLINE") + self.distTwrValveValue.set_markup("CLOSED") + + def __init__(self): + Gtk.Window.__init__(self, title="Oil Refining - HMI - Oil Refinery") + + self.set_border_width(100) + + self.initModbus() + + elementIndex = 0 + + # Grid + grid = Gtk.Grid() + grid.set_row_spacing(15) + grid.set_column_spacing(10) + self.add(grid) + + # Main title label + label = Gtk.Label() + label.set_markup("Oil Refining Process") + grid.attach(label, 0, elementIndex, 2, 1) + elementIndex += 1 + + # Crude Oil barrel + crudeOilLabel = Gtk.Label("Crude Oil Dumping Status") + crudeOilValue = Gtk.Label() + grid.attach(crudeOilLabel, 0, elementIndex, 1, 1) + grid.attach(crudeOilValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Boiler Valve + boilerValveLabel = Gtk.Label("Boiler Valve Status") + boilerValveValue = Gtk.Label() + grid.attach(boilerValveLabel, 0, elementIndex, 1, 1) + grid.attach(boilerValveValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Boiler Temperature + boilerTempLabel = Gtk.Label("Boiler Temperature") + boilerTempValue = Gtk.Label() + grid.attach(boilerTempLabel, 0, elementIndex, 1, 1) + grid.attach(boilerTempValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Distillation Tower + distTwrValveLabel = Gtk.Label("Distillation Tower Valve") + distTwrValveValue = Gtk.Label() + grid.attach(distTwrValveLabel, 0, elementIndex, 1, 1) + grid.attach(distTwrValveValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Process status + processStatusLabel = Gtk.Label("Process Status") + processStatusValue = Gtk.Label() + grid.attach(processStatusLabel, 0, elementIndex, 1, 1) + grid.attach(processStatusValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Connection status + connectionStatusLabel = Gtk.Label("Connection Status") + connectionStatusValue = Gtk.Label() + grid.attach(connectionStatusLabel, 0, elementIndex, 1, 1) + grid.attach(connectionStatusValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Run and Stop buttons + runButton = Gtk.Button("Run") + stopButton = Gtk.Button("Stop") + + runButton.connect("clicked", self.setProcess, 1) + stopButton.connect("clicked", self.setProcess, 0) + + grid.attach(runButton, 0, elementIndex, 1, 1) + grid.attach(stopButton, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Oil Refienery branding + virtualRefienery = Gtk.Label() + virtualRefienery.set_markup("Oil Refinery - HMI") + grid.attach(virtualRefienery, 0, elementIndex, 2, 1) + + # Attach Value Labels + self.crudeOilValue = crudeOilValue + self.boilerValveValue = boilerValveValue + self.boilerTempValue = boilerTempValue + self.distTwrValveValue = distTwrValveValue + self.processStatusValue = processStatusValue + self.connectionStatusValue = connectionStatusValue + + self.resetLabels() + GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) + + def setProcess(self, widget, data=None): + try: + self.modbusClient.write_register(0x10, data) + except: + pass + + def update_status(self): + + try: + rr = self.modbusClient.read_holding_registers(1,16) + regs = [] + + if not rr or not rr.registers: + raise ConnectionException + + regs = rr.registers + + if not regs or len(regs) < 16: + raise ConnectionException + + if regs[1] == 1: + self.crudeOilValue.set_markup("YES") + else: + self.crudeOilValue.set_markup("NO") + + if regs[0] == 1: + self.boilerValveValue.set_markup("OPEN") + else: + self.boilerValveValue.set_markup("CLOSED") + + if regs[2] == 1: + self.boilerTempValue.set_markup("NORMAL") + else: + self.boilerTempValue.set_markup("HOT") + + if regs[3] == 1: + self.distTwrValveValue.set_markup("OPEN") + else: + self.distTwrValveValue.set_markup("CLOSED") + + if regs[15] == 1: + self.processStatusValue.set_markup("RUNNING") + else: + self.processStatusValue.set_markup("STOPPED") + + self.connectionStatusValue.set_markup("ONLINE") + + + except ConnectionException: + if not self.modbusClient.connect(): + self.resetLabels() + except: + raise + finally: + return True + +def app_main(): + win = HMIWindow() + win.connect("delete-event", Gtk.main_quit) + win.connect("destroy", Gtk.main_quit) + win.show_all() + + +if __name__ == "__main__": + GObject.threads_init() + app_main() + Gtk.main() From 5e0a8867923e0129bc27aaeea1e8e63ae0611859 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Mon, 11 Jul 2016 12:54:32 -0400 Subject: [PATCH 002/239] Test commit --- test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +test From d876fccf92aea5ac2dad4ca0b9395105af31deae Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Mon, 11 Jul 2016 12:56:53 -0400 Subject: [PATCH 003/239] Renamed worlds and added attacks and start script to oil dir --- plants/oil-refinery/attacks/move_and_fill.py | 27 +++++++++++++++++++ plants/oil-refinery/attacks/never_stop.py | 27 +++++++++++++++++++ plants/oil-refinery/attacks/stop_all.py | 27 +++++++++++++++++++ plants/oil-refinery/attacks/stop_and_fill.py | 27 +++++++++++++++++++ .../oil-refinery/{hmi_oil.py => oil_hmi.py} | 0 .../{Display_Oil.py => oil_world.py} | 0 plants/oil-refinery/start.sh | 7 +++++ test.txt | 1 - 8 files changed, 115 insertions(+), 1 deletion(-) create mode 100755 plants/oil-refinery/attacks/move_and_fill.py create mode 100755 plants/oil-refinery/attacks/never_stop.py create mode 100755 plants/oil-refinery/attacks/stop_all.py create mode 100755 plants/oil-refinery/attacks/stop_and_fill.py rename plants/oil-refinery/{hmi_oil.py => oil_hmi.py} (100%) rename plants/oil-refinery/{Display_Oil.py => oil_world.py} (100%) create mode 100755 plants/oil-refinery/start.sh delete mode 100644 test.txt diff --git a/plants/oil-refinery/attacks/move_and_fill.py b/plants/oil-refinery/attacks/move_and_fill.py new file mode 100755 index 0000000..b1d99c2 --- /dev/null +++ b/plants/oil-refinery/attacks/move_and_fill.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient('localhost', port=5020) + +try: + client.connect() + while True: + rq = client.write_register(0x10, 1) # Run Plant, Run! + rq = client.write_register(0x1, 0) # Level Sensor + rq = client.write_register(0x2, 0) # Limit Switch + rq = client.write_register(0x3, 1) # Motor + rq = client.write_register(0x4, 1) # Nozzle +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery/attacks/never_stop.py b/plants/oil-refinery/attacks/never_stop.py new file mode 100755 index 0000000..2d1469e --- /dev/null +++ b/plants/oil-refinery/attacks/never_stop.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient('localhost', port=5020) + +try: + client.connect() + while True: + rq = client.write_register(0x10, 1) # Run Plant, Run! + rq = client.write_register(0x1, 0) # Level Sensor + rq = client.write_register(0x2, 0) # Limit Switch + rq = client.write_register(0x3, 1) # Motor + rq = client.write_register(0x4, 0) # Nozzle +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery/attacks/stop_all.py b/plants/oil-refinery/attacks/stop_all.py new file mode 100755 index 0000000..6719d3c --- /dev/null +++ b/plants/oil-refinery/attacks/stop_all.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient('localhost', port=5020) + +try: + client.connect() + while True: + rq = client.write_register(0x10, 1) # Run Plant, Run! + rq = client.write_register(0x1, 0) # Level Sensor + rq = client.write_register(0x2, 1) # Limit Switch + rq = client.write_register(0x3, 0) # Motor + rq = client.write_register(0x4, 0) # Nozzle +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery/attacks/stop_and_fill.py b/plants/oil-refinery/attacks/stop_and_fill.py new file mode 100755 index 0000000..63517ae --- /dev/null +++ b/plants/oil-refinery/attacks/stop_and_fill.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient('localhost', port=5020) + +try: + client.connect() + while True: + rq = client.write_register(0x10, 1) # Run Plant, Run! + rq = client.write_register(0x1, 0) # Level Sensor + rq = client.write_register(0x2, 1) # Limit Switch + rq = client.write_register(0x3, 0) # Motor + rq = client.write_register(0x4, 1) # Nozzle +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery/hmi_oil.py b/plants/oil-refinery/oil_hmi.py similarity index 100% rename from plants/oil-refinery/hmi_oil.py rename to plants/oil-refinery/oil_hmi.py diff --git a/plants/oil-refinery/Display_Oil.py b/plants/oil-refinery/oil_world.py similarity index 100% rename from plants/oil-refinery/Display_Oil.py rename to plants/oil-refinery/oil_world.py diff --git a/plants/oil-refinery/start.sh b/plants/oil-refinery/start.sh new file mode 100755 index 0000000..ea428f2 --- /dev/null +++ b/plants/oil-refinery/start.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +echo "VirtuaPlant -- Bottle-filling Factory" +echo "- Starting World View" +./world.py & +echo "- Starting HMI" +./hmi.py & diff --git a/test.txt b/test.txt deleted file mode 100644 index 9daeafb..0000000 --- a/test.txt +++ /dev/null @@ -1 +0,0 @@ -test From ec96b413ba8afa7b8475b8c714726419f7501298 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Mon, 11 Jul 2016 13:04:30 -0400 Subject: [PATCH 004/239] world.py now runs listening on network instead of localhost --- plants/bottle-filling/world.py | 2 +- plants/bottle-filling/world.py~ | 354 ++++++++++++++++++++++++++++++++ plants/oil-refinery/start.sh | 4 +- 3 files changed, 357 insertions(+), 3 deletions(-) create mode 100755 plants/bottle-filling/world.py~ diff --git a/plants/bottle-filling/world.py b/plants/bottle-filling/world.py index 0d9f1ac..66a20a9 100755 --- a/plants/bottle-filling/world.py +++ b/plants/bottle-filling/world.py @@ -344,7 +344,7 @@ def runWorld(): def startModbusServer(): - StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) + StartTcpServer(context, identity=identity, address=("172.27.158.32", MODBUS_SERVER_PORT)) def main(): reactor.callInThread(runWorld) diff --git a/plants/bottle-filling/world.py~ b/plants/bottle-filling/world.py~ new file mode 100755 index 0000000..0d9f1ac --- /dev/null +++ b/plants/bottle-filling/world.py~ @@ -0,0 +1,354 @@ +#!/usr/bin/env python + +######################################### +# Imports +######################################### +# - Logging +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +######################################### +# Logging +######################################### +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +######################################### +# Util Functions +######################################### +def PLCSetTag(addr, value): + context[0x0].setValues(3, addr, [value]) + +def PLCGetTag(addr): + return context[0x0].getValues(3, addr, count=1)[0] + +######################################### +# World Code +######################################### + +# "Constants" +SCREEN_WIDTH = 600 +SCREEN_HEIGHT = 350 +FPS=50.0 + +MODBUS_SERVER_PORT=5020 + +PLC_TAG_LEVEL_SENSOR = 0x1 +PLC_TAG_LIMIT_SWITCH = 0x2 +PLC_TAG_MOTOR = 0x3 +PLC_TAG_NOZZLE = 0x4 +PLC_TAG_RUN = 0x10 + +# Global Variables +global bottles +bottles = [] + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Shape functions + +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(181,182) + body.position = x, 410 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = 0x5 #liquid + space.add(body, shape) + return shape + +def draw_ball(screen, ball, color=THECOLORS['blue']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +def add_bottle_in_sensor(space): + + body = pymunk.Body() + body.position = (40, 300) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x7 # 'bottle_in' + space.add(shape) + return shape + +def add_level_sensor(space): + + body = pymunk.Body() + body.position = (155, 380) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x4 # level_sensor + space.add(shape) + return shape + +def add_limit_switch(space): + + body = pymunk.Body() + body.position = (200, 300) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x1 # switch + space.add(shape) + return shape + +def add_nozzle(space): + + body = pymunk.Body() + body.position = (180, 430) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +def add_base(space): + + body = pymunk.Body() + body.position = (0, 300) + shape = pymunk.Poly.create_box(body, (SCREEN_WIDTH, 20), ((SCREEN_WIDTH/2), -10), 0) + shape.friction = 1.0 + shape.collision_type = 0x6 # base + space.add(shape) + return shape + +def add_bottle(space): + mass = 10 + inertia = 0xFFFFFFFFF + body = pymunk.Body(mass, inertia) + body.position = (130,300) + l1 = pymunk.Segment(body, (-150, 0), (-100, 0), 2.0) + l2 = pymunk.Segment(body, (-150, 0), (-150, 100), 2.0) + l3 = pymunk.Segment(body, (-100, 0), (-100, 100), 2.0) + + # Glass friction + l1.friction = 0.94 + l2.friction = 0.94 + l3.friction = 0.94 + + # Set collision types for sensors + l1.collision_type = 0x2 # bottle_bottom + l2.collision_type = 0x3 # bottle_side + l3.collision_type = 0x3 # bottle_side + + space.add(l1, l2, l3, body) + return l1,l2,l3 + +def draw_polygon(screen, shape): + + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(screen, THECOLORS['black'], fpoints) + + +def draw_lines(screen, lines, color=THECOLORS['dodgerblue4']): + """Draw the lines""" + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) + p2 = to_pygame(pv2) + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Collision handlers +def no_collision(space, arbiter, *args, **kwargs): + return False + +def level_ok(space, arbiter, *args, **kwargs): + + log.debug("Level reached") + PLCSetTag(PLC_TAG_LIMIT_SWITCH, 0) # Limit Switch Release, Fill Bottle + PLCSetTag(PLC_TAG_LEVEL_SENSOR, 1) # Level Sensor Hit, Bottle Filled + PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle + return False + +def bottle_in_place(space, arbiter, *args, **kwargs): + + log.debug("Bottle in place") + PLCSetTag(PLC_TAG_LIMIT_SWITCH, 1) + PLCSetTag(PLC_TAG_LEVEL_SENSOR, 0) + PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle + return False + +def add_new_bottle(space, arbiter, *args, **kwargs): + global bottles + bottles.append(add_bottle(space)) + log.debug("Adding new bottle") + return False + +def runWorld(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Bottle-Filling Factory - World View - VirtuaPlant") + clock = pygame.time.Clock() + running = True + + space = pymunk.Space() + space.gravity = (0.0, -900.0) + + # Limit switch with bottle bottom + space.add_collision_handler(0x1, 0x2, begin=bottle_in_place) + # Level sensor with water + space.add_collision_handler(0x4, 0x5, begin=level_ok) + # Level sensor with ground + space.add_collision_handler(0x4, 0x6, begin=no_collision) + # Limit switch with ground + space.add_collision_handler(0x1, 0x6, begin=no_collision) + # Limit switch with bottle side + space.add_collision_handler(0x1, 0x3, begin=no_collision) + # Level sensor with bottle side + space.add_collision_handler(0x4, 0x3, begin=no_collision) + # Bottle in with bottle sides and bottom + space.add_collision_handler(0x7, 0x2, begin=no_collision, separate=add_new_bottle) + space.add_collision_handler(0x7, 0x3, begin=no_collision) + + base = add_base(space) + nozzle = add_nozzle(space) + limit_switch = add_limit_switch(space) + level_sensor = add_level_sensor(space) + bottle_in = add_bottle_in_sensor(space) + + global bottles + bottles.append(add_bottle(space)) + + balls = [] + + ticks_to_next_ball = 1 + + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + screen.fill(THECOLORS["white"]) + + if PLCGetTag(PLC_TAG_RUN): + + # Motor Logic + if (PLCGetTag(PLC_TAG_LIMIT_SWITCH) == 1): + PLCSetTag(PLC_TAG_MOTOR, 0) + + if (PLCGetTag(PLC_TAG_LEVEL_SENSOR) == 1): + PLCSetTag(PLC_TAG_MOTOR, 1) + + ticks_to_next_ball -= 1 + + if not PLCGetTag(PLC_TAG_LIMIT_SWITCH): + PLCSetTag(PLC_TAG_MOTOR, 1) + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + # Move the bottles + if PLCGetTag(PLC_TAG_MOTOR) == 1: + for bottle in bottles: + bottle[0].body.position.x += 0.25 + else: + PLCSetTag(PLC_TAG_MOTOR, 0) + + # Draw water balls + # Remove off-screen balls + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 150 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(screen, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + # Draw bottles + for bottle in bottles: + if bottle[0].body.position.x > SCREEN_WIDTH+150 or bottle[0].body.position.y < 150: + space.remove(bottle, bottle[0].body) + bottles.remove(bottle) + continue + draw_lines(screen, bottle) + + # Draw the base and nozzle + draw_polygon(screen, base) + draw_polygon(screen, nozzle) + # Draw the limit switch + draw_ball(screen, limit_switch, THECOLORS['green']) + # Draw the level sensor + draw_ball(screen, level_sensor, THECOLORS['red']) + + title = fontMedium.render(str("Bottle-filling factory"), 1, THECOLORS['deepskyblue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + screen.blit(title, (10, 40)) + screen.blit(name, (10, 10)) + screen.blit(instructions, (SCREEN_WIDTH-115, 10)) + + space.step(1/FPS) + pygame.display.flip() + + # Stop reactor if running + if reactor.running: + reactor.callFromThread(reactor.stop) + +######################################### +# Modbus Server Code +######################################### + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +identity = ModbusDeviceIdentification() +identity.VendorName = 'MockPLCs' +identity.ProductCode = 'MP' +identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' +identity.ProductName = 'MockPLC 3000' +identity.ModelName = 'MockPLC Ultimate' +identity.MajorMinorRevision = '1.0' + +def startModbusServer(): + + StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(runWorld) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/start.sh b/plants/oil-refinery/start.sh index ea428f2..3c19e3d 100755 --- a/plants/oil-refinery/start.sh +++ b/plants/oil-refinery/start.sh @@ -2,6 +2,6 @@ echo "VirtuaPlant -- Bottle-filling Factory" echo "- Starting World View" -./world.py & +./oil_world.py & echo "- Starting HMI" -./hmi.py & +./oil_hmi.py & From 9bd9e9dfea68bb50e82ae07ffce3ab7a8736f7d9 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Mon, 11 Jul 2016 13:15:42 -0400 Subject: [PATCH 005/239] new hmi --- plants/oil-refinery/hmi_oil.py | 181 +++++++++++++++++++++++++++++++++ plants/oil-refinery/oil_hmi.py | 6 -- 2 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 plants/oil-refinery/hmi_oil.py diff --git a/plants/oil-refinery/hmi_oil.py b/plants/oil-refinery/hmi_oil.py new file mode 100644 index 0000000..f98bc5e --- /dev/null +++ b/plants/oil-refinery/hmi_oil.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python + +from gi.repository import GLib, Gtk, GObject +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import pygtk +import socket + +MODBUS_SLEEP=1 + +class HMIWindow(Gtk.Window): + + def initModbus(self): + + self.modbusClient = ModbusClient('localhost', port=5020) + + def resetLabels(self): + self.crudeOilValue.set_markup("STOPPED") + self.boilerValveValue.set_markup("CLOSED") + self.boilerTempValue.set_markup("NORMAL") + self.processStatusValue.set_markup("STOPPED") + self.connectionStatusValue.set_markup("OFFLINE") + self.distTwrValveValue.set_markup("CLOSED") + + def __init__(self): + Gtk.Window.__init__(self, title="Oil Refining - HMI - Oil Refinery") + + self.set_border_width(100) + + self.initModbus() + + elementIndex = 0 + + # Grid + grid = Gtk.Grid() + grid.set_row_spacing(15) + grid.set_column_spacing(10) + self.add(grid) + + # Main title label + label = Gtk.Label() + label.set_markup("Oil Refining Process") + grid.attach(label, 0, elementIndex, 2, 1) + elementIndex += 1 + + # Crude Oil barrel + crudeOilLabel = Gtk.Label("Crude Oil Dumping Status") + crudeOilValue = Gtk.Label() + grid.attach(crudeOilLabel, 0, elementIndex, 1, 1) + grid.attach(crudeOilValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Boiler Valve + boilerValveLabel = Gtk.Label("Boiler Valve Status") + boilerValveValue = Gtk.Label() + grid.attach(boilerValveLabel, 0, elementIndex, 1, 1) + grid.attach(boilerValveValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Boiler Temperature + boilerTempLabel = Gtk.Label("Boiler Temperature") + boilerTempValue = Gtk.Label() + grid.attach(boilerTempLabel, 0, elementIndex, 1, 1) + grid.attach(boilerTempValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Distillation Tower + distTwrValveLabel = Gtk.Label("Distillation Tower Valve") + distTwrValveValue = Gtk.Label() + grid.attach(distTwrValveLabel, 0, elementIndex, 1, 1) + grid.attach(distTwrValveValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Process status + processStatusLabel = Gtk.Label("Process Status") + processStatusValue = Gtk.Label() + grid.attach(processStatusLabel, 0, elementIndex, 1, 1) + grid.attach(processStatusValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Connection status + connectionStatusLabel = Gtk.Label("Connection Status") + connectionStatusValue = Gtk.Label() + grid.attach(connectionStatusLabel, 0, elementIndex, 1, 1) + grid.attach(connectionStatusValue, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Run and Stop buttons + runButton = Gtk.Button("Run") + stopButton = Gtk.Button("Stop") + + runButton.connect("clicked", self.setProcess, 1) + stopButton.connect("clicked", self.setProcess, 0) + + grid.attach(runButton, 0, elementIndex, 1, 1) + grid.attach(stopButton, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Oil Refienery branding + virtualRefienery = Gtk.Label() + virtualRefienery.set_markup("Oil Refinery - HMI") + grid.attach(virtualRefienery, 0, elementIndex, 2, 1) + + # Attach Value Labels + self.crudeOilValue = crudeOilValue + self.boilerValveValue = boilerValveValue + self.boilerTempValue = boilerTempValue + self.distTwrValveValue = distTwrValveValue + self.processStatusValue = processStatusValue + self.connectionStatusValue = connectionStatusValue + + self.resetLabels() + GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) + + def setProcess(self, widget, data=None): + try: + self.modbusClient.write_register(0x10, data) + except: + pass + + def update_status(self): + + try: + rr = self.modbusClient.read_holding_registers(1,16) + regs = [] + + if not rr or not rr.registers: + raise ConnectionException + + regs = rr.registers + + if not regs or len(regs) < 16: + raise ConnectionException + + if regs[1] == 1: + self.crudeOilValue.set_markup("YES") + else: + self.crudeOilValue.set_markup("NO") + + if regs[0] == 1: + self.boilerValveValue.set_markup("OPEN") + else: + self.boilerValveValue.set_markup("CLOSED") + + if regs[2] == 1: + self.boilerTempValue.set_markup("NORMAL") + else: + self.boilerTempValue.set_markup("HOT") + + if regs[3] == 1: + self.distTwrValveValue.set_markup("OPEN") + else: + self.distTwrValveValue.set_markup("CLOSED") + + if regs[15] == 1: + self.processStatusValue.set_markup("RUNNING") + else: + self.processStatusValue.set_markup("STOPPED") + + self.connectionStatusValue.set_markup("ONLINE") + + + except ConnectionException: + if not self.modbusClient.connect(): + self.resetLabels() + except: + raise + finally: + return True + +def app_main(): + win = HMIWindow() + win.connect("delete-event", Gtk.main_quit) + win.connect("destroy", Gtk.main_quit) + win.show_all() + + +if __name__ == "__main__": + GObject.threads_init() + app_main() + Gtk.main() diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index dba16f1..f98bc5e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -6,12 +6,6 @@ import pygtk import socket -s = socket.socket() -host = '192.168.228.143' -port = 5020 -s.connect((host, port)) -#print s.recv(1024) - MODBUS_SLEEP=1 class HMIWindow(Gtk.Window): From 80735a3a6e9124612b949621670e1e0729799cd9 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Tue, 12 Jul 2016 10:38:00 -0400 Subject: [PATCH 006/239] new oil hmi --- plants/bottle-filling/hmi.py | 2 +- plants/oil-refinery/oil_hmi.py | 161 ++++++++------ plants/oil-refinery/world_oil.py | 356 +++++++++++++++++++++++++++++++ 3 files changed, 449 insertions(+), 70 deletions(-) create mode 100644 plants/oil-refinery/world_oil.py diff --git a/plants/bottle-filling/hmi.py b/plants/bottle-filling/hmi.py index 59f4392..357c0c1 100755 --- a/plants/bottle-filling/hmi.py +++ b/plants/bottle-filling/hmi.py @@ -10,7 +10,7 @@ class HMIWindow(Gtk.Window): def initModbus(self): - self.modbusClient = ModbusClient('localhost', port=5020) + self.modbusClient = ModbusClient('192.168.228.143', port=5020) def resetLabels(self): self.bottlePositionValue.set_markup("N/A") diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index f98bc5e..37d308e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -15,15 +15,16 @@ def initModbus(self): self.modbusClient = ModbusClient('localhost', port=5020) def resetLabels(self): - self.crudeOilValue.set_markup("STOPPED") - self.boilerValveValue.set_markup("CLOSED") - self.boilerTempValue.set_markup("NORMAL") - self.processStatusValue.set_markup("STOPPED") - self.connectionStatusValue.set_markup("OFFLINE") - self.distTwrValveValue.set_markup("CLOSED") + self.feed_pump_value.set_markup("STOPPED") + self.inlet_valve_value.set_markup("CLOSED") + self.outlet_valve_value.set_markup("CLOSED") + self.separator_value.set_markup("STOPPED") + self.discharge_pump_value.set_markup("STOPPED") + self.process_status_value.set_markup("STOPPED") + self.connection_status_value.set_markup("OFFLINE") def __init__(self): - Gtk.Window.__init__(self, title="Oil Refining - HMI - Oil Refinery") + Gtk.Window.__init__(self, title="Oil Refinery") self.set_border_width(100) @@ -39,75 +40,92 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("Oil Refining Process") - grid.attach(label, 0, elementIndex, 2, 1) + label.set_markup("Crude Oil Pretreatment Unit") + grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 - # Crude Oil barrel - crudeOilLabel = Gtk.Label("Crude Oil Dumping Status") - crudeOilValue = Gtk.Label() - grid.attach(crudeOilLabel, 0, elementIndex, 1, 1) - grid.attach(crudeOilValue, 1, elementIndex, 1, 1) + # Crude Oil Feed Pump + feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") + feed_pump_value = Gtk.Label() + feed_pump_start_button = Gtk.Button("START") + feed_pump_stop_button = Gtk.Button("STOP") + grid.attach(feed_pump_label, 0, elementIndex, 1, 1) + grid.attach(feed_pump_value, 1, elementIndex, 1, 1) + grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) + grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) elementIndex += 1 - # Boiler Valve - boilerValveLabel = Gtk.Label("Boiler Valve Status") - boilerValveValue = Gtk.Label() - grid.attach(boilerValveLabel, 0, elementIndex, 1, 1) - grid.attach(boilerValveValue, 1, elementIndex, 1, 1) + # Crude Oil Inlet Valve + inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") + inlet_valve_value = Gtk.Label() + inlet_valve_open_button = Gtk.Button("OPEN") + inlet_valve_close_button = Gtk.Button("CLOSE") + grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) + grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) + grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) + grid.attach(inlet_valve_close_button, 3, elementIndex, 1, 1) elementIndex += 1 - # Boiler Temperature - boilerTempLabel = Gtk.Label("Boiler Temperature") - boilerTempValue = Gtk.Label() - grid.attach(boilerTempLabel, 0, elementIndex, 1, 1) - grid.attach(boilerTempValue, 1, elementIndex, 1, 1) + # Crude Oil Outlet Valve + outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") + outlet_valve_value = Gtk.Label() + outlet_valve_open_button = Gtk.Button("OPEN") + outlet_valve_close_button = Gtk.Button("CLOSE") + grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) + grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) + grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) + grid.attach(outlet_valve_close_button, 3, elementIndex, 1, 1) elementIndex += 1 - # Distillation Tower - distTwrValveLabel = Gtk.Label("Distillation Tower Valve") - distTwrValveValue = Gtk.Label() - grid.attach(distTwrValveLabel, 0, elementIndex, 1, 1) - grid.attach(distTwrValveValue, 1, elementIndex, 1, 1) + # Crude Oil Discharge Pump + discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") + discharge_pump_value = Gtk.Label() + discharge_pump_start_button = Gtk.Button("START") + discharge_pump_stop_button = Gtk.Button("STOP") + grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) + grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) + grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) + grid.attach(discharge_pump_stop_button, 3, elementIndex, 1, 1) elementIndex += 1 - # Process status - processStatusLabel = Gtk.Label("Process Status") - processStatusValue = Gtk.Label() - grid.attach(processStatusLabel, 0, elementIndex, 1, 1) - grid.attach(processStatusValue, 1, elementIndex, 1, 1) + #Oil/Water Separator Vessel + separator_label = Gtk.Label("Oil/Water Separator Vessel") + separator_value = Gtk.Label() + separator_start_button = Gtk.Button("START") + separator_stop_button = Gtk.Button("STOP") + grid.attach(separator_label, 0, elementIndex, 1, 1) + grid.attach(separator_value, 1, elementIndex, 1, 1) + grid.attach(separator_start_button, 2, elementIndex, 1, 1) + grid.attach(separator_stop_button, 3, elementIndex, 1, 1) elementIndex += 1 - # Connection status - connectionStatusLabel = Gtk.Label("Connection Status") - connectionStatusValue = Gtk.Label() - grid.attach(connectionStatusLabel, 0, elementIndex, 1, 1) - grid.attach(connectionStatusValue, 1, elementIndex, 1, 1) + # Process status + process_status_label = Gtk.Label("Process Status") + process_status_value = Gtk.Label() + grid.attach(process_status_label, 0, elementIndex, 1, 1) + grid.attach(process_status_value, 1, elementIndex, 1, 1) elementIndex += 1 - # Run and Stop buttons - runButton = Gtk.Button("Run") - stopButton = Gtk.Button("Stop") - - runButton.connect("clicked", self.setProcess, 1) - stopButton.connect("clicked", self.setProcess, 0) - - grid.attach(runButton, 0, elementIndex, 1, 1) - grid.attach(stopButton, 1, elementIndex, 1, 1) + # Connection status + connection_status_label = Gtk.Label("Connection Status") + connection_status_value = Gtk.Label() + grid.attach(connection_status_label, 0, elementIndex, 1, 1) + grid.attach(connection_status_value, 1, elementIndex, 1, 1) elementIndex += 1 # Oil Refienery branding - virtualRefienery = Gtk.Label() - virtualRefienery.set_markup("Oil Refinery - HMI") - grid.attach(virtualRefienery, 0, elementIndex, 2, 1) + virtual_refinery = Gtk.Label() + virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") + grid.attach(virtual_refinery, 0, elementIndex, 4, 1) # Attach Value Labels - self.crudeOilValue = crudeOilValue - self.boilerValveValue = boilerValveValue - self.boilerTempValue = boilerTempValue - self.distTwrValveValue = distTwrValveValue - self.processStatusValue = processStatusValue - self.connectionStatusValue = connectionStatusValue + self.feed_pump_value = feed_pump_value + self.inlet_valve_value = inlet_valve_value + self.outlet_valve_value = outlet_valve_value + self.discharge_pump_value = discharge_pump_value + self.process_status_value = process_status_value + self.connection_status_value = connection_status_value + self.separator_value = separator_value self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) @@ -132,32 +150,37 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[1] == 1: - self.crudeOilValue.set_markup("YES") + if regs[0] == 1: + self.feed_pump_value.set_markup("RUNNING") else: - self.crudeOilValue.set_markup("NO") + self.feed_pump_value.set_markup("STOPPED") if regs[0] == 1: - self.boilerValveValue.set_markup("OPEN") + self.inlet_valve_value.set_markup("OPEN") + else: + self.inlet_valve_value.set_markup("CLOSED") + + if regs[1] == 1: + self.outlet_valve_value.set_markup("OPEN") else: - self.boilerValveValue.set_markup("CLOSED") + self.outlet_valve_value.set_markup("CLOSED") if regs[2] == 1: - self.boilerTempValue.set_markup("NORMAL") + self.discharge_pump_value.set_markup("RUNNING") else: - self.boilerTempValue.set_markup("HOT") + self.discharge_pump_value.set_markup("STOPPED") if regs[3] == 1: - self.distTwrValveValue.set_markup("OPEN") + self.separator_value.set_markup("RUNNING") else: - self.distTwrValveValue.set_markup("CLOSED") + self.separator_value.set_markup("span weight='bold' foreground='green'>STOPPEDRUNNING") + self.process_status_value.set_markup("RUNNING") else: - self.processStatusValue.set_markup("STOPPED") + self.process_status_value.set_markup("STOPPED") - self.connectionStatusValue.set_markup("ONLINE") + self.connection_status_value.set_markup("ONLINE") except ConnectionException: diff --git a/plants/oil-refinery/world_oil.py b/plants/oil-refinery/world_oil.py new file mode 100644 index 0000000..01685b4 --- /dev/null +++ b/plants/oil-refinery/world_oil.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python + +######################################### +# Imports +######################################### +# - Logging +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +######################################### +# Logging +######################################### +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +######################################### +# Util Functions +######################################### +def PLCSetTag(addr, value): + context[0x0].setValues(3, addr, [value]) + +def PLCGetTag(addr): + return context[0x0].getValues(3, addr, count=1)[0] + +######################################### +# World Code +######################################### + +# "Constants" +SCREEN_WIDTH = 600 +SCREEN_HEIGHT = 350 +FPS=50.0 + +MODBUS_SERVER_PORT=5020 + +PLC_TAG_LEVEL_SENSOR = 0x1 +PLC_TAG_LIMIT_SWITCH = 0x2 +PLC_TAG_MOTOR = 0x3 +PLC_TAG_NOZZLE = 0x4 +PLC_TAG_RUN = 0x10 + +# Global Variables +global bottles +bottles = [] + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Shape functions + +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(181,182) + body.position = x, 410 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = 0x5 #liquid + space.add(body, shape) + return shape + +def draw_ball(screen, ball, color=THECOLORS['blue']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +def add_bottle_in_sensor(space): + + body = pymunk.Body() + body.position = (40, 300) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x7 # 'bottle_in' + space.add(shape) + return shape + +def add_level_sensor(space): + + body = pymunk.Body() + body.position = (155, 380) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x4 # level_sensor + space.add(shape) + return shape + +def add_limit_switch(space): + + body = pymunk.Body() + body.position = (200, 300) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x1 # switch + space.add(shape) + return shape + +def add_nozzle(space): + + body = pymunk.Body() + body.position = (180, 430) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +def add_base(space): + + body = pymunk.Body() + body.position = (0, 300) + shape = pymunk.Poly.create_box(body, (SCREEN_WIDTH, 20), ((SCREEN_WIDTH/2), -10), 0) + shape.friction = 1.0 + shape.collision_type = 0x6 # base + space.add(shape) + return shape + +def add_bottle(space): + mass = 10 + inertia = 0xFFFFFFFFF + body = pymunk.Body(mass, inertia) + body.position = (130,300) + l1 = pymunk.Segment(body, (-80, 0), (-30, 0), 2.0) + l2 = pymunk.Segment(body, (-80, 0), (-80, 100), 2.0) + l3 = pymunk.Segment(body, (-30, 0), (-30, 100), 2.0) + + # Glass friction + l1.friction = 0.94 + l2.friction = 0.94 + l3.friction = 0.94 + + # Set collision types for sensors + l1.collision_type = 0x2 # bottle_bottom + l2.collision_type = 0x3 # bottle_side + l3.collision_type = 0x3 # bottle_side + + space.add(l1, l2, l3, body) + return l1,l2,l3 + +def draw_polygon(screen, shape): + + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(screen, THECOLORS['black'], fpoints) + + +def draw_lines(screen, lines, color=THECOLORS['dodgerblue4']): + """Draw the lines""" + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) + p2 = to_pygame(pv2) + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Collision handlers +def no_collision(space, arbiter, *args, **kwargs): + return False + +def level_ok(space, arbiter, *args, **kwargs): + + log.debug("Level reached") + PLCSetTag(PLC_TAG_LIMIT_SWITCH, 0) # Limit Switch Release, Fill Bottle + PLCSetTag(PLC_TAG_LEVEL_SENSOR, 1) # Level Sensor Hit, Bottle Filled + PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle + return False + +def bottle_in_place(space, arbiter, *args, **kwargs): + + log.debug("Bottle in place") + PLCSetTag(PLC_TAG_LIMIT_SWITCH, 1) + PLCSetTag(PLC_TAG_LEVEL_SENSOR, 0) + PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle + return False + +def add_new_bottle(space, arbiter, *args, **kwargs): + global bottles + bottles.append(add_bottle(space)) + log.debug("Adding new bottle") + return False + +def runWorld(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Bottle-Filling Factory - World View - VirtuaPlant") + clock = pygame.time.Clock() + running = True + + space = pymunk.Space() + space.gravity = (0.0, -900.0) + + # Limit switch with bottle bottom + space.add_collision_handler(0x1, 0x2, begin=bottle_in_place) + # Level sensor with water + space.add_collision_handler(0x4, 0x5, begin=level_ok) + # Level sensor with ground + space.add_collision_handler(0x4, 0x6, begin=no_collision) + # Limit switch with ground + space.add_collision_handler(0x1, 0x6, begin=no_collision) + # Limit switch with bottle side + space.add_collision_handler(0x1, 0x3, begin=no_collision) + # Level sensor with bottle side + space.add_collision_handler(0x4, 0x3, begin=no_collision) + # Bottle in with bottle sides and bottom + space.add_collision_handler(0x7, 0x2, begin=no_collision, separate=add_new_bottle) + space.add_collision_handler(0x7, 0x3, begin=no_collision) + + base = add_base(space) + nozzle = add_nozzle(space) + limit_switch = add_limit_switch(space) + level_sensor = add_level_sensor(space) + bottle_in = add_bottle_in_sensor(space) + + global bottles + bottles.append(add_bottle(space)) + + balls = [] + + ticks_to_next_ball = 1 + + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + screen.fill(THECOLORS["white"]) + + if PLCGetTag(PLC_TAG_RUN): + + # Motor Logic + if (PLCGetTag(PLC_TAG_LIMIT_SWITCH) == 1): + PLCSetTag(PLC_TAG_MOTOR, 0) + + if (PLCGetTag(PLC_TAG_LEVEL_SENSOR) == 1): + PLCSetTag(PLC_TAG_MOTOR, 1) + + ticks_to_next_ball -= 1 + + if not PLCGetTag(PLC_TAG_LIMIT_SWITCH): + PLCSetTag(PLC_TAG_MOTOR, 1) + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + # Move the bottles + if PLCGetTag(PLC_TAG_MOTOR) == 1: + for bottle in bottles: + bottle[0].body.position.x += 0.25 + else: + PLCSetTag(PLC_TAG_MOTOR, 0) + + # Draw water balls + # Remove off-screen balls + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 150 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(screen, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + # Draw bottles + for bottle in bottles: + if bottle[0].body.position.x > SCREEN_WIDTH+150 or bottle[0].body.position.y < 150: + space.remove(bottle, bottle[0].body) + bottles.remove(bottle) + continue + draw_lines(screen, bottle) + + # Draw the base and nozzle + draw_polygon(screen, base) + draw_polygon(screen, nozzle) + # Draw the limit switch + draw_ball(screen, limit_switch, THECOLORS['green']) + # Draw the level sensor + draw_ball(screen, level_sensor, THECOLORS['red']) + + title = fontMedium.render(str("Bottle-filling factory"), 1, THECOLORS['deepskyblue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + screen.blit(title, (10, 40)) + screen.blit(name, (10, 10)) + screen.blit(instructions, (SCREEN_WIDTH-115, 10)) + + space.step(1/FPS) + pygame.display.flip() + + # Stop reactor if running + if reactor.running: + reactor.callFromThread(reactor.stop) + +######################################### +# Modbus Server Code +######################################### + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +identity = ModbusDeviceIdentification() +identity.VendorName = 'MockPLCs' +identity.ProductCode = 'MP' +identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' +identity.ProductName = 'MockPLC 3000' +identity.ModelName = 'MockPLC Ultimate' +identity.MajorMinorRevision = '1.0' + +def startModbusServer(): + + StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(runWorld) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) From fc0b04c8b9bb9171ec125ca6dd876dd9c348b4de Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Wed, 20 Jul 2016 14:09:28 -0400 Subject: [PATCH 007/239] revision hmi & display --- plants/bottle-filling/hmi.py | 4 +- plants/bottle-filling/world.py | 2 +- plants/oil-refinery/hmi_oil.py | 181 ---------------- plants/oil-refinery/oil_hmi.py | 3 +- plants/oil-refinery/oil_world.py | 312 ++++++++++++++++++++++++--- plants/oil-refinery/world_oil.py | 356 ------------------------------- 6 files changed, 289 insertions(+), 569 deletions(-) delete mode 100644 plants/oil-refinery/hmi_oil.py delete mode 100644 plants/oil-refinery/world_oil.py diff --git a/plants/bottle-filling/hmi.py b/plants/bottle-filling/hmi.py index 357c0c1..695b751 100755 --- a/plants/bottle-filling/hmi.py +++ b/plants/bottle-filling/hmi.py @@ -10,7 +10,7 @@ class HMIWindow(Gtk.Window): def initModbus(self): - self.modbusClient = ModbusClient('192.168.228.143', port=5020) + self.modbusClient = ModbusClient('172.27.158.32', port=5020) def resetLabels(self): self.bottlePositionValue.set_markup("N/A") @@ -175,4 +175,4 @@ def app_main(): if __name__ == "__main__": GObject.threads_init() app_main() - Gtk.main() + Gtk.main() \ No newline at end of file diff --git a/plants/bottle-filling/world.py b/plants/bottle-filling/world.py index 66a20a9..35f48ae 100755 --- a/plants/bottle-filling/world.py +++ b/plants/bottle-filling/world.py @@ -351,4 +351,4 @@ def main(): startModbusServer() if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) \ No newline at end of file diff --git a/plants/oil-refinery/hmi_oil.py b/plants/oil-refinery/hmi_oil.py deleted file mode 100644 index f98bc5e..0000000 --- a/plants/oil-refinery/hmi_oil.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env python - -from gi.repository import GLib, Gtk, GObject -from pymodbus.client.sync import ModbusTcpClient as ModbusClient -from pymodbus.exceptions import ConnectionException -import pygtk -import socket - -MODBUS_SLEEP=1 - -class HMIWindow(Gtk.Window): - - def initModbus(self): - - self.modbusClient = ModbusClient('localhost', port=5020) - - def resetLabels(self): - self.crudeOilValue.set_markup("STOPPED") - self.boilerValveValue.set_markup("CLOSED") - self.boilerTempValue.set_markup("NORMAL") - self.processStatusValue.set_markup("STOPPED") - self.connectionStatusValue.set_markup("OFFLINE") - self.distTwrValveValue.set_markup("CLOSED") - - def __init__(self): - Gtk.Window.__init__(self, title="Oil Refining - HMI - Oil Refinery") - - self.set_border_width(100) - - self.initModbus() - - elementIndex = 0 - - # Grid - grid = Gtk.Grid() - grid.set_row_spacing(15) - grid.set_column_spacing(10) - self.add(grid) - - # Main title label - label = Gtk.Label() - label.set_markup("Oil Refining Process") - grid.attach(label, 0, elementIndex, 2, 1) - elementIndex += 1 - - # Crude Oil barrel - crudeOilLabel = Gtk.Label("Crude Oil Dumping Status") - crudeOilValue = Gtk.Label() - grid.attach(crudeOilLabel, 0, elementIndex, 1, 1) - grid.attach(crudeOilValue, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Boiler Valve - boilerValveLabel = Gtk.Label("Boiler Valve Status") - boilerValveValue = Gtk.Label() - grid.attach(boilerValveLabel, 0, elementIndex, 1, 1) - grid.attach(boilerValveValue, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Boiler Temperature - boilerTempLabel = Gtk.Label("Boiler Temperature") - boilerTempValue = Gtk.Label() - grid.attach(boilerTempLabel, 0, elementIndex, 1, 1) - grid.attach(boilerTempValue, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Distillation Tower - distTwrValveLabel = Gtk.Label("Distillation Tower Valve") - distTwrValveValue = Gtk.Label() - grid.attach(distTwrValveLabel, 0, elementIndex, 1, 1) - grid.attach(distTwrValveValue, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Process status - processStatusLabel = Gtk.Label("Process Status") - processStatusValue = Gtk.Label() - grid.attach(processStatusLabel, 0, elementIndex, 1, 1) - grid.attach(processStatusValue, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Connection status - connectionStatusLabel = Gtk.Label("Connection Status") - connectionStatusValue = Gtk.Label() - grid.attach(connectionStatusLabel, 0, elementIndex, 1, 1) - grid.attach(connectionStatusValue, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Run and Stop buttons - runButton = Gtk.Button("Run") - stopButton = Gtk.Button("Stop") - - runButton.connect("clicked", self.setProcess, 1) - stopButton.connect("clicked", self.setProcess, 0) - - grid.attach(runButton, 0, elementIndex, 1, 1) - grid.attach(stopButton, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Oil Refienery branding - virtualRefienery = Gtk.Label() - virtualRefienery.set_markup("Oil Refinery - HMI") - grid.attach(virtualRefienery, 0, elementIndex, 2, 1) - - # Attach Value Labels - self.crudeOilValue = crudeOilValue - self.boilerValveValue = boilerValveValue - self.boilerTempValue = boilerTempValue - self.distTwrValveValue = distTwrValveValue - self.processStatusValue = processStatusValue - self.connectionStatusValue = connectionStatusValue - - self.resetLabels() - GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - - def setProcess(self, widget, data=None): - try: - self.modbusClient.write_register(0x10, data) - except: - pass - - def update_status(self): - - try: - rr = self.modbusClient.read_holding_registers(1,16) - regs = [] - - if not rr or not rr.registers: - raise ConnectionException - - regs = rr.registers - - if not regs or len(regs) < 16: - raise ConnectionException - - if regs[1] == 1: - self.crudeOilValue.set_markup("YES") - else: - self.crudeOilValue.set_markup("NO") - - if regs[0] == 1: - self.boilerValveValue.set_markup("OPEN") - else: - self.boilerValveValue.set_markup("CLOSED") - - if regs[2] == 1: - self.boilerTempValue.set_markup("NORMAL") - else: - self.boilerTempValue.set_markup("HOT") - - if regs[3] == 1: - self.distTwrValveValue.set_markup("OPEN") - else: - self.distTwrValveValue.set_markup("CLOSED") - - if regs[15] == 1: - self.processStatusValue.set_markup("RUNNING") - else: - self.processStatusValue.set_markup("STOPPED") - - self.connectionStatusValue.set_markup("ONLINE") - - - except ConnectionException: - if not self.modbusClient.connect(): - self.resetLabels() - except: - raise - finally: - return True - -def app_main(): - win = HMIWindow() - win.connect("delete-event", Gtk.main_quit) - win.connect("destroy", Gtk.main_quit) - win.show_all() - - -if __name__ == "__main__": - GObject.threads_init() - app_main() - Gtk.main() diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 37d308e..3ebf75c 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from gi.repository import GLib, Gtk, GObject +from gi.repository import GLib, Gtk, Gdk, GObject from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.exceptions import ConnectionException import pygtk @@ -25,6 +25,7 @@ def resetLabels(self): def __init__(self): Gtk.Window.__init__(self, title="Oil Refinery") + #self.gtk_widget_override_background_color(Gtk.StateType.NORMAL, Gtk.Window("green")) self.set_border_width(100) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 96bd964..8f317f3 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -1,8 +1,7 @@ -# for logging events -import logging +import logging -# imports the twisted software and uses the reactor function to drive the inferace -from twisted.internet import reactor +# - Multithreading +from twisted.internet import reactor # - Modbus from pymodbus.server.async import StartTcpServer @@ -18,67 +17,324 @@ from pygame.color import * import pymunk -# Log Information +import socket + logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) -# Utility Functions def PLCSetTag(addr, value): context[0x0].setValues(3, addr, [value]) def PLCGetTag(addr): return context[0x0].getValues(3, addr, count=1)[0] -# "Constants" -SCREEN_WIDTH = 600 -SCREEN_HEIGHT = 350 +SCREEN_WIDTH = 640 +SCREEN_HEIGHT = 550 FPS=50.0 MODBUS_SERVER_PORT=5020 PLC_TAG_LEVEL_SENSOR = 0x1 PLC_TAG_LIMIT_SWITCH = 0x2 -PLC_TAG_OIL_BARREL = 0x4 +PLC_TAG_PUMP = 0x3 +PLC_TAG_NOZZLE = 0x4 PLC_TAG_RUN = 0x10 -#Global Variable -#global boiler - def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" return int(p.x), int(-p.y+600) -def add_oil(space): +def add_ball(space): mass = 0.01 radius = 3 inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 body._bodycontents.h_limit = 1 - x = random.randint(181,182) - body.position = x, 410 + x = random.randint(180, 181) + body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) shape.collision_type = 0x5 #liquid space.add(body, shape) return shape -def draw_oil(screen, ball, color=THECOLORS['brown4']): +def draw_ball(screen, ball, color=THECOLORS['black']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) -def oil_barrel(space): +def add_tank_in_sensor(space): + body = pymunk.Body() - body.position = (100, 480) - shape = pymunk.Poly.create_box(body, (80, 100), (0, 0), 0) + body.position = (10, 320) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x7 # 'bottle_in' space.add(shape) return shape -def boiler(space): - mass = 100 - inertia = 0xFFFFFFFFF - body = pymunk.Body(mass, inertia) - body.position = (130,300) - l1 = pymunk.Segment(body, (-150, 0), (-100, 0), 2.0) - l2 = pymunk.Segment(body, (-150, 0), (-150, 100), 2.0) - l3 = pymunk.Segment(body, (-100, 0), (-100, 100), 2.0) \ No newline at end of file +def add_level_sensor(space): + + body = pymunk.Body() + body.position = (125, 400) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x4 # level_sensor + space.add(shape) + return shape + + +def add_limit_switch(space): + + body = pymunk.Body() + body.position = (165, 415) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x1 # switch + space.add(shape) + return shape + +def add_nozzle(space): + + body = pymunk.Body() + body.position = (179, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +def add_oil_unit(space): + #rotation_limit_body = pymunk.Body() + #rotation_limit_body.position = (200,300) + + #rotation_center_body = pymunk.Body() + #rotation_center_body.position = (300,300) + + body = pymunk.Body() + body.position = (300,300) + #feed pump + l1 = pymunk.Segment(body, (-100, 270), (-100, 115), 5) + l2 = pymunk.Segment(body, (-135, 270), (-135, 115), 5) + #l3 = pymunk.Segment(body, (-135, 115), (-100, 115), 5) + #l3 = pymunk.Segment(body, (-250, 180), (-135, 180), 5) + #l4 = pymunk.Segment(body, (-215, 200), (-115, 200), 5) + #l5 = pymunk.Segment(body, (-135, 180), (-135, 120), 5) + #l6 = pymunk.Segment(body, (-115, 200), (-115, 120), 5) + + #oil storage unit + l7 = pymunk.Segment(body, (-185, 115), (-185, 20), 5) + l8 = pymunk.Segment(body, (-65, 115), (-65, 20), 5) + l9 = pymunk.Segment(body, (-185,20), (-115, 20), 5) + l10 = pymunk.Segment(body, (-90, 20), (-65, 20), 5) + + #pipe to separator vessel + l11 = pymunk.Segment(body, (-115, 20), (-115, -45), 5) + l12 = pymunk.Segment(body, (-90, 20), (-90, -25), 5) + l13 = pymunk.Segment(body, (-115, -45), (-40, -45), 5) + l14 = pymunk.Segment(body, (-90, -25), (-40, -25), 5) + + #separator vessel + l15 = pymunk.Segment(body, (-40, -45), (-40, -75), 5) + l16 = pymunk.Segment(body, (-40, -25), (-40, 5), 5) + l17 = pymunk.Segment(body, (-40, -75), (80, -75), 5) + l18 = pymunk.Segment(body, (-40, 5), (120, 5), 5) + l19 = pymunk.Segment(body, (100, -75), (120, -75), 5) + l22 = pymunk.Segment(body, (120, -75), (120, -55), 5) + l23 = pymunk.Segment(body, (120, -30), (120, 5), 5) + + #waste water pipe + l20 = pymunk.Segment(body, (80, -75), (80, -115), 5) + l21 = pymunk.Segment(body, (100, -75), (100, -115), 5) + + #separator exit pipe + l24 = pymunk.Segment(body, (120, -30), (600, -30), 5) + l25 = pymunk.Segment(body, (120, -55), (600, -55), 5) + + #waste water storage + l26 = pymunk.Segment(body, (80, -115), (20, -115), 5) + l27 = pymunk.Segment(body, (20, -115), (20, -185), 5) + l28 = pymunk.Segment(body, (20, -185), (140, -185), 5) + l29 = pymunk.Segment(body, (140, -185), (140, -115), 5) + l30 = pymunk.Segment(body, (140, -115), (100, -115), 5) + + #rotation_center_joint = pymunk.PinJoint(body, rotation_center_body, (-135,115), (-100, 115)) + #joint_limit = 25 + #rotation_limit_joint = pymunk.SlideJoint(body, rotation_limit_body, (-135,115), (-100,115), 5, joint_limit) + + space.add(l1, l2, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30) # 3 + + return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30 + +def draw_polygon(screen, shape): + + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(screen, THECOLORS['darkgreen'], fpoints) + +def draw_lines(screen, lines): + + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + +def no_collision(space, arbiter, *args, **kwargs): + return False + +def level_ok(space, arbiter, *args, **kwargs): + + log.debug("Level reached") + PLCSetTag(PLC_TAG_LIMIT_SWITCH, 0) # Limit Switch Release, Fill Bottle + PLCSetTag(PLC_TAG_LEVEL_SENSOR, 1) # Level Sensor Hit, Bottle Filled + PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle + return False + +def oil_storage_ready(space, arbiter, *args, **kwargs): + + log.debug("Storage bin ready") + PLCSetTag(PLC_TAG_LIMIT_SWITCH, 1) + PLCSetTag(PLC_TAG_LEVEL_SENSOR, 0) + PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) + # Level sensor with water + space.add_collision_handler(0x4, 0x5, begin=level_ok) + # Level sensor with ground + space.add_collision_handler(0x4, 0x6, begin=no_collision) + # Limit switch with ground + space.add_collision_handler(0x1, 0x6, begin=no_collision) + # Limit switch with bottle side + space.add_collision_handler(0x1, 0x3, begin=no_collision) + # Level sensor with bottle side + space.add_collision_handler(0x4, 0x3, begin=no_collision) + + space.add_collision_handler(0x7, 0x2, begin=no_collision) + space.add_collision_handler(0x7, 0x3, begin=no_collision) + + nozzle = add_nozzle(space) + lines = add_oil_unit(space) + limit_switch = add_limit_switch(space) + level_sensor = add_level_sensor(space) + tank_in = add_tank_in_sensor(space) + + balls = [] + + ticks_to_next_ball = 1 + + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + screen.fill(THECOLORS["grey"]) + + if PLCGetTag(PLC_TAG_RUN): + + # Motor Logic + if (PLCGetTag(PLC_TAG_LIMIT_SWITCH) == 1): + PLCSetTag(PLC_TAG_PUMP, 0) + + if (PLCGetTag(PLC_TAG_LEVEL_SENSOR) == 1): + PLCSetTag(PLC_TAG_PUMP, 1) + + ticks_to_next_ball -= 1 + + if not PLCGetTag(PLC_TAG_LIMIT_SWITCH): + PLCSetTag(PLC_TAG_PUMP, 1) + + if ticks_to_next_ball <= 0: #and PLCGetTag(PLC_TAG_NOZZLE): + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + else: + PLCSetTag(PLC_TAG_PUMP, 0) + + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(screen, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(screen, nozzle) + draw_lines(screen, lines) + draw_ball(screen, limit_switch, THECOLORS['red']) + draw_ball(screen, level_sensor, THECOLORS['red']) + + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + screen.blit(title, (300, 40)) + screen.blit(name, (347, 10)) + screen.blit(instructions, (SCREEN_WIDTH-115, 10)) + screen.blit(feed_pump_label, (65, 80)) + screen.blit(oil_storage_label, (240, 190)) + screen.blit(separator_label, (270,275)) + screen.blit(waste_water_label, (265, 490)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +identity = ModbusDeviceIdentification() +identity.VendorName = 'MockPLCs' +identity.ProductCode = 'MP' +identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' +identity.ProductName = 'MockPLC 4000' +identity.ModelName = 'MockPLC Platinum' +identity.MajorMinorRevision = '1.0' + +def startModbusServer(): + + StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file diff --git a/plants/oil-refinery/world_oil.py b/plants/oil-refinery/world_oil.py deleted file mode 100644 index 01685b4..0000000 --- a/plants/oil-refinery/world_oil.py +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env python - -######################################### -# Imports -######################################### -# - Logging -import logging - -# - Multithreading -from twisted.internet import reactor - -# - Modbus -from pymodbus.server.async import StartTcpServer -from pymodbus.device import ModbusDeviceIdentification -from pymodbus.datastore import ModbusSequentialDataBlock -from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext -from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer - -# - World Simulator -import sys, random -import pygame -from pygame.locals import * -from pygame.color import * -import pymunk - -import socket - -######################################### -# Logging -######################################### -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -######################################### -# Util Functions -######################################### -def PLCSetTag(addr, value): - context[0x0].setValues(3, addr, [value]) - -def PLCGetTag(addr): - return context[0x0].getValues(3, addr, count=1)[0] - -######################################### -# World Code -######################################### - -# "Constants" -SCREEN_WIDTH = 600 -SCREEN_HEIGHT = 350 -FPS=50.0 - -MODBUS_SERVER_PORT=5020 - -PLC_TAG_LEVEL_SENSOR = 0x1 -PLC_TAG_LIMIT_SWITCH = 0x2 -PLC_TAG_MOTOR = 0x3 -PLC_TAG_NOZZLE = 0x4 -PLC_TAG_RUN = 0x10 - -# Global Variables -global bottles -bottles = [] - -def to_pygame(p): - """Small hack to convert pymunk to pygame coordinates""" - return int(p.x), int(-p.y+600) - -# Shape functions - -def add_ball(space): - mass = 0.01 - radius = 3 - inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) - body = pymunk.Body(mass, inertia) - body._bodycontents.v_limit = 120 - body._bodycontents.h_limit = 1 - x = random.randint(181,182) - body.position = x, 410 - shape = pymunk.Circle(body, radius, (0,0)) - shape.collision_type = 0x5 #liquid - space.add(body, shape) - return shape - -def draw_ball(screen, ball, color=THECOLORS['blue']): - p = int(ball.body.position.x), 600-int(ball.body.position.y) - pygame.draw.circle(screen, color, p, int(ball.radius), 2) - -def add_bottle_in_sensor(space): - - body = pymunk.Body() - body.position = (40, 300) - radius = 2 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x7 # 'bottle_in' - space.add(shape) - return shape - -def add_level_sensor(space): - - body = pymunk.Body() - body.position = (155, 380) - radius = 3 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x4 # level_sensor - space.add(shape) - return shape - -def add_limit_switch(space): - - body = pymunk.Body() - body.position = (200, 300) - radius = 2 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x1 # switch - space.add(shape) - return shape - -def add_nozzle(space): - - body = pymunk.Body() - body.position = (180, 430) - shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) - space.add(shape) - return shape - -def add_base(space): - - body = pymunk.Body() - body.position = (0, 300) - shape = pymunk.Poly.create_box(body, (SCREEN_WIDTH, 20), ((SCREEN_WIDTH/2), -10), 0) - shape.friction = 1.0 - shape.collision_type = 0x6 # base - space.add(shape) - return shape - -def add_bottle(space): - mass = 10 - inertia = 0xFFFFFFFFF - body = pymunk.Body(mass, inertia) - body.position = (130,300) - l1 = pymunk.Segment(body, (-80, 0), (-30, 0), 2.0) - l2 = pymunk.Segment(body, (-80, 0), (-80, 100), 2.0) - l3 = pymunk.Segment(body, (-30, 0), (-30, 100), 2.0) - - # Glass friction - l1.friction = 0.94 - l2.friction = 0.94 - l3.friction = 0.94 - - # Set collision types for sensors - l1.collision_type = 0x2 # bottle_bottom - l2.collision_type = 0x3 # bottle_side - l3.collision_type = 0x3 # bottle_side - - space.add(l1, l2, l3, body) - return l1,l2,l3 - -def draw_polygon(screen, shape): - - points = shape.get_vertices() - fpoints = [] - for p in points: - fpoints.append(to_pygame(p)) - pygame.draw.polygon(screen, THECOLORS['black'], fpoints) - - -def draw_lines(screen, lines, color=THECOLORS['dodgerblue4']): - """Draw the lines""" - for line in lines: - body = line.body - pv1 = body.position + line.a.rotated(body.angle) - pv2 = body.position + line.b.rotated(body.angle) - p1 = to_pygame(pv1) - p2 = to_pygame(pv2) - pygame.draw.lines(screen, color, False, [p1,p2]) - -# Collision handlers -def no_collision(space, arbiter, *args, **kwargs): - return False - -def level_ok(space, arbiter, *args, **kwargs): - - log.debug("Level reached") - PLCSetTag(PLC_TAG_LIMIT_SWITCH, 0) # Limit Switch Release, Fill Bottle - PLCSetTag(PLC_TAG_LEVEL_SENSOR, 1) # Level Sensor Hit, Bottle Filled - PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle - return False - -def bottle_in_place(space, arbiter, *args, **kwargs): - - log.debug("Bottle in place") - PLCSetTag(PLC_TAG_LIMIT_SWITCH, 1) - PLCSetTag(PLC_TAG_LEVEL_SENSOR, 0) - PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle - return False - -def add_new_bottle(space, arbiter, *args, **kwargs): - global bottles - bottles.append(add_bottle(space)) - log.debug("Adding new bottle") - return False - -def runWorld(): - pygame.init() - screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) - pygame.display.set_caption("Bottle-Filling Factory - World View - VirtuaPlant") - clock = pygame.time.Clock() - running = True - - space = pymunk.Space() - space.gravity = (0.0, -900.0) - - # Limit switch with bottle bottom - space.add_collision_handler(0x1, 0x2, begin=bottle_in_place) - # Level sensor with water - space.add_collision_handler(0x4, 0x5, begin=level_ok) - # Level sensor with ground - space.add_collision_handler(0x4, 0x6, begin=no_collision) - # Limit switch with ground - space.add_collision_handler(0x1, 0x6, begin=no_collision) - # Limit switch with bottle side - space.add_collision_handler(0x1, 0x3, begin=no_collision) - # Level sensor with bottle side - space.add_collision_handler(0x4, 0x3, begin=no_collision) - # Bottle in with bottle sides and bottom - space.add_collision_handler(0x7, 0x2, begin=no_collision, separate=add_new_bottle) - space.add_collision_handler(0x7, 0x3, begin=no_collision) - - base = add_base(space) - nozzle = add_nozzle(space) - limit_switch = add_limit_switch(space) - level_sensor = add_level_sensor(space) - bottle_in = add_bottle_in_sensor(space) - - global bottles - bottles.append(add_bottle(space)) - - balls = [] - - ticks_to_next_ball = 1 - - fontBig = pygame.font.SysFont(None, 40) - fontMedium = pygame.font.SysFont(None, 26) - fontSmall = pygame.font.SysFont(None, 18) - - while running: - clock.tick(FPS) - - for event in pygame.event.get(): - if event.type == QUIT: - running = False - elif event.type == KEYDOWN and event.key == K_ESCAPE: - running = False - - screen.fill(THECOLORS["white"]) - - if PLCGetTag(PLC_TAG_RUN): - - # Motor Logic - if (PLCGetTag(PLC_TAG_LIMIT_SWITCH) == 1): - PLCSetTag(PLC_TAG_MOTOR, 0) - - if (PLCGetTag(PLC_TAG_LEVEL_SENSOR) == 1): - PLCSetTag(PLC_TAG_MOTOR, 1) - - ticks_to_next_ball -= 1 - - if not PLCGetTag(PLC_TAG_LIMIT_SWITCH): - PLCSetTag(PLC_TAG_MOTOR, 1) - - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): - ticks_to_next_ball = 1 - ball_shape = add_ball(space) - balls.append(ball_shape) - - # Move the bottles - if PLCGetTag(PLC_TAG_MOTOR) == 1: - for bottle in bottles: - bottle[0].body.position.x += 0.25 - else: - PLCSetTag(PLC_TAG_MOTOR, 0) - - # Draw water balls - # Remove off-screen balls - balls_to_remove = [] - for ball in balls: - if ball.body.position.y < 150 or ball.body.position.x > SCREEN_WIDTH+150: - balls_to_remove.append(ball) - - draw_ball(screen, ball) - - for ball in balls_to_remove: - space.remove(ball, ball.body) - balls.remove(ball) - - # Draw bottles - for bottle in bottles: - if bottle[0].body.position.x > SCREEN_WIDTH+150 or bottle[0].body.position.y < 150: - space.remove(bottle, bottle[0].body) - bottles.remove(bottle) - continue - draw_lines(screen, bottle) - - # Draw the base and nozzle - draw_polygon(screen, base) - draw_polygon(screen, nozzle) - # Draw the limit switch - draw_ball(screen, limit_switch, THECOLORS['green']) - # Draw the level sensor - draw_ball(screen, level_sensor, THECOLORS['red']) - - title = fontMedium.render(str("Bottle-filling factory"), 1, THECOLORS['deepskyblue']) - name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) - instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) - screen.blit(title, (10, 40)) - screen.blit(name, (10, 10)) - screen.blit(instructions, (SCREEN_WIDTH-115, 10)) - - space.step(1/FPS) - pygame.display.flip() - - # Stop reactor if running - if reactor.running: - reactor.callFromThread(reactor.stop) - -######################################### -# Modbus Server Code -######################################### - -store = ModbusSlaveContext( - di = ModbusSequentialDataBlock(0, [0]*100), - co = ModbusSequentialDataBlock(0, [0]*100), - hr = ModbusSequentialDataBlock(0, [0]*100), - ir = ModbusSequentialDataBlock(0, [0]*100)) - -context = ModbusServerContext(slaves=store, single=True) - -identity = ModbusDeviceIdentification() -identity.VendorName = 'MockPLCs' -identity.ProductCode = 'MP' -identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' -identity.ProductName = 'MockPLC 3000' -identity.ModelName = 'MockPLC Ultimate' -identity.MajorMinorRevision = '1.0' - -def startModbusServer(): - - StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) - -def main(): - reactor.callInThread(runWorld) - startModbusServer() - -if __name__ == '__main__': - sys.exit(main()) From 0939c1aff68837fba9e36f17dfae1e0d0c7d30f4 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Mon, 25 Jul 2016 11:24:35 -0400 Subject: [PATCH 008/239] 7/25-edit --- plants/bottle-filling/hmi.py | 2 +- plants/bottle-filling/world.py | 2 +- plants/oil-refinery/oil_hmi.py | 58 ++++++++++++++------ plants/oil-refinery/oil_world.py | 94 ++++++++++++++++++++++---------- 4 files changed, 108 insertions(+), 48 deletions(-) diff --git a/plants/bottle-filling/hmi.py b/plants/bottle-filling/hmi.py index 695b751..882c52d 100755 --- a/plants/bottle-filling/hmi.py +++ b/plants/bottle-filling/hmi.py @@ -10,7 +10,7 @@ class HMIWindow(Gtk.Window): def initModbus(self): - self.modbusClient = ModbusClient('172.27.158.32', port=5020) + self.modbusClient = ModbusClient('localhost', port=5020) def resetLabels(self): self.bottlePositionValue.set_markup("N/A") diff --git a/plants/bottle-filling/world.py b/plants/bottle-filling/world.py index 35f48ae..d3d33b1 100755 --- a/plants/bottle-filling/world.py +++ b/plants/bottle-filling/world.py @@ -344,7 +344,7 @@ def runWorld(): def startModbusServer(): - StartTcpServer(context, identity=identity, address=("172.27.158.32", MODBUS_SERVER_PORT)) + StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) def main(): reactor.callInThread(runWorld) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 3ebf75c..d6fc0bd 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -3,8 +3,8 @@ from gi.repository import GLib, Gtk, Gdk, GObject from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.exceptions import ConnectionException -import pygtk -import socket + + MODBUS_SLEEP=1 @@ -15,12 +15,12 @@ def initModbus(self): self.modbusClient = ModbusClient('localhost', port=5020) def resetLabels(self): - self.feed_pump_value.set_markup("STOPPED") - self.inlet_valve_value.set_markup("CLOSED") - self.outlet_valve_value.set_markup("CLOSED") - self.separator_value.set_markup("STOPPED") - self.discharge_pump_value.set_markup("STOPPED") - self.process_status_value.set_markup("STOPPED") + self.feed_pump_value.set_markup("N/A") + self.inlet_valve_value.set_markup("N/A") + self.outlet_valve_value.set_markup("N/A") + self.separator_value.set_markup("N/A") + self.discharge_pump_value.set_markup("N/A") + self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") def __init__(self): @@ -48,8 +48,13 @@ def __init__(self): # Crude Oil Feed Pump feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") feed_pump_value = Gtk.Label() + feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") + + feed_pump_start_button.connect("clicked", self.setProcess, 1) + feed_pump_stop_button.connect("clicked", self.setProcess, 0) + grid.attach(feed_pump_label, 0, elementIndex, 1, 1) grid.attach(feed_pump_value, 1, elementIndex, 1, 1) grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) @@ -59,8 +64,13 @@ def __init__(self): # Crude Oil Inlet Valve inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") inlet_valve_value = Gtk.Label() + inlet_valve_open_button = Gtk.Button("OPEN") inlet_valve_close_button = Gtk.Button("CLOSE") + + inlet_valve_open_button.connect("clicked", self.setProcess, 1) + inlet_valve_close_button.connect("clicked", self.setProcess, 0) + grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) @@ -70,8 +80,13 @@ def __init__(self): # Crude Oil Outlet Valve outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") outlet_valve_value = Gtk.Label() + outlet_valve_open_button = Gtk.Button("OPEN") outlet_valve_close_button = Gtk.Button("CLOSE") + + outlet_valve_open_button.connect("clicked", self.setProcess, 1) + outlet_valve_close_button.connect("clicked", self.setProcess, 0) + grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) @@ -80,9 +95,14 @@ def __init__(self): # Crude Oil Discharge Pump discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") - discharge_pump_value = Gtk.Label() + discharge_pump_value = Gtk.Label() + discharge_pump_start_button = Gtk.Button("START") discharge_pump_stop_button = Gtk.Button("STOP") + + discharge_pump_start_button.connect("clicked", self.setProcess, 1) + discharge_pump_stop_button.connect("clicked", self.setProcess, 0) + grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) @@ -92,8 +112,13 @@ def __init__(self): #Oil/Water Separator Vessel separator_label = Gtk.Label("Oil/Water Separator Vessel") separator_value = Gtk.Label() + separator_start_button = Gtk.Button("START") separator_stop_button = Gtk.Button("STOP") + + separator_start_button.connect("clicked", self.setProcess, 1) + separator_stop_button.connect("clicked", self.setProcess, 0) + grid.attach(separator_label, 0, elementIndex, 1, 1) grid.attach(separator_value, 1, elementIndex, 1, 1) grid.attach(separator_start_button, 2, elementIndex, 1, 1) @@ -110,6 +135,7 @@ def __init__(self): # Connection status connection_status_label = Gtk.Label("Connection Status") connection_status_value = Gtk.Label() + grid.attach(connection_status_label, 0, elementIndex, 1, 1) grid.attach(connection_status_value, 1, elementIndex, 1, 1) elementIndex += 1 @@ -117,7 +143,7 @@ def __init__(self): # Oil Refienery branding virtual_refinery = Gtk.Label() virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") - grid.attach(virtual_refinery, 0, elementIndex, 4, 1) + grid.attach(virtual_refinery, 0, elementIndex, 2, 1) # Attach Value Labels self.feed_pump_value = feed_pump_value @@ -151,12 +177,12 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[0] == 1: + if regs[2] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") - if regs[0] == 1: + if regs[2] == 1: self.inlet_valve_value.set_markup("OPEN") else: self.inlet_valve_value.set_markup("CLOSED") @@ -166,15 +192,15 @@ def update_status(self): else: self.outlet_valve_value.set_markup("CLOSED") - if regs[2] == 1: - self.discharge_pump_value.set_markup("RUNNING") + if regs[1] == 1: + self.discharge_pump_value.set_markup("RUNNING") else: self.discharge_pump_value.set_markup("STOPPED") - if regs[3] == 1: + if regs[1] == 1: self.separator_value.set_markup("RUNNING") else: - self.separator_value.set_markup("span weight='bold' foreground='green'>STOPPEDSTOPPED") if regs[15] == 1: self.process_status_value.set_markup("RUNNING") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 8f317f3..0726222 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -35,9 +35,11 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 -PLC_TAG_LEVEL_SENSOR = 0x1 -PLC_TAG_LIMIT_SWITCH = 0x2 -PLC_TAG_PUMP = 0x3 +PLC_TANK_LEVEL = 0x1 +PLC_INLET_VALVE = 0x2 +PLC_OUTLET_VALVE = 0x2 +PLC_FEED_PUMP = 0x3 +PLC_DISCHARGE_PUMP = 0x3 PLC_TAG_NOZZLE = 0x4 PLC_TAG_RUN = 0x10 @@ -63,28 +65,37 @@ def draw_ball(screen, ball, color=THECOLORS['black']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) -def add_tank_in_sensor(space): +def outlet_valve_sensor(space): body = pymunk.Body() - body.position = (10, 320) + body.position = (185, 320) radius = 2 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = 0x7 # 'bottle_in' space.add(shape) return shape -def add_level_sensor(space): +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (380, 225) + radius = 2 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x7 + space.add(shape) + return shape + +def tank_level_sensor(space): body = pymunk.Body() body.position = (125, 400) radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x4 # level_sensor + shape.collision_type = 0x4 # tank_level space.add(shape) return shape -def add_limit_switch(space): +def inlet_valve_sensor(space): body = pymunk.Body() body.position = (165, 415) @@ -153,8 +164,12 @@ def add_oil_unit(space): l26 = pymunk.Segment(body, (80, -115), (20, -115), 5) l27 = pymunk.Segment(body, (20, -115), (20, -185), 5) l28 = pymunk.Segment(body, (20, -185), (140, -185), 5) - l29 = pymunk.Segment(body, (140, -185), (140, -115), 5) - l30 = pymunk.Segment(body, (140, -115), (100, -115), 5) + l29 = pymunk.Segment(body, (140, -185), (140, -170), 5) + l30 = pymunk.Segment(body, (140, -145), (140, -115), 5) + l31 = pymunk.Segment(body, (140, -115), (100, -115), 5) + l32 = pymunk.Segment(body, (140, -145), (600, -145), 5) + l33 = pymunk.Segment(body, (140, -170), (600, -170), 5) + #rotation_center_joint = pymunk.PinJoint(body, rotation_center_body, (-135,115), (-100, 115)) #joint_limit = 25 @@ -162,9 +177,9 @@ def add_oil_unit(space): space.add(l1, l2, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, - l26, l27, l28, l29, l30) # 3 + l26, l27, l28, l29, l30, l31, l32, l33) # 3 - return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30 + return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30,l31,l32,l33 def draw_polygon(screen, shape): @@ -190,17 +205,21 @@ def no_collision(space, arbiter, *args, **kwargs): def level_ok(space, arbiter, *args, **kwargs): log.debug("Level reached") - PLCSetTag(PLC_TAG_LIMIT_SWITCH, 0) # Limit Switch Release, Fill Bottle - PLCSetTag(PLC_TAG_LEVEL_SENSOR, 1) # Level Sensor Hit, Bottle Filled + PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle + PLCSetTag(PLC_OUTLET_VALVE, 1) + PLCSetTag(PLC_DISCHARGE_PUMP, 1) return False def oil_storage_ready(space, arbiter, *args, **kwargs): log.debug("Storage bin ready") - PLCSetTag(PLC_TAG_LIMIT_SWITCH, 1) - PLCSetTag(PLC_TAG_LEVEL_SENSOR, 0) + PLCSetTag(PLC_INLET_VALVE, 1) + PLCSetTag(PLC_TANK_LEVEL, 0) PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle + PLCSetTag(PLC_OUTLET_VALVE, 0) + PLCSetTag(PLC_DISCHARGE_PUMP, 0) return False def run_world(): @@ -230,9 +249,11 @@ def run_world(): nozzle = add_nozzle(space) lines = add_oil_unit(space) - limit_switch = add_limit_switch(space) - level_sensor = add_level_sensor(space) - tank_in = add_tank_in_sensor(space) + inlet_valve = inlet_valve_sensor(space) + tank_level = tank_level_sensor(space) + tank_in = outlet_valve_sensor(space) + separator_vessel = separator_vessel_release(space) + outlet_valve = outlet_valve_sensor(space) balls = [] @@ -256,23 +277,34 @@ def run_world(): if PLCGetTag(PLC_TAG_RUN): # Motor Logic - if (PLCGetTag(PLC_TAG_LIMIT_SWITCH) == 1): - PLCSetTag(PLC_TAG_PUMP, 0) - - if (PLCGetTag(PLC_TAG_LEVEL_SENSOR) == 1): - PLCSetTag(PLC_TAG_PUMP, 1) + if (PLCGetTag(PLC_FEED_PUMP) == 1): + PLCSetTag(PLC_INLET_VALVE, 1) + PLCSetTag(PLC_TAG_NOZZLE, 1) + + if (PLCGetTag(PLC_INLET_VALVE) == 1): + PLCSetTag(PLC_OUTLET_VALVE, 0) + PLCSetTag(PLC_DISCHARGE_PUMP, 0) + + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_OUTLET_VALVE, 1) + PLCSetTag(PLC_DISCHARGE_PUMP, 1) + + if (PLCGetTag(PLC_OUTLET_VALVE) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + PLCSetTag(PLC_INLET_VALVE, 0) + PLCSetTag(PLC_TAG_NOZZLE, 0) ticks_to_next_ball -= 1 - if not PLCGetTag(PLC_TAG_LIMIT_SWITCH): - PLCSetTag(PLC_TAG_PUMP, 1) + if not PLCGetTag(PLC_INLET_VALVE): + PLCSetTag(PLC_FEED_PUMP, 1) - if ticks_to_next_ball <= 0: #and PLCGetTag(PLC_TAG_NOZZLE): + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): ticks_to_next_ball = 1 ball_shape = add_ball(space) balls.append(ball_shape) else: - PLCSetTag(PLC_TAG_PUMP, 0) + PLCSetTag(PLC_TAG_NOZZLE, 0) balls_to_remove = [] @@ -288,8 +320,10 @@ def run_world(): draw_polygon(screen, nozzle) draw_lines(screen, lines) - draw_ball(screen, limit_switch, THECOLORS['red']) - draw_ball(screen, level_sensor, THECOLORS['red']) + draw_ball(screen, inlet_valve, THECOLORS['red']) + draw_ball(screen, tank_level, THECOLORS['red']) + draw_ball(screen, separator_vessel, THECOLORS['red']) + draw_ball(screen, outlet_valve, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) From 220ee1c75515becf349d7a34a68850b5b75ddf88 Mon Sep 17 00:00:00 2001 From: Ike-Clinton Date: Mon, 25 Jul 2016 11:27:15 -0400 Subject: [PATCH 009/239] Testing collab --- ike-test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 ike-test.txt diff --git a/ike-test.txt b/ike-test.txt new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/ike-test.txt @@ -0,0 +1 @@ +hello From ef19d19ccc97b9d8bcf881450691651be63e53e6 Mon Sep 17 00:00:00 2001 From: Ike-Clinton Date: Mon, 25 Jul 2016 11:27:37 -0400 Subject: [PATCH 010/239] remove ike-test.txt --- ike-test.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 ike-test.txt diff --git a/ike-test.txt b/ike-test.txt deleted file mode 100644 index ce01362..0000000 --- a/ike-test.txt +++ /dev/null @@ -1 +0,0 @@ -hello From c0748c03c19f02bd609ea4e4e2cf070aa4be0731 Mon Sep 17 00:00:00 2001 From: Ike-Clinton Date: Mon, 25 Jul 2016 11:31:47 -0400 Subject: [PATCH 011/239] Fixed startup script --- plants/oil-refinery/oil_world.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 0726222..761a345 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python import logging # - Multithreading @@ -371,4 +372,4 @@ def main(): startModbusServer() if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) From eb3a1aa53bcb6736c5e9ebc50fb67698fa50b814 Mon Sep 17 00:00:00 2001 From: Ike-Clinton Date: Mon, 25 Jul 2016 11:38:52 -0400 Subject: [PATCH 012/239] Removing inlet valve --- plants/oil-refinery/oil_world.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 761a345..1adadbf 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -96,15 +96,15 @@ def tank_level_sensor(space): return shape -def inlet_valve_sensor(space): - - body = pymunk.Body() - body.position = (165, 415) - radius = 2 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x1 # switch - space.add(shape) - return shape +#def inlet_valve_sensor(space): +# +# body = pymunk.Body() +# body.position = (165, 415) +# radius = 2 +# shape = pymunk.Circle(body, radius, (0, 0)) +# shape.collision_type = 0x1 # switch +# space.add(shape) +# return shape def add_nozzle(space): @@ -250,7 +250,7 @@ def run_world(): nozzle = add_nozzle(space) lines = add_oil_unit(space) - inlet_valve = inlet_valve_sensor(space) +# inlet_valve = inlet_valve_sensor(space) tank_level = tank_level_sensor(space) tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) From 3a1330a1ab3389275a6d23e78a8f3d79122dfef0 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 15:41:28 +0000 Subject: [PATCH 013/239] Test commit from c9 --- test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..e69de29 From 1385650b88aeed5b095d762c764a602530ffd6e1 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 15:41:55 +0000 Subject: [PATCH 014/239] remove test --- test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.txt diff --git a/test.txt b/test.txt deleted file mode 100644 index e69de29..0000000 From 27ac72ce0e0fc31698c90a5273bfcbfd4a066c4d Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 15:47:51 +0000 Subject: [PATCH 015/239] Removed inlet valve --- plants/oil-refinery/oil_hmi.py | 36 ++++++++++++++++---------------- plants/oil-refinery/oil_world.py | 22 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index d6fc0bd..2633104 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -16,7 +16,7 @@ def initModbus(self): def resetLabels(self): self.feed_pump_value.set_markup("N/A") - self.inlet_valve_value.set_markup("N/A") +# self.inlet_valve_value.set_markup("N/A") self.outlet_valve_value.set_markup("N/A") self.separator_value.set_markup("N/A") self.discharge_pump_value.set_markup("N/A") @@ -61,21 +61,21 @@ def __init__(self): grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) elementIndex += 1 - # Crude Oil Inlet Valve - inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") - inlet_valve_value = Gtk.Label() + #Crude Oil Inlet Valve +# inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") +# inlet_valve_value = Gtk.Label() - inlet_valve_open_button = Gtk.Button("OPEN") - inlet_valve_close_button = Gtk.Button("CLOSE") +# inlet_valve_open_button = Gtk.Button("OPEN") +# inlet_valve_close_button = Gtk.Button("CLOSE") - inlet_valve_open_button.connect("clicked", self.setProcess, 1) - inlet_valve_close_button.connect("clicked", self.setProcess, 0) +# inlet_valve_open_button.connect("clicked", self.setProcess, 1) +# inlet_valve_close_button.connect("clicked", self.setProcess, 0) - grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) - grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) - grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) - grid.attach(inlet_valve_close_button, 3, elementIndex, 1, 1) - elementIndex += 1 +# grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) +# grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) +# grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) +# grid.attach(inlet_valve_close_button, 3, elementIndex, 1, 1) +# elementIndex += 1 # Crude Oil Outlet Valve outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") @@ -147,7 +147,7 @@ def __init__(self): # Attach Value Labels self.feed_pump_value = feed_pump_value - self.inlet_valve_value = inlet_valve_value +# self.inlet_valve_value = inlet_valve_value self.outlet_valve_value = outlet_valve_value self.discharge_pump_value = discharge_pump_value self.process_status_value = process_status_value @@ -182,10 +182,10 @@ def update_status(self): else: self.feed_pump_value.set_markup("STOPPED") - if regs[2] == 1: - self.inlet_valve_value.set_markup("OPEN") - else: - self.inlet_valve_value.set_markup("CLOSED") +# if regs[2] == 1: +# self.inlet_valve_value.set_markup("OPEN") +# else: +# self.inlet_valve_value.set_markup("CLOSED") if regs[1] == 1: self.outlet_valve_value.set_markup("OPEN") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 1adadbf..5a53d31 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -37,7 +37,7 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 PLC_TANK_LEVEL = 0x1 -PLC_INLET_VALVE = 0x2 +##PLC_INLET_VALVE = 0x2 PLC_OUTLET_VALVE = 0x2 PLC_FEED_PUMP = 0x3 PLC_DISCHARGE_PUMP = 0x3 @@ -206,7 +206,7 @@ def no_collision(space, arbiter, *args, **kwargs): def level_ok(space, arbiter, *args, **kwargs): log.debug("Level reached") - PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle + # PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle PLCSetTag(PLC_OUTLET_VALVE, 1) @@ -216,7 +216,7 @@ def level_ok(space, arbiter, *args, **kwargs): def oil_storage_ready(space, arbiter, *args, **kwargs): log.debug("Storage bin ready") - PLCSetTag(PLC_INLET_VALVE, 1) + # PLCSetTag(PLC_INLET_VALVE, 1) PLCSetTag(PLC_TANK_LEVEL, 0) PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle PLCSetTag(PLC_OUTLET_VALVE, 0) @@ -279,12 +279,12 @@ def run_world(): # Motor Logic if (PLCGetTag(PLC_FEED_PUMP) == 1): - PLCSetTag(PLC_INLET_VALVE, 1) +# PLCSetTag(PLC_INLET_VALVE, 1) PLCSetTag(PLC_TAG_NOZZLE, 1) - if (PLCGetTag(PLC_INLET_VALVE) == 1): - PLCSetTag(PLC_OUTLET_VALVE, 0) - PLCSetTag(PLC_DISCHARGE_PUMP, 0) +# if (PLCGetTag(PLC_INLET_VALVE) == 1): +# PLCSetTag(PLC_OUTLET_VALVE, 0) +# PLCSetTag(PLC_DISCHARGE_PUMP, 0) if (PLCGetTag(PLC_TANK_LEVEL) == 1): @@ -293,12 +293,12 @@ def run_world(): if (PLCGetTag(PLC_OUTLET_VALVE) == 1): PLCSetTag(PLC_FEED_PUMP, 0) - PLCSetTag(PLC_INLET_VALVE, 0) + # PLCSetTag(PLC_INLET_VALVE, 0) PLCSetTag(PLC_TAG_NOZZLE, 0) ticks_to_next_ball -= 1 - if not PLCGetTag(PLC_INLET_VALVE): - PLCSetTag(PLC_FEED_PUMP, 1) +# if not PLCGetTag(PLC_INLET_VALVE): +# PLCSetTag(PLC_FEED_PUMP, 1) if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): ticks_to_next_ball = 1 @@ -321,7 +321,7 @@ def run_world(): draw_polygon(screen, nozzle) draw_lines(screen, lines) - draw_ball(screen, inlet_valve, THECOLORS['red']) +# draw_ball(screen, inlet_valve, THECOLORS['red']) draw_ball(screen, tank_level, THECOLORS['red']) draw_ball(screen, separator_vessel, THECOLORS['red']) draw_ball(screen, outlet_valve, THECOLORS['red']) From e723b0501cee203ee311eb05336aaa504a833536 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 15:50:00 +0000 Subject: [PATCH 016/239] Fixed nozzle --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5a53d31..a64f5c2 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -297,8 +297,8 @@ def run_world(): PLCSetTag(PLC_TAG_NOZZLE, 0) ticks_to_next_ball -= 1 -# if not PLCGetTag(PLC_INLET_VALVE): -# PLCSetTag(PLC_FEED_PUMP, 1) + if PLCGetTag(PLC_TAG_NOZZLE): + PLCSetTag(PLC_FEED_PUMP, 1) if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): ticks_to_next_ball = 1 From a5e2819805d234da821c96d0d98b67871c138173 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 15:51:13 +0000 Subject: [PATCH 017/239] fix --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a64f5c2..6018d27 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -297,7 +297,7 @@ def run_world(): PLCSetTag(PLC_TAG_NOZZLE, 0) ticks_to_next_ball -= 1 - if PLCGetTag(PLC_TAG_NOZZLE): + if PLCGetTag(PLC_TAG_NOZZLE) == 1: PLCSetTag(PLC_FEED_PUMP, 1) if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): From 1bb8fff8e906a560dedbfc857f94540f927970d4 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:14:36 +0000 Subject: [PATCH 018/239] Renamed nozzle to pump, remove discharge pump --- plants/oil-refinery/oil_hmi.py | 36 ++++++++++++++++---------------- plants/oil-refinery/oil_world.py | 31 +++++++++------------------ 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 2633104..c78925f 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -19,7 +19,7 @@ def resetLabels(self): # self.inlet_valve_value.set_markup("N/A") self.outlet_valve_value.set_markup("N/A") self.separator_value.set_markup("N/A") - self.discharge_pump_value.set_markup("N/A") +# self.discharge_pump_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") @@ -46,7 +46,7 @@ def __init__(self): elementIndex += 1 # Crude Oil Feed Pump - feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") + feed_pump_label = Gtk.Label("Crude Oil Tank Feed Nozzle") feed_pump_value = Gtk.Label() feed_pump_start_button = Gtk.Button("START") @@ -94,20 +94,20 @@ def __init__(self): elementIndex += 1 # Crude Oil Discharge Pump - discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") - discharge_pump_value = Gtk.Label() +# discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") +# discharge_pump_value = Gtk.Label() - discharge_pump_start_button = Gtk.Button("START") - discharge_pump_stop_button = Gtk.Button("STOP") +# discharge_pump_start_button = Gtk.Button("START") +# discharge_pump_stop_button = Gtk.Button("STOP") - discharge_pump_start_button.connect("clicked", self.setProcess, 1) - discharge_pump_stop_button.connect("clicked", self.setProcess, 0) +# discharge_pump_start_button.connect("clicked", self.setProcess, 1) +# discharge_pump_stop_button.connect("clicked", self.setProcess, 0) - grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) - grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) - grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) - grid.attach(discharge_pump_stop_button, 3, elementIndex, 1, 1) - elementIndex += 1 +# grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) +# grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) +# grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) +# grid.attach(discharge_pump_stop_button, 3, elementIndex, 1, 1) +# elementIndex += 1 #Oil/Water Separator Vessel separator_label = Gtk.Label("Oil/Water Separator Vessel") @@ -149,7 +149,7 @@ def __init__(self): self.feed_pump_value = feed_pump_value # self.inlet_valve_value = inlet_valve_value self.outlet_valve_value = outlet_valve_value - self.discharge_pump_value = discharge_pump_value +# self.discharge_pump_value = discharge_pump_value self.process_status_value = process_status_value self.connection_status_value = connection_status_value self.separator_value = separator_value @@ -192,10 +192,10 @@ def update_status(self): else: self.outlet_valve_value.set_markup("CLOSED") - if regs[1] == 1: - self.discharge_pump_value.set_markup("RUNNING") - else: - self.discharge_pump_value.set_markup("STOPPED") +# if regs[1] == 1: +# self.discharge_pump_value.set_markup("RUNNING") +# else: +# self.discharge_pump_value.set_markup("STOPPED") if regs[1] == 1: self.separator_value.set_markup("RUNNING") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 6018d27..31c6d51 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -37,11 +37,10 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 PLC_TANK_LEVEL = 0x1 -##PLC_INLET_VALVE = 0x2 +#PLC_INLET_VALVE = 0x2 PLC_OUTLET_VALVE = 0x2 PLC_FEED_PUMP = 0x3 PLC_DISCHARGE_PUMP = 0x3 -PLC_TAG_NOZZLE = 0x4 PLC_TAG_RUN = 0x10 def to_pygame(p): @@ -106,7 +105,7 @@ def tank_level_sensor(space): # space.add(shape) # return shape -def add_nozzle(space): +def add_pump(space): body = pymunk.Body() body.position = (179, 585) @@ -208,7 +207,7 @@ def level_ok(space, arbiter, *args, **kwargs): log.debug("Level reached") # PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled - PLCSetTag(PLC_TAG_NOZZLE, 0) # Close nozzle + PLCSetTag(PLC_FEED_PUMP, 0) # Close pump PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_DISCHARGE_PUMP, 1) return False @@ -218,7 +217,7 @@ def oil_storage_ready(space, arbiter, *args, **kwargs): log.debug("Storage bin ready") # PLCSetTag(PLC_INLET_VALVE, 1) PLCSetTag(PLC_TANK_LEVEL, 0) - PLCSetTag(PLC_TAG_NOZZLE, 1) # Open nozzle + PLCSetTag(PLC_FEED_PUMP, 1) # Open pump PLCSetTag(PLC_OUTLET_VALVE, 0) PLCSetTag(PLC_DISCHARGE_PUMP, 0) return False @@ -248,7 +247,7 @@ def run_world(): space.add_collision_handler(0x7, 0x2, begin=no_collision) space.add_collision_handler(0x7, 0x3, begin=no_collision) - nozzle = add_nozzle(space) + pump = add_pump(space) lines = add_oil_unit(space) # inlet_valve = inlet_valve_sensor(space) tank_level = tank_level_sensor(space) @@ -276,36 +275,26 @@ def run_world(): screen.fill(THECOLORS["grey"]) if PLCGetTag(PLC_TAG_RUN): - # Motor Logic if (PLCGetTag(PLC_FEED_PUMP) == 1): # PLCSetTag(PLC_INLET_VALVE, 1) - PLCSetTag(PLC_TAG_NOZZLE, 1) + PLCSetTag(PLC_OUTLET_VALVE, 0) -# if (PLCGetTag(PLC_INLET_VALVE) == 1): -# PLCSetTag(PLC_OUTLET_VALVE, 0) -# PLCSetTag(PLC_DISCHARGE_PUMP, 0) if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) - PLCSetTag(PLC_DISCHARGE_PUMP, 1) - - if (PLCGetTag(PLC_OUTLET_VALVE) == 1): PLCSetTag(PLC_FEED_PUMP, 0) # PLCSetTag(PLC_INLET_VALVE, 0) - PLCSetTag(PLC_TAG_NOZZLE, 0) + ticks_to_next_ball -= 1 - - if PLCGetTag(PLC_TAG_NOZZLE) == 1: - PLCSetTag(PLC_FEED_PUMP, 1) - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_NOZZLE): + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_PUMP): ticks_to_next_ball = 1 ball_shape = add_ball(space) balls.append(ball_shape) else: - PLCSetTag(PLC_TAG_NOZZLE, 0) + PLCSetTag(PLC_TAG_PUMP, 0) balls_to_remove = [] @@ -319,7 +308,7 @@ def run_world(): space.remove(ball, ball.body) balls.remove(ball) - draw_polygon(screen, nozzle) + draw_polygon(screen, pump) draw_lines(screen, lines) # draw_ball(screen, inlet_valve, THECOLORS['red']) draw_ball(screen, tank_level, THECOLORS['red']) From 0206a78a636b3a7a094a87632b3d233102136fd1 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:16:29 +0000 Subject: [PATCH 019/239] Fix line 297 TAG_PUMP --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 31c6d51..9151d15 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -294,7 +294,7 @@ def run_world(): ball_shape = add_ball(space) balls.append(ball_shape) else: - PLCSetTag(PLC_TAG_PUMP, 0) + PLCSetTag(PLC_FEED_PUMP, 0) balls_to_remove = [] From 7093c00696fddf1f733812f9785f77c6fb5d95d2 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:17:45 +0000 Subject: [PATCH 020/239] Fix tag --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 9151d15..853e379 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -289,7 +289,7 @@ def run_world(): ticks_to_next_ball -= 1 - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_TAG_PUMP): + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): ticks_to_next_ball = 1 ball_shape = add_ball(space) balls.append(ball_shape) From c942bd448c58aa11654b761d6bbaca2cf9d43908 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:21:32 +0000 Subject: [PATCH 021/239] minor text fixes --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index c78925f..0329bc7 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -46,7 +46,7 @@ def __init__(self): elementIndex += 1 # Crude Oil Feed Pump - feed_pump_label = Gtk.Label("Crude Oil Tank Feed Nozzle") + feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") feed_pump_value = Gtk.Label() feed_pump_start_button = Gtk.Button("START") From c8fff7b40ba07fe96ca4b3bf4b1c607d43f356a0 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:23:40 +0000 Subject: [PATCH 022/239] Fixed id --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 0329bc7..23351d0 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -177,7 +177,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[2] == 1: + if regs[3] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") From 40750103843aaca707b9feb9efadecffa3942a0e Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:25:43 +0000 Subject: [PATCH 023/239] run at startup --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 853e379..4d2532f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -294,7 +294,7 @@ def run_world(): ball_shape = add_ball(space) balls.append(ball_shape) else: - PLCSetTag(PLC_FEED_PUMP, 0) + PLCSetTag(PLC_FEED_PUMP, 1) balls_to_remove = [] From ffb7d2298c34154747b2532cf9b5c823b58dc248 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:33:00 +0000 Subject: [PATCH 024/239] fixes --- plants/oil-refinery/oil_world.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 4d2532f..6eba5a6 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -40,7 +40,6 @@ def PLCGetTag(addr): #PLC_INLET_VALVE = 0x2 PLC_OUTLET_VALVE = 0x2 PLC_FEED_PUMP = 0x3 -PLC_DISCHARGE_PUMP = 0x3 PLC_TAG_RUN = 0x10 def to_pygame(p): @@ -209,7 +208,7 @@ def level_ok(space, arbiter, *args, **kwargs): PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled PLCSetTag(PLC_FEED_PUMP, 0) # Close pump PLCSetTag(PLC_OUTLET_VALVE, 1) - PLCSetTag(PLC_DISCHARGE_PUMP, 1) +# PLCSetTag(PLC_DISCHARGE_PUMP, 1) return False def oil_storage_ready(space, arbiter, *args, **kwargs): @@ -219,7 +218,7 @@ def oil_storage_ready(space, arbiter, *args, **kwargs): PLCSetTag(PLC_TANK_LEVEL, 0) PLCSetTag(PLC_FEED_PUMP, 1) # Open pump PLCSetTag(PLC_OUTLET_VALVE, 0) - PLCSetTag(PLC_DISCHARGE_PUMP, 0) +# PLCSetTag(PLC_DISCHARGE_PUMP, 0) return False def run_world(): @@ -274,18 +273,14 @@ def run_world(): screen.fill(THECOLORS["grey"]) - if PLCGetTag(PLC_TAG_RUN): - # Motor Logic - if (PLCGetTag(PLC_FEED_PUMP) == 1): -# PLCSetTag(PLC_INLET_VALVE, 1) - PLCSetTag(PLC_OUTLET_VALVE, 0) - - - if (PLCGetTag(PLC_TANK_LEVEL) == 1): - - PLCSetTag(PLC_OUTLET_VALVE, 1) - PLCSetTag(PLC_FEED_PUMP, 0) - # PLCSetTag(PLC_INLET_VALVE, 0) + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_OUTLET_VALVE, 1) + PLCSetTag(PLC_FEED_PUMP, 0) + else: + PLCSetTag(PLC_OUTLET_VALVE, 0) ticks_to_next_ball -= 1 @@ -293,8 +288,8 @@ def run_world(): ticks_to_next_ball = 1 ball_shape = add_ball(space) balls.append(ball_shape) - else: - PLCSetTag(PLC_FEED_PUMP, 1) +# else: +# PLCSetTag(PLC_FEED_PUMP, 1) balls_to_remove = [] From 36664c476bcbdc1d90449786845da4cea2326bb2 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:36:40 +0000 Subject: [PATCH 025/239] change to 0x10 --- plants/oil-refinery/oil_world.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 6eba5a6..b42a810 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -39,8 +39,7 @@ def PLCGetTag(addr): PLC_TANK_LEVEL = 0x1 #PLC_INLET_VALVE = 0x2 PLC_OUTLET_VALVE = 0x2 -PLC_FEED_PUMP = 0x3 -PLC_TAG_RUN = 0x10 +PLC_FEED_PUMP = 0x10 def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" From c4d0ca85b0bb01dab5dcf15911593eb6d80c5a5b Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:43:30 +0000 Subject: [PATCH 026/239] Rewriting setProcess --- plants/oil-refinery/oil_hmi.py | 5 +++-- plants/oil-refinery/oil_world.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 23351d0..50a6dc2 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -54,6 +54,7 @@ def __init__(self): feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) + feed_pump_stop_button.register=(0x10) grid.attach(feed_pump_label, 0, elementIndex, 1, 1) grid.attach(feed_pump_value, 1, elementIndex, 1, 1) @@ -157,9 +158,9 @@ def __init__(self): self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - def setProcess(self, widget, data=None): + def setProcess(self, widget, register, data=None): try: - self.modbusClient.write_register(0x10, data) + self.modbusClient.write_register(register, data) except: pass diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b42a810..123b6c0 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -36,10 +36,10 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 -PLC_TANK_LEVEL = 0x1 -#PLC_INLET_VALVE = 0x2 -PLC_OUTLET_VALVE = 0x2 PLC_FEED_PUMP = 0x10 +PLC_TANK_LEVEL = 0x11 +PLC_OUTLET_VALVE = 0x12 + def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" From 0274d45bac8eeadbd6a7e12fea6c3f3f71152085 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 16:50:57 +0000 Subject: [PATCH 027/239] working on setProcess --- plants/oil-refinery/oil_hmi.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 50a6dc2..6627ec9 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -9,7 +9,6 @@ MODBUS_SLEEP=1 class HMIWindow(Gtk.Window): - def initModbus(self): self.modbusClient = ModbusClient('localhost', port=5020) @@ -54,7 +53,6 @@ def __init__(self): feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) - feed_pump_stop_button.register=(0x10) grid.attach(feed_pump_label, 0, elementIndex, 1, 1) grid.attach(feed_pump_value, 1, elementIndex, 1, 1) @@ -158,9 +156,9 @@ def __init__(self): self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - def setProcess(self, widget, register, data=None): + def setProcess(self, widget, data=None): try: - self.modbusClient.write_register(register, data) + self.modbusClient.write_register(0x10, data) except: pass From 840ab54c4b50889c6f7caea72739b999121a8349 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:41:38 +0000 Subject: [PATCH 028/239] Changing set process --- plants/oil-refinery/oil_hmi.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 6627ec9..722e442 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,6 +51,9 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") + feed_pump_start_button.connect("clicked", self.modbusClient.write_register(0x10, data), 1) + feed_pump_stop_button.connect("clicked", self.modbusClient.write_register(0x10, data), 0) + feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) @@ -156,9 +159,9 @@ def __init__(self): self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - def setProcess(self, widget, data=None): + def setProcess(self, widget, register, data=None): try: - self.modbusClient.write_register(0x10, data) + self.modbusClient.write_register(register, data) except: pass From 976bee2b2033e59880bc7573e4f692ed7dd051e3 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:42:33 +0000 Subject: [PATCH 029/239] Fix --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 722e442..8000c1b 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,8 +51,8 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") - feed_pump_start_button.connect("clicked", self.modbusClient.write_register(0x10, data), 1) - feed_pump_stop_button.connect("clicked", self.modbusClient.write_register(0x10, data), 0) + feed_pump_start_button.connect("clicked", self.modbusClient.write_register(0x10, None), 1) + feed_pump_stop_button.connect("clicked", self.modbusClient.write_register(0x10, None), 0) feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) From 91c932d5bfaec23d3c7a1262586d71702b8a153f Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:44:41 +0000 Subject: [PATCH 030/239] Fix --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 8000c1b..67b7120 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -159,9 +159,9 @@ def __init__(self): self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - def setProcess(self, widget, register, data=None): + def setProcess(self, widget, data=None): try: - self.modbusClient.write_register(register, data) + self.modbusClient.write_register(0x10, data) except: pass From 2a4bbbd49169b8545a30b466d043bc4e5d104d06 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:52:25 +0000 Subject: [PATCH 031/239] Added new setCommand func --- plants/oil-refinery/oil_hmi.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 67b7120..9d9afab 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,8 +51,8 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") - feed_pump_start_button.connect("clicked", self.modbusClient.write_register(0x10, None), 1) - feed_pump_stop_button.connect("clicked", self.modbusClient.write_register(0x10, None), 0) + feed_pump_start_button.connect("clicked", self.setCommand(0x10), 1) + feed_pump_stop_button.connect("clicked", self.setCommand(0x10), 0) feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) @@ -164,6 +164,12 @@ def setProcess(self, widget, data=None): self.modbusClient.write_register(0x10, data) except: pass + + def setCommand(register, data=None): + try: + self.modbusClient.write_register(register, data) + except: + pass def update_status(self): From 2b503f8f23e7feb8f41e62d7e242cf6f22228628 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:54:15 +0000 Subject: [PATCH 032/239] Added new setCommand func --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 9d9afab..293a700 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,8 +51,8 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") - feed_pump_start_button.connect("clicked", self.setCommand(0x10), 1) - feed_pump_stop_button.connect("clicked", self.setCommand(0x10), 0) + feed_pump_start_button.connect("clicked", setCommand(0x10), 1) + feed_pump_stop_button.connect("clicked", setCommand(0x10), 0) feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) From 957c0275efbfe5094dc5dcf341cc6f0c5feb85d7 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:55:03 +0000 Subject: [PATCH 033/239] Added new setCommand func --- plants/oil-refinery/oil_hmi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 293a700..a8e5c52 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,8 +51,8 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") - feed_pump_start_button.connect("clicked", setCommand(0x10), 1) - feed_pump_stop_button.connect("clicked", setCommand(0x10), 0) + feed_pump_start_button.connect("clicked", self.setCommand(0x10), 1) + feed_pump_stop_button.connect("clicked", self.setCommand(0x10), 0) feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) @@ -165,7 +165,7 @@ def setProcess(self, widget, data=None): except: pass - def setCommand(register, data=None): + def setCommand(self, widget, register, data=None): try: self.modbusClient.write_register(register, data) except: From 71c494ef15bca070845bf1950b6eca9f571bba73 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:56:03 +0000 Subject: [PATCH 034/239] Added new setCommand func --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index a8e5c52..0a02715 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,8 +51,8 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") - feed_pump_start_button.connect("clicked", self.setCommand(0x10), 1) - feed_pump_stop_button.connect("clicked", self.setCommand(0x10), 0) + feed_pump_start_button.connect("clicked", self.setCommand(self, 0x10), 1) + feed_pump_stop_button.connect("clicked", self.setCommand(self, 0x10), 0) feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) From f4eaa52bb25504e183a6d79d3f5f0594fcd9ca43 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:57:30 +0000 Subject: [PATCH 035/239] Added new setCommand func --- plants/oil-refinery/oil_hmi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 0a02715..414f6e6 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -159,15 +159,15 @@ def __init__(self): self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - def setProcess(self, widget, data=None): + def setPump(self, widget, data=None): try: self.modbusClient.write_register(0x10, data) except: pass - def setCommand(self, widget, register, data=None): + def setOutputValve(self, widget, data=None): try: - self.modbusClient.write_register(register, data) + self.modbusClient.write_register(0x11, data) except: pass From 754aa24eba081a9b6b92f10e948348961ab34006 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 17:58:41 +0000 Subject: [PATCH 036/239] Each process now has own func --- plants/oil-refinery/oil_hmi.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 414f6e6..1b38a0b 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -51,8 +51,8 @@ def __init__(self): feed_pump_start_button = Gtk.Button("START") feed_pump_stop_button = Gtk.Button("STOP") - feed_pump_start_button.connect("clicked", self.setCommand(self, 0x10), 1) - feed_pump_stop_button.connect("clicked", self.setCommand(self, 0x10), 0) + feed_pump_start_button.connect("clicked", self.setPump, 1) + feed_pump_stop_button.connect("clicked", self.setPump, 0) feed_pump_start_button.connect("clicked", self.setProcess, 1) feed_pump_stop_button.connect("clicked", self.setProcess, 0) @@ -165,6 +165,12 @@ def setPump(self, widget, data=None): except: pass + def setProcess(self, widget, data=None): + try: + self.modbusClient.write_register(0x10, data) + except: + pass + def setOutputValve(self, widget, data=None): try: self.modbusClient.write_register(0x11, data) From 33b47548f8fe9a6f2ebba59b0d22bbe43a74f67e Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:04:48 +0000 Subject: [PATCH 037/239] Each process now has own func --- plants/oil-refinery/oil_world.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 123b6c0..29eac03 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -110,6 +110,16 @@ def add_pump(space): shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) space.add(shape) return shape + +def draw_valve(space): + body = pymunk.Body() + body.position = (300, 300) + valve = pymunk.Segment(body, (-115, 20), -90, 20), 5) + + space.add(valve) + return valve + +def remove_valve(space): def add_oil_unit(space): #rotation_limit_body = pymunk.Body() From 0dcc0659b0f5968dc54f3f3b36c7c68ee5d766e1 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:05:35 +0000 Subject: [PATCH 038/239] Add and del valve --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 29eac03..6ec64a3 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -114,13 +114,13 @@ def add_pump(space): def draw_valve(space): body = pymunk.Body() body.position = (300, 300) - valve = pymunk.Segment(body, (-115, 20), -90, 20), 5) + valve = pymunk.Segment(body, (-115, 20), (-90, 20), 5) space.add(valve) return valve def remove_valve(space): - + return 0 def add_oil_unit(space): #rotation_limit_body = pymunk.Body() #rotation_limit_body.position = (200,300) From 54b80b24b57d540d58317388a2e9829f497e12f9 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:05:58 +0000 Subject: [PATCH 039/239] Add and del valve --- plants/oil-refinery/oil_world.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 6ec64a3..fdf1b9b 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -121,6 +121,7 @@ def draw_valve(space): def remove_valve(space): return 0 + def add_oil_unit(space): #rotation_limit_body = pymunk.Body() #rotation_limit_body.position = (200,300) From c6f00dc83fde7a57f50195c353187a543260af2b Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:06:52 +0000 Subject: [PATCH 040/239] Add and del valve --- plants/oil-refinery/oil_hmi.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 1b38a0b..da458a5 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -54,9 +54,6 @@ def __init__(self): feed_pump_start_button.connect("clicked", self.setPump, 1) feed_pump_stop_button.connect("clicked", self.setPump, 0) - feed_pump_start_button.connect("clicked", self.setProcess, 1) - feed_pump_stop_button.connect("clicked", self.setProcess, 0) - grid.attach(feed_pump_label, 0, elementIndex, 1, 1) grid.attach(feed_pump_value, 1, elementIndex, 1, 1) grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) From c00d1650b73500ca665fa1057d918de672af8fbc Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:08:40 +0000 Subject: [PATCH 041/239] Add and del valve --- plants/oil-refinery/oil_world.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index fdf1b9b..5f4110e 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -289,6 +289,7 @@ def run_world(): if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) + draw_valve(space) else: PLCSetTag(PLC_OUTLET_VALVE, 0) From e025bdc7afcfc455478f94db8482560ef78a435b Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:10:50 +0000 Subject: [PATCH 042/239] Add and del valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5f4110e..ef65191 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -289,7 +289,7 @@ def run_world(): if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) - draw_valve(space) + valve = draw_valve(space) else: PLCSetTag(PLC_OUTLET_VALVE, 0) From 3e5a7159408d252a803b65b45816be9a808bafa4 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:12:51 +0000 Subject: [PATCH 043/239] Add and del valve --- plants/oil-refinery/oil_world.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ef65191..625430c 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -115,7 +115,6 @@ def draw_valve(space): body = pymunk.Body() body.position = (300, 300) valve = pymunk.Segment(body, (-115, 20), (-90, 20), 5) - space.add(valve) return valve @@ -258,11 +257,11 @@ def run_world(): pump = add_pump(space) lines = add_oil_unit(space) -# inlet_valve = inlet_valve_sensor(space) tank_level = tank_level_sensor(space) tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) outlet_valve = outlet_valve_sensor(space) + valve = draw_valve(space) balls = [] @@ -289,7 +288,6 @@ def run_world(): if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) - valve = draw_valve(space) else: PLCSetTag(PLC_OUTLET_VALVE, 0) From 304e9ad8e755b07ecefbe0c081a1f93d1aefc6ab Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:17:58 +0000 Subject: [PATCH 044/239] Add and del valve --- plants/oil-refinery/oil_world.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 625430c..ae864d4 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -261,7 +261,7 @@ def run_world(): tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) outlet_valve = outlet_valve_sensor(space) - valve = draw_valve(space) + valve = tank_outlet_valve(space) balls = [] @@ -284,10 +284,13 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: - + # Draw the valve if the pump is on + draw_lines(screen, valve) + # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) + else: PLCSetTag(PLC_OUTLET_VALVE, 0) From 24851f880810a12194337ba7fe866e2f7c59dccf Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:20:06 +0000 Subject: [PATCH 045/239] Add and del valve --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ae864d4..3017a9d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -111,7 +111,7 @@ def add_pump(space): space.add(shape) return shape -def draw_valve(space): +def add_outlet_valve(space): body = pymunk.Body() body.position = (300, 300) valve = pymunk.Segment(body, (-115, 20), (-90, 20), 5) @@ -261,7 +261,7 @@ def run_world(): tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) outlet_valve = outlet_valve_sensor(space) - valve = tank_outlet_valve(space) + valve = add_outlet_valve(space) balls = [] From e82c1e3faae9820be1bfa402b90983a990ecb56c Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:22:43 +0000 Subject: [PATCH 046/239] Add and del valve --- plants/oil-refinery/oil_world.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 3017a9d..0ced47e 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -196,6 +196,14 @@ def draw_polygon(screen, shape): for p in points: fpoints.append(to_pygame(p)) pygame.draw.polygon(screen, THECOLORS['darkgreen'], fpoints) + +def draw_line(screen, lines): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) def draw_lines(screen, lines): @@ -285,7 +293,7 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on - draw_lines(screen, valve) + draw_line(screen, valve) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) From 94c6616e42ba6350bd929b1d1e3a49e450822cad Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:23:42 +0000 Subject: [PATCH 047/239] Add and del valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 0ced47e..d81f86f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -197,7 +197,7 @@ def draw_polygon(screen, shape): fpoints.append(to_pygame(p)) pygame.draw.polygon(screen, THECOLORS['darkgreen'], fpoints) -def draw_line(screen, lines): +def draw_line(screen, line): body = line.body pv1 = body.position + line.a.rotated(body.angle) # 1 pv2 = body.position + line.b.rotated(body.angle) From 591d640501313ea444555d2d08fb28070c3469c1 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:30:38 +0000 Subject: [PATCH 048/239] Add and del valve --- plants/oil-refinery/oil_world.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index d81f86f..0919782 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -190,7 +190,6 @@ def add_oil_unit(space): return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30,l31,l32,l33 def draw_polygon(screen, shape): - points = shape.get_vertices() fpoints = [] for p in points: @@ -269,7 +268,6 @@ def run_world(): tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) outlet_valve = outlet_valve_sensor(space) - valve = add_outlet_valve(space) balls = [] @@ -293,6 +291,7 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on + valve = add_outlet_valve(space) draw_line(screen, valve) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): @@ -301,6 +300,7 @@ def run_world(): else: PLCSetTag(PLC_OUTLET_VALVE, 0) + space.remove(valve, valve.body) ticks_to_next_ball -= 1 @@ -325,7 +325,6 @@ def run_world(): draw_polygon(screen, pump) draw_lines(screen, lines) -# draw_ball(screen, inlet_valve, THECOLORS['red']) draw_ball(screen, tank_level, THECOLORS['red']) draw_ball(screen, separator_vessel, THECOLORS['red']) draw_ball(screen, outlet_valve, THECOLORS['red']) From c08f9dacda2d1ae71244e187babca37a8db4f7d6 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:34:42 +0000 Subject: [PATCH 049/239] Add and del valve --- plants/oil-refinery/oil_world.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 0919782..26fa5e9 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -300,8 +300,11 @@ def run_world(): else: PLCSetTag(PLC_OUTLET_VALVE, 0) - space.remove(valve, valve.body) - + try + space.remove(valve, valve.body) + except + pass + ticks_to_next_ball -= 1 if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): From d01774624e97733f5660e32944936600c646aa19 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:35:12 +0000 Subject: [PATCH 050/239] Add and del valve --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 26fa5e9..1fbc5e1 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -300,9 +300,9 @@ def run_world(): else: PLCSetTag(PLC_OUTLET_VALVE, 0) - try + try: space.remove(valve, valve.body) - except + except: pass ticks_to_next_ball -= 1 From 85f87561043f207b146151286fcbf649308e8d57 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:37:34 +0000 Subject: [PATCH 051/239] Add and del valve --- plants/oil-refinery/oil_hmi.py | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index da458a5..f74a388 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -14,13 +14,13 @@ def initModbus(self): self.modbusClient = ModbusClient('localhost', port=5020) def resetLabels(self): - self.feed_pump_value.set_markup("N/A") + self.feed_pump_value.set_markup(" weight='bold' foreground='gray33'>N/A") # self.inlet_valve_value.set_markup("N/A") - self.outlet_valve_value.set_markup("N/A") - self.separator_value.set_markup("N/A") + self.outlet_valve_value.set_markup(" weight='bold' foreground='gray33'>N/A") + self.separator_value.set_markup(" weight='bold' foreground='gray33'>N/A") # self.discharge_pump_value.set_markup("N/A") - self.process_status_value.set_markup("N/A") - self.connection_status_value.set_markup("OFFLINE") + self.process_status_value.set_markup(" weight='bold' foreground='gray33'>N/A") + self.connection_status_value.set_markup(" weight='bold' foreground='red'>OFFLINE") def __init__(self): Gtk.Window.__init__(self, title="Oil Refinery") @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("Crude Oil Pretreatment Unit") + label.set_markup(" weight='bold' size='x-large' color='black'>Crude Oil Pretreatment Unit") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 @@ -141,7 +141,7 @@ def __init__(self): # Oil Refienery branding virtual_refinery = Gtk.Label() - virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") + virtual_refinery.set_markup(" size='small'>Crude Oil Pretreatment Unit - HMI") grid.attach(virtual_refinery, 0, elementIndex, 2, 1) # Attach Value Labels @@ -189,19 +189,19 @@ def update_status(self): raise ConnectionException if regs[3] == 1: - self.feed_pump_value.set_markup("RUNNING") + self.feed_pump_value.set_markup(" weight='bold' foreground='green'>RUNNING") else: - self.feed_pump_value.set_markup("STOPPED") + self.feed_pump_value.set_markup(" weight='bold' foreground='red'>STOPPED") # if regs[2] == 1: -# self.inlet_valve_value.set_markup("OPEN") +# self.inlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") # else: -# self.inlet_valve_value.set_markup("CLOSED") +# self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") if regs[1] == 1: - self.outlet_valve_value.set_markup("OPEN") + self.outlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") else: - self.outlet_valve_value.set_markup("CLOSED") + self.outlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") # if regs[1] == 1: # self.discharge_pump_value.set_markup("RUNNING") @@ -209,16 +209,16 @@ def update_status(self): # self.discharge_pump_value.set_markup("STOPPED") if regs[1] == 1: - self.separator_value.set_markup("RUNNING") + self.separator_value.set_markup(" weight='bold' foreground='green'>RUNNING") else: - self.separator_value.set_markup("span weight='bold' foreground='red'>STOPPED") + self.separator_value.set_markup(" weight='bold' foreground='red'>STOPPED") if regs[15] == 1: - self.process_status_value.set_markup("RUNNING") + self.process_status_value.set_markup(" weight='bold' foreground='green'>RUNNING") else: - self.process_status_value.set_markup("STOPPED") + self.process_status_value.set_markup(" weight='bold' foreground='red'>STOPPED") - self.connection_status_value.set_markup("ONLINE") + self.connection_status_value.set_markup(" weight='bold' foreground='green'>ONLINE") except ConnectionException: From 846bc20206aa682ee06a458f8983dd451f07c537 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:38:28 +0000 Subject: [PATCH 052/239] Add and del valve --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index f74a388..2204da1 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -216,9 +216,9 @@ def update_status(self): if regs[15] == 1: self.process_status_value.set_markup(" weight='bold' foreground='green'>RUNNING") else: - self.process_status_value.set_markup(" weight='bold' foreground='red'>STOPPED") + self.process_status_value.set_markup("STOPPED >") - self.connection_status_value.set_markup(" weight='bold' foreground='green'>ONLINE") + self.connection_status_value.set_markup("ONLINE >") except ConnectionException: From ffac06ee9d4694228c3578a24bb5e26bf61d287e Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:39:21 +0000 Subject: [PATCH 053/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 2204da1..c90bd4a 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -216,9 +216,9 @@ def update_status(self): if regs[15] == 1: self.process_status_value.set_markup(" weight='bold' foreground='green'>RUNNING") else: - self.process_status_value.set_markup("STOPPED >") + self.process_status_value.set_markup("STOPPED />") - self.connection_status_value.set_markup("ONLINE >") + self.connection_status_value.set_markup("ONLINE />") except ConnectionException: From 803aa867a00841f4b8f03ced7719b3d0baaf3263 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:42:09 +0000 Subject: [PATCH 054/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index c90bd4a..4eee6da 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -189,9 +189,9 @@ def update_status(self): raise ConnectionException if regs[3] == 1: - self.feed_pump_value.set_markup(" weight='bold' foreground='green'>RUNNING") + self.feed_pump_value.set_markup("RUNNING>") else: - self.feed_pump_value.set_markup(" weight='bold' foreground='red'>STOPPED") + self.feed_pump_value.set_markup("STOPPED /span>") # if regs[2] == 1: # self.inlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") From 6179731bac075802f707e91e621353b13d444e95 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:43:12 +0000 Subject: [PATCH 055/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 4eee6da..93fa5b6 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -141,7 +141,7 @@ def __init__(self): # Oil Refienery branding virtual_refinery = Gtk.Label() - virtual_refinery.set_markup(" size='small'>Crude Oil Pretreatment Unit - HMI") + virtual_refinery.set_markup(" size='small'>Crude Oil Pretreatment Unit - HMI") grid.attach(virtual_refinery, 0, elementIndex, 2, 1) # Attach Value Labels From 1ea0587b8a0dfce05a7513ff2311b2c3be9ea420 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:44:38 +0000 Subject: [PATCH 056/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 93fa5b6..572d3f0 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup(" weight='bold' size='x-large' color='black'>Crude Oil Pretreatment Unit") + label.set_markup("Crude Oil Pretreatment Unit />") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From 6810add63c68db6e327feb717852ac5beec288de Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:45:52 +0000 Subject: [PATCH 057/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 572d3f0..b1b1c4a 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("Crude Oil Pretreatment Unit />") + label.set_markup("Crude Oil Pretreatment Unit") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From a5ffa31dd52545007d08615c31fea23722b7076c Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:46:32 +0000 Subject: [PATCH 058/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index b1b1c4a..22fa505 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("Crude Oil Pretreatment Unit") + label.set_markup("") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From 58971663dcf3ba96e82a4a3a7263f499f207da3d Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:47:06 +0000 Subject: [PATCH 059/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 22fa505..6d12b9e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("") + label.set_markup("") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From af82d0241ca507e7192e1339c05d84b72f91838f Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:47:36 +0000 Subject: [PATCH 060/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 6d12b9e..c8ee506 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("") + label.set_markup("Crude Oil Pretreatment Unit /span>") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From af737c9b5b85b33e06a510edb7a088112e441f20 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:48:54 +0000 Subject: [PATCH 061/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index c8ee506..0573cab 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -40,7 +40,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("Crude Oil Pretreatment Unit /span>") + label.set_markup("Crude Oil Pretreatment Unit ") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From e605dcde2ee1379b6a6c80bb74793fb65437fba6 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:50:28 +0000 Subject: [PATCH 062/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 0573cab..29ef996 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -141,7 +141,7 @@ def __init__(self): # Oil Refienery branding virtual_refinery = Gtk.Label() - virtual_refinery.set_markup(" size='small'>Crude Oil Pretreatment Unit - HMI") + virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") grid.attach(virtual_refinery, 0, elementIndex, 2, 1) # Attach Value Labels @@ -189,9 +189,9 @@ def update_status(self): raise ConnectionException if regs[3] == 1: - self.feed_pump_value.set_markup("RUNNING>") + self.feed_pump_value.set_markup("RUNNING") else: - self.feed_pump_value.set_markup("STOPPED /span>") + self.feed_pump_value.set_markup("STOPPED") # if regs[2] == 1: # self.inlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") @@ -199,9 +199,9 @@ def update_status(self): # self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") if regs[1] == 1: - self.outlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") + self.outlet_valve_value.set_markup("OPEN") else: - self.outlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") + self.outlet_valve_value.set_markup("CLOSED") # if regs[1] == 1: # self.discharge_pump_value.set_markup("RUNNING") @@ -209,16 +209,16 @@ def update_status(self): # self.discharge_pump_value.set_markup("STOPPED") if regs[1] == 1: - self.separator_value.set_markup(" weight='bold' foreground='green'>RUNNING") + self.separator_value.set_markup("RUNNING") else: - self.separator_value.set_markup(" weight='bold' foreground='red'>STOPPED") + self.separator_value.set_markup("STOPPED") if regs[15] == 1: - self.process_status_value.set_markup(" weight='bold' foreground='green'>RUNNING") + self.process_status_value.set_markup("RUNNING") else: - self.process_status_value.set_markup("STOPPED />") + self.process_status_value.set_markup("STOPPED ") - self.connection_status_value.set_markup("ONLINE />") + self.connection_status_value.set_markup("ONLINE ") except ConnectionException: From 468b1109d05349b31408374cc03800e5e5eab1c5 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:51:21 +0000 Subject: [PATCH 063/239] fixing markup --- plants/oil-refinery/oil_hmi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 29ef996..60db8c4 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -14,13 +14,13 @@ def initModbus(self): self.modbusClient = ModbusClient('localhost', port=5020) def resetLabels(self): - self.feed_pump_value.set_markup(" weight='bold' foreground='gray33'>N/A") + self.feed_pump_value.set_markup("N/A") # self.inlet_valve_value.set_markup("N/A") - self.outlet_valve_value.set_markup(" weight='bold' foreground='gray33'>N/A") - self.separator_value.set_markup(" weight='bold' foreground='gray33'>N/A") + self.outlet_valve_value.set_markup("N/A") + self.separator_value.set_markup("N/A") # self.discharge_pump_value.set_markup("N/A") - self.process_status_value.set_markup(" weight='bold' foreground='gray33'>N/A") - self.connection_status_value.set_markup(" weight='bold' foreground='red'>OFFLINE") + self.process_status_value.set_markup("N/A") + self.connection_status_value.set_markup("OFFLINE") def __init__(self): Gtk.Window.__init__(self, title="Oil Refinery") @@ -214,7 +214,7 @@ def update_status(self): self.separator_value.set_markup("STOPPED") if regs[15] == 1: - self.process_status_value.set_markup("RUNNING") + self.process_status_value.set_markup("RUNNING ") else: self.process_status_value.set_markup("STOPPED ") From f7226c1c02875a1505dc4cf059eb4bc5196c8f9a Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:53:18 +0000 Subject: [PATCH 064/239] Fixed pump logic --- plants/oil-refinery/oil_world.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 1fbc5e1..62abf4a 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -298,12 +298,12 @@ def run_world(): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) - else: - PLCSetTag(PLC_OUTLET_VALVE, 0) - try: - space.remove(valve, valve.body) - except: - pass + else: + PLCSetTag(PLC_OUTLET_VALVE, 0) + try: + space.remove(valve, valve.body) + except: + pass ticks_to_next_ball -= 1 From 563731445805e1f282f4e2957a90f93a85d1a394 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:55:46 +0000 Subject: [PATCH 065/239] Fixed pump logic --- plants/oil-refinery/oil_world.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 62abf4a..0ac02c2 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -297,20 +297,23 @@ def run_world(): if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) - - else: - PLCSetTag(PLC_OUTLET_VALVE, 0) - try: - space.remove(valve, valve.body) - except: - pass + # Draw balls ticks_to_next_ball -= 1 if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): ticks_to_next_ball = 1 ball_shape = add_ball(space) balls.append(ball_shape) + + else: + # PLCSetTag(PLC_OUTLET_VALVE, 0) + try: + space.remove(valve, valve.body) + except: + pass + + # else: # PLCSetTag(PLC_FEED_PUMP, 1) From b9519a897b7892b64e633fe785fc9e9732a393f0 Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 18:57:34 +0000 Subject: [PATCH 066/239] Fixed pump logic --- plants/oil-refinery/oil_world.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 0ac02c2..ff8a7a0 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -299,12 +299,7 @@ def run_world(): PLCSetTag(PLC_FEED_PUMP, 0) # Draw balls - ticks_to_next_ball -= 1 - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): - ticks_to_next_ball = 1 - ball_shape = add_ball(space) - balls.append(ball_shape) else: # PLCSetTag(PLC_OUTLET_VALVE, 0) @@ -318,6 +313,13 @@ def run_world(): # PLCSetTag(PLC_FEED_PUMP, 1) + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + balls_to_remove = [] for ball in balls: if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: From 68af7b6f8e964b2d3fdbcbe8db7c4ba466bcc5da Mon Sep 17 00:00:00 2001 From: Ike Date: Mon, 25 Jul 2016 19:02:30 +0000 Subject: [PATCH 067/239] Fixed pump logic --- plants/oil-refinery/oil_world.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ff8a7a0..e399264 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -297,14 +297,12 @@ def run_world(): if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 0) - - # Draw balls - - + else: # PLCSetTag(PLC_OUTLET_VALVE, 0) try: space.remove(valve, valve.body) + valve.kill() except: pass From cccb08e21683f1ffb722641fb52ae29856aa17d9 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 11:53:45 +0000 Subject: [PATCH 068/239] fixed oil storage lines --- plants/oil-refinery/oil_world.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e399264..b1f5482 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -131,8 +131,8 @@ def add_oil_unit(space): body = pymunk.Body() body.position = (300,300) #feed pump - l1 = pymunk.Segment(body, (-100, 270), (-100, 115), 5) - l2 = pymunk.Segment(body, (-135, 270), (-135, 115), 5) + l1 = pymunk.Segment(body, (-100, 270), (-100, 145), 5) + l2 = pymunk.Segment(body, (-135, 270), (-135, 145), 5) #l3 = pymunk.Segment(body, (-135, 115), (-100, 115), 5) #l3 = pymunk.Segment(body, (-250, 180), (-135, 180), 5) #l4 = pymunk.Segment(body, (-215, 200), (-115, 200), 5) @@ -140,8 +140,8 @@ def add_oil_unit(space): #l6 = pymunk.Segment(body, (-115, 200), (-115, 120), 5) #oil storage unit - l7 = pymunk.Segment(body, (-185, 115), (-185, 20), 5) - l8 = pymunk.Segment(body, (-65, 115), (-65, 20), 5) + l7 = pymunk.Segment(body, (-185, 130), (-185, 20), 5) + l8 = pymunk.Segment(body, (-65, 130), (-65, 20), 5) l9 = pymunk.Segment(body, (-185,20), (-115, 20), 5) l10 = pymunk.Segment(body, (-90, 20), (-65, 20), 5) @@ -302,7 +302,6 @@ def run_world(): # PLCSetTag(PLC_OUTLET_VALVE, 0) try: space.remove(valve, valve.body) - valve.kill() except: pass From d6996ec63497a38a63cc9046e98e85ca2e4a5870 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:04:06 +0000 Subject: [PATCH 069/239] start/stop --- plants/oil-refinery/oil_world.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b1f5482..12404ae 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -288,22 +288,24 @@ def run_world(): screen.fill(THECOLORS["grey"]) + valve = add_outlet_valve(space) + draw_line(screen, valve) # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on - valve = add_outlet_valve(space) - draw_line(screen, valve) + #valve = add_outlet_valve(space) + #draw_line(screen, valve) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_OUTLET_VALVE, 1) - PLCSetTag(PLC_FEED_PUMP, 0) + PLCSetTag(PLC_FEED_PUMP, 1) - else: + #else: # PLCSetTag(PLC_OUTLET_VALVE, 0) - try: - space.remove(valve, valve.body) - except: - pass + # try: + # space.remove(valve, valve.body) + # except: + # pass # else: From cbecf68dec3c9ae0bec6acb42d0e873f9095775e Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:07:46 +0000 Subject: [PATCH 070/239] changed registers --- plants/oil-refinery/oil_hmi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 60db8c4..b738477 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -164,13 +164,13 @@ def setPump(self, widget, data=None): def setProcess(self, widget, data=None): try: - self.modbusClient.write_register(0x10, data) + self.modbusClient.write_register(0x11, data) except: pass def setOutputValve(self, widget, data=None): try: - self.modbusClient.write_register(0x11, data) + self.modbusClient.write_register(0x12, data) except: pass @@ -188,7 +188,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[3] == 1: + if regs[11] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") @@ -198,7 +198,7 @@ def update_status(self): # else: # self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") - if regs[1] == 1: + if regs[12] == 1: self.outlet_valve_value.set_markup("OPEN") else: self.outlet_valve_value.set_markup("CLOSED") @@ -208,7 +208,7 @@ def update_status(self): # else: # self.discharge_pump_value.set_markup("STOPPED") - if regs[1] == 1: + if regs[3] == 1: self.separator_value.set_markup("RUNNING") else: self.separator_value.set_markup("STOPPED") From 08762c06c2ecb38873cd1aa8b8f1367b2c9f8725 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:36:55 +0000 Subject: [PATCH 071/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index b738477..0248877 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -188,7 +188,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[11] == 1: + if regs[1] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") From 9444989c6fbe88cf15dcd1666910e54e7ad619f1 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:37:50 +0000 Subject: [PATCH 072/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 0248877..3d014a8 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -188,7 +188,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[1] == 1: + if regs[10] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") From c5370268fa4b34e416298bedae4765e3c1a70a6a Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:43:11 +0000 Subject: [PATCH 073/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 8 ++++---- plants/oil-refinery/oil_world.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 3d014a8..95c8fb1 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -188,7 +188,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[10] == 1: + if regs[1] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") @@ -198,7 +198,7 @@ def update_status(self): # else: # self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") - if regs[12] == 1: + if regs[3] == 1: self.outlet_valve_value.set_markup("OPEN") else: self.outlet_valve_value.set_markup("CLOSED") @@ -208,12 +208,12 @@ def update_status(self): # else: # self.discharge_pump_value.set_markup("STOPPED") - if regs[3] == 1: + if regs[4] == 1: self.separator_value.set_markup("RUNNING") else: self.separator_value.set_markup("STOPPED") - if regs[15] == 1: + if regs[1] == 1: self.process_status_value.set_markup("RUNNING ") else: self.process_status_value.set_markup("STOPPED ") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 12404ae..a950941 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -36,9 +36,9 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 -PLC_FEED_PUMP = 0x10 -PLC_TANK_LEVEL = 0x11 -PLC_OUTLET_VALVE = 0x12 +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 def to_pygame(p): From 089ceff3ab8040158757d49711b6dca321422cca Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:49:13 +0000 Subject: [PATCH 074/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 22 ++++++++++++++-------- plants/oil-refinery/oil_world.py | 1 + 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 95c8fb1..813af2a 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -83,8 +83,8 @@ def __init__(self): outlet_valve_open_button = Gtk.Button("OPEN") outlet_valve_close_button = Gtk.Button("CLOSE") - outlet_valve_open_button.connect("clicked", self.setProcess, 1) - outlet_valve_close_button.connect("clicked", self.setProcess, 0) + outlet_valve_open_button.connect("clicked", self.setOutputValve, 1) + outlet_valve_close_button.connect("clicked", self.setOutputValve, 0) grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) @@ -115,8 +115,8 @@ def __init__(self): separator_start_button = Gtk.Button("START") separator_stop_button = Gtk.Button("STOP") - separator_start_button.connect("clicked", self.setProcess, 1) - separator_stop_button.connect("clicked", self.setProcess, 0) + separator_start_button.connect("clicked", self.setSepVessel, 1) + separator_stop_button.connect("clicked", self.setSepVessel, 0) grid.attach(separator_label, 0, elementIndex, 1, 1) grid.attach(separator_value, 1, elementIndex, 1, 1) @@ -158,19 +158,25 @@ def __init__(self): def setPump(self, widget, data=None): try: - self.modbusClient.write_register(0x10, data) + self.modbusClient.write_register(0x01, data) except: pass - def setProcess(self, widget, data=None): + def setTankLevel(self, widget, data=None): try: - self.modbusClient.write_register(0x11, data) + self.modbusClient.write_register(0x02, data) except: pass def setOutputValve(self, widget, data=None): try: - self.modbusClient.write_register(0x12, data) + self.modbusClient.write_register(0x03, data) + except: + pass + + def setSepVessel(self, widget, data=None): + try: + self.modbusClient.write_register(0x04, data) except: pass diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a950941..a3589cd 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -39,6 +39,7 @@ def PLCGetTag(addr): PLC_FEED_PUMP = 0x01 PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 def to_pygame(p): From f77e40eff826ccf6376e962bc44dc9f6c1634a31 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:51:26 +0000 Subject: [PATCH 075/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 813af2a..5592b44 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -194,7 +194,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[1] == 1: + if regs[2] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") From da1d040b04ce7733a5a2c7c1fb19c30ed8406893 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:52:10 +0000 Subject: [PATCH 076/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 5592b44..521c960 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -194,7 +194,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[2] == 1: + if regs[3] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") @@ -219,7 +219,7 @@ def update_status(self): else: self.separator_value.set_markup("STOPPED") - if regs[1] == 1: + if regs[3] == 1: self.process_status_value.set_markup("RUNNING ") else: self.process_status_value.set_markup("STOPPED ") From a677d24d29abc55e550417a1c6073c2de4358ec5 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:53:48 +0000 Subject: [PATCH 077/239] fix pump status message --- plants/oil-refinery/oil_hmi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 521c960..5767bf8 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -194,7 +194,7 @@ def update_status(self): if not regs or len(regs) < 16: raise ConnectionException - if regs[3] == 1: + if regs[0] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") @@ -204,7 +204,7 @@ def update_status(self): # else: # self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") - if regs[3] == 1: + if regs[2] == 1: self.outlet_valve_value.set_markup("OPEN") else: self.outlet_valve_value.set_markup("CLOSED") @@ -214,7 +214,7 @@ def update_status(self): # else: # self.discharge_pump_value.set_markup("STOPPED") - if regs[4] == 1: + if regs[3] == 1: self.separator_value.set_markup("RUNNING") else: self.separator_value.set_markup("STOPPED") From fc096dbe4864be66832e8b843e2b4c89107227e0 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 17:57:16 +0000 Subject: [PATCH 078/239] remove valve --- plants/oil-refinery/oil_world.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a3589cd..b3ac9c8 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -289,8 +289,6 @@ def run_world(): screen.fill(THECOLORS["grey"]) - valve = add_outlet_valve(space) - draw_line(screen, valve) # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on From 6dd57eb9578b5062892f046c47fc33988b8eb6f5 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:06:27 +0000 Subject: [PATCH 079/239] remove valve --- plants/oil-refinery/oil_world.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b3ac9c8..e2c62b5 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -93,7 +93,6 @@ def tank_level_sensor(space): space.add(shape) return shape - #def inlet_valve_sensor(space): # # body = pymunk.Body() @@ -111,16 +110,7 @@ def add_pump(space): shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) space.add(shape) return shape - -def add_outlet_valve(space): - body = pymunk.Body() - body.position = (300, 300) - valve = pymunk.Segment(body, (-115, 20), (-90, 20), 5) - space.add(valve) - return valve - -def remove_valve(space): - return 0 + def add_oil_unit(space): #rotation_limit_body = pymunk.Body() @@ -296,17 +286,8 @@ def run_world(): #draw_line(screen, valve) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): - PLCSetTag(PLC_OUTLET_VALVE, 1) PLCSetTag(PLC_FEED_PUMP, 1) - - #else: - # PLCSetTag(PLC_OUTLET_VALVE, 0) - # try: - # space.remove(valve, valve.body) - # except: - # pass - - + if # else: # PLCSetTag(PLC_FEED_PUMP, 1) From 8ddaa71d41521cba76aafa00b3ff051aa5d541f0 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:07:01 +0000 Subject: [PATCH 080/239] remove valve --- plants/oil-refinery/oil_hmi.py | 3 ++- plants/oil-refinery/oil_world.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 5767bf8..d8a757f 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -138,7 +138,8 @@ def __init__(self): grid.attach(connection_status_label, 0, elementIndex, 1, 1) grid.attach(connection_status_value, 1, elementIndex, 1, 1) elementIndex += 1 - + + # Oil Refienery branding virtual_refinery = Gtk.Label() virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e2c62b5..82d33be 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -287,7 +287,7 @@ def run_world(): # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 1) - if + # else: # PLCSetTag(PLC_FEED_PUMP, 1) From 4d4a34ab7f320a35e36febc7de3f50668e9ce217 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:13:18 +0000 Subject: [PATCH 081/239] remove valve --- plants/oil-refinery/oil_world.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 82d33be..8d3f970 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -217,6 +217,12 @@ def level_ok(space, arbiter, *args, **kwargs): PLCSetTag(PLC_OUTLET_VALVE, 1) # PLCSetTag(PLC_DISCHARGE_PUMP, 1) return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False def oil_storage_ready(space, arbiter, *args, **kwargs): @@ -249,7 +255,9 @@ def run_world(): space.add_collision_handler(0x1, 0x3, begin=no_collision) # Level sensor with bottle side space.add_collision_handler(0x4, 0x3, begin=no_collision) - + + space.add_collision_handler(0x7, 0x5, begin=sep_on) + space.add_collision_handler(0x7, 0x2, begin=no_collision) space.add_collision_handler(0x7, 0x3, begin=no_collision) @@ -287,10 +295,6 @@ def run_world(): # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 1) - -# else: -# PLCSetTag(PLC_FEED_PUMP, 1) - ticks_to_next_ball -= 1 From f8cf5784823270ff76f22781a4c405079fb01fe1 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:14:39 +0000 Subject: [PATCH 082/239] add sep handler --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 8d3f970..a72791a 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -76,8 +76,8 @@ def outlet_valve_sensor(space): def separator_vessel_release(space): body = pymunk.Body() - body.position = (380, 225) - radius = 2 + body.position = (390, 225) + radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = 0x7 space.add(shape) From f568d9aa9f821f6837b64515a54752c5b9827aa9 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:15:06 +0000 Subject: [PATCH 083/239] add sep handler --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a72791a..bcd615c 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -76,7 +76,7 @@ def outlet_valve_sensor(space): def separator_vessel_release(space): body = pymunk.Body() - body.position = (390, 225) + body.position = (385, 225) radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = 0x7 From 2cbe3b612c3766a43d47f7b01df50853088f99c9 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:15:27 +0000 Subject: [PATCH 084/239] add sep handler --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index bcd615c..a72791a 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -76,7 +76,7 @@ def outlet_valve_sensor(space): def separator_vessel_release(space): body = pymunk.Body() - body.position = (385, 225) + body.position = (390, 225) radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = 0x7 From 7b0c9a80ab6cbdfe3a4d4ec45a9c83153c447781 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:22:51 +0000 Subject: [PATCH 085/239] add sep handler --- plants/oil-refinery/oil_world.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a72791a..e59d417 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -60,7 +60,7 @@ def add_ball(space): space.add(body, shape) return shape -def draw_ball(screen, ball, color=THECOLORS['black']): +def draw_ball(screen, ball, color=THECOLORS['brown']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) @@ -70,7 +70,7 @@ def outlet_valve_sensor(space): body.position = (185, 320) radius = 2 shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x7 # 'bottle_in' + shape.collision_type = 0x8 # 'bottle_in' space.add(shape) return shape @@ -93,16 +93,6 @@ def tank_level_sensor(space): space.add(shape) return shape -#def inlet_valve_sensor(space): -# -# body = pymunk.Body() -# body.position = (165, 415) -# radius = 2 -# shape = pymunk.Circle(body, radius, (0, 0)) -# shape.collision_type = 0x1 # switch -# space.add(shape) -# return shape - def add_pump(space): body = pymunk.Body() From a125c347541f335ea37cf2ba616222bf900f2f24 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:23:31 +0000 Subject: [PATCH 086/239] add sep handler --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e59d417..ddafdc8 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -175,7 +175,7 @@ def draw_polygon(screen, shape): fpoints = [] for p in points: fpoints.append(to_pygame(p)) - pygame.draw.polygon(screen, THECOLORS['darkgreen'], fpoints) + pygame.draw.polygon(screen, THECOLORS['black'], fpoints) def draw_line(screen, line): body = line.body From 7c4f56f2f9a1dc276bb4b47b9d9cf654e9493828 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 26 Jul 2016 18:28:50 +0000 Subject: [PATCH 087/239] removed outlet valve --- plants/oil-refinery/oil_hmi.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index d8a757f..185713e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -77,20 +77,20 @@ def __init__(self): # elementIndex += 1 # Crude Oil Outlet Valve - outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") - outlet_valve_value = Gtk.Label() +# outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") +# outlet_valve_value = Gtk.Label() - outlet_valve_open_button = Gtk.Button("OPEN") - outlet_valve_close_button = Gtk.Button("CLOSE") +# outlet_valve_open_button = Gtk.Button("OPEN") +# outlet_valve_close_button = Gtk.Button("CLOSE") - outlet_valve_open_button.connect("clicked", self.setOutputValve, 1) - outlet_valve_close_button.connect("clicked", self.setOutputValve, 0) +# outlet_valve_open_button.connect("clicked", self.setOutputValve, 1) +# outlet_valve_close_button.connect("clicked", self.setOutputValve, 0) - grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) - grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) - grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) - grid.attach(outlet_valve_close_button, 3, elementIndex, 1, 1) - elementIndex += 1 +# grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) +# grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) +# grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) +# grid.attach(outlet_valve_close_button, 3, elementIndex, 1, 1) +# elementIndex += 1 # Crude Oil Discharge Pump # discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") @@ -148,7 +148,7 @@ def __init__(self): # Attach Value Labels self.feed_pump_value = feed_pump_value # self.inlet_valve_value = inlet_valve_value - self.outlet_valve_value = outlet_valve_value +# self.outlet_valve_value = outlet_valve_value # self.discharge_pump_value = discharge_pump_value self.process_status_value = process_status_value self.connection_status_value = connection_status_value @@ -205,10 +205,10 @@ def update_status(self): # else: # self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") - if regs[2] == 1: - self.outlet_valve_value.set_markup("OPEN") - else: - self.outlet_valve_value.set_markup("CLOSED") +# if regs[2] == 1: +# self.outlet_valve_value.set_markup("OPEN") +# else: +# self.outlet_valve_value.set_markup("CLOSED") # if regs[1] == 1: # self.discharge_pump_value.set_markup("RUNNING") From e3f55eb7675943136d64d86c301842d9edf83979 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Wed, 27 Jul 2016 10:30:51 -0400 Subject: [PATCH 088/239] added attack scripts --- plants/bottle-filling/attacks/stop_all.py | 2 +- .../{move_and_fill.py => constant_running.py} | 9 +++---- .../{never_stop.py => nothing_runs.py} | 9 +++---- plants/oil-refinery/attacks/stop_all.py | 27 ------------------- plants/oil-refinery/attacks/stop_and_fill.py | 27 ------------------- 5 files changed, 9 insertions(+), 65 deletions(-) rename plants/oil-refinery/attacks/{move_and_fill.py => constant_running.py} (65%) rename plants/oil-refinery/attacks/{never_stop.py => nothing_runs.py} (65%) delete mode 100755 plants/oil-refinery/attacks/stop_all.py delete mode 100755 plants/oil-refinery/attacks/stop_and_fill.py diff --git a/plants/bottle-filling/attacks/stop_all.py b/plants/bottle-filling/attacks/stop_all.py index 6719d3c..23436f3 100755 --- a/plants/bottle-filling/attacks/stop_all.py +++ b/plants/bottle-filling/attacks/stop_all.py @@ -16,7 +16,7 @@ try: client.connect() while True: - rq = client.write_register(0x10, 1) # Run Plant, Run! + rq = client.write_register(0x01, 1) # Run Plant, Run! rq = client.write_register(0x1, 0) # Level Sensor rq = client.write_register(0x2, 1) # Limit Switch rq = client.write_register(0x3, 0) # Motor diff --git a/plants/oil-refinery/attacks/move_and_fill.py b/plants/oil-refinery/attacks/constant_running.py similarity index 65% rename from plants/oil-refinery/attacks/move_and_fill.py rename to plants/oil-refinery/attacks/constant_running.py index b1d99c2..c08ef9f 100755 --- a/plants/oil-refinery/attacks/move_and_fill.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -16,11 +16,10 @@ try: client.connect() while True: - rq = client.write_register(0x10, 1) # Run Plant, Run! - rq = client.write_register(0x1, 0) # Level Sensor - rq = client.write_register(0x2, 0) # Limit Switch - rq = client.write_register(0x3, 1) # Motor - rq = client.write_register(0x4, 1) # Nozzle + rq = client.write_register(0x01, 1) # Run Plant, Run! + rq = client.write_register(0x02, 0) # Level Sensor + rq = client.write_register(0x04, 0) # Limit Switch + except KeyboardInterrupt: client.close() except ConnectionException: diff --git a/plants/oil-refinery/attacks/never_stop.py b/plants/oil-refinery/attacks/nothing_runs.py similarity index 65% rename from plants/oil-refinery/attacks/never_stop.py rename to plants/oil-refinery/attacks/nothing_runs.py index 2d1469e..4a1edd6 100755 --- a/plants/oil-refinery/attacks/never_stop.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -16,11 +16,10 @@ try: client.connect() while True: - rq = client.write_register(0x10, 1) # Run Plant, Run! - rq = client.write_register(0x1, 0) # Level Sensor - rq = client.write_register(0x2, 0) # Limit Switch - rq = client.write_register(0x3, 1) # Motor - rq = client.write_register(0x4, 0) # Nozzle + rq = client.write_register(0x01, 0) # Run Plant, Run! + rq = client.write_register(0x02, 0) # Level Sensor + rq = client.write_register(0x04, 1) # Limit Switch + except KeyboardInterrupt: client.close() except ConnectionException: diff --git a/plants/oil-refinery/attacks/stop_all.py b/plants/oil-refinery/attacks/stop_all.py deleted file mode 100755 index 6719d3c..0000000 --- a/plants/oil-refinery/attacks/stop_all.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python - -from pymodbus.client.sync import ModbusTcpClient as ModbusClient -from pymodbus.exceptions import ConnectionException -import logging - -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -##################################### -# Code -##################################### -client = ModbusClient('localhost', port=5020) - -try: - client.connect() - while True: - rq = client.write_register(0x10, 1) # Run Plant, Run! - rq = client.write_register(0x1, 0) # Level Sensor - rq = client.write_register(0x2, 1) # Limit Switch - rq = client.write_register(0x3, 0) # Motor - rq = client.write_register(0x4, 0) # Nozzle -except KeyboardInterrupt: - client.close() -except ConnectionException: - print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery/attacks/stop_and_fill.py b/plants/oil-refinery/attacks/stop_and_fill.py deleted file mode 100755 index 63517ae..0000000 --- a/plants/oil-refinery/attacks/stop_and_fill.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python - -from pymodbus.client.sync import ModbusTcpClient as ModbusClient -from pymodbus.exceptions import ConnectionException -import logging - -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -##################################### -# Code -##################################### -client = ModbusClient('localhost', port=5020) - -try: - client.connect() - while True: - rq = client.write_register(0x10, 1) # Run Plant, Run! - rq = client.write_register(0x1, 0) # Level Sensor - rq = client.write_register(0x2, 1) # Limit Switch - rq = client.write_register(0x3, 0) # Motor - rq = client.write_register(0x4, 1) # Nozzle -except KeyboardInterrupt: - client.close() -except ConnectionException: - print "Unable to connect / Connection lost" From 9d55cb2d3bec6bbd23054fa2caf7c8a8f234dc7c Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Thu, 28 Jul 2016 09:54:41 -0400 Subject: [PATCH 089/239] adding test scripts --- .../attacks/constant_running.py | 26 ++ .../oil-refinery_test/attacks/nothing_runs.py | 26 ++ plants/oil-refinery_test/oil_hmi.py | 249 ++++++++++++ plants/oil-refinery_test/oil_world.py | 384 ++++++++++++++++++ plants/oil-refinery_test/start.sh | 7 + 5 files changed, 692 insertions(+) create mode 100755 plants/oil-refinery_test/attacks/constant_running.py create mode 100755 plants/oil-refinery_test/attacks/nothing_runs.py create mode 100755 plants/oil-refinery_test/oil_hmi.py create mode 100755 plants/oil-refinery_test/oil_world.py create mode 100755 plants/oil-refinery_test/start.sh diff --git a/plants/oil-refinery_test/attacks/constant_running.py b/plants/oil-refinery_test/attacks/constant_running.py new file mode 100755 index 0000000..c08ef9f --- /dev/null +++ b/plants/oil-refinery_test/attacks/constant_running.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient('localhost', port=5020) + +try: + client.connect() + while True: + rq = client.write_register(0x01, 1) # Run Plant, Run! + rq = client.write_register(0x02, 0) # Level Sensor + rq = client.write_register(0x04, 0) # Limit Switch + +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery_test/attacks/nothing_runs.py b/plants/oil-refinery_test/attacks/nothing_runs.py new file mode 100755 index 0000000..4a1edd6 --- /dev/null +++ b/plants/oil-refinery_test/attacks/nothing_runs.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient('localhost', port=5020) + +try: + client.connect() + while True: + rq = client.write_register(0x01, 0) # Run Plant, Run! + rq = client.write_register(0x02, 0) # Level Sensor + rq = client.write_register(0x04, 1) # Limit Switch + +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery_test/oil_hmi.py b/plants/oil-refinery_test/oil_hmi.py new file mode 100755 index 0000000..adb0d77 --- /dev/null +++ b/plants/oil-refinery_test/oil_hmi.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python + +from gi.repository import GLib, Gtk, Gdk, GObject +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException + + + +MODBUS_SLEEP=1 + +class HMIWindow(Gtk.Window): + def initModbus(self): + + self.modbusClient = ModbusClient('localhost', port=5020) + + def resetLabels(self): + self.feed_pump_value.set_markup("N/A") +# self.inlet_valve_value.set_markup("N/A") +# self.outlet_valve_value.set_markup("N/A") + self.separator_value.set_markup("N/A") +# self.discharge_pump_value.set_markup("N/A") + self.process_status_value.set_markup("N/A") + self.connection_status_value.set_markup("OFFLINE") + + def __init__(self): + Gtk.Window.__init__(self, title="Oil Refinery") + #self.gtk_widget_override_background_color(Gtk.StateType.NORMAL, Gtk.Window("green")) + + self.set_border_width(100) + + self.initModbus() + + elementIndex = 0 + + # Grid + grid = Gtk.Grid() + grid.set_row_spacing(15) + grid.set_column_spacing(10) + self.add(grid) + + # Main title label + label = Gtk.Label() + label.set_markup("Crude Oil Pretreatment Unit ") + grid.attach(label, 0, elementIndex, 4, 1) + elementIndex += 1 + + # Crude Oil Feed Pump + feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") + feed_pump_value = Gtk.Label() + + feed_pump_start_button = Gtk.Button("START") + feed_pump_stop_button = Gtk.Button("STOP") + + feed_pump_start_button.connect("clicked", self.setPump, 1) + feed_pump_stop_button.connect("clicked", self.setPump, 0) + + grid.attach(feed_pump_label, 0, elementIndex, 1, 1) + grid.attach(feed_pump_value, 1, elementIndex, 1, 1) + grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) + grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) + elementIndex += 1 + + #Crude Oil Inlet Valve +# inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") +# inlet_valve_value = Gtk.Label() + +# inlet_valve_open_button = Gtk.Button("OPEN") +# inlet_valve_close_button = Gtk.Button("CLOSE") + +# inlet_valve_open_button.connect("clicked", self.setProcess, 1) +# inlet_valve_close_button.connect("clicked", self.setProcess, 0) + +# grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) +# grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) +# grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) +# grid.attach(inlet_valve_close_button, 3, elementIndex, 1, 1) +# elementIndex += 1 + + # Crude Oil Outlet Valve +# outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") +# outlet_valve_value = Gtk.Label() + +# outlet_valve_open_button = Gtk.Button("OPEN") +# outlet_valve_close_button = Gtk.Button("CLOSE") + +# outlet_valve_open_button.connect("clicked", self.setOutputValve, 1) +# outlet_valve_close_button.connect("clicked", self.setOutputValve, 0) + +# grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) +# grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) +# grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) +# grid.attach(outlet_valve_close_button, 3, elementIndex, 1, 1) +# elementIndex += 1 + + # Crude Oil Discharge Pump +# discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") +# discharge_pump_value = Gtk.Label() + +# discharge_pump_start_button = Gtk.Button("START") +# discharge_pump_stop_button = Gtk.Button("STOP") + +# discharge_pump_start_button.connect("clicked", self.setProcess, 1) +# discharge_pump_stop_button.connect("clicked", self.setProcess, 0) + +# grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) +# grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) +# grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) +# grid.attach(discharge_pump_stop_button, 3, elementIndex, 1, 1) +# elementIndex += 1 + + #Oil/Water Separator Vessel + separator_label = Gtk.Label("Oil/Water Separator Vessel") + separator_value = Gtk.Label() + + separator_start_button = Gtk.Button("START") + separator_stop_button = Gtk.Button("STOP") + + separator_start_button.connect("clicked", self.setSepVessel, 1) + separator_stop_button.connect("clicked", self.setSepVessel, 0) + + grid.attach(separator_label, 0, elementIndex, 1, 1) + grid.attach(separator_value, 1, elementIndex, 1, 1) + grid.attach(separator_start_button, 2, elementIndex, 1, 1) + grid.attach(separator_stop_button, 3, elementIndex, 1, 1) + elementIndex += 1 + + # Process status + process_status_label = Gtk.Label("Process Status") + process_status_value = Gtk.Label() + grid.attach(process_status_label, 0, elementIndex, 1, 1) + grid.attach(process_status_value, 1, elementIndex, 1, 1) + elementIndex += 1 + + # Connection status + connection_status_label = Gtk.Label("Connection Status") + connection_status_value = Gtk.Label() + + grid.attach(connection_status_label, 0, elementIndex, 1, 1) + grid.attach(connection_status_value, 1, elementIndex, 1, 1) + elementIndex += 1 + + + # Oil Refienery branding + virtual_refinery = Gtk.Label() + virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") + grid.attach(virtual_refinery, 0, elementIndex, 2, 1) + + # Attach Value Labels + self.feed_pump_value = feed_pump_value +# self.inlet_valve_value = inlet_valve_value +# self.outlet_valve_value = outlet_valve_value +# self.discharge_pump_value = discharge_pump_value + self.process_status_value = process_status_value + self.connection_status_value = connection_status_value + self.separator_value = separator_value + + self.resetLabels() + GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) + + def setPump(self, widget, data=None): + try: + self.modbusClient.write_register(0x01, data) + except: + pass + + def setTankLevel(self, widget, data=None): + try: + self.modbusClient.write_register(0x02, data) + except: + pass + + def setSepFeed(self, widget, data=None): + try: + self.modbusClient.write_register(0x05, data) + except: + pass + + def setSepVessel(self, widget, data=None): + try: + self.modbusClient.write_register(0x04, data) + except: + pass + + def update_status(self): + + try: + rr = self.modbusClient.read_holding_registers(1,16) + regs = [] + + if not rr or not rr.registers: + raise ConnectionException + + regs = rr.registers + + if not regs or len(regs) < 16: + raise ConnectionException + + if regs[0] == 1: + self.feed_pump_value.set_markup("RUNNING") + else: + self.feed_pump_value.set_markup("STOPPED") + +# if regs[2] == 1: +# self.inlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") +# else: +# self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") + +# if regs[2] == 1: +# self.outlet_valve_value.set_markup("OPEN") +# else: +# self.outlet_valve_value.set_markup("CLOSED") + +# if regs[1] == 1: +# self.discharge_pump_value.set_markup("RUNNING") +# else: +# self.discharge_pump_value.set_markup("STOPPED") + + if regs[3] == 1: + self.separator_value.set_markup("RUNNING") + else: + self.separator_value.set_markup("STOPPED") + + if regs[3] == 1: + self.process_status_value.set_markup("RUNNING ") + else: + self.process_status_value.set_markup("STOPPED ") + + self.connection_status_value.set_markup("ONLINE ") + + + except ConnectionException: + if not self.modbusClient.connect(): + self.resetLabels() + except: + raise + finally: + return True + +def app_main(): + win = HMIWindow() + win.connect("delete-event", Gtk.main_quit) + win.connect("destroy", Gtk.main_quit) + win.show_all() + + +if __name__ == "__main__": + GObject.threads_init() + app_main() + Gtk.main() diff --git a/plants/oil-refinery_test/oil_world.py b/plants/oil-refinery_test/oil_world.py new file mode 100755 index 0000000..fe1b9ba --- /dev/null +++ b/plants/oil-refinery_test/oil_world.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +def PLCSetTag(addr, value): + context[0x0].setValues(3, addr, [value]) + +def PLCGetTag(addr): + return context[0x0].getValues(3, addr, count=1)[0] + +SCREEN_WIDTH = 640 +SCREEN_HEIGHT = 550 +FPS=50.0 + +MODBUS_SERVER_PORT=5020 + +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(180, 181) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = 0x5 #liquid + space.add(body, shape) + return shape + +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +def separator_vessel_feed(space): + + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x8 # 'bottle_in' + space.add(shape) + return shape + +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (390, 225) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x7 + space.add(shape) + return shape + +def tank_level_sensor(space): + + body = pymunk.Body() + body.position = (125, 400) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = 0x4 # tank_level + space.add(shape) + return shape + +def add_pump(space): + + body = pymunk.Body() + body.position = (179, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + + +def add_oil_unit(space): + #rotation_limit_body = pymunk.Body() + #rotation_limit_body.position = (200,300) + + #rotation_center_body = pymunk.Body() + #rotation_center_body.position = (300,300) + + body = pymunk.Body() + body.position = (300,300) + #feed pump + l1 = pymunk.Segment(body, (-100, 270), (-100, 145), 5) + l2 = pymunk.Segment(body, (-135, 270), (-135, 145), 5) + #l3 = pymunk.Segment(body, (-135, 115), (-100, 115), 5) + #l3 = pymunk.Segment(body, (-250, 180), (-135, 180), 5) + #l4 = pymunk.Segment(body, (-215, 200), (-115, 200), 5) + #l5 = pymunk.Segment(body, (-135, 180), (-135, 120), 5) + #l6 = pymunk.Segment(body, (-115, 200), (-115, 120), 5) + + #oil storage unit + l7 = pymunk.Segment(body, (-185, 130), (-185, 20), 5) + l8 = pymunk.Segment(body, (-65, 130), (-65, 20), 5) + l9 = pymunk.Segment(body, (-185,20), (-115, 20), 5) + l10 = pymunk.Segment(body, (-90, 20), (-65, 20), 5) + + #pipe to separator vessel + l11 = pymunk.Segment(body, (-115, 20), (-115, -45), 5) + l12 = pymunk.Segment(body, (-90, 20), (-90, -25), 5) + l13 = pymunk.Segment(body, (-115, -45), (-40, -45), 5) + l14 = pymunk.Segment(body, (-90, -25), (-40, -25), 5) + + #separator vessel + l15 = pymunk.Segment(body, (-40, -45), (-40, -75), 5) + l16 = pymunk.Segment(body, (-40, -25), (-40, 5), 5) + l17 = pymunk.Segment(body, (-40, -75), (80, -75), 5) + l18 = pymunk.Segment(body, (-40, 5), (120, 5), 5) + l19 = pymunk.Segment(body, (100, -75), (120, -75), 5) + l22 = pymunk.Segment(body, (120, -75), (120, -55), 5) + l23 = pymunk.Segment(body, (120, -30), (120, 5), 5) + + #waste water pipe + l20 = pymunk.Segment(body, (80, -75), (80, -115), 5) + l21 = pymunk.Segment(body, (100, -75), (100, -115), 5) + + #separator exit pipe + l24 = pymunk.Segment(body, (120, -30), (600, -30), 5) + l25 = pymunk.Segment(body, (120, -55), (600, -55), 5) + + #waste water storage + l26 = pymunk.Segment(body, (80, -115), (20, -115), 5) + l27 = pymunk.Segment(body, (20, -115), (20, -185), 5) + l28 = pymunk.Segment(body, (20, -185), (140, -185), 5) + l29 = pymunk.Segment(body, (140, -185), (140, -170), 5) + l30 = pymunk.Segment(body, (140, -145), (140, -115), 5) + l31 = pymunk.Segment(body, (140, -115), (100, -115), 5) + l32 = pymunk.Segment(body, (140, -145), (600, -145), 5) + l33 = pymunk.Segment(body, (140, -170), (600, -170), 5) + + + #rotation_center_joint = pymunk.PinJoint(body, rotation_center_body, (-135,115), (-100, 115)) + #joint_limit = 25 + #rotation_limit_joint = pymunk.SlideJoint(body, rotation_limit_body, (-135,115), (-100,115), 5, joint_limit) + + space.add(l1, l2, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33) # 3 + + return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30,l31,l32,l33 + +def draw_polygon(screen, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(screen, THECOLORS['black'], fpoints) + +def draw_line(screen, line): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + +def draw_lines(screen, lines): + + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + +def no_collision(space, arbiter, *args, **kwargs): + return False + +def level_ok(space, arbiter, *args, **kwargs): + + log.debug("Level reached") + # PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled + PLCSetTag(PLC_FEED_PUMP, 0) # Close pump + PLCSetTag(PLC_OUTLET_VALVE, 1) +# PLCSetTag(PLC_DISCHARGE_PUMP, 1) + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +def sep_feed(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def oil_storage_ready(space, arbiter, *args, **kwargs): + + log.debug("Storage bin ready") + # PLCSetTag(PLC_INLET_VALVE, 1) + PLCSetTag(PLC_TANK_LEVEL, 0) + PLCSetTag(PLC_FEED_PUMP, 1) # Open pump + PLCSetTag(PLC_OUTLET_VALVE, 0) +# PLCSetTag(PLC_DISCHARGE_PUMP, 0) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) + # Level sensor with water + space.add_collision_handler(0x4, 0x5, begin=level_ok) + # Level sensor with ground + space.add_collision_handler(0x4, 0x6, begin=no_collision) + # Limit switch with ground + space.add_collision_handler(0x1, 0x6, begin=no_collision) + # Limit switch with bottle side + space.add_collision_handler(0x1, 0x3, begin=no_collision) + # Level sensor with bottle side + space.add_collision_handler(0x4, 0x3, begin=no_collision) + +# space.add_collision_handler(0x7, 0x5, begin=sep_feed) +# space.add_collision_handler(0x7, 0x5, begin=sep_on) +# space.add_collision_handler(0x7, 0x5, stop=sep_off) + + space.add_collision_handler(0x7, 0x2, begin=no_collision) + space.add_collision_handler(0x7, 0x3, begin=no_collision) + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) +# tank_in = outlet_valve_sensor(space) + separator_vessel = separator_vessel_release(space) +# outlet_valve = outlet_valve_sensor(space) + separator_feed = separator_vessel_feed(space) + + + balls = [] + + ticks_to_next_ball = 1 + + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + space.add_collision_handler(0x7, 0x5, stop=sep_on) + space.add_collision_handler(0x8, 0x5, stop=sep_feed) + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 1) + PLCSetTag(PLC_SEP_VESSEL, 1) + PLCSetTag(PLC_SEP_FEED, 1) + space.add_collision_handler(0x7, 0x5, begin=sep_on) + space.add_collision_handler(0x8, 0x5, begin=sep_feed) + + if (PLCGetTag(PLC_SEP_VESSEL) == 0): + space.add_collision_handler(0x7, 0x5, stop=sep_on) + space.add_collision_handler(0x8, 0x5, stop=sep_feed) +# if (PLCGetTag(PLC_SEP_VESSEL) == 0): +# PLCSetTag(PLC_FEED_PUMP, 1) + +# if (PLCGetTag(PLC_TANK_LEVEL) == 0): + + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(screen, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(screen, pump) + draw_lines(screen, lines) + draw_ball(screen, tank_level, THECOLORS['red']) + draw_ball(screen, separator_vessel, THECOLORS['red']) + draw_ball(screen, separator_feed, THECOLORS['red']) + #draw_ball(screen, separator_feed, THECOLORS['red']) + + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + screen.blit(title, (300, 40)) + screen.blit(name, (347, 10)) + screen.blit(instructions, (SCREEN_WIDTH-115, 10)) + screen.blit(feed_pump_label, (65, 80)) + screen.blit(oil_storage_label, (240, 190)) + screen.blit(separator_label, (270,275)) + screen.blit(waste_water_label, (265, 490)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +identity = ModbusDeviceIdentification() +identity.VendorName = 'MockPLCs' +identity.ProductCode = 'MP' +identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' +identity.ProductName = 'MockPLC 4000' +identity.ModelName = 'MockPLC Platinum' +identity.MajorMinorRevision = '1.0' + +def startModbusServer(): + + StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery_test/start.sh b/plants/oil-refinery_test/start.sh new file mode 100755 index 0000000..3c19e3d --- /dev/null +++ b/plants/oil-refinery_test/start.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +echo "VirtuaPlant -- Bottle-filling Factory" +echo "- Starting World View" +./oil_world.py & +echo "- Starting HMI" +./oil_hmi.py & From f0f9649f1141c77fefdc7b82e2f65f426cf1fa9b Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 14:14:10 +0000 Subject: [PATCH 090/239] sensor add --- plants/oil-refinery/oil_world.py | 36 +++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ddafdc8..5f9ee1d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -40,7 +40,7 @@ def PLCGetTag(addr): PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 PLC_SEP_VESSEL = 0x04 - +PLC_SEP_FEED = 0x04 def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" @@ -64,11 +64,11 @@ def draw_ball(screen, ball, color=THECOLORS['brown']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) -def outlet_valve_sensor(space): +def separator_vessel_feed(space): body = pymunk.Body() - body.position = (185, 320) - radius = 2 + body.position = (420, 257) + radius = 4 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = 0x8 # 'bottle_in' space.add(shape) @@ -214,6 +214,11 @@ def sep_on(space, arbiter, *args, **kwargs): PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing return False +def sep_feed(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + def oil_storage_ready(space, arbiter, *args, **kwargs): log.debug("Storage bin ready") @@ -256,7 +261,8 @@ def run_world(): tank_level = tank_level_sensor(space) tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) - outlet_valve = outlet_valve_sensor(space) + separator_feed = separator_vessel_feed(space) +# outlet_valve = outlet_valve_sensor(space) balls = [] @@ -280,12 +286,22 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on - #valve = add_outlet_valve(space) - #draw_line(screen, valve) + + space.add_collision_handler(0x7, 0x5, stop=sep_on) + space.add_collision_handler(0x8, 0x5, stop=sep_feed) + # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 1) - + PLCSetTag(PLC_SEP_VESSEL, 1) + PLCSetTag(PLC_SEP_FEED, 1) + space.add_collision_handler(0x7, 0x5, begin=sep_on) + space.add_collision_handler(0x8, 0x5, begin=sep_feed) + + if (PLCGetTag(PLC_SEP_VESSEL) == 0): + space.add_collision_handler(0x7, 0x5, stop=sep_on) + space.add_collision_handler(0x8, 0x5, stop=sep_feed) + ticks_to_next_ball -= 1 if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): @@ -308,8 +324,8 @@ def run_world(): draw_lines(screen, lines) draw_ball(screen, tank_level, THECOLORS['red']) draw_ball(screen, separator_vessel, THECOLORS['red']) - draw_ball(screen, outlet_valve, THECOLORS['red']) - + draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) From 8942d477f1927add70bf145dfc4fa1c0c4c588d3 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Thu, 28 Jul 2016 11:19:00 -0400 Subject: [PATCH 091/239] separator sensors --- plants/oil-refinery/oil_hmi.py | 6 +- plants/oil-refinery/oil_world.py | 46 ++- .../attacks/constant_running.py | 26 -- .../oil-refinery_test/attacks/nothing_runs.py | 26 -- plants/oil-refinery_test/oil_hmi.py | 249 ------------ plants/oil-refinery_test/oil_world.py | 384 ------------------ plants/oil-refinery_test/start.sh | 7 - 7 files changed, 39 insertions(+), 705 deletions(-) delete mode 100755 plants/oil-refinery_test/attacks/constant_running.py delete mode 100755 plants/oil-refinery_test/attacks/nothing_runs.py delete mode 100755 plants/oil-refinery_test/oil_hmi.py delete mode 100755 plants/oil-refinery_test/oil_world.py delete mode 100755 plants/oil-refinery_test/start.sh diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 185713e..adb0d77 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -16,7 +16,7 @@ def initModbus(self): def resetLabels(self): self.feed_pump_value.set_markup("N/A") # self.inlet_valve_value.set_markup("N/A") - self.outlet_valve_value.set_markup("N/A") +# self.outlet_valve_value.set_markup("N/A") self.separator_value.set_markup("N/A") # self.discharge_pump_value.set_markup("N/A") self.process_status_value.set_markup("N/A") @@ -169,9 +169,9 @@ def setTankLevel(self, widget, data=None): except: pass - def setOutputValve(self, widget, data=None): + def setSepFeed(self, widget, data=None): try: - self.modbusClient.write_register(0x03, data) + self.modbusClient.write_register(0x05, data) except: pass diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ddafdc8..7cba904 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -40,6 +40,7 @@ def PLCGetTag(addr): PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 def to_pygame(p): @@ -64,11 +65,11 @@ def draw_ball(screen, ball, color=THECOLORS['brown']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) -def outlet_valve_sensor(space): +def separator_vessel_feed(space): body = pymunk.Body() - body.position = (185, 320) - radius = 2 + body.position = (420, 257) + radius = 4 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = 0x8 # 'bottle_in' space.add(shape) @@ -205,6 +206,7 @@ def level_ok(space, arbiter, *args, **kwargs): PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled PLCSetTag(PLC_FEED_PUMP, 0) # Close pump PLCSetTag(PLC_OUTLET_VALVE, 1) + # PLCSetTag(PLC_DISCHARGE_PUMP, 1) return False @@ -214,6 +216,11 @@ def sep_on(space, arbiter, *args, **kwargs): PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing return False +def sep_feed(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + def oil_storage_ready(space, arbiter, *args, **kwargs): log.debug("Storage bin ready") @@ -246,18 +253,22 @@ def run_world(): # Level sensor with bottle side space.add_collision_handler(0x4, 0x3, begin=no_collision) - space.add_collision_handler(0x7, 0x5, begin=sep_on) - +# space.add_collision_handler(0x7, 0x5, begin=sep_feed) +# space.add_collision_handler(0x7, 0x5, begin=sep_on) +# space.add_collision_handler(0x7, 0x5, stop=sep_off) + space.add_collision_handler(0x7, 0x2, begin=no_collision) space.add_collision_handler(0x7, 0x3, begin=no_collision) pump = add_pump(space) lines = add_oil_unit(space) tank_level = tank_level_sensor(space) - tank_in = outlet_valve_sensor(space) +# tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) - outlet_valve = outlet_valve_sensor(space) +# outlet_valve = outlet_valve_sensor(space) + separator_feed = separator_vessel_feed(space) + balls = [] ticks_to_next_ball = 1 @@ -280,11 +291,25 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on - #valve = add_outlet_valve(space) - #draw_line(screen, valve) + space.add_collision_handler(0x7, 0x5, stop=sep_on) + space.add_collision_handler(0x8, 0x5, stop=sep_feed) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 1) + PLCSetTag(PLC_SEP_VESSEL, 1) + PLCSetTag(PLC_SEP_FEED, 1) + space.add_collision_handler(0x7, 0x5, begin=sep_on) + space.add_collision_handler(0x8, 0x5, begin=sep_feed) + + if (PLCGetTag(PLC_SEP_VESSEL) == 0): + space.add_collision_handler(0x7, 0x5, stop=sep_on) + space.add_collision_handler(0x8, 0x5, stop=sep_feed) +# if (PLCGetTag(PLC_SEP_VESSEL) == 0): +# PLCSetTag(PLC_FEED_PUMP, 1) + +# if (PLCGetTag(PLC_TANK_LEVEL) == 0): + + ticks_to_next_ball -= 1 @@ -308,7 +333,8 @@ def run_world(): draw_lines(screen, lines) draw_ball(screen, tank_level, THECOLORS['red']) draw_ball(screen, separator_vessel, THECOLORS['red']) - draw_ball(screen, outlet_valve, THECOLORS['red']) + draw_ball(screen, separator_feed, THECOLORS['red']) + #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) diff --git a/plants/oil-refinery_test/attacks/constant_running.py b/plants/oil-refinery_test/attacks/constant_running.py deleted file mode 100755 index c08ef9f..0000000 --- a/plants/oil-refinery_test/attacks/constant_running.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -from pymodbus.client.sync import ModbusTcpClient as ModbusClient -from pymodbus.exceptions import ConnectionException -import logging - -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -##################################### -# Code -##################################### -client = ModbusClient('localhost', port=5020) - -try: - client.connect() - while True: - rq = client.write_register(0x01, 1) # Run Plant, Run! - rq = client.write_register(0x02, 0) # Level Sensor - rq = client.write_register(0x04, 0) # Limit Switch - -except KeyboardInterrupt: - client.close() -except ConnectionException: - print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery_test/attacks/nothing_runs.py b/plants/oil-refinery_test/attacks/nothing_runs.py deleted file mode 100755 index 4a1edd6..0000000 --- a/plants/oil-refinery_test/attacks/nothing_runs.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -from pymodbus.client.sync import ModbusTcpClient as ModbusClient -from pymodbus.exceptions import ConnectionException -import logging - -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -##################################### -# Code -##################################### -client = ModbusClient('localhost', port=5020) - -try: - client.connect() - while True: - rq = client.write_register(0x01, 0) # Run Plant, Run! - rq = client.write_register(0x02, 0) # Level Sensor - rq = client.write_register(0x04, 1) # Limit Switch - -except KeyboardInterrupt: - client.close() -except ConnectionException: - print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery_test/oil_hmi.py b/plants/oil-refinery_test/oil_hmi.py deleted file mode 100755 index adb0d77..0000000 --- a/plants/oil-refinery_test/oil_hmi.py +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/env python - -from gi.repository import GLib, Gtk, Gdk, GObject -from pymodbus.client.sync import ModbusTcpClient as ModbusClient -from pymodbus.exceptions import ConnectionException - - - -MODBUS_SLEEP=1 - -class HMIWindow(Gtk.Window): - def initModbus(self): - - self.modbusClient = ModbusClient('localhost', port=5020) - - def resetLabels(self): - self.feed_pump_value.set_markup("N/A") -# self.inlet_valve_value.set_markup("N/A") -# self.outlet_valve_value.set_markup("N/A") - self.separator_value.set_markup("N/A") -# self.discharge_pump_value.set_markup("N/A") - self.process_status_value.set_markup("N/A") - self.connection_status_value.set_markup("OFFLINE") - - def __init__(self): - Gtk.Window.__init__(self, title="Oil Refinery") - #self.gtk_widget_override_background_color(Gtk.StateType.NORMAL, Gtk.Window("green")) - - self.set_border_width(100) - - self.initModbus() - - elementIndex = 0 - - # Grid - grid = Gtk.Grid() - grid.set_row_spacing(15) - grid.set_column_spacing(10) - self.add(grid) - - # Main title label - label = Gtk.Label() - label.set_markup("Crude Oil Pretreatment Unit ") - grid.attach(label, 0, elementIndex, 4, 1) - elementIndex += 1 - - # Crude Oil Feed Pump - feed_pump_label = Gtk.Label("Crude Oil Tank Feed Pump") - feed_pump_value = Gtk.Label() - - feed_pump_start_button = Gtk.Button("START") - feed_pump_stop_button = Gtk.Button("STOP") - - feed_pump_start_button.connect("clicked", self.setPump, 1) - feed_pump_stop_button.connect("clicked", self.setPump, 0) - - grid.attach(feed_pump_label, 0, elementIndex, 1, 1) - grid.attach(feed_pump_value, 1, elementIndex, 1, 1) - grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) - grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) - elementIndex += 1 - - #Crude Oil Inlet Valve -# inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") -# inlet_valve_value = Gtk.Label() - -# inlet_valve_open_button = Gtk.Button("OPEN") -# inlet_valve_close_button = Gtk.Button("CLOSE") - -# inlet_valve_open_button.connect("clicked", self.setProcess, 1) -# inlet_valve_close_button.connect("clicked", self.setProcess, 0) - -# grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) -# grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) -# grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) -# grid.attach(inlet_valve_close_button, 3, elementIndex, 1, 1) -# elementIndex += 1 - - # Crude Oil Outlet Valve -# outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") -# outlet_valve_value = Gtk.Label() - -# outlet_valve_open_button = Gtk.Button("OPEN") -# outlet_valve_close_button = Gtk.Button("CLOSE") - -# outlet_valve_open_button.connect("clicked", self.setOutputValve, 1) -# outlet_valve_close_button.connect("clicked", self.setOutputValve, 0) - -# grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) -# grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) -# grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) -# grid.attach(outlet_valve_close_button, 3, elementIndex, 1, 1) -# elementIndex += 1 - - # Crude Oil Discharge Pump -# discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") -# discharge_pump_value = Gtk.Label() - -# discharge_pump_start_button = Gtk.Button("START") -# discharge_pump_stop_button = Gtk.Button("STOP") - -# discharge_pump_start_button.connect("clicked", self.setProcess, 1) -# discharge_pump_stop_button.connect("clicked", self.setProcess, 0) - -# grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) -# grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) -# grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) -# grid.attach(discharge_pump_stop_button, 3, elementIndex, 1, 1) -# elementIndex += 1 - - #Oil/Water Separator Vessel - separator_label = Gtk.Label("Oil/Water Separator Vessel") - separator_value = Gtk.Label() - - separator_start_button = Gtk.Button("START") - separator_stop_button = Gtk.Button("STOP") - - separator_start_button.connect("clicked", self.setSepVessel, 1) - separator_stop_button.connect("clicked", self.setSepVessel, 0) - - grid.attach(separator_label, 0, elementIndex, 1, 1) - grid.attach(separator_value, 1, elementIndex, 1, 1) - grid.attach(separator_start_button, 2, elementIndex, 1, 1) - grid.attach(separator_stop_button, 3, elementIndex, 1, 1) - elementIndex += 1 - - # Process status - process_status_label = Gtk.Label("Process Status") - process_status_value = Gtk.Label() - grid.attach(process_status_label, 0, elementIndex, 1, 1) - grid.attach(process_status_value, 1, elementIndex, 1, 1) - elementIndex += 1 - - # Connection status - connection_status_label = Gtk.Label("Connection Status") - connection_status_value = Gtk.Label() - - grid.attach(connection_status_label, 0, elementIndex, 1, 1) - grid.attach(connection_status_value, 1, elementIndex, 1, 1) - elementIndex += 1 - - - # Oil Refienery branding - virtual_refinery = Gtk.Label() - virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") - grid.attach(virtual_refinery, 0, elementIndex, 2, 1) - - # Attach Value Labels - self.feed_pump_value = feed_pump_value -# self.inlet_valve_value = inlet_valve_value -# self.outlet_valve_value = outlet_valve_value -# self.discharge_pump_value = discharge_pump_value - self.process_status_value = process_status_value - self.connection_status_value = connection_status_value - self.separator_value = separator_value - - self.resetLabels() - GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) - - def setPump(self, widget, data=None): - try: - self.modbusClient.write_register(0x01, data) - except: - pass - - def setTankLevel(self, widget, data=None): - try: - self.modbusClient.write_register(0x02, data) - except: - pass - - def setSepFeed(self, widget, data=None): - try: - self.modbusClient.write_register(0x05, data) - except: - pass - - def setSepVessel(self, widget, data=None): - try: - self.modbusClient.write_register(0x04, data) - except: - pass - - def update_status(self): - - try: - rr = self.modbusClient.read_holding_registers(1,16) - regs = [] - - if not rr or not rr.registers: - raise ConnectionException - - regs = rr.registers - - if not regs or len(regs) < 16: - raise ConnectionException - - if regs[0] == 1: - self.feed_pump_value.set_markup("RUNNING") - else: - self.feed_pump_value.set_markup("STOPPED") - -# if regs[2] == 1: -# self.inlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") -# else: -# self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") - -# if regs[2] == 1: -# self.outlet_valve_value.set_markup("OPEN") -# else: -# self.outlet_valve_value.set_markup("CLOSED") - -# if regs[1] == 1: -# self.discharge_pump_value.set_markup("RUNNING") -# else: -# self.discharge_pump_value.set_markup("STOPPED") - - if regs[3] == 1: - self.separator_value.set_markup("RUNNING") - else: - self.separator_value.set_markup("STOPPED") - - if regs[3] == 1: - self.process_status_value.set_markup("RUNNING ") - else: - self.process_status_value.set_markup("STOPPED ") - - self.connection_status_value.set_markup("ONLINE ") - - - except ConnectionException: - if not self.modbusClient.connect(): - self.resetLabels() - except: - raise - finally: - return True - -def app_main(): - win = HMIWindow() - win.connect("delete-event", Gtk.main_quit) - win.connect("destroy", Gtk.main_quit) - win.show_all() - - -if __name__ == "__main__": - GObject.threads_init() - app_main() - Gtk.main() diff --git a/plants/oil-refinery_test/oil_world.py b/plants/oil-refinery_test/oil_world.py deleted file mode 100755 index fe1b9ba..0000000 --- a/plants/oil-refinery_test/oil_world.py +++ /dev/null @@ -1,384 +0,0 @@ -#!/usr/bin/env python -import logging - -# - Multithreading -from twisted.internet import reactor - -# - Modbus -from pymodbus.server.async import StartTcpServer -from pymodbus.device import ModbusDeviceIdentification -from pymodbus.datastore import ModbusSequentialDataBlock -from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext -from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer - -# - World Simulator -import sys, random -import pygame -from pygame.locals import * -from pygame.color import * -import pymunk - -import socket - -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -def PLCSetTag(addr, value): - context[0x0].setValues(3, addr, [value]) - -def PLCGetTag(addr): - return context[0x0].getValues(3, addr, count=1)[0] - -SCREEN_WIDTH = 640 -SCREEN_HEIGHT = 550 -FPS=50.0 - -MODBUS_SERVER_PORT=5020 - -PLC_FEED_PUMP = 0x01 -PLC_TANK_LEVEL = 0x02 -PLC_OUTLET_VALVE = 0x03 -PLC_SEP_VESSEL = 0x04 -PLC_SEP_FEED = 0x05 - - -def to_pygame(p): - """Small hack to convert pymunk to pygame coordinates""" - return int(p.x), int(-p.y+600) - -def add_ball(space): - mass = 0.01 - radius = 3 - inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) - body = pymunk.Body(mass, inertia) - body._bodycontents.v_limit = 120 - body._bodycontents.h_limit = 1 - x = random.randint(180, 181) - body.position = x, 565 - shape = pymunk.Circle(body, radius, (0,0)) - shape.collision_type = 0x5 #liquid - space.add(body, shape) - return shape - -def draw_ball(screen, ball, color=THECOLORS['brown']): - p = int(ball.body.position.x), 600-int(ball.body.position.y) - pygame.draw.circle(screen, color, p, int(ball.radius), 2) - -def separator_vessel_feed(space): - - body = pymunk.Body() - body.position = (420, 257) - radius = 4 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x8 # 'bottle_in' - space.add(shape) - return shape - -def separator_vessel_release(space): - body = pymunk.Body() - body.position = (390, 225) - radius = 3 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x7 - space.add(shape) - return shape - -def tank_level_sensor(space): - - body = pymunk.Body() - body.position = (125, 400) - radius = 3 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x4 # tank_level - space.add(shape) - return shape - -def add_pump(space): - - body = pymunk.Body() - body.position = (179, 585) - shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) - space.add(shape) - return shape - - -def add_oil_unit(space): - #rotation_limit_body = pymunk.Body() - #rotation_limit_body.position = (200,300) - - #rotation_center_body = pymunk.Body() - #rotation_center_body.position = (300,300) - - body = pymunk.Body() - body.position = (300,300) - #feed pump - l1 = pymunk.Segment(body, (-100, 270), (-100, 145), 5) - l2 = pymunk.Segment(body, (-135, 270), (-135, 145), 5) - #l3 = pymunk.Segment(body, (-135, 115), (-100, 115), 5) - #l3 = pymunk.Segment(body, (-250, 180), (-135, 180), 5) - #l4 = pymunk.Segment(body, (-215, 200), (-115, 200), 5) - #l5 = pymunk.Segment(body, (-135, 180), (-135, 120), 5) - #l6 = pymunk.Segment(body, (-115, 200), (-115, 120), 5) - - #oil storage unit - l7 = pymunk.Segment(body, (-185, 130), (-185, 20), 5) - l8 = pymunk.Segment(body, (-65, 130), (-65, 20), 5) - l9 = pymunk.Segment(body, (-185,20), (-115, 20), 5) - l10 = pymunk.Segment(body, (-90, 20), (-65, 20), 5) - - #pipe to separator vessel - l11 = pymunk.Segment(body, (-115, 20), (-115, -45), 5) - l12 = pymunk.Segment(body, (-90, 20), (-90, -25), 5) - l13 = pymunk.Segment(body, (-115, -45), (-40, -45), 5) - l14 = pymunk.Segment(body, (-90, -25), (-40, -25), 5) - - #separator vessel - l15 = pymunk.Segment(body, (-40, -45), (-40, -75), 5) - l16 = pymunk.Segment(body, (-40, -25), (-40, 5), 5) - l17 = pymunk.Segment(body, (-40, -75), (80, -75), 5) - l18 = pymunk.Segment(body, (-40, 5), (120, 5), 5) - l19 = pymunk.Segment(body, (100, -75), (120, -75), 5) - l22 = pymunk.Segment(body, (120, -75), (120, -55), 5) - l23 = pymunk.Segment(body, (120, -30), (120, 5), 5) - - #waste water pipe - l20 = pymunk.Segment(body, (80, -75), (80, -115), 5) - l21 = pymunk.Segment(body, (100, -75), (100, -115), 5) - - #separator exit pipe - l24 = pymunk.Segment(body, (120, -30), (600, -30), 5) - l25 = pymunk.Segment(body, (120, -55), (600, -55), 5) - - #waste water storage - l26 = pymunk.Segment(body, (80, -115), (20, -115), 5) - l27 = pymunk.Segment(body, (20, -115), (20, -185), 5) - l28 = pymunk.Segment(body, (20, -185), (140, -185), 5) - l29 = pymunk.Segment(body, (140, -185), (140, -170), 5) - l30 = pymunk.Segment(body, (140, -145), (140, -115), 5) - l31 = pymunk.Segment(body, (140, -115), (100, -115), 5) - l32 = pymunk.Segment(body, (140, -145), (600, -145), 5) - l33 = pymunk.Segment(body, (140, -170), (600, -170), 5) - - - #rotation_center_joint = pymunk.PinJoint(body, rotation_center_body, (-135,115), (-100, 115)) - #joint_limit = 25 - #rotation_limit_joint = pymunk.SlideJoint(body, rotation_limit_body, (-135,115), (-100,115), 5, joint_limit) - - space.add(l1, l2, l7, l8, l9, l10, l11, l12, l13, l14, l15, - l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, - l26, l27, l28, l29, l30, l31, l32, l33) # 3 - - return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30,l31,l32,l33 - -def draw_polygon(screen, shape): - points = shape.get_vertices() - fpoints = [] - for p in points: - fpoints.append(to_pygame(p)) - pygame.draw.polygon(screen, THECOLORS['black'], fpoints) - -def draw_line(screen, line): - body = line.body - pv1 = body.position + line.a.rotated(body.angle) # 1 - pv2 = body.position + line.b.rotated(body.angle) - p1 = to_pygame(pv1) # 2 - p2 = to_pygame(pv2) - pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) - -def draw_lines(screen, lines): - - for line in lines: - body = line.body - pv1 = body.position + line.a.rotated(body.angle) # 1 - pv2 = body.position + line.b.rotated(body.angle) - p1 = to_pygame(pv1) # 2 - p2 = to_pygame(pv2) - pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) - -def no_collision(space, arbiter, *args, **kwargs): - return False - -def level_ok(space, arbiter, *args, **kwargs): - - log.debug("Level reached") - # PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle - PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled - PLCSetTag(PLC_FEED_PUMP, 0) # Close pump - PLCSetTag(PLC_OUTLET_VALVE, 1) -# PLCSetTag(PLC_DISCHARGE_PUMP, 1) - return False - -# This fires when the separator level is hit -def sep_on(space, arbiter, *args, **kwargs): - log.debug("Begin separation") - PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing - return False - -def sep_feed(space, arbiter, *args, **kwargs): - log.debug("Outlet Feed") - PLCSetTag(PLC_SEP_FEED, 1) - return False - -def oil_storage_ready(space, arbiter, *args, **kwargs): - - log.debug("Storage bin ready") - # PLCSetTag(PLC_INLET_VALVE, 1) - PLCSetTag(PLC_TANK_LEVEL, 0) - PLCSetTag(PLC_FEED_PUMP, 1) # Open pump - PLCSetTag(PLC_OUTLET_VALVE, 0) -# PLCSetTag(PLC_DISCHARGE_PUMP, 0) - return False - -def run_world(): - pygame.init() - screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) - pygame.display.set_caption("Crude Oil Pretreatment Unit") - clock = pygame.time.Clock() - running = True - - space = pymunk.Space() #2 - space.gravity = (0.0, -900.0) - - space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) - # Level sensor with water - space.add_collision_handler(0x4, 0x5, begin=level_ok) - # Level sensor with ground - space.add_collision_handler(0x4, 0x6, begin=no_collision) - # Limit switch with ground - space.add_collision_handler(0x1, 0x6, begin=no_collision) - # Limit switch with bottle side - space.add_collision_handler(0x1, 0x3, begin=no_collision) - # Level sensor with bottle side - space.add_collision_handler(0x4, 0x3, begin=no_collision) - -# space.add_collision_handler(0x7, 0x5, begin=sep_feed) -# space.add_collision_handler(0x7, 0x5, begin=sep_on) -# space.add_collision_handler(0x7, 0x5, stop=sep_off) - - space.add_collision_handler(0x7, 0x2, begin=no_collision) - space.add_collision_handler(0x7, 0x3, begin=no_collision) - - pump = add_pump(space) - lines = add_oil_unit(space) - tank_level = tank_level_sensor(space) -# tank_in = outlet_valve_sensor(space) - separator_vessel = separator_vessel_release(space) -# outlet_valve = outlet_valve_sensor(space) - separator_feed = separator_vessel_feed(space) - - - balls = [] - - ticks_to_next_ball = 1 - - fontBig = pygame.font.SysFont(None, 40) - fontMedium = pygame.font.SysFont(None, 26) - fontSmall = pygame.font.SysFont(None, 18) - - while running: - clock.tick(FPS) - - for event in pygame.event.get(): - if event.type == QUIT: - running = False - elif event.type == KEYDOWN and event.key == K_ESCAPE: - running = False - - screen.fill(THECOLORS["grey"]) - - # If the feed pump is on - if PLCGetTag(PLC_FEED_PUMP) == 1: - # Draw the valve if the pump is on - space.add_collision_handler(0x7, 0x5, stop=sep_on) - space.add_collision_handler(0x8, 0x5, stop=sep_feed) - # If the oil reaches the level sensor at the top of the tank - if (PLCGetTag(PLC_TANK_LEVEL) == 1): - PLCSetTag(PLC_FEED_PUMP, 1) - PLCSetTag(PLC_SEP_VESSEL, 1) - PLCSetTag(PLC_SEP_FEED, 1) - space.add_collision_handler(0x7, 0x5, begin=sep_on) - space.add_collision_handler(0x8, 0x5, begin=sep_feed) - - if (PLCGetTag(PLC_SEP_VESSEL) == 0): - space.add_collision_handler(0x7, 0x5, stop=sep_on) - space.add_collision_handler(0x8, 0x5, stop=sep_feed) -# if (PLCGetTag(PLC_SEP_VESSEL) == 0): -# PLCSetTag(PLC_FEED_PUMP, 1) - -# if (PLCGetTag(PLC_TANK_LEVEL) == 0): - - - - ticks_to_next_ball -= 1 - - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): - ticks_to_next_ball = 1 - ball_shape = add_ball(space) - balls.append(ball_shape) - - balls_to_remove = [] - for ball in balls: - if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: - balls_to_remove.append(ball) - - draw_ball(screen, ball) - - for ball in balls_to_remove: - space.remove(ball, ball.body) - balls.remove(ball) - - draw_polygon(screen, pump) - draw_lines(screen, lines) - draw_ball(screen, tank_level, THECOLORS['red']) - draw_ball(screen, separator_vessel, THECOLORS['red']) - draw_ball(screen, separator_feed, THECOLORS['red']) - #draw_ball(screen, separator_feed, THECOLORS['red']) - - title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) - name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) - instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) - feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) - oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) - separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) - waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) - screen.blit(title, (300, 40)) - screen.blit(name, (347, 10)) - screen.blit(instructions, (SCREEN_WIDTH-115, 10)) - screen.blit(feed_pump_label, (65, 80)) - screen.blit(oil_storage_label, (240, 190)) - screen.blit(separator_label, (270,275)) - screen.blit(waste_water_label, (265, 490)) - - space.step(1/FPS) - pygame.display.flip() - - if reactor.running: - reactor.callFromThread(reactor.stop) - -store = ModbusSlaveContext( - di = ModbusSequentialDataBlock(0, [0]*100), - co = ModbusSequentialDataBlock(0, [0]*100), - hr = ModbusSequentialDataBlock(0, [0]*100), - ir = ModbusSequentialDataBlock(0, [0]*100)) - -context = ModbusServerContext(slaves=store, single=True) - -identity = ModbusDeviceIdentification() -identity.VendorName = 'MockPLCs' -identity.ProductCode = 'MP' -identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' -identity.ProductName = 'MockPLC 4000' -identity.ModelName = 'MockPLC Platinum' -identity.MajorMinorRevision = '1.0' - -def startModbusServer(): - - StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) - -def main(): - reactor.callInThread(run_world) - startModbusServer() - -if __name__ == '__main__': - sys.exit(main()) diff --git a/plants/oil-refinery_test/start.sh b/plants/oil-refinery_test/start.sh deleted file mode 100755 index 3c19e3d..0000000 --- a/plants/oil-refinery_test/start.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -echo "VirtuaPlant -- Bottle-filling Factory" -echo "- Starting World View" -./oil_world.py & -echo "- Starting HMI" -./oil_hmi.py & From 58327857db3ff5dc094d15a3260093e3e780a249 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 21:29:48 +0000 Subject: [PATCH 092/239] stash --- plants/oil-refinery/oil_hmi.py | 6 +++--- plants/oil-refinery/oil_world.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 185713e..adb0d77 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -16,7 +16,7 @@ def initModbus(self): def resetLabels(self): self.feed_pump_value.set_markup("N/A") # self.inlet_valve_value.set_markup("N/A") - self.outlet_valve_value.set_markup("N/A") +# self.outlet_valve_value.set_markup("N/A") self.separator_value.set_markup("N/A") # self.discharge_pump_value.set_markup("N/A") self.process_status_value.set_markup("N/A") @@ -169,9 +169,9 @@ def setTankLevel(self, widget, data=None): except: pass - def setOutputValve(self, widget, data=None): + def setSepFeed(self, widget, data=None): try: - self.modbusClient.write_register(0x03, data) + self.modbusClient.write_register(0x05, data) except: pass diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5f9ee1d..56d7445 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -40,7 +40,7 @@ def PLCGetTag(addr): PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 PLC_SEP_VESSEL = 0x04 -PLC_SEP_FEED = 0x04 +PLC_SEP_FEED = 0x05 def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" From ae0a3b2d81c2793720f39404084fd9d0935211f2 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 21:55:27 +0000 Subject: [PATCH 093/239] Cleaned up code, removed legacy code, added comments, simplified --- plants/oil-refinery/oil_hmi.py | 102 +++++--------------------- plants/oil-refinery/oil_world.py | 122 ++++++++++++------------------- 2 files changed, 67 insertions(+), 157 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index adb0d77..8c12442 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -10,28 +10,25 @@ class HMIWindow(Gtk.Window): def initModbus(self): - + # Create modbus connection to specified address and port self.modbusClient = ModbusClient('localhost', port=5020) + # Default values for the HMI labels def resetLabels(self): self.feed_pump_value.set_markup("N/A") -# self.inlet_valve_value.set_markup("N/A") -# self.outlet_valve_value.set_markup("N/A") self.separator_value.set_markup("N/A") -# self.discharge_pump_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") def __init__(self): + # Window title Gtk.Window.__init__(self, title="Oil Refinery") - #self.gtk_widget_override_background_color(Gtk.StateType.NORMAL, Gtk.Window("green")) - self.set_border_width(100) + #Create modbus connection self.initModbus() elementIndex = 0 - # Grid grid = Gtk.Grid() grid.set_row_spacing(15) @@ -60,54 +57,6 @@ def __init__(self): grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) elementIndex += 1 - #Crude Oil Inlet Valve -# inlet_valve_label = Gtk.Label("Crude Oil Tank Inlet Valve") -# inlet_valve_value = Gtk.Label() - -# inlet_valve_open_button = Gtk.Button("OPEN") -# inlet_valve_close_button = Gtk.Button("CLOSE") - -# inlet_valve_open_button.connect("clicked", self.setProcess, 1) -# inlet_valve_close_button.connect("clicked", self.setProcess, 0) - -# grid.attach(inlet_valve_label, 0, elementIndex, 1, 1) -# grid.attach(inlet_valve_value, 1, elementIndex, 1, 1) -# grid.attach(inlet_valve_open_button, 2, elementIndex, 1, 1) -# grid.attach(inlet_valve_close_button, 3, elementIndex, 1, 1) -# elementIndex += 1 - - # Crude Oil Outlet Valve -# outlet_valve_label = Gtk.Label("Crude Oil Tank Outlet Valve") -# outlet_valve_value = Gtk.Label() - -# outlet_valve_open_button = Gtk.Button("OPEN") -# outlet_valve_close_button = Gtk.Button("CLOSE") - -# outlet_valve_open_button.connect("clicked", self.setOutputValve, 1) -# outlet_valve_close_button.connect("clicked", self.setOutputValve, 0) - -# grid.attach(outlet_valve_label, 0, elementIndex, 1, 1) -# grid.attach(outlet_valve_value, 1, elementIndex, 1, 1) -# grid.attach(outlet_valve_open_button, 2, elementIndex, 1, 1) -# grid.attach(outlet_valve_close_button, 3, elementIndex, 1, 1) -# elementIndex += 1 - - # Crude Oil Discharge Pump -# discharge_pump_label = Gtk.Label("Crude Oil Tank Discharge Pump") -# discharge_pump_value = Gtk.Label() - -# discharge_pump_start_button = Gtk.Button("START") -# discharge_pump_stop_button = Gtk.Button("STOP") - -# discharge_pump_start_button.connect("clicked", self.setProcess, 1) -# discharge_pump_stop_button.connect("clicked", self.setProcess, 0) - -# grid.attach(discharge_pump_label, 0, elementIndex, 1, 1) -# grid.attach(discharge_pump_value, 1, elementIndex, 1, 1) -# grid.attach(discharge_pump_start_button, 2, elementIndex, 1, 1) -# grid.attach(discharge_pump_stop_button, 3, elementIndex, 1, 1) -# elementIndex += 1 - #Oil/Water Separator Vessel separator_label = Gtk.Label("Oil/Water Separator Vessel") separator_value = Gtk.Label() @@ -134,7 +83,6 @@ def __init__(self): # Connection status connection_status_label = Gtk.Label("Connection Status") connection_status_value = Gtk.Label() - grid.attach(connection_status_label, 0, elementIndex, 1, 1) grid.attach(connection_status_value, 1, elementIndex, 1, 1) elementIndex += 1 @@ -147,34 +95,36 @@ def __init__(self): # Attach Value Labels self.feed_pump_value = feed_pump_value -# self.inlet_valve_value = inlet_valve_value -# self.outlet_valve_value = outlet_valve_value -# self.discharge_pump_value = discharge_pump_value self.process_status_value = process_status_value self.connection_status_value = connection_status_value self.separator_value = separator_value + # Set default label values self.resetLabels() GObject.timeout_add_seconds(MODBUS_SLEEP, self.update_status) + # Control the feed pump register values def setPump(self, widget, data=None): try: self.modbusClient.write_register(0x01, data) except: pass + # Control the tank level register values def setTankLevel(self, widget, data=None): try: self.modbusClient.write_register(0x02, data) except: pass - + + # Control the separator feed register values def setSepFeed(self, widget, data=None): try: self.modbusClient.write_register(0x05, data) except: pass + # Control the separator vessel level register values def setSepVessel(self, widget, data=None): try: self.modbusClient.write_register(0x04, data) @@ -184,47 +134,35 @@ def setSepVessel(self, widget, data=None): def update_status(self): try: + # Store the registers of the PLC in "rr" rr = self.modbusClient.read_holding_registers(1,16) regs = [] + # If we get back a blank response, something happened connecting to the PLC if not rr or not rr.registers: raise ConnectionException - + + # Regs is an iterable list of register key:values regs = rr.registers if not regs or len(regs) < 16: raise ConnectionException - + + # If the feed pump "0x01" is set to 1, then the pump is running if regs[0] == 1: self.feed_pump_value.set_markup("RUNNING") else: self.feed_pump_value.set_markup("STOPPED") - -# if regs[2] == 1: -# self.inlet_valve_value.set_markup(" weight='bold' foreground='green'>OPEN") -# else: -# self.inlet_valve_value.set_markup(" weight='bold' foreground='red'>CLOSED") - -# if regs[2] == 1: -# self.outlet_valve_value.set_markup("OPEN") -# else: -# self.outlet_valve_value.set_markup("CLOSED") - -# if regs[1] == 1: -# self.discharge_pump_value.set_markup("RUNNING") -# else: -# self.discharge_pump_value.set_markup("STOPPED") - + + # If the feed pump "0x04" is set to 1, separator is currently processing if regs[3] == 1: self.separator_value.set_markup("RUNNING") - else: - self.separator_value.set_markup("STOPPED") - - if regs[3] == 1: self.process_status_value.set_markup("RUNNING ") else: + self.separator_value.set_markup("STOPPED") self.process_status_value.set_markup("STOPPED ") + # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index facef48..0d03c10 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -24,32 +24,40 @@ log = logging.getLogger() log.setLevel(logging.INFO) +# Helper function to set PLC values def PLCSetTag(addr, value): context[0x0].setValues(3, addr, [value]) +# Helper function that returns PLC values def PLCGetTag(addr): return context[0x0].getValues(3, addr, count=1)[0] +# Display settings SCREEN_WIDTH = 640 SCREEN_HEIGHT = 550 FPS=50.0 +# Port the world will listen on MODBUS_SERVER_PORT=5020 +# PLC Register values for various control functions PLC_FEED_PUMP = 0x01 PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 PLC_SEP_VESSEL = 0x04 PLC_SEP_FEED = 0x05 -<<<<<<< HEAD -======= ->>>>>>> 8942d477f1927add70bf145dfc4fa1c0c4c588d3 +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +separator_collision = 0x8 +sep_vessel_collision = 0x7 def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" return int(p.x), int(-p.y+600) +# Add "oil" to the world space def add_ball(space): mass = 0.01 radius = 3 @@ -60,69 +68,62 @@ def add_ball(space): x = random.randint(180, 181) body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) - shape.collision_type = 0x5 #liquid + shape.collision_type = ball_collision #liquid space.add(body, shape) return shape +# Add a ball to the space def draw_ball(screen, ball, color=THECOLORS['brown']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) +# Add the separator vessel feed def separator_vessel_feed(space): - body = pymunk.Body() body.position = (420, 257) radius = 4 shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x8 # 'bottle_in' + shape.collision_type = separator_collision # Collision value for separator space.add(shape) return shape +# Add the separator vessel release def separator_vessel_release(space): body = pymunk.Body() body.position = (390, 225) radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x7 + shape.collision_type = sep_vessel_collision space.add(shape) return shape +# Add the tank level sensor def tank_level_sensor(space): - body = pymunk.Body() body.position = (125, 400) radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = 0x4 # tank_level + shape.collision_type = tank_level_collision # tank_level space.add(shape) return shape +# Add the feed pump to the space def add_pump(space): - body = pymunk.Body() body.position = (179, 585) shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) space.add(shape) return shape - +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets def add_oil_unit(space): - #rotation_limit_body = pymunk.Body() - #rotation_limit_body.position = (200,300) - - #rotation_center_body = pymunk.Body() - #rotation_center_body.position = (300,300) - body = pymunk.Body() body.position = (300,300) + #feed pump l1 = pymunk.Segment(body, (-100, 270), (-100, 145), 5) l2 = pymunk.Segment(body, (-135, 270), (-135, 145), 5) - #l3 = pymunk.Segment(body, (-135, 115), (-100, 115), 5) - #l3 = pymunk.Segment(body, (-250, 180), (-135, 180), 5) - #l4 = pymunk.Segment(body, (-215, 200), (-115, 200), 5) - #l5 = pymunk.Segment(body, (-135, 180), (-135, 120), 5) - #l6 = pymunk.Segment(body, (-115, 200), (-115, 120), 5) #oil storage unit l7 = pymunk.Segment(body, (-185, 130), (-185, 20), 5) @@ -163,11 +164,6 @@ def add_oil_unit(space): l32 = pymunk.Segment(body, (140, -145), (600, -145), 5) l33 = pymunk.Segment(body, (140, -170), (600, -170), 5) - - #rotation_center_joint = pymunk.PinJoint(body, rotation_center_body, (-135,115), (-100, 115)) - #joint_limit = 25 - #rotation_limit_joint = pymunk.SlideJoint(body, rotation_limit_body, (-135,115), (-100,115), 5, joint_limit) - space.add(l1, l2, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33) # 3 @@ -181,6 +177,7 @@ def draw_polygon(screen, shape): fpoints.append(to_pygame(p)) pygame.draw.polygon(screen, THECOLORS['black'], fpoints) +# Draw a single line to the screen def draw_line(screen, line): body = line.body pv1 = body.position + line.a.rotated(body.angle) # 1 @@ -189,8 +186,8 @@ def draw_line(screen, line): p2 = to_pygame(pv2) pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) +# Draw lines from an iterable list def draw_lines(screen, lines): - for line in lines: body = line.body pv1 = body.position + line.a.rotated(body.angle) # 1 @@ -199,18 +196,17 @@ def draw_lines(screen, lines): p2 = to_pygame(pv2) pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) +# Default collision function for objects def no_collision(space, arbiter, *args, **kwargs): return False +# Called when level sensor in tank is hit def level_ok(space, arbiter, *args, **kwargs): log.debug("Level reached") - # PLCSetTag(PLC_INLET_VALVE, 0) # Limit Switch Release, Fill Bottle - PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Bottle Filled - PLCSetTag(PLC_FEED_PUMP, 0) # Close pump - PLCSetTag(PLC_OUTLET_VALVE, 1) - -# PLCSetTag(PLC_DISCHARGE_PUMP, 1) + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump + PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 return False # This fires when the separator level is hit @@ -223,19 +219,13 @@ def sep_feed(space, arbiter, *args, **kwargs): log.debug("Outlet Feed") PLCSetTag(PLC_SEP_FEED, 1) return False -<<<<<<< HEAD - -======= ->>>>>>> 8942d477f1927add70bf145dfc4fa1c0c4c588d3 def oil_storage_ready(space, arbiter, *args, **kwargs): log.debug("Storage bin ready") - # PLCSetTag(PLC_INLET_VALVE, 1) PLCSetTag(PLC_TANK_LEVEL, 0) PLCSetTag(PLC_FEED_PUMP, 1) # Open pump PLCSetTag(PLC_OUTLET_VALVE, 0) -# PLCSetTag(PLC_DISCHARGE_PUMP, 0) return False def run_world(): @@ -249,16 +239,16 @@ def run_world(): space.gravity = (0.0, -900.0) space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) - # Level sensor with water - space.add_collision_handler(0x4, 0x5, begin=level_ok) + # When oil collides with tank_level, call level_ok + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_ok) # Level sensor with ground - space.add_collision_handler(0x4, 0x6, begin=no_collision) + #space.add_collision_handler(0x4, 0x6, begin=no_collision) # Limit switch with ground - space.add_collision_handler(0x1, 0x6, begin=no_collision) + #space.add_collision_handler(0x1, 0x6, begin=no_collision) # Limit switch with bottle side - space.add_collision_handler(0x1, 0x3, begin=no_collision) + #space.add_collision_handler(0x1, 0x3, begin=no_collision) # Level sensor with bottle side - space.add_collision_handler(0x4, 0x3, begin=no_collision) + #space.add_collision_handler(0x4, 0x3, begin=no_collision) # space.add_collision_handler(0x7, 0x5, begin=sep_feed) # space.add_collision_handler(0x7, 0x5, begin=sep_on) @@ -270,26 +260,22 @@ def run_world(): pump = add_pump(space) lines = add_oil_unit(space) tank_level = tank_level_sensor(space) -# tank_in = outlet_valve_sensor(space) separator_vessel = separator_vessel_release(space) -<<<<<<< HEAD separator_feed = separator_vessel_feed(space) -# outlet_valve = outlet_valve_sensor(space) -======= -# outlet_valve = outlet_valve_sensor(space) separator_feed = separator_vessel_feed(space) ->>>>>>> 8942d477f1927add70bf145dfc4fa1c0c4c588d3 balls = [] ticks_to_next_ball = 1 + # Set font settings fontBig = pygame.font.SysFont(None, 40) fontMedium = pygame.font.SysFont(None, 26) fontSmall = pygame.font.SysFont(None, 18) while running: + # Advance the game clock clock.tick(FPS) for event in pygame.event.get(): @@ -303,15 +289,10 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on -<<<<<<< HEAD - space.add_collision_handler(0x7, 0x5, stop=sep_on) space.add_collision_handler(0x8, 0x5, stop=sep_feed) - -======= space.add_collision_handler(0x7, 0x5, stop=sep_on) space.add_collision_handler(0x8, 0x5, stop=sep_feed) ->>>>>>> 8942d477f1927add70bf145dfc4fa1c0c4c588d3 # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 1) @@ -323,17 +304,11 @@ def run_world(): if (PLCGetTag(PLC_SEP_VESSEL) == 0): space.add_collision_handler(0x7, 0x5, stop=sep_on) space.add_collision_handler(0x8, 0x5, stop=sep_feed) -<<<<<<< HEAD - -======= # if (PLCGetTag(PLC_SEP_VESSEL) == 0): # PLCSetTag(PLC_FEED_PUMP, 1) # if (PLCGetTag(PLC_TANK_LEVEL) == 0): - - ->>>>>>> 8942d477f1927add70bf145dfc4fa1c0c4c588d3 ticks_to_next_ball -= 1 if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): @@ -357,12 +332,8 @@ def run_world(): draw_ball(screen, tank_level, THECOLORS['red']) draw_ball(screen, separator_vessel, THECOLORS['red']) draw_ball(screen, separator_feed, THECOLORS['red']) -<<<<<<< HEAD - -======= - #draw_ball(screen, separator_feed, THECOLORS['red']) ->>>>>>> 8942d477f1927add70bf145dfc4fa1c0c4c588d3 + #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) @@ -392,16 +363,17 @@ def run_world(): context = ModbusServerContext(slaves=store, single=True) +# Modbus PLC server information identity = ModbusDeviceIdentification() -identity.VendorName = 'MockPLCs' -identity.ProductCode = 'MP' -identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' -identity.ProductName = 'MockPLC 4000' -identity.ModelName = 'MockPLC Platinum' -identity.MajorMinorRevision = '1.0' +identity.VendorName = 'Siemens Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://w3.siemens.com/markets/global/en/oil-gas/pages/refining-petrochemical-industry.aspx' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Siemens ORP 3850' +identity.MajorMinorRevision = '2.09.01' def startModbusServer(): - + # Run a modbus server on specified address and modbus port (5020) StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) def main(): From 0044e223c348433162edcc31552b958f0b9a1b68 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 22:00:32 +0000 Subject: [PATCH 094/239] minor changes --- plants/oil-refinery/oil_world.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 0d03c10..3be4604 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -201,7 +201,7 @@ def no_collision(space, arbiter, *args, **kwargs): return False # Called when level sensor in tank is hit -def level_ok(space, arbiter, *args, **kwargs): +def level_reached(space, arbiter, *args, **kwargs): log.debug("Level reached") PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full @@ -214,6 +214,12 @@ def sep_on(space, arbiter, *args, **kwargs): log.debug("Begin separation") PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False def sep_feed(space, arbiter, *args, **kwargs): log.debug("Outlet Feed") @@ -221,7 +227,6 @@ def sep_feed(space, arbiter, *args, **kwargs): return False def oil_storage_ready(space, arbiter, *args, **kwargs): - log.debug("Storage bin ready") PLCSetTag(PLC_TANK_LEVEL, 0) PLCSetTag(PLC_FEED_PUMP, 1) # Open pump @@ -235,12 +240,13 @@ def run_world(): clock = pygame.time.Clock() running = True + # Create game space (world) and set gravity to normal space = pymunk.Space() #2 space.gravity = (0.0, -900.0) space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) # When oil collides with tank_level, call level_ok - space.add_collision_handler(tank_level_collision, ball_collision, begin=level_ok) + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) # Level sensor with ground #space.add_collision_handler(0x4, 0x6, begin=no_collision) # Limit switch with ground From 24638f38609ed5d358e7991ff62dfb3958b1755b Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 22:02:47 +0000 Subject: [PATCH 095/239] Pump should turn on automatically now --- plants/oil-refinery/oil_world.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 3be4604..36cd12a 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -202,13 +202,20 @@ def no_collision(space, arbiter, *args, **kwargs): # Called when level sensor in tank is hit def level_reached(space, arbiter, *args, **kwargs): - log.debug("Level reached") PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 return False +# Called when level sensor in tank is ok +def level_ok(space, arbiter, *args, **kwargs): + log.debug("Level ok") + PLCSetTag(PLC_TANK_LEVEL, 0) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 1) # Turn off the pump + PLCSetTag(PLC_OUTLET_VALVE, 0) # Set the outlet valve to 1 + return False + # This fires when the separator level is hit def sep_on(space, arbiter, *args, **kwargs): log.debug("Begin separation") @@ -247,6 +254,7 @@ def run_world(): space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) # When oil collides with tank_level, call level_ok space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(tank_level_collision, ball_collision, stop=level_ok) # Level sensor with ground #space.add_collision_handler(0x4, 0x6, begin=no_collision) # Limit switch with ground From e54b742b4b3174695b627cd3f78f3b2bdc9accb8 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 22:48:10 +0000 Subject: [PATCH 096/239] Fixing auto pump --- plants/oil-refinery/oil_world.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 36cd12a..444a37f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -211,7 +211,7 @@ def level_reached(space, arbiter, *args, **kwargs): # Called when level sensor in tank is ok def level_ok(space, arbiter, *args, **kwargs): log.debug("Level ok") - PLCSetTag(PLC_TANK_LEVEL, 0) # Level Sensor Hit, Tank full + PLCSetTag(PLC_TANK_LEVEL, 0) # Level Sensor ok, tank empty enough PLCSetTag(PLC_FEED_PUMP, 1) # Turn off the pump PLCSetTag(PLC_OUTLET_VALVE, 0) # Set the outlet valve to 1 return False @@ -254,7 +254,10 @@ def run_world(): space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) # When oil collides with tank_level, call level_ok space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) - space.add_collision_handler(tank_level_collision, ball_collision, stop=level_ok) + + # the line below doesn't do what expected. + space.add_collision_handler(tank_level_collision, ball_collision, separate=level_ok) + # Level sensor with ground #space.add_collision_handler(0x4, 0x6, begin=no_collision) # Limit switch with ground From 31c92beacc2be4a258ac4036721e9aa8de51e8a3 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 22:51:18 +0000 Subject: [PATCH 097/239] working on logic --- plants/oil-refinery/oil_world.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 444a37f..a946886 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -256,7 +256,7 @@ def run_world(): space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) # the line below doesn't do what expected. - space.add_collision_handler(tank_level_collision, ball_collision, separate=level_ok) + # space.add_collision_handler(tank_level_collision, ball_collision, separate=level_ok) # Level sensor with ground #space.add_collision_handler(0x4, 0x6, begin=no_collision) @@ -271,8 +271,8 @@ def run_world(): # space.add_collision_handler(0x7, 0x5, begin=sep_on) # space.add_collision_handler(0x7, 0x5, stop=sep_off) - space.add_collision_handler(0x7, 0x2, begin=no_collision) - space.add_collision_handler(0x7, 0x3, begin=no_collision) + #space.add_collision_handler(0x7, 0x2, begin=no_collision) + #space.add_collision_handler(0x7, 0x3, begin=no_collision) pump = add_pump(space) lines = add_oil_unit(space) @@ -312,7 +312,7 @@ def run_world(): space.add_collision_handler(0x8, 0x5, stop=sep_feed) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): - PLCSetTag(PLC_FEED_PUMP, 1) + PLCSetTag(PLC_FEED_PUMP, 0) PLCSetTag(PLC_SEP_VESSEL, 1) PLCSetTag(PLC_SEP_FEED, 1) space.add_collision_handler(0x7, 0x5, begin=sep_on) From 744bd5b4f30d5fd9c7ea96d708a2c51fc074c040 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 22:53:17 +0000 Subject: [PATCH 098/239] working on logic --- plants/oil-refinery/oil_world.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a946886..8040c79 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -321,14 +321,9 @@ def run_world(): if (PLCGetTag(PLC_SEP_VESSEL) == 0): space.add_collision_handler(0x7, 0x5, stop=sep_on) space.add_collision_handler(0x8, 0x5, stop=sep_feed) -# if (PLCGetTag(PLC_SEP_VESSEL) == 0): -# PLCSetTag(PLC_FEED_PUMP, 1) - -# if (PLCGetTag(PLC_TANK_LEVEL) == 0): - ticks_to_next_ball -= 1 - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP): + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: ticks_to_next_ball = 1 ball_shape = add_ball(space) balls.append(ball_shape) From b7690e0bc702d7cd6d06e6d823b8e9883e7dce61 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:02:27 +0000 Subject: [PATCH 099/239] working on logic --- plants/oil-refinery/oil_world.py | 53 ++++++++------------------------ 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 8040c79..b3692ff 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -208,14 +208,6 @@ def level_reached(space, arbiter, *args, **kwargs): PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 return False -# Called when level sensor in tank is ok -def level_ok(space, arbiter, *args, **kwargs): - log.debug("Level ok") - PLCSetTag(PLC_TANK_LEVEL, 0) # Level Sensor ok, tank empty enough - PLCSetTag(PLC_FEED_PUMP, 1) # Turn off the pump - PLCSetTag(PLC_OUTLET_VALVE, 0) # Set the outlet valve to 1 - return False - # This fires when the separator level is hit def sep_on(space, arbiter, *args, **kwargs): log.debug("Begin separation") @@ -228,7 +220,7 @@ def sep_off(space, arbiter, *args, **kwargs): PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing return False -def sep_feed(space, arbiter, *args, **kwargs): +def sep_feed_on(space, arbiter, *args, **kwargs): log.debug("Outlet Feed") PLCSetTag(PLC_SEP_FEED, 1) return False @@ -250,29 +242,9 @@ def run_world(): # Create game space (world) and set gravity to normal space = pymunk.Space() #2 space.gravity = (0.0, -900.0) - - space.add_collision_handler(0x1, 0x2, begin=oil_storage_ready) - # When oil collides with tank_level, call level_ok - space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) - # the line below doesn't do what expected. - # space.add_collision_handler(tank_level_collision, ball_collision, separate=level_ok) - - # Level sensor with ground - #space.add_collision_handler(0x4, 0x6, begin=no_collision) - # Limit switch with ground - #space.add_collision_handler(0x1, 0x6, begin=no_collision) - # Limit switch with bottle side - #space.add_collision_handler(0x1, 0x3, begin=no_collision) - # Level sensor with bottle side - #space.add_collision_handler(0x4, 0x3, begin=no_collision) - -# space.add_collision_handler(0x7, 0x5, begin=sep_feed) -# space.add_collision_handler(0x7, 0x5, begin=sep_on) -# space.add_collision_handler(0x7, 0x5, stop=sep_off) - - #space.add_collision_handler(0x7, 0x2, begin=no_collision) - #space.add_collision_handler(0x7, 0x3, begin=no_collision) + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) pump = add_pump(space) lines = add_oil_unit(space) @@ -306,21 +278,22 @@ def run_world(): # If the feed pump is on if PLCGetTag(PLC_FEED_PUMP) == 1: # Draw the valve if the pump is on - space.add_collision_handler(0x7, 0x5, stop=sep_on) - space.add_collision_handler(0x8, 0x5, stop=sep_feed) - space.add_collision_handler(0x7, 0x5, stop=sep_on) - space.add_collision_handler(0x8, 0x5, stop=sep_feed) # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 0) PLCSetTag(PLC_SEP_VESSEL, 1) PLCSetTag(PLC_SEP_FEED, 1) space.add_collision_handler(0x7, 0x5, begin=sep_on) - space.add_collision_handler(0x8, 0x5, begin=sep_feed) - - if (PLCGetTag(PLC_SEP_VESSEL) == 0): - space.add_collision_handler(0x7, 0x5, stop=sep_on) - space.add_collision_handler(0x8, 0x5, stop=sep_feed) + space.add_collision_handler(0x8, 0x5, begin=sep_feed_on) + + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(0x7, 0x5, begin=sep_on) + space.add_collision_handler(0x8, 0x5, begin=sep_feed_on) + + + ticks_to_next_ball -= 1 if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: From 0d9dd624750b3632944dae6106e57ebc3666eb55 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:04:02 +0000 Subject: [PATCH 100/239] working on logic --- plants/oil-refinery/oil_world.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b3692ff..4cd446e 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -291,6 +291,9 @@ def run_world(): if PLCGetTag(PLC_SEP_VESSEL) == 1: space.add_collision_handler(0x7, 0x5, begin=sep_on) space.add_collision_handler(0x8, 0x5, begin=sep_feed_on) + else: + space.add_collision_handler(0x7, 0x5, begin=no_collision) + space.add_collision_handler(0x8, 0x5, begin=no_collision) From 921294d6fa7ae1e0ef1b3373ddc74c821af8cdab Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:07:09 +0000 Subject: [PATCH 101/239] working on logic --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 4cd446e..f287b9f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -198,7 +198,7 @@ def draw_lines(screen, lines): # Default collision function for objects def no_collision(space, arbiter, *args, **kwargs): - return False + return True # Called when level sensor in tank is hit def level_reached(space, arbiter, *args, **kwargs): From deff38c46751b4fee164fe88aa26956061e486d8 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:15:02 +0000 Subject: [PATCH 102/239] working on logic --- plants/oil-refinery/oil_hmi.py | 14 +++++++------- plants/oil-refinery/oil_world.py | 24 ++++++++---------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 8c12442..1f5e89e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -116,13 +116,6 @@ def setTankLevel(self, widget, data=None): self.modbusClient.write_register(0x02, data) except: pass - - # Control the separator feed register values - def setSepFeed(self, widget, data=None): - try: - self.modbusClient.write_register(0x05, data) - except: - pass # Control the separator vessel level register values def setSepVessel(self, widget, data=None): @@ -130,6 +123,13 @@ def setSepVessel(self, widget, data=None): self.modbusClient.write_register(0x04, data) except: pass + + # Control the separator feed register values + def setSepFeed(self, widget, data=None): + try: + self.modbusClient.write_register(0x05, data) + except: + pass def update_status(self): diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f287b9f..bb975be 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -197,8 +197,9 @@ def draw_lines(screen, lines): pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) # Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" def no_collision(space, arbiter, *args, **kwargs): - return True + return True # Called when level sensor in tank is hit def level_reached(space, arbiter, *args, **kwargs): @@ -225,13 +226,6 @@ def sep_feed_on(space, arbiter, *args, **kwargs): PLCSetTag(PLC_SEP_FEED, 1) return False -def oil_storage_ready(space, arbiter, *args, **kwargs): - log.debug("Storage bin ready") - PLCSetTag(PLC_TANK_LEVEL, 0) - PLCSetTag(PLC_FEED_PUMP, 1) # Open pump - PLCSetTag(PLC_OUTLET_VALVE, 0) - return False - def run_world(): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) @@ -281,19 +275,17 @@ def run_world(): # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 0) - PLCSetTag(PLC_SEP_VESSEL, 1) - PLCSetTag(PLC_SEP_FEED, 1) - space.add_collision_handler(0x7, 0x5, begin=sep_on) - space.add_collision_handler(0x8, 0x5, begin=sep_feed_on) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) # If the separator process is turned on if PLCGetTag(PLC_SEP_VESSEL) == 1: - space.add_collision_handler(0x7, 0x5, begin=sep_on) - space.add_collision_handler(0x8, 0x5, begin=sep_feed_on) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) else: - space.add_collision_handler(0x7, 0x5, begin=no_collision) - space.add_collision_handler(0x8, 0x5, begin=no_collision) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) From e4ba0a0c5e6a74fecdd3d4ab9191045a91f04127 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:20:52 +0000 Subject: [PATCH 103/239] adding manual control for level sensor --- plants/oil-refinery/oil_hmi.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 1f5e89e..ee64c3f 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -56,6 +56,22 @@ def __init__(self): grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) elementIndex += 1 + + # Level Switch + level_switch_label = Gtk.Label("Crude Oil Tank Level Switch") + level_switch_value = Gtk.Label() + + level_switch_start_button = Gtk.Button("ON") + level_switch_stop_button = Gtk.Button("OFF") + + level_switch_start_button.connect("clicked", self.setTankLevel, 1) + level_switch_stop_button.connect("clicked", self.setTankLevel, 0) + + grid.attach(level_switch_label, 0, elementIndex, 1, 1) + grid.attach(level_switch_value, 1, elementIndex, 1, 1) + grid.attach(level_switch_start_button, 2, elementIndex, 1, 1) + grid.attach(level_switch_stop_button, 3, elementIndex, 1, 1) + elementIndex += 1 #Oil/Water Separator Vessel separator_label = Gtk.Label("Oil/Water Separator Vessel") From dffde490bed675eae6a596f3c8697739ca6ccfd9 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:23:39 +0000 Subject: [PATCH 104/239] Added manual level control --- plants/oil-refinery/oil_hmi.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index ee64c3f..d4a577d 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -170,6 +170,12 @@ def update_status(self): else: self.feed_pump_value.set_markup("STOPPED") + # If the level sensor is ON + if regs[1] == 1: + self.level_switch_value.set_markup("ON") + else: + self.level_switch_value.set_markup("OFF") + # If the feed pump "0x04" is set to 1, separator is currently processing if regs[3] == 1: self.separator_value.set_markup("RUNNING") From 0fcd76df475885e7d8022ee0bf342de6a2cbb2b1 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:24:35 +0000 Subject: [PATCH 105/239] Added manual level control --- plants/oil-refinery/oil_hmi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index d4a577d..4f56f62 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -114,6 +114,7 @@ def __init__(self): self.process_status_value = process_status_value self.connection_status_value = connection_status_value self.separator_value = separator_value + self.level_switch_value = level_switch_value # Set default label values self.resetLabels() From a5882ce084871b83ef6222ca237e20ab73a2a175 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:25:22 +0000 Subject: [PATCH 106/239] Added manual level control --- plants/oil-refinery/oil_hmi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 4f56f62..d03fe75 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -17,6 +17,7 @@ def initModbus(self): def resetLabels(self): self.feed_pump_value.set_markup("N/A") self.separator_value.set_markup("N/A") + self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") From 01224f4a66d699107373033afda1798876f6d114 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:36:55 +0000 Subject: [PATCH 107/239] Fixed attack scripts, other minor changes, added todo list --- plants/oil-refinery/attacks/nothing_runs.py | 2 +- plants/oil-refinery/todo.txt | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 plants/oil-refinery/todo.txt diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index 4a1edd6..c7b1465 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -18,7 +18,7 @@ while True: rq = client.write_register(0x01, 0) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor - rq = client.write_register(0x04, 1) # Limit Switch + rq = client.write_register(0x04, 0) # Limit Switch except KeyboardInterrupt: client.close() diff --git a/plants/oil-refinery/todo.txt b/plants/oil-refinery/todo.txt new file mode 100644 index 0000000..ed498cb --- /dev/null +++ b/plants/oil-refinery/todo.txt @@ -0,0 +1,9 @@ +TODO list +- Add more mini-game aspect to it + - Show amount of oil successfully processed, + - Show amount of oil lost due to overflow + - Show amount of oil successfully shipped + - Show oil shipments missed due to lack of oil processed + +- Make it prettier/more graphical +- Add background image \ No newline at end of file From e47b30314dbe726e9fbf953434f6967abf58245f Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:42:31 +0000 Subject: [PATCH 108/239] Testing command line args on nothing_runs.py --- plants/oil-refinery/attacks/nothing_runs.py | 33 ++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index c7b1465..a50bbfc 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -4,6 +4,37 @@ from pymodbus.exceptions import ConnectionException import logging +import argparse +import os +import sys + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This attack scripts sets register values so that nothing on the PLC will run', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="target", + help = "Target modbus IP address") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + + logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) @@ -11,7 +42,7 @@ ##################################### # Code ##################################### -client = ModbusClient('localhost', port=5020) +client = ModbusClient(target, port=5020) try: client.connect() From 0b3705ea96549683cdbbdf23ca58b41e6e03b4e0 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:44:06 +0000 Subject: [PATCH 109/239] Fixed: args.target --- plants/oil-refinery/attacks/nothing_runs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index a50bbfc..555b86d 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -42,7 +42,7 @@ def error(self, message): ##################################### # Code ##################################### -client = ModbusClient(target, port=5020) +client = ModbusClient(args.target, port=5020) try: client.connect() From cd58309c3c6ccde0ea8ea174629f5db969abb753 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:47:32 +0000 Subject: [PATCH 110/239] Fancifying attack scripts --- plants/oil-refinery/attacks/nothing_runs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index 555b86d..3052a59 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -7,6 +7,7 @@ import argparse import os import sys +import time # Override Argument parser to throw error and generate help message # if undefined args are passed @@ -46,6 +47,10 @@ def error(self, message): try: client.connect() + print "Connecting to PLC . . . Please wait " + time.sleep(3) + print ". . . Attacking PLC at " + args.target + print ". . . Jamming all PLC commands!" while True: rq = client.write_register(0x01, 0) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor From 4de34c692d5f1e3215560f17f5bc78eac00cf03e Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:53:01 +0000 Subject: [PATCH 111/239] Fancifying attack scripts --- .../oil-refinery/attacks/constant_running.py | 37 +++++++++++++++++++ plants/oil-refinery/attacks/nothing_runs.py | 5 ++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/attacks/constant_running.py b/plants/oil-refinery/attacks/constant_running.py index c08ef9f..69bf677 100755 --- a/plants/oil-refinery/attacks/constant_running.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -4,6 +4,37 @@ from pymodbus.exceptions import ConnectionException import logging +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This attack scripts sets register values so the PLC constantly spews oil into the system', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="target", + help = "Target modbus IP address") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) @@ -15,6 +46,12 @@ try: client.connect() + print ". . . Connecting to PLC" + print ". . . Please wait." + time.sleep(3) + print ". . . Attacking PLC at " + args.target + print ". . . Attack successful!" + print "PLC will now constantly pump oil" while True: rq = client.write_register(0x01, 1) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index 3052a59..f458dce 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -42,12 +42,13 @@ def error(self, message): ##################################### # Code -##################################### +#####################################git c client = ModbusClient(args.target, port=5020) try: client.connect() - print "Connecting to PLC . . . Please wait " + print ". . . Connecting to PLC" + print ". . . Please wait." time.sleep(3) print ". . . Attacking PLC at " + args.target print ". . . Jamming all PLC commands!" From 7b25ab59f0eef1a1d7e42b322cd128143c3fa5be Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 28 Jul 2016 23:56:50 +0000 Subject: [PATCH 112/239] Fancifying attack scripts --- plants/oil-refinery/attacks/constant_running.py | 1 + plants/oil-refinery/attacks/nothing_runs.py | 1 + 2 files changed, 2 insertions(+) diff --git a/plants/oil-refinery/attacks/constant_running.py b/plants/oil-refinery/attacks/constant_running.py index 69bf677..d7745e5 100755 --- a/plants/oil-refinery/attacks/constant_running.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -50,6 +50,7 @@ def error(self, message): print ". . . Please wait." time.sleep(3) print ". . . Attacking PLC at " + args.target + time.sleep(1) print ". . . Attack successful!" print "PLC will now constantly pump oil" while True: diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index f458dce..2b1018d 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -51,6 +51,7 @@ def error(self, message): print ". . . Please wait." time.sleep(3) print ". . . Attacking PLC at " + args.target + time.sleep(1) print ". . . Jamming all PLC commands!" while True: rq = client.write_register(0x01, 0) # Run Plant, Run! From 6d85d026fe4f8eecc497f5b40764828f9c9f2111 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 00:01:47 +0000 Subject: [PATCH 113/239] Added arg parse to attack scripts and hmi and world. Changed start.sh to default to localhost --- .../oil-refinery/attacks/constant_running.py | 2 +- plants/oil-refinery/oil_hmi.py | 30 ++++++++++++++++++- plants/oil-refinery/oil_world.py | 30 ++++++++++++++++++- plants/oil-refinery/start.sh | 4 +-- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/attacks/constant_running.py b/plants/oil-refinery/attacks/constant_running.py index d7745e5..32ff7a0 100755 --- a/plants/oil-refinery/attacks/constant_running.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -52,7 +52,7 @@ def error(self, message): print ". . . Attacking PLC at " + args.target time.sleep(1) print ". . . Attack successful!" - print "PLC will now constantly pump oil" + print ". . . PLC will now constantly pump oil" while True: rq = client.write_register(0x01, 1) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index d03fe75..ac94b62 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -4,6 +4,34 @@ from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.exceptions import ConnectionException +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script runs the SCADA HMI to control the PLC', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to connect the HMI to") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + MODBUS_SLEEP=1 @@ -11,7 +39,7 @@ class HMIWindow(Gtk.Window): def initModbus(self): # Create modbus connection to specified address and port - self.modbusClient = ModbusClient('localhost', port=5020) + self.modbusClient = ModbusClient(server_addr, port=5020) # Default values for the HMI labels def resetLabels(self): diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index bb975be..62a443f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -20,6 +20,34 @@ import socket +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + logging.basicConfig() log = logging.getLogger() log.setLevel(logging.INFO) @@ -354,7 +382,7 @@ def run_world(): def startModbusServer(): # Run a modbus server on specified address and modbus port (5020) - StartTcpServer(context, identity=identity, address=("localhost", MODBUS_SERVER_PORT)) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) def main(): reactor.callInThread(run_world) diff --git a/plants/oil-refinery/start.sh b/plants/oil-refinery/start.sh index 3c19e3d..4bdf341 100755 --- a/plants/oil-refinery/start.sh +++ b/plants/oil-refinery/start.sh @@ -2,6 +2,6 @@ echo "VirtuaPlant -- Bottle-filling Factory" echo "- Starting World View" -./oil_world.py & +./oil_world.py -t localhost& echo "- Starting HMI" -./oil_hmi.py & +./oil_hmi.py -t localhost& From 19e445587d0421e7d0456b45cc3cb6d568664827 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 00:02:55 +0000 Subject: [PATCH 114/239] minor fix to server_addr var --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index ac94b62..b195981 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -39,7 +39,7 @@ def error(self, message): class HMIWindow(Gtk.Window): def initModbus(self): # Create modbus connection to specified address and port - self.modbusClient = ModbusClient(server_addr, port=5020) + self.modbusClient = ModbusClient(args.server_addr, port=5020) # Default values for the HMI labels def resetLabels(self): From 72dd6168e9d00b4030340afaddd8eaf16d0c0796 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 00:06:17 +0000 Subject: [PATCH 115/239] Fixing args var --- plants/oil-refinery/attacks/constant_running.py | 2 +- plants/oil-refinery/start.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/attacks/constant_running.py b/plants/oil-refinery/attacks/constant_running.py index 32ff7a0..d2a3351 100755 --- a/plants/oil-refinery/attacks/constant_running.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -42,7 +42,7 @@ def error(self, message): ##################################### # Code ##################################### -client = ModbusClient('localhost', port=5020) +client = ModbusClient(args.target, port=5020) try: client.connect() diff --git a/plants/oil-refinery/start.sh b/plants/oil-refinery/start.sh index 4bdf341..125e37c 100755 --- a/plants/oil-refinery/start.sh +++ b/plants/oil-refinery/start.sh @@ -2,6 +2,6 @@ echo "VirtuaPlant -- Bottle-filling Factory" echo "- Starting World View" -./oil_world.py -t localhost& +./oil_world.py -t localhost & echo "- Starting HMI" -./oil_hmi.py -t localhost& +./oil_hmi.py -t localhost & From f009d36f492ac5d9cb2e6508c9035622e03a6bb4 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 00:08:10 +0000 Subject: [PATCH 116/239] Fixing args var --- plants/oil-refinery/oil_hmi.py | 3 ++- plants/oil-refinery/oil_world.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index b195981..56d0775 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -32,7 +32,8 @@ def error(self, message): parser.print_help() sys.exit(1) - +# Split and process arguments into "args" +args = parser.parse_args() MODBUS_SLEEP=1 diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 62a443f..59c82bb 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -47,6 +47,9 @@ def error(self, message): if len(sys.argv)==1: parser.print_help() sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() logging.basicConfig() log = logging.getLogger() From 47baa5cbaeb64be2d1d80db685f75d5b4c6a16a9 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 00:12:50 +0000 Subject: [PATCH 117/239] Finalizing --- plants/oil-refinery/attacks/constant_running.py | 2 +- plants/oil-refinery/attacks/nothing_runs.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/attacks/constant_running.py b/plants/oil-refinery/attacks/constant_running.py index d2a3351..df38c8b 100755 --- a/plants/oil-refinery/attacks/constant_running.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -49,7 +49,7 @@ def error(self, message): print ". . . Connecting to PLC" print ". . . Please wait." time.sleep(3) - print ". . . Attacking PLC at " + args.target + print ". . . Attacking PLC at " + args.target + ":5020" time.sleep(1) print ". . . Attack successful!" print ". . . PLC will now constantly pump oil" diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index 2b1018d..081de98 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -50,8 +50,9 @@ def error(self, message): print ". . . Connecting to PLC" print ". . . Please wait." time.sleep(3) - print ". . . Attacking PLC at " + args.target + print ". . . Attacking PLC at " + args.target + ":5020" time.sleep(1) + print ". . . Attack successful!" print ". . . Jamming all PLC commands!" while True: rq = client.write_register(0x01, 0) # Run Plant, Run! From 1c9dd647515ffc6cf01ed5794ef86217d23e0f28 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 17:40:34 +0000 Subject: [PATCH 118/239] fixed separator pipe --- plants/oil-refinery/oil_world.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 59c82bb..aabb388 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -121,8 +121,8 @@ def separator_vessel_feed(space): # Add the separator vessel release def separator_vessel_release(space): body = pymunk.Body() - body.position = (390, 225) - radius = 3 + body.position = (387, 225) + radius = 4 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = sep_vessel_collision space.add(shape) @@ -171,14 +171,14 @@ def add_oil_unit(space): #separator vessel l15 = pymunk.Segment(body, (-40, -45), (-40, -75), 5) l16 = pymunk.Segment(body, (-40, -25), (-40, 5), 5) - l17 = pymunk.Segment(body, (-40, -75), (80, -75), 5) + l17 = pymunk.Segment(body, (-40, -75), (75, -75), 5) l18 = pymunk.Segment(body, (-40, 5), (120, 5), 5) l19 = pymunk.Segment(body, (100, -75), (120, -75), 5) l22 = pymunk.Segment(body, (120, -75), (120, -55), 5) l23 = pymunk.Segment(body, (120, -30), (120, 5), 5) #waste water pipe - l20 = pymunk.Segment(body, (80, -75), (80, -115), 5) + l20 = pymunk.Segment(body, (75, -75), (75, -115), 5) l21 = pymunk.Segment(body, (100, -75), (100, -115), 5) #separator exit pipe @@ -186,7 +186,7 @@ def add_oil_unit(space): l25 = pymunk.Segment(body, (120, -55), (600, -55), 5) #waste water storage - l26 = pymunk.Segment(body, (80, -115), (20, -115), 5) + l26 = pymunk.Segment(body, (75, -115), (20, -115), 5) l27 = pymunk.Segment(body, (20, -115), (20, -185), 5) l28 = pymunk.Segment(body, (20, -185), (140, -185), 5) l29 = pymunk.Segment(body, (140, -185), (140, -170), 5) From 86ddedb4f5127ace3a4852747a5e316d53668721 Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 18:17:07 +0000 Subject: [PATCH 119/239] title size changed --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 56d0775..e69ee0f 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -67,7 +67,7 @@ def __init__(self): # Main title label label = Gtk.Label() - label.set_markup("Crude Oil Pretreatment Unit ") + label.set_markup("Crude Oil Pretreatment Unit ") grid.attach(label, 0, elementIndex, 4, 1) elementIndex += 1 From ece013896a904d53fc6b6b2090ec989a8a6548ae Mon Sep 17 00:00:00 2001 From: Ike Date: Fri, 29 Jul 2016 18:23:07 +0000 Subject: [PATCH 120/239] screen placement --- plants/oil-refinery/oil_hmi.py | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index e69ee0f..9855d45 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -68,7 +68,7 @@ def __init__(self): # Main title label label = Gtk.Label() label.set_markup("Crude Oil Pretreatment Unit ") - grid.attach(label, 0, elementIndex, 4, 1) + grid.attach(label, 4, elementIndex, 4, 1) elementIndex += 1 # Crude Oil Feed Pump @@ -81,10 +81,10 @@ def __init__(self): feed_pump_start_button.connect("clicked", self.setPump, 1) feed_pump_stop_button.connect("clicked", self.setPump, 0) - grid.attach(feed_pump_label, 0, elementIndex, 1, 1) - grid.attach(feed_pump_value, 1, elementIndex, 1, 1) - grid.attach(feed_pump_start_button, 2, elementIndex, 1, 1) - grid.attach(feed_pump_stop_button, 3, elementIndex, 1, 1) + grid.attach(feed_pump_label, 4, elementIndex, 1, 1) + grid.attach(feed_pump_value, 5, elementIndex, 1, 1) + grid.attach(feed_pump_start_button, 6, elementIndex, 1, 1) + grid.attach(feed_pump_stop_button, 7, elementIndex, 1, 1) elementIndex += 1 # Level Switch @@ -97,10 +97,10 @@ def __init__(self): level_switch_start_button.connect("clicked", self.setTankLevel, 1) level_switch_stop_button.connect("clicked", self.setTankLevel, 0) - grid.attach(level_switch_label, 0, elementIndex, 1, 1) - grid.attach(level_switch_value, 1, elementIndex, 1, 1) - grid.attach(level_switch_start_button, 2, elementIndex, 1, 1) - grid.attach(level_switch_stop_button, 3, elementIndex, 1, 1) + grid.attach(level_switch_label, 4, elementIndex, 1, 1) + grid.attach(level_switch_value, 5, elementIndex, 1, 1) + grid.attach(level_switch_start_button, 6, elementIndex, 1, 1) + grid.attach(level_switch_stop_button, 7, elementIndex, 1, 1) elementIndex += 1 #Oil/Water Separator Vessel @@ -113,31 +113,31 @@ def __init__(self): separator_start_button.connect("clicked", self.setSepVessel, 1) separator_stop_button.connect("clicked", self.setSepVessel, 0) - grid.attach(separator_label, 0, elementIndex, 1, 1) - grid.attach(separator_value, 1, elementIndex, 1, 1) - grid.attach(separator_start_button, 2, elementIndex, 1, 1) - grid.attach(separator_stop_button, 3, elementIndex, 1, 1) + grid.attach(separator_label, 4, elementIndex, 1, 1) + grid.attach(separator_value, 5, elementIndex, 1, 1) + grid.attach(separator_start_button, 6, elementIndex, 1, 1) + grid.attach(separator_stop_button, 7, elementIndex, 1, 1) elementIndex += 1 # Process status process_status_label = Gtk.Label("Process Status") process_status_value = Gtk.Label() - grid.attach(process_status_label, 0, elementIndex, 1, 1) - grid.attach(process_status_value, 1, elementIndex, 1, 1) + grid.attach(process_status_label, 4, elementIndex, 1, 1) + grid.attach(process_status_value, 5, elementIndex, 1, 1) elementIndex += 1 # Connection status connection_status_label = Gtk.Label("Connection Status") connection_status_value = Gtk.Label() - grid.attach(connection_status_label, 0, elementIndex, 1, 1) - grid.attach(connection_status_value, 1, elementIndex, 1, 1) + grid.attach(connection_status_label, 4, elementIndex, 1, 1) + grid.attach(connection_status_value, 5, elementIndex, 1, 1) elementIndex += 1 # Oil Refienery branding virtual_refinery = Gtk.Label() virtual_refinery.set_markup("Crude Oil Pretreatment Unit - HMI") - grid.attach(virtual_refinery, 0, elementIndex, 2, 1) + grid.attach(virtual_refinery, 4, elementIndex, 2, 1) # Attach Value Labels self.feed_pump_value = feed_pump_value From 6b31bc45d4d60882a7bf761469b258552174d309 Mon Sep 17 00:00:00 2001 From: Ike Date: Sat, 30 Jul 2016 09:15:05 +0000 Subject: [PATCH 121/239] changed sensor colors --- plants/oil-refinery/oil_world.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index aabb388..07a4c01 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -340,9 +340,9 @@ def run_world(): draw_polygon(screen, pump) draw_lines(screen, lines) - draw_ball(screen, tank_level, THECOLORS['red']) - draw_ball(screen, separator_vessel, THECOLORS['red']) - draw_ball(screen, separator_feed, THECOLORS['red']) + draw_ball(screen, tank_level, THECOLORS['black']) + draw_ball(screen, separator_vessel, THECOLORS['black']) + draw_ball(screen, separator_feed, THECOLORS['black']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) @@ -352,6 +352,10 @@ def run_world(): oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + screen.blit(title, (300, 40)) screen.blit(name, (347, 10)) screen.blit(instructions, (SCREEN_WIDTH-115, 10)) @@ -359,6 +363,9 @@ def run_world(): screen.blit(oil_storage_label, (240, 190)) screen.blit(separator_label, (270,275)) screen.blit(waste_water_label, (265, 490)) + screen.blit(tank_sensor, (10, 187)) + screen.blit(separator_release, (425, 315)) + screen.blit(waste_sensor, (402, 375)) space.step(1/FPS) pygame.display.flip() From 150c5c01f980476f7b0196c272b0368b5e45a9e5 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:03:11 +0000 Subject: [PATCH 122/239] Adding oil processed/spilled --- plants/oil-refinery/oil_hmi.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 9855d45..bc5ac8b 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -49,6 +49,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") + self.oil_processed_value.set_markup("0") + self.oil_spilled_value.set_markup("0") def __init__(self): # Window title @@ -133,6 +135,20 @@ def __init__(self): grid.attach(connection_status_value, 5, elementIndex, 1, 1) elementIndex += 1 + # Oil Processed Status + oil_processed_label = Gtk.Label("Oil Processed Status") + oil_processed_value = Gtk.Label() + grid.attach(oil_processed_label, 4, elementIndex, 1, 1) + grid.attach(oil_processed_value, 5, elementIndex, 1, 1) + elementIndex += 1 + + # Oil Spilled Status + oil_spilled_label = Gtk.Label("Oil Spilled Status") + oil_spilled_value = Gtk.Label() + grid.attach(oil_spilled_label, 4, elementIndex, 1, 1) + grid.attach(oil_spilled_value, 5, elementIndex, 1, 1) + elementIndex += 1 + # Oil Refienery branding virtual_refinery = Gtk.Label() @@ -145,6 +161,8 @@ def __init__(self): self.connection_status_value = connection_status_value self.separator_value = separator_value self.level_switch_value = level_switch_value + self.oil_processed = oil_processed_value + self.oil_spilled = oil_spilled_value # Set default label values self.resetLabels() From 814ab62b181b5a711663aa4cc74f85674ebc0a5a Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:13:21 +0000 Subject: [PATCH 123/239] Adding oil processed/spilled --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index bc5ac8b..24ec69e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +# IMPORTS # from gi.repository import GLib, Gtk, Gdk, GObject from pymodbus.client.sync import ModbusTcpClient as ModbusClient from pymodbus.exceptions import ConnectionException @@ -9,8 +10,7 @@ import sys import time -# Override Argument parser to throw error and generate help message -# if undefined args are passed +# Argument Parsing class MyParser(argparse.ArgumentParser): def error(self, message): sys.stderr.write('error: %s\n' % message) From 4f0f1593416d5013c26115158e7e2ba300a267b1 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:14:38 +0000 Subject: [PATCH 124/239] Adding oil processed/spilled --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 24ec69e..9d72972 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -49,8 +49,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - self.oil_processed_value.set_markup("0") - self.oil_spilled_value.set_markup("0") + #self.oil_processed_value.set_markup("0") + #self.oil_spilled_value.set_markup("0") def __init__(self): # Window title From ae586efcefe04dc51ecb819be770b29cf6694e93 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:17:09 +0000 Subject: [PATCH 125/239] Adding oil processed/spilled --- plants/oil-refinery/oil_hmi.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 9d72972..5c26a01 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -49,8 +49,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - #self.oil_processed_value.set_markup("0") - #self.oil_spilled_value.set_markup("0") + self.oil_processed_value.set_markup("0") + self.oil_spilled_value.set_markup("0") def __init__(self): # Window title @@ -161,8 +161,8 @@ def __init__(self): self.connection_status_value = connection_status_value self.separator_value = separator_value self.level_switch_value = level_switch_value - self.oil_processed = oil_processed_value - self.oil_spilled = oil_spilled_value + self.oil_processed_value = oil_processed_value + self.oil_spilled_value = oil_spilled_value # Set default label values self.resetLabels() From 225080e4ecd1a2d84f5385208dc34cbdba24df00 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:18:09 +0000 Subject: [PATCH 126/239] Adding oil processed/spilled --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 5c26a01..da5a948 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -49,7 +49,7 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - self.oil_processed_value.set_markup("0") + self.oil_processed_value.set_markup("0") self.oil_spilled_value.set_markup("0") def __init__(self): From 16a420d62f761abf2e75681585a8a3359a37cb72 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:27:00 +0000 Subject: [PATCH 127/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 07a4c01..2b3ce8b 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -83,6 +83,7 @@ def PLCGetTag(addr): ball_collision = 0x5 separator_collision = 0x8 sep_vessel_collision = 0x7 +oil_spill_collision = 0x9 def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" @@ -137,6 +138,17 @@ def tank_level_sensor(space): shape.collision_type = tank_level_collision # tank_level space.add(shape) return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + #body.position = (125, 800) + a = (125, 600) + b = (400, 600) + radius = 5 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # tank_level + space.add(shape) + return shape # Add the feed pump to the space def add_pump(space): @@ -240,6 +252,10 @@ def level_reached(space, arbiter, *args, **kwargs): PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 return False +def oil_spilled(space, arbiter, *args, **kwargs): + log.debug("Oil Spilled") + return False + # This fires when the separator level is hit def sep_on(space, arbiter, *args, **kwargs): log.debug("Begin separation") @@ -270,6 +286,7 @@ def run_world(): # When oil collides with tank_level, call level_reached space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) pump = add_pump(space) lines = add_oil_unit(space) @@ -277,6 +294,7 @@ def run_world(): separator_vessel = separator_vessel_release(space) separator_feed = separator_vessel_feed(space) separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) balls = [] From 0ade6f0d34cba88f196c1861575e05e0197e2900 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:28:56 +0000 Subject: [PATCH 128/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 2b3ce8b..e8cd136 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,7 +141,7 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - #body.position = (125, 800) + body.position = (125, 600) a = (125, 600) b = (400, 600) radius = 5 From 49e1b043eeb00436c82d252315cf38e2c241ad56 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:31:34 +0000 Subject: [PATCH 129/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e8cd136..af47e1d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -144,8 +144,8 @@ def oil_spill_sensor(space): body.position = (125, 600) a = (125, 600) b = (400, 600) - radius = 5 - shape = pymunk.Segment(body, a, b, radius) + radius = 7 + shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = oil_spill_collision # tank_level space.add(shape) return shape From 2f303555d9b4294f3a214af467856afba26215b8 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:32:22 +0000 Subject: [PATCH 130/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index af47e1d..c078798 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,9 +141,7 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (125, 600) - a = (125, 600) - b = (400, 600) + body.position = (125, 425) radius = 7 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = oil_spill_collision # tank_level From 08d7ffbcae026eb5e5c3d9817feb262c42ef3574 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:34:04 +0000 Subject: [PATCH 131/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index c078798..72a4bdf 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -359,6 +359,7 @@ def run_world(): draw_ball(screen, tank_level, THECOLORS['black']) draw_ball(screen, separator_vessel, THECOLORS['black']) draw_ball(screen, separator_feed, THECOLORS['black']) + draw_ball(screen, oil_spill, THECOLORS['black']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From b4b2855211a6db66e881a0482f179057549b4ffa Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:34:41 +0000 Subject: [PATCH 132/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 72a4bdf..caefe32 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -359,7 +359,7 @@ def run_world(): draw_ball(screen, tank_level, THECOLORS['black']) draw_ball(screen, separator_vessel, THECOLORS['black']) draw_ball(screen, separator_feed, THECOLORS['black']) - draw_ball(screen, oil_spill, THECOLORS['black']) + draw_line(screen, oil_spill, THECOLORS['black']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From 7d03b105614445faaae69ceef82613478a55f547 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:36:18 +0000 Subject: [PATCH 133/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index caefe32..bc00c0d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,7 +143,9 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (125, 425) radius = 7 - shape = pymunk.Circle(body, radius, (0, 0)) + a = (0, 25) + b = (300, 25) + shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) return shape @@ -359,7 +361,7 @@ def run_world(): draw_ball(screen, tank_level, THECOLORS['black']) draw_ball(screen, separator_vessel, THECOLORS['black']) draw_ball(screen, separator_feed, THECOLORS['black']) - draw_line(screen, oil_spill, THECOLORS['black']) + draw_line(screen, oil_spill) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From 61a37dc6711169cd2ac1e92582e200964671172e Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:37:36 +0000 Subject: [PATCH 134/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index bc00c0d..1663db7 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,10 +141,10 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (125, 425) + body.position = (0, 700) radius = 7 - a = (0, 25) - b = (300, 25) + a = (0, 0) + b = (600, 0) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From 20c6156c6cb363f7481f3de14caf0a53540d14a5 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:38:35 +0000 Subject: [PATCH 135/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 1663db7..55b6237 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,10 +141,10 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (0, 700) + body.position = (0, 525) radius = 7 a = (0, 0) - b = (600, 0) + b = (640, 0) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From a6294aa7574e1c14d11ad46be208c73ef732f6a0 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:39:19 +0000 Subject: [PATCH 136/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 55b6237..52facc4 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,7 +141,7 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (0, 525) + body.position = (0, 0) radius = 7 a = (0, 0) b = (640, 0) From 434950741064005a4be91e6788b9db163addac4b Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:39:39 +0000 Subject: [PATCH 137/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 52facc4..59a3726 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,7 +141,7 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (0, 0) + body.position = (0, 550) radius = 7 a = (0, 0) b = (640, 0) From 2d808df6925d81ece11439b3e954f050df6a963a Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:39:59 +0000 Subject: [PATCH 138/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 59a3726..f3c03e7 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,8 +143,8 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 550) radius = 7 - a = (0, 0) - b = (640, 0) + a = (0, 400) + b = (640, 400) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From 93bf3a65e28ed5d4eb30900df46841e69696fcd9 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:40:23 +0000 Subject: [PATCH 139/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f3c03e7..ccd9b62 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,8 +143,8 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 550) radius = 7 - a = (0, 400) - b = (640, 400) + a = (0, 100) + b = (640, 100) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From b6c80d6205e98fa4e04be5a04ec5508d53ba49ce Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:41:03 +0000 Subject: [PATCH 140/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ccd9b62..48c4508 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,10 +141,10 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (0, 550) + body.position = (0, 25) radius = 7 - a = (0, 100) - b = (640, 100) + a = (0, 0) + b = (640, 0) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From 68e7dfe5b78d11f535bffdcdc71a5726c5c6fe7f Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:41:41 +0000 Subject: [PATCH 141/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 48c4508..57f8b56 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -141,10 +141,10 @@ def tank_level_sensor(space): def oil_spill_sensor(space): body = pymunk.Body() - body.position = (0, 25) + body.position = (0, 0) radius = 7 - a = (0, 0) - b = (640, 0) + a = (0, 200) + b = (640, 200) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From fb68c258974096955f56814c98e488587c5bcdd4 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:42:07 +0000 Subject: [PATCH 142/239] Adding sensor for spilled oil --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 57f8b56..d4e713d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,8 +143,8 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 0) radius = 7 - a = (0, 200) - b = (640, 200) + a = (0, 100) + b = (640, 100) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From d96e4d982a31d35d81bbabc32b22ab79d0e21113 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:46:47 +0000 Subject: [PATCH 143/239] Added overloaded draw_line function to accept optional color argument --- plants/oil-refinery/oil_world.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index d4e713d..9899719 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,8 +143,8 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 0) radius = 7 - a = (0, 100) - b = (640, 100) + a = (0, 50) + b = (SCREEN_WIDTH, 50) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) @@ -221,14 +221,17 @@ def draw_polygon(screen, shape): pygame.draw.polygon(screen, THECOLORS['black'], fpoints) # Draw a single line to the screen -def draw_line(screen, line): +def draw_line(screen, line, color = None): body = line.body pv1 = body.position + line.a.rotated(body.angle) # 1 pv2 = body.position + line.b.rotated(body.angle) p1 = to_pygame(pv1) # 2 p2 = to_pygame(pv2) - pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) - + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + # Draw lines from an iterable list def draw_lines(screen, lines): for line in lines: @@ -361,7 +364,7 @@ def run_world(): draw_ball(screen, tank_level, THECOLORS['black']) draw_ball(screen, separator_vessel, THECOLORS['black']) draw_ball(screen, separator_feed, THECOLORS['black']) - draw_line(screen, oil_spill) + draw_line(screen, oil_spill, THECOLORS['red']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From a7887edc3a28caed637512d3b48dbfe71cd8486a Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:48:00 +0000 Subject: [PATCH 144/239] Adjusting sensor position --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 9899719..1a54e34 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,8 +143,8 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 0) radius = 7 - a = (0, 50) - b = (SCREEN_WIDTH, 50) + a = (0, 100) + b = (SCREEN_WIDTH, 100) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From ddaba41775dd4b075a8a51d1b0580530403d29e3 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:48:43 +0000 Subject: [PATCH 145/239] Adjusting sensor position --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 1a54e34..49c8b98 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -143,8 +143,8 @@ def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 0) radius = 7 - a = (0, 100) - b = (SCREEN_WIDTH, 100) + a = (0, 75) + b = (SCREEN_WIDTH, 75) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # tank_level space.add(shape) From 107e7f49af07b608f8571413d3ba753383ca9e87 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:57:20 +0000 Subject: [PATCH 146/239] Display amount of oil spilled --- plants/oil-refinery/oil_hmi.py | 15 +++++++++++++-- plants/oil-refinery/oil_world.py | 5 ++++- plants/oil-refinery/todo.txt | 7 ++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index da5a948..b0abe66 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -38,6 +38,9 @@ def error(self, message): MODBUS_SLEEP=1 class HMIWindow(Gtk.Window): + oil_processed_amount = 0 + oil_spilled_amount = 0 + def initModbus(self): # Create modbus connection to specified address and port self.modbusClient = ModbusClient(args.server_addr, port=5020) @@ -49,8 +52,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - self.oil_processed_value.set_markup("0") - self.oil_spilled_value.set_markup("0") + self.oil_processed_value.set_markup("" + oil_processed_amount + "") + self.oil_spilled_value.set_markup("" + oil_spilled_amount + "") def __init__(self): # Window title @@ -232,6 +235,14 @@ def update_status(self): else: self.separator_value.set_markup("STOPPED") self.process_status_value.set_markup("STOPPED ") + + if regs[5] == 1: + oil_spilled_amount += 1 + self.separator_value.set_markup("RUNNING") + self.process_status_value.set_markup("RUNNING ") + else: + self.separator_value.set_markup("STOPPED") + self.process_status_value.set_markup("STOPPED ") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 49c8b98..a0138a3 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -77,6 +77,7 @@ def PLCGetTag(addr): PLC_OUTLET_VALVE = 0x03 PLC_SEP_VESSEL = 0x04 PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 # Collision types tank_level_collision = 0x4 @@ -257,6 +258,9 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") + PLCSetTag(PLC_OIL_SPILL, 1) # We lost a unit of oil + PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False # This fires when the separator level is hit @@ -340,7 +344,6 @@ def run_world(): space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) - ticks_to_next_ball -= 1 if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: diff --git a/plants/oil-refinery/todo.txt b/plants/oil-refinery/todo.txt index ed498cb..e29d969 100644 --- a/plants/oil-refinery/todo.txt +++ b/plants/oil-refinery/todo.txt @@ -6,4 +6,9 @@ TODO list - Show oil shipments missed due to lack of oil processed - Make it prettier/more graphical -- Add background image \ No newline at end of file +- Add background image + +- Oil Spilled/Processed + - Add sensors in processing pipes + - Add sensor at bottom of world/above level sensor + \ No newline at end of file From 0551e8b4fa9a02f18c3eaf8513c137961a249d6d Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 19:57:36 +0000 Subject: [PATCH 147/239] Display amount of oil spilled --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index b0abe66..5e9e352 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -52,8 +52,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - self.oil_processed_value.set_markup("" + oil_processed_amount + "") - self.oil_spilled_value.set_markup("" + oil_spilled_amount + "") + self.oil_processed_value.set_markup("" + self.oil_processed_amount + "") + self.oil_spilled_value.set_markup("" + self.oil_spilled_amount + "") def __init__(self): # Window title From 2a765d430ca92c26dff66617cf7403da8082c17c Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:00:07 +0000 Subject: [PATCH 148/239] Display amount of oil spilled --- plants/oil-refinery/oil_hmi.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 5e9e352..ec12423 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -236,13 +236,10 @@ def update_status(self): self.separator_value.set_markup("STOPPED") self.process_status_value.set_markup("STOPPED ") + # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[5] == 1: - oil_spilled_amount += 1 - self.separator_value.set_markup("RUNNING") - self.process_status_value.set_markup("RUNNING ") - else: - self.separator_value.set_markup("STOPPED") - self.process_status_value.set_markup("STOPPED ") + self.oil_spilled_amount += 1 + self.oil_spilled_value.set_markup("" + self.oil_spilled_amount + "ml") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") From 768f51eb620927ffc0c1d17700812a33c2788aba Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:03:01 +0000 Subject: [PATCH 149/239] Fixed type error concatenating strings and ints --- plants/oil-refinery/oil_hmi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index ec12423..cb7bf61 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -52,8 +52,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - self.oil_processed_value.set_markup("" + self.oil_processed_amount + "") - self.oil_spilled_value.set_markup("" + self.oil_spilled_amount + "") + self.oil_processed_value.set_markup("" + str(self.oil_processed_amount) + "") + self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + "") def __init__(self): # Window title @@ -239,7 +239,7 @@ def update_status(self): # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[5] == 1: self.oil_spilled_amount += 1 - self.oil_spilled_value.set_markup("" + self.oil_spilled_amount + "ml") + self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + "ml") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") From 48502f2b3d3ec183302e13f311e5f4673d915584 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:04:28 +0000 Subject: [PATCH 150/239] Collision not registering --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a0138a3..42db9ee 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -259,7 +259,7 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") PLCSetTag(PLC_OIL_SPILL, 1) # We lost a unit of oil - PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil + #PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil maybe add sleep here PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False From fda0e561ca301445d6ebc5eb98ce1a35b123382f Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:05:32 +0000 Subject: [PATCH 151/239] Collision not registering --- plants/oil-refinery/oil_world.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 42db9ee..0fa858f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -147,7 +147,7 @@ def oil_spill_sensor(space): a = (0, 75) b = (SCREEN_WIDTH, 75) shape = pymunk.Segment(body, a, b, radius) - shape.collision_type = oil_spill_collision # tank_level + shape.collision_type = oil_spill_collision # oil spill sensor space.add(shape) return shape @@ -258,6 +258,7 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") + print "oil spilled" PLCSetTag(PLC_OIL_SPILL, 1) # We lost a unit of oil #PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil maybe add sleep here PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump From 6118ba57a638346071304f183d2eaf4a4d7bb07a Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:08:24 +0000 Subject: [PATCH 152/239] PLC Updates are slow --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 0fa858f..1c9d05d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -258,9 +258,9 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") - print "oil spilled" PLCSetTag(PLC_OIL_SPILL, 1) # We lost a unit of oil - #PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil maybe add sleep here + time.sleep(0.1) + PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil maybe add sleep here PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False From 8f5f2a1b1faeabf35293c45736957ac5603e8c6e Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:16:17 +0000 Subject: [PATCH 153/239] Changing how oil spilled/processed is registered. Use register data section. --- plants/oil-refinery/oil_hmi.py | 6 +++--- plants/oil-refinery/oil_world.py | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index cb7bf61..b05a65f 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -237,9 +237,9 @@ def update_status(self): self.process_status_value.set_markup("STOPPED ") # If the oil spilled tag gets set, increase the amount of oil we have spilled - if regs[5] == 1: - self.oil_spilled_amount += 1 - self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + "ml") + if regs[5]: + #self.oil_spilled_amount += 1 + self.oil_spilled_value.set_markup("" + str(regs[5]) + "ml") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 1c9d05d..461fb7d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -71,6 +71,10 @@ def PLCGetTag(addr): # Port the world will listen on MODBUS_SERVER_PORT=5020 +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + # PLC Register values for various control functions PLC_FEED_PUMP = 0x01 PLC_TANK_LEVEL = 0x02 @@ -78,6 +82,7 @@ def PLCGetTag(addr): PLC_SEP_VESSEL = 0x04 PLC_SEP_FEED = 0x05 PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 # Collision types tank_level_collision = 0x4 @@ -258,9 +263,8 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") - PLCSetTag(PLC_OIL_SPILL, 1) # We lost a unit of oil - time.sleep(0.1) - PLCSetTag(PLC_OIL_SPILL, 0) # We have now accounted for that unit of oil maybe add sleep here + oil_spilled_amount += 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False From 09595f285e1b84cf450490c927d9225fbc95f5bf Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:20:32 +0000 Subject: [PATCH 154/239] Fixing reference before assignment --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 461fb7d..05984f4 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -263,7 +263,7 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") - oil_spilled_amount += 1 + self.oil_spilled_amount = self.oil_spilled_amount + 1 PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False From 63ea575401c404c7376ac460e7208ceef1137da6 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:22:22 +0000 Subject: [PATCH 155/239] Fixing reference before assignment --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 05984f4..30f9f18 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -263,7 +263,7 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): log.debug("Oil Spilled") - self.oil_spilled_amount = self.oil_spilled_amount + 1 + oil_spilled_amount = oil_spilled_amount + 1 PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False From d1de6d1a7a0b2b5323d9da6781363cced807cba6 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:24:39 +0000 Subject: [PATCH 156/239] Fixing reference before assignment --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 30f9f18..477fc4c 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -72,8 +72,8 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 # Amount of oil spilled/processed -oil_spilled_amount = 0 -oil_processed_amount = 0 +global oil_spilled_amount = 0 +global oil_processed_amount = 0 # PLC Register values for various control functions PLC_FEED_PUMP = 0x01 From 8d98ac51e2b737def773c6a3f833321c818109a0 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:25:43 +0000 Subject: [PATCH 157/239] Fixing reference before assignment --- plants/oil-refinery/oil_world.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 477fc4c..947da8a 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -72,8 +72,10 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 # Amount of oil spilled/processed -global oil_spilled_amount = 0 -global oil_processed_amount = 0 +global oil_spilled_amount +global oil_processed_amount +oil_spilled_amount = 0 +oil_processed_amount = 0 # PLC Register values for various control functions PLC_FEED_PUMP = 0x01 From 5534645d0e5ef995768ac993df204fd5008c41fc Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:30:17 +0000 Subject: [PATCH 158/239] Fixing reference before assignment --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 947da8a..e2df511 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -72,8 +72,6 @@ def PLCGetTag(addr): MODBUS_SERVER_PORT=5020 # Amount of oil spilled/processed -global oil_spilled_amount -global oil_processed_amount oil_spilled_amount = 0 oil_processed_amount = 0 @@ -264,6 +262,8 @@ def level_reached(space, arbiter, *args, **kwargs): return False def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount log.debug("Oil Spilled") oil_spilled_amount = oil_spilled_amount + 1 PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil From e636850175a590dbf8ee5569dd4c6fdec2f3f7ce Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 20:34:27 +0000 Subject: [PATCH 159/239] Changed volume labels to be liters not ml --- plants/oil-refinery/oil_hmi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index b05a65f..8639e8e 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -52,8 +52,8 @@ def resetLabels(self): self.level_switch_value.set_markup("N/A") self.process_status_value.set_markup("N/A") self.connection_status_value.set_markup("OFFLINE") - self.oil_processed_value.set_markup("" + str(self.oil_processed_amount) + "") - self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + "") + self.oil_processed_value.set_markup("" + str(self.oil_processed_amount) + " Liters") + self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + " Liters") def __init__(self): # Window title @@ -239,7 +239,7 @@ def update_status(self): # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[5]: #self.oil_spilled_amount += 1 - self.oil_spilled_value.set_markup("" + str(regs[5]) + "ml") + self.oil_spilled_value.set_markup("" + str(regs[5]) + " Liters") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") From 4855719750699a9eba98166083b6a333115e9e19 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 2 Aug 2016 21:11:21 +0000 Subject: [PATCH 160/239] minor text fixes --- plants/oil-refinery/oil_world.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e2df511..057785c 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -415,11 +415,11 @@ def run_world(): # Modbus PLC server information identity = ModbusDeviceIdentification() -identity.VendorName = 'Siemens Oil Refining Platform' +identity.VendorName = 'Simmons Oil Refining Platform' identity.ProductCode = 'SORP' -identity.VendorUrl = 'http://w3.siemens.com/markets/global/en/oil-gas/pages/refining-petrochemical-industry.aspx' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' identity.ProductName = 'SORP 3850' -identity.ModelName = 'Siemens ORP 3850' +identity.ModelName = 'Simmons ORP 3850' identity.MajorMinorRevision = '2.09.01' def startModbusServer(): From 6f82d2103714c89a4af5f8a4a4f3c033ed239d49 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Wed, 10 Aug 2016 14:47:34 -0400 Subject: [PATCH 161/239] updates --- plants/oil-refinery/oil_unit.png | Bin 0 -> 16613 bytes plants/oil-refinery/oil_world.py | 134 ++++++++++++++++++------------- 2 files changed, 80 insertions(+), 54 deletions(-) create mode 100755 plants/oil-refinery/oil_unit.png diff --git a/plants/oil-refinery/oil_unit.png b/plants/oil-refinery/oil_unit.png new file mode 100755 index 0000000000000000000000000000000000000000..e571a61f1994b4a3a06061e826217f6b770c047e GIT binary patch literal 16613 zcmdtJc|6qn-#w;)-w z@07AmC=A(uua7$C`~6+N`*%OC>$;c6DqKV5w49iNfBa#7RrM+gl^48k{q`>S_nvzgT_+Uk zz&qs6j`#K%cTp%=cSX6Yxcf#kLzd4NP5-QOkeP|vsQ4^z^XQ`FMVhxcDQb<}^?r0T z9F9rZ>`+4Wgiv#= zsBjpUs?f&Ta>?*X#u7}C{m8Jp2cn>F%$2#ff4QUjX(DZd~fJr(lOASSyD-P zpY^TRF3VO)NeQ{B8uodPt{g*2r}?iRYSf*skJ${qa!7misu!oN&E*{%Lm=$U#gP3f zmxn$4^}WY(${Sj~eh51vvk~Dv&P={Qd3pB(L;9qJRH1Y!u_v_$4YFZ(XXHTy0wO~G ziO2$336T;atw){70k|Y-uXy3XG?kdpaQUaKF=Dp;(J~uT>f@`F++3G(yHpUgFRdZ5 z%w@*Ped(K}lCp9EfvcSO_mAmUb{8C$HV^*9qx zcJPe!ZKuzVS+HOmeu`hwnQjZ?UB34WVSkZu&e#wTO{WShtty*r@I>Y zu%MBSEltXm!POW`_eY%rRN)fLV_iDc>`%Nkd|IZU3%rNc3aWrAP2sdN#`;Pe=$E_Qt5PN zR?}FNapLcB+QiMNq|FZ^R-N@99k?!XC5nYyB)f5E1EP)mYjTx|f0e$<${ zn_DS9L2IG@Oz_Q-hn>W#DDqTCda%>teq^QjH{(-6*4;0xjN|&|zZJB`ZmlG3?P&^P zlWZEWuTBu#q8e{S;D|$Y1ZvHw}OV3T*m> zC?3yPx7I8IXydFkBtel5{HMhExAFhCbm8y8i05!{$m8MT6P9$HUBv3@>hf>jNbBnd zG>8f&-)12T7?wpd^Xo-dd9Ar?Dk?Sm?w|>s?a0tPgJ@YYhWf3qBRn$FEW)fgc3c16 z31C5f_cpzkhg>~kgiMu+RANPVrlhm=inikoZJcoL32_z4QOtu|+32ZWtKY zG&D3cfs8A`6>B#>prH$$6~6aL7CDARFFI2>N+1m#z?^13Qe}h-#R}hg?Mqw(P4+{4 z7&jJdAYVY(kU$_H&exZttJqfGzDX<1vcHhLke>JuzLI^{1s9rYRM`}GOjrd}CU-s2((Z*zM200_W#QTQpz8tN`}}Y3{a-uDe{lW(xxwVCEM#e~)#ziwX3_KWj)F`~ zOkMd7U+Rc!i<520#!;*;A=B-o0Ly{mY}ZFT9U`{Q1ATpf*jnk&(EyrMf1$Wb_K9NE zTN`tg9QZF!FU2Ygl-3klbu}o*iP>h3LEfWY7Ti6=kA(7jk+%AgGEs&ux<%9?bgQk$ zLF^ZwQ?}w;>kA1h6^LERoeSj+YFtU0+#f-dG+62}F7RsxEeUhUz<%545L8SPr^ zEOojS;=a&)DVs9g3h7Xjmb#Rw*UTnF0`x{sHRHxU!b6#u6A|sncKR_6M{q=umsh$V=!VUH z5k!)vz2~vKV#Rpsxv*5t0`pci_YthH=g)gu+S=nU3hEpox-_gAB8p#Mi6MknVcT2Q ziU;hRyuIhYDr#Y|qk;H*CKP8_?$5WIf0Pp2OEd4oe)&4Rh9xmmHs*Y)e&h zfG|fW+Re?XWy*JWGdwCvhmV7-c!~a+Mo4?leX?4DM1*sa4I!L1cc8m1DLGY>H<~wg zbGhLZz3eG5n`l>&nNM#XwyaK-;wAr?e@BbNUeeC7{u28n;X@KdyMGG1&Kg+9+zb1l zN$xT7Xx6g|Pv#({ij&piFNYwrcc!Vvy`W5T!TqcfI=4=)AXYztpUg;7HfNm{ld5jn ziRAl-p2GEbG*q_q4wSpvk9PZfynmYBPmTW%yG1JQqmJiQ1yXme@mxHQIiJ{7w36`` z(q4U{$oHXQ@6GjPpRE$AXqn=2L}Jjaqx=!Jgm1L4WXT7|`Vi);tPtV@5ekVi-FnC}lE#2lB>CcQgF z-@i1Ht`L0k7!x_UuZcR`Ym^k1oV$oikp?TMDPQGV4wT}*UQPGU8r%WpG&-7!BnK^t z`LB_O^+g_#vJGB2D66Y#I=qZH?i12}LW4DY=H%@LkyuMZpK0-SCLVgvlI*xR^F+70 z)&4yGg_oSSZ+{Y`o9MIYW>1%se<$@p8!rtjw=Lh^tHwV}9dQjy zR3od9>Ar$=;Y(U#mfbIOZ-un`x(-N`?vY?6<=xp_es_wkxkJZWY*Tp2=>F$j$Yu`{ zh?o`EPnU+A!|--oZ79nKR{H2-CfW#Q{SWt2^JK}pYEP*?iqX5bj#i3tZyON}s((sr zZv8DpCYGkrCkZL!9-x(IhHWWdxrW-fnd<3I-e;exyyw(o=o<6m%X@wETP$10JovO< zBqIWT4gwBhES0?1%t_kOFWM$+`IM@8JCEs!v+<89n@b7QNImSJ#Vrr3H;Qa$A|!g( zkKBcwoRfOVpj5Ps&Trmq%<_ z0&IDvW{B;Tz{@N}o{lzO%LsDkX!4{u-b-BnvxW#=ST&I--?$VNpUi>()|*$Ox6$BJ z&VVE0%xoy5aFPshr}49u-j^h-()V3GCF6Z1Pum5qZLr|ncKLHApM#Y0nVB3*i(Z?O zW)%k8l5lF)mIzNy#l{}$Fm{BhOg%}u3r;IdnjgvegNY}Cd7zAYDoB2cPwFZCLbc1K zl418OaY*v+Jhd8^F;Q<-__c8+o~NAc2MmnSQ(2iR7AU-G2M4kIr9;{8iSzlftN~xE z4Hb2Wi$#gHQiJF9igT-LNHlj>C z&BmtsbZ8dC;_T{_yjz<+6#1~&>GSm}7T>E{j9x}>yX-sQvP;vCv(KcjO>sw7 zr6}<;b)>83Iw(DIRv?L7G*d+@IZ2V2Ijc|ktmpO5#Ku&naggqq>C>717_IHb_Z+=2 zpyMu)dC9iFuqO78foh-XV^Cn1Tv`6J7O5pu4(o=@pQ6|N@zHW6rrpoI4!mm%BvgrKQR}f|tCv^Mm9}|DJZtgp5e&_Ss$1Occ zvqD4rn70!Q`Mc-_nUA_AiOzc7#keY*9yZ`FuB;bRe9}y3N-#fD_XyddmBOB+F_V(K zS9$Vi>pY=Kfx3S1CP?DJOtEQ?vq*!>)jQ4UB&wwQqQxD0q4YfcvY_YX2ClDVemQ4t zB937&;Z>UG$LRD6A|Lf=ayCq_w;dML7jHYEY8Ucd;mF;7&;}zb&H2`vL_Ol>Qc1PA zLI5@(oVIWvGOHKj%WkWts4Y<*1VLF_no&M4C0RzByhTx6-uOqGe1tG0Jf+*;!&IFn z2k*>T28dz-`-MMK0VvMO>P zA2m>Fi+X?wk#Q-DE~tb3R*-@5T!QPc+pfcZ!)O`;uRiU}#TYu&GIg(gJrg_onjgEl zkC_iqJV(KNj)<}|J&(d>)ufZ!Wbq{!{M@iqr~4EpQlDt|>ND+}C<}I-<-9hMt|2Gj zrDky&3JT)QlY&LUIU*$FpCSe_i`FJ$=_Grc=__BQGK?|vJhiv#$w^o)P=WmSD-+o| zr?hU(<8-aelkjVZD_91wlHj9Y#NBrIY{cn^rw7<1qKj<@B+%S(2#5hi(DQ&lC^q5) z`FnYO?Xw*$R--t!2P-`d62Q;&cLlV( z(0b$0k!vi2B&ALp)Sh!pWV@lVnA6w)x*YYqO>_s7>iU#)$(k^FSxdw& zzhp49uqjc>!=2Jm>SS*2#`?#s@v;G$<$m`cq}XcZAI2iFzdQ*aw(RFUDAPt0OPAl! zor;EnSfUXpGW4fUw^Q?l9Q?ex&&MnsLGvm;!-wh)f=mltI>zFyD~*EH_l0A9mio+x zH`ayYD7zz!3UVBlJGIo^8slVqsusK_r2+MEBt!~)VPIn7tQ1?WT>g8}Y1I%0)zai+ zoka#?&!3!}Cp=A|46g*>p!x_Ugg1o3A=*U%pCjFFXCjX^MxEo&DlF{OKgh-}aqpAw zLcAtYK_04hzd@Ai$y;dE6@{EAcW^QzygM(A1ONTg)!fVe)flhEHih90=dX>%MCY>& zJ|Yc1SMOBX8J-unLWDG`GY3nx{`~PJ;i9UZ_w?hZqKWn3@COP3jLBsupI-^+>?<&@ z+!`)04|bJ#S~AbV(;PG_T}_Bzi%6_9l!CIM#RfW{nO(UFCNkw zm7^7Q!NQBeB`{TKt>WV*W8$#e1lyc9D`r*@TXyqhqQYa_)y1inR#ED^Ldy;YYep%= zaDFtpgj`(uRn>^ zOqCZmJukqk#A`q6k^5!|xs{ZN4h{eUxzbfiHS_MNx9Wt5yUpJnP5ki@W#4Q{Qi;Cs zCZ=0<4Dh}jA%6X0XQgL#l9qb3mu7KvybpLWtK~`|The9nNhfnBOGREAw$2DBE09LL zv)7jA)ZORORboafmkD+NW|qQ2H!_^hS^}!B=G>{MTkT!x8g20o z)X@Mz_b>j7)Py=fJEqdr_8^{dG-T^jP?-DH#&W`%ZC`$^#|zr5@>cRiC5cheHQ+*~ zW&Ym-V*WP({(la|`CkU(g0@Tdrn;xcRl$zGif_lO9Vl684Wgp~@h|%0W)iNmHiUqH zGp*oZZnq>##obh9cY=uHv{{{De@y7E-@?{KRLx_Kh<6+}w6)FB)RXLhJz;gD-GB5` zMGkNk*YaEXi>wp2&P{9mv|`(y8Ak*(@T-*TiDMV&b(-joyF%^M z8qa%w5(o!BHZ(6Cns=6g1ny|SP3qC3r?%yp0c~48`Ku;kd-Sa;HqP(|$=1IrCJLqFOEsL1)J{#rG}9RP+*uU8Xi`eQ&b zA3oFQt8gn=`Tp)81-H0GCWQM0a{T%@pBp<@wU$Grkv`=H9y=?7@0w8a(#$~ROqsw} zU`blerszQ?)I+He&6xI81_rKEp5Gt9b=ptM;Zh2lA)R65AmC`x znIDzH^L@6wDXn`xoQ1T`;SNQ>pn82iVCD0ZQ%w-5$6g4->ZemMyBK-Ap0RLjC>!?l zojI!_4JWIK#6^2=u9z=?Z;ihtWtd)cMJgn_-7ktKn1MZKyd36d!{ zmXm2POCzgih+dIZ#PV~4D6El@-G=z-7&&yqhR^BQE0FS-)e@M7%a9G3(wAYnx)?~n zBh*6)5co_(Gsa=d*iTqF^87{6;(L3amGgt3;KO3flwVK-&afHamdc)MnBul2godz& z5;>lMG=_Y{LZ6SBGOnF{VsF?CnQTJObxd^NDVbpd*CD(S)cN*^r7HI17$%&#rI%B_ z0kjf~$-#6zVITz_z4&&}bD{asBPCE}m2|a)ib+3Bu==yd#B6RBop}q#rlKG6Vq0al zJd1LVPv1G|`TZ*39(MrHn^buyi?K~DjbHC6Y2+Nxq5S%o8=ETsROsE4gC(1d6$0jf z|M=_dW)uLyuD-a+NZ#5Q*%AfzuW(bjB1b`|k#6rXP&2P?cKBc&;&4VQq+$posgVS@ zzZ`H-$}HMtI9w|M7`%rlur> zf*Gw&!7ol~Zd0>9J7gD;R1#rRefQf8SM;eQNhdsWKf+c?qv65G!%l;gj#_CViBF!D zB?7Sr%q^j&n?6~L8!JnTBQDL2%C>_C;f`q=e&iP8b(@sK{F9&OX{_%5XU4K4!9Zww}1j3%l}} z;@9BR-o<<#Sh}JqFFAbN?$w(zHL`A*GudgnVg@D!-(iG=CoK8xL!-#@)+VRu56Lam+8n1+!8^ky7j$30EpbnGF) zzU!69oeJ>iZT3I|9C^LG(S35C>DCa~wsE zV@eAPtuh`IVE~8=T<3;sy7#g7AOZvWg6#akHKhG+92n$$ce>Bkra|&izeAu42q_yO zup)r%|10Q(_-M8|C`1#4NCtgDUjr}`U4$ZN=Nv&R4Fn6k%*N~H-FXZQiK0y@Dn&MA zXXYgC$3lyw;1>hWAGKXB$)b-rm{hs3OYxT--p2Iapu9cif#|O+lVSKx6GbFuM*~0} zGXk~dzkR(9xVsr35-nvG9z(#u-{GS>1c;Od8gRV_5S1k_lnr9O)IH6bk+t57=8e@L zW-9EO2Do#$EbydM|4QsZS!ZMsCNiXqoHK{431)<<#dhWFlD=yp1TIGMv>PS6BsAw? z#aO}c8hqF0Gcmm7(y?@9X0;@@^m~CwD+Z}R`;kTM0v7oUCDsu}- zjGdq%Kxg1VcQ`c&8-A$MmV-65zjVe`|FU^wMy zGBZ9EFP$x;WWw&1#L(044$2TQrbh`lswZT7W=KZq-jpEObKc<9g}lc!etXe-Gp>Qc zjPb7UVzacf9b0;xdaj#)vjyP(@873zhysB;f%}m>x$|Xn+$HsXx3qoRHxs&0cijFm zP2&*tsJJ6h{Qmb_e{YDSK^vz<6gr6J1t;^(fh!WxxPNi-E71-ZqUhlAErFD7BP~cw0j`I{xAv zfanP`jK5^gM9#`7YhYwyp_6AhzX_o1vX$h=*k4l`7l6K+CzsaES+Xt0CV9-3g41GG zV&q9~0PTza!5JfGoKy&0MgM`qG!0_P9`tk%4u^}@N>_8EB%eu-&!ejWO7QL!RIV+W zJXPe#C%)ff_o-6{M|;Mwh0!p^CSK?0{_ zlZ{IGmjf6?PXnhR1Q5wmqzp)IV!t%%2VkYYjc}HO3Ox)G9j9J3P6SG^8~yv#YDvA<%@|8_@llY{jK|B=`zFBUl9 z@lLYVup@LrSThS4ME5G~fI{H!m0uCU1!z(~Tpk(&@}kRTs7y33VyEA}f60W2$Mzi5 zcFU0nN;XlwqbA_r#&-4?``Eh74bSkG06@E)F=jK$8vJYTSr|+C1=Tn)@kWCJv!_7o zS>D;V>(DvaAju}66RL?L!A*f&x`k5e;m&cL_x$;?L?t1w1i0NA=DqA{h?LD+ z;vMQz_p?cKet=-ybV|SY#l_~Wp9)S8@WnrzA`o6Q?hbqY?um!w9RhBaK_O%nYD^@K z&G9=yE19m(BZN;5G-T1D@Q$66C4 z#L@ND1@vJ+-D^3IMRc3qJstsyFXCT@$u=l$FBJ(auegz=EpGnT&TSdfOeDA_7QN&y z<;9jo_DAR#+rqNXG3cm_fX?yexP3QR-!M;9$n=fC-@Lu)lIdQ#Y$h&+>>Mo}J3pi}f1`aB< z$2e}N+|{Eo_KI7+Q}|xlP2?_PL`(@(ib%5{-ZoB5QF7pd<}qcj&6bj3tJz%MtNkA` zWi3DbFpV-a6M&v6C+jX--a}*WdVmExvAaZ0!P}@GGAJL{{f(mMNY-Ml9qwN zw{N}^&2i>>CDs#CksM5hDZE&~g`A+I)>Vxaaj4R!eI|n}P;5732?9q@FY9&}()SXc5Fu#s~S86fkRt)IbL_w0HOX9WmW z4|<$Ol;H*u8dtwGSD=={nl$D?^W2Sew0PM?RY!A9x%R zpjYBjCvT~M_{ww@L!%qf&d$(SSYJLfOx98@_ui=3zE~WzMLu^xw*9;xHQm9z~%ZMX~xeCco>h6MJ%Riyt*bfRlcO=Saj44 zYU@o)1^v3s->GeRJe)ta(qoycSQ@ngRf%JUZMjQJP4s4ds(~A|t0kIw>%gVBj7Q`^ zlJwjRGzy6=51I&+tvhNtuFa@fepEBy$<_;=t@MaXq2vh9WDz>*0lz(|5JC{pWaMeS zm81ObXB2`|PjGYlt|O(7^YUby+4pcBMN@?pr*yTJ%bZ(57vef`#Mw-xp0!!wOWOPk znQtC8GqFj=$`spDi0I|nH0sOSY41A8X>)~^iovPiv$zT2X;&`er*Z9$;6%9h!-YIy z7Sz3CQxIH2>F+9yf8wJMt%`e#tHUPg922vSoVq_(sdhUbji%&0Ii=>l9}$`+QABLI zKIF`>5YhtXclZp0KAW#6vPt3@x?;*_d}e>C)%!V+R+uwd>6qS)G+Z=R88?^t=hrQz z)@@&=NrcMfYdq7mfXVD&sTuH2{@Dj)rJ;B{(f(;9PK(f4WLS2Yrq=1ORMb|fR%)si z>m~gArkL)XV}Bu%;KrU)i@zZ0^6h)%#iGo!*26-m74Y?rnDh)+L4h1?1Ltrh)7t8H z&0M_n5}6UJ6}PW%Uo9DUst-2(g&*|)N-Klz!C#{?(s&M80WEK?(GwbK)p}fvkvthn z;UMkAk2l2-O&6y+-k(7D)UF-%NKiG=DYW=(z+7i+AcFF$sSi<Gwb? z0vdOmc-2~M*38-gpma?)E&B*~xFGscDDdu1cM?aj1048espXr3ekXp9!hd?bV*z-f z`>m}|j@*X4MtsS5VIt1^M(w$xSBujf=PaMZfoyC#cpo8`__Yk<1x+F2&>lohG|u&a zCP@EmdIXa5Juv`T5;d?q$FQ7h=3ar~+;C-ft8QGO)lk33CKCH;#zvr4FlV;aKjx6S zrbV<;%Lxdt8?w}+UtYo24Fkq@ME|(2CsbA!Kfb<2e`sm$UcmQRgC1=utpBjK0^xdSPQ`?#M@6?xqsnD+#k>E zLEmW4sV9mUmN_f-pEe6KNFtf?VK*mt*8|7WG_tknx(%(>evr~54e($^&qYByD~~jk zitP&}5Yv$ub{oRe#gC$G&bA_32QF?K*%*ORCS5L+4=asnJqnpN%4_w?o=# zMxF@Wjhw-W?!%c-qjP!(p!V)S@AdPq<6Lol)pwS#uXDD)s1aJuq9IX|j5?9W-^0w7 zJs;fnL5KBP$m;q+Yl6_2^fJ<`GEMz-E|IsF1B`b#L1yWfwTv>0rT zWksup&^r$nfRwm^$W78Mw9sr1x)}D=iOZV)p3f91 zN(IpF<{JMa2^S@b@#i0X8?GEU7M;zJl4>1$cu-33h99~?YMQt+gCnD00e1^zfTt|* zA_T{H#7>RNU;!#%Q6}T9N%lim(*hczlx|8}Ca-zSRZi@8?ryu-{3tPaauUm>@LpuA z3(3?|Z^Y)D&fy@9LV=V`u#VM3@4U=R4Yq6YiE} zc#K!`5 zrrFk`Rm^5yX7O7B^z^xfSt_QeU7WfxpETyS!O zbuJE$kkgfCZ$wf*Eu zDAmyt8CNwa7pYS=sdV(3I)(ZHUixC2@9hLH(}9(=0JCE~F-E%;&}fB4_vKkzFCQni z<`tyH(7a)2)r3b17lMxqnaZkDM+(>mb z!j_Ec9+HnB@{iI5}a~S85?US(%aJKkc$?C;H7uBVxxOV&x=etNZ zBfJH<{89y6-d|8{)l60_v=q#GcA$f=&fLWk*IAAmy}b3H6#TI&f)Lu444FYXGO=M` zs;rP>(+cl)V4S)IyL@b(Ui$k1m)FG>PlgbGoqAXsn#~TU8&$fynJOBO@j#DQHqxGt zyq~EI6}?;ktguJr?-PcY<+h9qah2tseAo|-eX-_BN0KtRi>!NE5HMP83Xgy?lE#!N z7u6+ko8AkQ1#UnPwyzH`%yffId76;`eP|E9#+p{7adZL5)KTf-nu{57 zc+b{7p$P``4zi6q#68ETqM^1hW;W}6vdf=@PH3Y{5T@e77rTZdbd07>JZ{(VSS92_ zR&?AqCl6P)7&zm`NMQW<5{`VdIY#(>QXbv9u&>MOrl=4Vf+nct8bytp$Cfc(sC(8DHBrFX~Y^9a>3KF_Ww^l~tY0K-!i% z$1XV)1qpcKGb$G*KHa$rU0dR*lU444Yxh;h{hKO)2^n5XvpnZKo-iX-jC5wVtVu(M zqebujN&FIx_E579=Tq0{G<-k-{gBrEm~@PSgw=5YmatNTs=3>#W7blrPGe7A zn!_DIIP(!p-iQ5vaYX$7ofgq|^{Kik`%e2xYUIjfYH*Wzl9!o$@JU-hf4>CgAxJd5 zJ&M(Rb?>>bPTM}gidzWmZRAD0F>$d0Vst_hPi!^D?OWda_<{|Qwc^C(T%V1sm9Jsy zO;N_)me6*$QiJ`RUhqxCEv+i8!$8Alb0J9;T=*Gvz&R?%rq#3Qd{+T#kdsYsKL{lv zkIZbFKeSV{9e-8(MnzD>T8sx9Q>NGnjK4IQ~grdPYz&I#ksf#i((9__eE$&=%8!0s`sJivIrF8&3P85pWknvGxnlJtZc5$Ri2P^ zX)0G;zJc=`n)tZLIP1g*h9wN0!S}dkI+GW^ybnIty<66+=G=utI|#T<+-TgH+CdDrDda7 zX{8@L*sVdF4+i?=fagw{!^xPjQ^25{`1uDd2SB7iTKiu9zGuIjFGmDaU?_)AM~?cT z(7ao~X^g)9y$2v!Y96THV&BO~UPqW2nxxmVe{f@wyz>y<{~s1;y9Iz--5^9`Gk9(n zk`7U99GZSpF=Lw20XWDZn*qyC5MpvIwjW8n>9l=I54cpKZy{ao{QL3z&<1xA3HB)| z!j50->wyeZ3u#F8WF|j3<=yKHT{z+}xG*6}%0nz~36)ZJ?!wNg$%g9(rS9_Y!;1$? zuUdRXd|}B$5~h~#6xs?}wa5F+lSCo(x+w#04Q~zd3JecjyMq}m*qNb;bc`b%(eq=C z*{08P>V{U(Y)_-wlNibOYYmCGl)({I>C_ojN=lFFZhvXdooAlu6HofA|M;_4v$NJ> zLOz6`6OV4#T3-n&E_%F=MPh*N^x4(#dje(Qf!o39Rcu-zO`xz~#rHo;7DyPhAd-eq z2uytOxr=*G>#-~sFm6r+O-bv6FO-;-_l!9;X ztuSqjJbdlWZus~vA9j|`W%|kGJwd~l2)M-*0qok>Iwm<)nPmU#oW1||w z%e9)2GJSeoF@&HNjW+XwM0xL;650M}$YI05-{MDW(q^qgQ@@ z3En4x@a7BsGLSW1!|eZj1S$3D=&JKCUCh1c-339v#vyO7VsYr^cs?e#B?1vVeYvA02YxwjtQl zpHj%5Co4fWp&U#`y&O~k^?ioh-jrd` zO1W=b7$Xmbt|5ZHO$c9y1b;j|$=h+$$ZwF!Ut@tP+azKhv!r3zfS5>DliPiSHtq<6 zJ#v9B(MrzFq@20vc_suhyx+&n6A`?sA&VnUzZIc>)ER}$S;UX^frqVo^HuuBX?Tbh z((I}^n2^2a;y6fq&daP$o}oOsYZy>`oa^h^vsJ$btj27T<|227x`~7pBWkfE#E*6N zp-K-7Zu+HMjR_r8wfs zHvZ8k116p!1=DG0H!GS&jRtM`Jh~PPE$a^~2skrH9N;Zs^y0~$C<{sCMa07D?$d4C zA~X%bu9JN4o?P}y#h9i++w1a6X?q`c+gWSQM{=j69~|cHK`RCGJrXLi>C2ah;#7{* zAPRwY1CM{9F-q`KtMr;pWiyyd#g_V>Uvm;tFg&Y-F>-pMQa`)mJsfSK_o^iU=i3RB zH!pd2mt@#biXtN;8Ge}xqiKj9M7|?iLB4+|NH)MzLM>wZcNU&yDP^xy6cgu~c?eIJ zYHMpBJv;gqB#+i5E*h-xYW2VA9s~AyXeE}wVLHLgme!yQLb7| z;z_SXO<`cak#;~z%V`$mA>&kcb{vZ#bInq2Kv^WTYH$tP{9?F0xAZdU$m`!(*%>dq0`vC=Ih>qVdaMbDS zGXo{9d|KYKtw@17;f*|JKUt3S460166vZQNAXt&twPdIWV*z}u z!xD2Um-L{^FS#Wda~fcYCn^pO4(GS~*WvDD6Rw6_V`qv3)+G{XZB!@IzfA)D7ATa< g|D8WDY1*O*x{<&r{Df)^9S|r*w3=MbwOfDw56E*ABLDyZ literal 0 HcmV?d00001 diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 057785c..332852b 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -64,8 +64,8 @@ def PLCGetTag(addr): return context[0x0].getValues(3, addr, count=1)[0] # Display settings -SCREEN_WIDTH = 640 -SCREEN_HEIGHT = 550 +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 FPS=50.0 # Port the world will listen on @@ -90,6 +90,7 @@ def PLCGetTag(addr): separator_collision = 0x8 sep_vessel_collision = 0x7 oil_spill_collision = 0x9 +outlet_valve_collision = 0x6 def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" @@ -138,13 +139,22 @@ def separator_vessel_release(space): # Add the tank level sensor def tank_level_sensor(space): body = pymunk.Body() - body.position = (125, 400) + body.position = (115, 535) radius = 3 shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = tank_level_collision # tank_level space.add(shape) return shape +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 0) @@ -170,54 +180,56 @@ def add_oil_unit(space): body = pymunk.Body() body.position = (300,300) - #feed pump - l1 = pymunk.Segment(body, (-100, 270), (-100, 145), 5) - l2 = pymunk.Segment(body, (-135, 270), (-135, 145), 5) - #oil storage unit - l7 = pymunk.Segment(body, (-185, 130), (-185, 20), 5) - l8 = pymunk.Segment(body, (-65, 130), (-65, 20), 5) - l9 = pymunk.Segment(body, (-185,20), (-115, 20), 5) - l10 = pymunk.Segment(body, (-90, 20), (-65, 20), 5) + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) #pipe to separator vessel - l11 = pymunk.Segment(body, (-115, 20), (-115, -45), 5) - l12 = pymunk.Segment(body, (-90, 20), (-90, -25), 5) - l13 = pymunk.Segment(body, (-115, -45), (-40, -45), 5) - l14 = pymunk.Segment(body, (-90, -25), (-40, -25), 5) + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) #separator vessel - l15 = pymunk.Segment(body, (-40, -45), (-40, -75), 5) - l16 = pymunk.Segment(body, (-40, -25), (-40, 5), 5) - l17 = pymunk.Segment(body, (-40, -75), (75, -75), 5) - l18 = pymunk.Segment(body, (-40, 5), (120, 5), 5) - l19 = pymunk.Segment(body, (100, -75), (120, -75), 5) - l22 = pymunk.Segment(body, (120, -75), (120, -55), 5) - l23 = pymunk.Segment(body, (120, -30), (120, 5), 5) + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + + #separator exit pipe + l24 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l25 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l26 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l27 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line #waste water pipe - l20 = pymunk.Segment(body, (75, -75), (75, -115), 5) - l21 = pymunk.Segment(body, (100, -75), (100, -115), 5) - - #separator exit pipe - l24 = pymunk.Segment(body, (120, -30), (600, -30), 5) - l25 = pymunk.Segment(body, (120, -55), (600, -55), 5) - - #waste water storage - l26 = pymunk.Segment(body, (75, -115), (20, -115), 5) - l27 = pymunk.Segment(body, (20, -115), (20, -185), 5) - l28 = pymunk.Segment(body, (20, -185), (140, -185), 5) - l29 = pymunk.Segment(body, (140, -185), (140, -170), 5) - l30 = pymunk.Segment(body, (140, -145), (140, -115), 5) - l31 = pymunk.Segment(body, (140, -115), (100, -115), 5) - l32 = pymunk.Segment(body, (140, -145), (600, -145), 5) - l33 = pymunk.Segment(body, (140, -170), (600, -170), 5) - - space.add(l1, l2, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l28 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l29 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l30 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l31 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l32 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l33 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33) # 3 - return l1,l2,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30,l31,l32,l33 + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33) def draw_polygon(screen, shape): points = shape.get_vertices() @@ -294,6 +306,7 @@ def run_world(): clock = pygame.time.Clock() running = True + # Create game space (world) and set gravity to normal space = pymunk.Space() #2 space.gravity = (0.0, -900.0) @@ -309,6 +322,7 @@ def run_world(): separator_feed = separator_vessel_feed(space) separator_feed = separator_vessel_feed(space) oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) balls = [] @@ -330,6 +344,8 @@ def run_world(): elif event.type == KEYDOWN and event.key == K_ESCAPE: running = False + bg = pygame.image.load("oil_unit.png") + screen.fill(THECOLORS["grey"]) # If the feed pump is on @@ -341,7 +357,16 @@ def run_world(): space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) - + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: + #space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + # If the separator process is turned on if PLCGetTag(PLC_SEP_VESSEL) == 1: space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) @@ -370,11 +395,11 @@ def run_world(): balls.remove(ball) draw_polygon(screen, pump) - draw_lines(screen, lines) - draw_ball(screen, tank_level, THECOLORS['black']) - draw_ball(screen, separator_vessel, THECOLORS['black']) - draw_ball(screen, separator_feed, THECOLORS['black']) - draw_line(screen, oil_spill, THECOLORS['red']) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_ball(bg, outlet, THECOLORS['black']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) @@ -388,16 +413,17 @@ def run_world(): separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) - screen.blit(title, (300, 40)) - screen.blit(name, (347, 10)) - screen.blit(instructions, (SCREEN_WIDTH-115, 10)) - screen.blit(feed_pump_label, (65, 80)) - screen.blit(oil_storage_label, (240, 190)) - screen.blit(separator_label, (270,275)) + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + #bg.blit(feed_pump_label, (65, 80)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) screen.blit(waste_water_label, (265, 490)) - screen.blit(tank_sensor, (10, 187)) + bg.blit(tank_sensor, (125, 50)) screen.blit(separator_release, (425, 315)) screen.blit(waste_sensor, (402, 375)) + screen.blit(bg, (0, 0)) space.step(1/FPS) pygame.display.flip() From f77c18960ce742c2851765e97c5a73302039f0b7 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 19:18:50 +0000 Subject: [PATCH 162/239] added outlet closed function --- plants/oil-refinery/oil_world.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 332852b..f2fd650 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -299,6 +299,11 @@ def sep_feed_on(space, arbiter, *args, **kwargs): PLCSetTag(PLC_SEP_FEED, 1) return False +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + def run_world(): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) From 225e1a0754c076398a1e0794d280618b9749d6b5 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 19:41:41 +0000 Subject: [PATCH 163/239] added separator line --- plants/oil-refinery/oil_world.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f2fd650..c97f184 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -208,28 +208,29 @@ def add_oil_unit(space): l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #separator exit pipe - l24 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line - l25 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line - l26 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line - l27 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line #waste water pipe - l28 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line - l29 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line - l30 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line - l31 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line - l32 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line - l33 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, - l26, l27, l28, l29, l30, l31, l32, l33) # 3 + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, - l31,l32,l33) + l31,l32,l33,l34) def draw_polygon(screen, shape): points = shape.get_vertices() From 7be6415a3ca0eda8a6ddcc16c53d18326375173b Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 19:49:17 +0000 Subject: [PATCH 164/239] added outlet logic to hmi --- plants/oil-refinery/oil_hmi.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 8639e8e..07be4eb 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -54,7 +54,8 @@ def resetLabels(self): self.connection_status_value.set_markup("OFFLINE") self.oil_processed_value.set_markup("" + str(self.oil_processed_amount) + " Liters") self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + " Liters") - + self.outlet_valve_value.set_markup("N/A") + def __init__(self): # Window title Gtk.Window.__init__(self, title="Oil Refinery") @@ -107,6 +108,22 @@ def __init__(self): grid.attach(level_switch_start_button, 6, elementIndex, 1, 1) grid.attach(level_switch_stop_button, 7, elementIndex, 1, 1) elementIndex += 1 + + #outlet valve + outlet_valve_label = Gtk.Label("Outlet Valve") + outlet_valve_value = Gtk.Label() + + outlet_vlave_open_button = Gtk.Button("OPEN") + outlet_valve_close_button = Gtk.Button("CLOSE") + + outlet_vlave_open_button.connect("clicked", self.setOutletValve, 1) + outlet_valve_close_button.connect("clicked", self.setOutletValve, 0) + + grid.attach(outlet_valve_label, 4, elementIndex, 1, 1) + grid.attach(outlet_valve_value, 5, elementIndex, 1, 1) + grid.attach(outlet_vlave_open_button, 6, elementIndex, 1, 1) + grid.attach(outlet_valve_close_button, 7, elementIndex, 1, 1) + elementIndex += 1 #Oil/Water Separator Vessel separator_label = Gtk.Label("Oil/Water Separator Vessel") @@ -166,6 +183,7 @@ def __init__(self): self.level_switch_value = level_switch_value self.oil_processed_value = oil_processed_value self.oil_spilled_value = oil_spilled_value + self.outlet_valve_value = outlet_valve_value # Set default label values self.resetLabels() @@ -199,6 +217,12 @@ def setSepFeed(self, widget, data=None): except: pass + def setOutletValve(self, widget, data=None): + try: + self.modbusClient.write_register(0x03, data) + except: + pass + def update_status(self): try: @@ -227,6 +251,11 @@ def update_status(self): self.level_switch_value.set_markup("ON") else: self.level_switch_value.set_markup("OFF") + + if regs[2] == 1: + self.outlet_valve_value.set_markup("OPEN") + else: + self.outlet_valve_value.set_markup("CLOSED") # If the feed pump "0x04" is set to 1, separator is currently processing if regs[3] == 1: From a19725c99cc5339d584f7a54aa0309e519260c3a Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 20:00:31 +0000 Subject: [PATCH 165/239] world update --- plants/oil-refinery/oil_world.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index c97f184..c40d503 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -104,7 +104,7 @@ def add_ball(space): body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 body._bodycontents.h_limit = 1 - x = random.randint(180, 181) + x = random.randint(59, 60) body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) shape.collision_type = ball_collision #liquid @@ -259,7 +259,7 @@ def draw_lines(screen, lines): pv2 = body.position + line.b.rotated(body.angle) p1 = to_pygame(pv1) # 2 p2 = to_pygame(pv2) - pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) # Default collision function for objects # Returning true makes the two objects collide normally just like "walls/pipes" @@ -271,7 +271,7 @@ def level_reached(space, arbiter, *args, **kwargs): log.debug("Level reached") PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump - PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 return False def oil_spilled(space, arbiter, *args, **kwargs): @@ -300,6 +300,11 @@ def sep_feed_on(space, arbiter, *args, **kwargs): PLCSetTag(PLC_SEP_FEED, 1) return False +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + def outlet_valve_closed(space, arbiter, *args, **kwargs): log.debug("Outlet valve close") PLCSetTag(PLC_OUTLET_VALVE, 0) @@ -394,7 +399,7 @@ def run_world(): if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: balls_to_remove.append(ball) - draw_ball(screen, ball) + draw_ball(bg, ball) for ball in balls_to_remove: space.remove(ball, ball.body) From 80140d9348984b3b704ff9869e4cd8609c1f4dcc Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 20:16:14 +0000 Subject: [PATCH 166/239] added pump --- plants/oil-refinery/oil_world.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index c40d503..a467606 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -104,7 +104,7 @@ def add_ball(space): body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 body._bodycontents.h_limit = 1 - x = random.randint(59, 60) + x = random.randint(62, 63) body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) shape.collision_type = ball_collision #liquid @@ -169,7 +169,7 @@ def oil_spill_sensor(space): # Add the feed pump to the space def add_pump(space): body = pymunk.Body() - body.position = (179, 585) + body.position = (70, 585) shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) space.add(shape) return shape @@ -232,12 +232,12 @@ def add_oil_unit(space): l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, l31,l32,l33,l34) -def draw_polygon(screen, shape): +def draw_polygon(bg, shape): points = shape.get_vertices() fpoints = [] for p in points: fpoints.append(to_pygame(p)) - pygame.draw.polygon(screen, THECOLORS['black'], fpoints) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) # Draw a single line to the screen def draw_line(screen, line, color = None): @@ -405,7 +405,7 @@ def run_world(): space.remove(ball, ball.body) balls.remove(ball) - draw_polygon(screen, pump) + draw_polygon(bg, pump) draw_lines(bg, lines) draw_ball(bg, tank_level, THECOLORS['black']) draw_ball(bg, separator_vessel, THECOLORS['black']) From ae5440488ffae64002835b0dd86061cc791d3b0e Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 20:47:30 +0000 Subject: [PATCH 167/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index a467606..b2de392 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -104,7 +104,7 @@ def add_ball(space): body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 body._bodycontents.h_limit = 1 - x = random.randint(62, 63) + x = random.randint(69, 70) body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) shape.collision_type = ball_collision #liquid @@ -149,8 +149,11 @@ def tank_level_sensor(space): def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) + # Check these coords and adjust + a = (0, 0) + b = (50, 0) radius = 4 - shape = pymunk.Circle(body, radius, (0, 0)) + shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision space.add(shape) return shape @@ -208,7 +211,7 @@ def add_oil_unit(space): l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line - l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line #separator exit pipe l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line @@ -410,7 +413,7 @@ def run_world(): draw_ball(bg, tank_level, THECOLORS['black']) draw_ball(bg, separator_vessel, THECOLORS['black']) draw_ball(bg, separator_feed, THECOLORS['black']) - draw_ball(bg, outlet, THECOLORS['black']) + draw_line(bg, outlet) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From ffba0ed069de2f00a99518caae79c2189dfd0447 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 20:48:30 +0000 Subject: [PATCH 168/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b2de392..8a83cdb 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -150,8 +150,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (0, 0) - b = (50, 0) + a = (-10, 0) + b = (10, 0) radius = 4 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision @@ -426,6 +426,7 @@ def run_world(): tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) bg.blit(title, (300, 40)) bg.blit(name, (347, 10)) @@ -435,6 +436,7 @@ def run_world(): bg.blit(separator_label, (385,275)) screen.blit(waste_water_label, (265, 490)) bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (170, )) screen.blit(separator_release, (425, 315)) screen.blit(waste_sensor, (402, 375)) screen.blit(bg, (0, 0)) From ac87679222f780c481b8f0e85b136443b9fc7716 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 20:51:41 +0000 Subject: [PATCH 169/239] outlet label --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 8a83cdb..5f2ad21 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -436,7 +436,7 @@ def run_world(): bg.blit(separator_label, (385,275)) screen.blit(waste_water_label, (265, 490)) bg.blit(tank_sensor, (125, 50)) - bg.blit(outlet_sensor, (170, )) + bg.blit(outlet_sensor, (115, 150)) screen.blit(separator_release, (425, 315)) screen.blit(waste_sensor, (402, 375)) screen.blit(bg, (0, 0)) From 7816eccffccaeab635e7c632d8cbf57b6de69e3c Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 20:53:55 +0000 Subject: [PATCH 170/239] outlet label --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5f2ad21..ceea9e1 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -436,7 +436,7 @@ def run_world(): bg.blit(separator_label, (385,275)) screen.blit(waste_water_label, (265, 490)) bg.blit(tank_sensor, (125, 50)) - bg.blit(outlet_sensor, (115, 150)) + bg.blit(outlet_sensor, (125, 160)) screen.blit(separator_release, (425, 315)) screen.blit(waste_sensor, (402, 375)) screen.blit(bg, (0, 0)) From 4ce0049fb8f13d09fa18af81f264439406b0a7dd Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:02:52 +0000 Subject: [PATCH 171/239] labels --- plants/oil-refinery/oil_world.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ceea9e1..6bca654 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -436,9 +436,9 @@ def run_world(): bg.blit(separator_label, (385,275)) screen.blit(waste_water_label, (265, 490)) bg.blit(tank_sensor, (125, 50)) - bg.blit(outlet_sensor, (125, 160)) - screen.blit(separator_release, (425, 315)) - screen.blit(waste_sensor, (402, 375)) + bg.blit(outlet_sensor, (125, 185)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) screen.blit(bg, (0, 0)) space.step(1/FPS) From 319bc334156c6ea7d3348273c301ee7fb1e85616 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:13:14 +0000 Subject: [PATCH 172/239] labels --- plants/oil-refinery/.~c9_invoke_O3CHfv.py | 476 ++++++++++++++++++++++ plants/oil-refinery/oil_world.py | 4 +- 2 files changed, 478 insertions(+), 2 deletions(-) create mode 100644 plants/oil-refinery/.~c9_invoke_O3CHfv.py diff --git a/plants/oil-refinery/.~c9_invoke_O3CHfv.py b/plants/oil-refinery/.~c9_invoke_O3CHfv.py new file mode 100644 index 0000000..69c3bd5 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_O3CHfv.py @@ -0,0 +1,476 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Helper function to set PLC values +def PLCSetTag(addr, value): + context[0x0].setValues(3, addr, [value]) + +# Helper function that returns PLC values +def PLCGetTag(addr): + return context[0x0].getValues(3, addr, count=1)[0] + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +separator_collision = 0x8 +sep_vessel_collision = 0x7 +oil_spill_collision = 0x9 +outlet_valve_collision = 0x6 + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-10, 0) + b = (10, 0) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: + #space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 6bca654..69c3bd5 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -431,12 +431,12 @@ def run_world(): bg.blit(title, (300, 40)) bg.blit(name, (347, 10)) bg.blit(instructions, (SCREEN_WIDTH-115, 0)) - #bg.blit(feed_pump_label, (65, 80)) + bg.blit(feed_pump_label, (80, 0)) bg.blit(oil_storage_label, (125, 100)) bg.blit(separator_label, (385,275)) screen.blit(waste_water_label, (265, 490)) bg.blit(tank_sensor, (125, 50)) - bg.blit(outlet_sensor, (125, 185)) + bg.blit(outlet_sensor, (90, 195)) bg.blit(separator_release, (350, 375)) bg.blit(waste_sensor, (90, 375)) screen.blit(bg, (0, 0)) From 63f97712d37d0a7c9c59a9bb94b5386dfb3c953f Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:49:17 +0000 Subject: [PATCH 173/239] Converting sensors into lines --- plants/oil-refinery/.~c9_invoke_O3CHfv.py | 476 ---------------------- plants/oil-refinery/oil_world.py | 4 +- 2 files changed, 2 insertions(+), 478 deletions(-) delete mode 100644 plants/oil-refinery/.~c9_invoke_O3CHfv.py diff --git a/plants/oil-refinery/.~c9_invoke_O3CHfv.py b/plants/oil-refinery/.~c9_invoke_O3CHfv.py deleted file mode 100644 index 69c3bd5..0000000 --- a/plants/oil-refinery/.~c9_invoke_O3CHfv.py +++ /dev/null @@ -1,476 +0,0 @@ -#!/usr/bin/env python -import logging - -# - Multithreading -from twisted.internet import reactor - -# - Modbus -from pymodbus.server.async import StartTcpServer -from pymodbus.device import ModbusDeviceIdentification -from pymodbus.datastore import ModbusSequentialDataBlock -from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext -from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer - -# - World Simulator -import sys, random -import pygame -from pygame.locals import * -from pygame.color import * -import pymunk - -import socket - -import argparse -import os -import sys -import time - -# Override Argument parser to throw error and generate help message -# if undefined args are passed -class MyParser(argparse.ArgumentParser): - def error(self, message): - sys.stderr.write('error: %s\n' % message) - self.print_help() - sys.exit(2) - -# Create argparser object to add command line args and help option -parser = MyParser( - description = 'This Python script starts the SCADA/ICS World Server', - epilog = '', - add_help = True) - -# Add a "-i" argument to receive a filename -parser.add_argument("-t", action = "store", dest="server_addr", - help = "Modbus server IP address to listen on") - -# Print help if no args are supplied -if len(sys.argv)==1: - parser.print_help() - sys.exit(1) - -# Split and process arguments into "args" -args = parser.parse_args() - -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.INFO) - -# Helper function to set PLC values -def PLCSetTag(addr, value): - context[0x0].setValues(3, addr, [value]) - -# Helper function that returns PLC values -def PLCGetTag(addr): - return context[0x0].getValues(3, addr, count=1)[0] - -# Display settings -SCREEN_WIDTH = 580 -SCREEN_HEIGHT = 460 -FPS=50.0 - -# Port the world will listen on -MODBUS_SERVER_PORT=5020 - -# Amount of oil spilled/processed -oil_spilled_amount = 0 -oil_processed_amount = 0 - -# PLC Register values for various control functions -PLC_FEED_PUMP = 0x01 -PLC_TANK_LEVEL = 0x02 -PLC_OUTLET_VALVE = 0x03 -PLC_SEP_VESSEL = 0x04 -PLC_SEP_FEED = 0x05 -PLC_OIL_SPILL = 0x06 -PLC_OIL_PROCESSED = 0x07 - -# Collision types -tank_level_collision = 0x4 -ball_collision = 0x5 -separator_collision = 0x8 -sep_vessel_collision = 0x7 -oil_spill_collision = 0x9 -outlet_valve_collision = 0x6 - -def to_pygame(p): - """Small hack to convert pymunk to pygame coordinates""" - return int(p.x), int(-p.y+600) - -# Add "oil" to the world space -def add_ball(space): - mass = 0.01 - radius = 3 - inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) - body = pymunk.Body(mass, inertia) - body._bodycontents.v_limit = 120 - body._bodycontents.h_limit = 1 - x = random.randint(69, 70) - body.position = x, 565 - shape = pymunk.Circle(body, radius, (0,0)) - shape.collision_type = ball_collision #liquid - space.add(body, shape) - return shape - -# Add a ball to the space -def draw_ball(screen, ball, color=THECOLORS['brown']): - p = int(ball.body.position.x), 600-int(ball.body.position.y) - pygame.draw.circle(screen, color, p, int(ball.radius), 2) - -# Add the separator vessel feed -def separator_vessel_feed(space): - body = pymunk.Body() - body.position = (420, 257) - radius = 4 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = separator_collision # Collision value for separator - space.add(shape) - return shape - -# Add the separator vessel release -def separator_vessel_release(space): - body = pymunk.Body() - body.position = (387, 225) - radius = 4 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = sep_vessel_collision - space.add(shape) - return shape - -# Add the tank level sensor -def tank_level_sensor(space): - body = pymunk.Body() - body.position = (115, 535) - radius = 3 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = tank_level_collision # tank_level - space.add(shape) - return shape - -def outlet_valve_sensor(space): - body = pymunk.Body() - body.position = (70, 410) - # Check these coords and adjust - a = (-10, 0) - b = (10, 0) - radius = 4 - shape = pymunk.Segment(body, a, b, radius) - shape.collision_type = outlet_valve_collision - space.add(shape) - return shape - -def oil_spill_sensor(space): - body = pymunk.Body() - body.position = (0, 0) - radius = 7 - a = (0, 75) - b = (SCREEN_WIDTH, 75) - shape = pymunk.Segment(body, a, b, radius) - shape.collision_type = oil_spill_collision # oil spill sensor - space.add(shape) - return shape - -# Add the feed pump to the space -def add_pump(space): - body = pymunk.Body() - body.position = (70, 585) - shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) - space.add(shape) - return shape - -# Draw the various "pipes" that the oil flows through -# TODO: Get rid of magic numbers and add constants + offsets -def add_oil_unit(space): - body = pymunk.Body() - body.position = (300,300) - - #oil storage unit - l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line - l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) - l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line - l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) - - #pipe to separator vessel - l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line - l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line - l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) - l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line - l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line - l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) - - #separator vessel - l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line - l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line - l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) - l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line - l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) - l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line - l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line - l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line - l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line - l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line - l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line - l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line - l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line - - #separator exit pipe - l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line - l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line - l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line - l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line - - #waste water pipe - l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line - l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line - l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line - l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line - l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line - l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line - - space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, - l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, - l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 - - return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, - l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, - l31,l32,l33,l34) - -def draw_polygon(bg, shape): - points = shape.get_vertices() - fpoints = [] - for p in points: - fpoints.append(to_pygame(p)) - pygame.draw.polygon(bg, THECOLORS['black'], fpoints) - -# Draw a single line to the screen -def draw_line(screen, line, color = None): - body = line.body - pv1 = body.position + line.a.rotated(body.angle) # 1 - pv2 = body.position + line.b.rotated(body.angle) - p1 = to_pygame(pv1) # 2 - p2 = to_pygame(pv2) - if color is None: - pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) - else: - pygame.draw.lines(screen, color, False, [p1,p2]) - -# Draw lines from an iterable list -def draw_lines(screen, lines): - for line in lines: - body = line.body - pv1 = body.position + line.a.rotated(body.angle) # 1 - pv2 = body.position + line.b.rotated(body.angle) - p1 = to_pygame(pv1) # 2 - p2 = to_pygame(pv2) - pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) - -# Default collision function for objects -# Returning true makes the two objects collide normally just like "walls/pipes" -def no_collision(space, arbiter, *args, **kwargs): - return True - -# Called when level sensor in tank is hit -def level_reached(space, arbiter, *args, **kwargs): - log.debug("Level reached") - PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full - PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump -# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 - return False - -def oil_spilled(space, arbiter, *args, **kwargs): - global oil_spilled_amount - global oil_processed_amount - log.debug("Oil Spilled") - oil_spilled_amount = oil_spilled_amount + 1 - PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil - PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump - return False - -# This fires when the separator level is hit -def sep_on(space, arbiter, *args, **kwargs): - log.debug("Begin separation") - PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing - return False - -# This fires when the separator is not processing -def sep_off(space, arbiter, *args, **kwargs): - log.debug("Begin separation") - PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing - return False - -def sep_feed_on(space, arbiter, *args, **kwargs): - log.debug("Outlet Feed") - PLCSetTag(PLC_SEP_FEED, 1) - return False - -def outlet_valve_open(space, arbiter, *args, **kwargs): - log.debug("Outlet valve open") - PLCSetTag(PLC_OUTLET_VALVE, 1) - return False - -def outlet_valve_closed(space, arbiter, *args, **kwargs): - log.debug("Outlet valve close") - PLCSetTag(PLC_OUTLET_VALVE, 0) - return False - -def run_world(): - pygame.init() - screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) - pygame.display.set_caption("Crude Oil Pretreatment Unit") - clock = pygame.time.Clock() - running = True - - - # Create game space (world) and set gravity to normal - space = pymunk.Space() #2 - space.gravity = (0.0, -900.0) - - # When oil collides with tank_level, call level_reached - space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) - space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) - - pump = add_pump(space) - lines = add_oil_unit(space) - tank_level = tank_level_sensor(space) - separator_vessel = separator_vessel_release(space) - separator_feed = separator_vessel_feed(space) - separator_feed = separator_vessel_feed(space) - oil_spill = oil_spill_sensor(space) - outlet = outlet_valve_sensor(space) - - - balls = [] - - ticks_to_next_ball = 1 - - # Set font settings - fontBig = pygame.font.SysFont(None, 40) - fontMedium = pygame.font.SysFont(None, 26) - fontSmall = pygame.font.SysFont(None, 18) - - while running: - # Advance the game clock - clock.tick(FPS) - - for event in pygame.event.get(): - if event.type == QUIT: - running = False - elif event.type == KEYDOWN and event.key == K_ESCAPE: - running = False - - bg = pygame.image.load("oil_unit.png") - - screen.fill(THECOLORS["grey"]) - - # If the feed pump is on - if PLCGetTag(PLC_FEED_PUMP) == 1: - # Draw the valve if the pump is on - # If the oil reaches the level sensor at the top of the tank - if (PLCGetTag(PLC_TANK_LEVEL) == 1): - PLCSetTag(PLC_FEED_PUMP, 0) - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) - space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) - - else: - space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) - - if PLCGetTag(PLC_OUTLET_VALVE) == 1: - #space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) - space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - - else: - space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) - - # If the separator process is turned on - if PLCGetTag(PLC_SEP_VESSEL) == 1: - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) - space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) - else: - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) - space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) - - - ticks_to_next_ball -= 1 - - if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: - ticks_to_next_ball = 1 - ball_shape = add_ball(space) - balls.append(ball_shape) - - balls_to_remove = [] - for ball in balls: - if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: - balls_to_remove.append(ball) - - draw_ball(bg, ball) - - for ball in balls_to_remove: - space.remove(ball, ball.body) - balls.remove(ball) - - draw_polygon(bg, pump) - draw_lines(bg, lines) - draw_ball(bg, tank_level, THECOLORS['black']) - draw_ball(bg, separator_vessel, THECOLORS['black']) - draw_ball(bg, separator_feed, THECOLORS['black']) - draw_line(bg, outlet) - - #draw_ball(screen, separator_feed, THECOLORS['red']) - title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) - name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) - instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) - feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) - oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) - separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) - waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) - tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) - separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) - waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) - outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) - - bg.blit(title, (300, 40)) - bg.blit(name, (347, 10)) - bg.blit(instructions, (SCREEN_WIDTH-115, 0)) - bg.blit(feed_pump_label, (80, 0)) - bg.blit(oil_storage_label, (125, 100)) - bg.blit(separator_label, (385,275)) - screen.blit(waste_water_label, (265, 490)) - bg.blit(tank_sensor, (125, 50)) - bg.blit(outlet_sensor, (90, 195)) - bg.blit(separator_release, (350, 375)) - bg.blit(waste_sensor, (90, 375)) - screen.blit(bg, (0, 0)) - - space.step(1/FPS) - pygame.display.flip() - - if reactor.running: - reactor.callFromThread(reactor.stop) - -store = ModbusSlaveContext( - di = ModbusSequentialDataBlock(0, [0]*100), - co = ModbusSequentialDataBlock(0, [0]*100), - hr = ModbusSequentialDataBlock(0, [0]*100), - ir = ModbusSequentialDataBlock(0, [0]*100)) - -context = ModbusServerContext(slaves=store, single=True) - -# Modbus PLC server information -identity = ModbusDeviceIdentification() -identity.VendorName = 'Simmons Oil Refining Platform' -identity.ProductCode = 'SORP' -identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' -identity.ProductName = 'SORP 3850' -identity.ModelName = 'Simmons ORP 3850' -identity.MajorMinorRevision = '2.09.01' - -def startModbusServer(): - # Run a modbus server on specified address and modbus port (5020) - StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) - -def main(): - reactor.callInThread(run_world) - startModbusServer() - -if __name__ == '__main__': - sys.exit(main()) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 69c3bd5..270d7f0 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -150,8 +150,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (-10, 0) - b = (10, 0) + a = (-12, -10) + b = (12, -10) radius = 4 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision From 1fdbd20d161e40e2a795ce0c52e321527e7a40fd Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:50:40 +0000 Subject: [PATCH 174/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 270d7f0..51d37b5 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -150,8 +150,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (-12, -10) - b = (12, -10) + a = (-12, 10) + b = (12, 10) radius = 4 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision From 8df8606ecbaf70d252853535231e45afffe8e9f6 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:51:22 +0000 Subject: [PATCH 175/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 51d37b5..1476344 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -150,8 +150,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (-12, 10) - b = (12, 10) + a = (-14, 10) + b = (14, 10) radius = 4 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision From 5cd2e9246703a61481fe5d65aafefb0c648701b8 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:51:39 +0000 Subject: [PATCH 176/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 1476344..e2c383c 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -150,8 +150,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (-14, 10) - b = (14, 10) + a = (-20, 10) + b = (20, 10) radius = 4 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision From 48675d19de3ca7874a508aa104f7d6630607cf6c Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:55:01 +0000 Subject: [PATCH 177/239] Converting sensors into lines --- plants/oil-refinery/oil_hmi.py | 4 ++-- plants/oil-refinery/oil_world.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 07be4eb..0d56fee 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -116,8 +116,8 @@ def __init__(self): outlet_vlave_open_button = Gtk.Button("OPEN") outlet_valve_close_button = Gtk.Button("CLOSE") - outlet_vlave_open_button.connect("clicked", self.setOutletValve, 1) - outlet_valve_close_button.connect("clicked", self.setOutletValve, 0) + outlet_vlave_open_button.connect("clicked", self.setOutletValve, 0) + outlet_valve_close_button.connect("clicked", self.setOutletValve, 1) grid.attach(outlet_valve_label, 4, elementIndex, 1, 1) grid.attach(outlet_valve_value, 5, elementIndex, 1, 1) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e2c383c..5bcffc9 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -87,10 +87,11 @@ def PLCGetTag(addr): # Collision types tank_level_collision = 0x4 ball_collision = 0x5 -separator_collision = 0x8 +outlet_valve_collision = 0x6 sep_vessel_collision = 0x7 +separator_collision = 0x8 oil_spill_collision = 0x9 -outlet_valve_collision = 0x6 + def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" @@ -328,6 +329,7 @@ def run_world(): # When oil collides with tank_level, call level_reached space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + pump = add_pump(space) lines = add_oil_unit(space) @@ -374,11 +376,9 @@ def run_world(): else: space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) - if PLCGetTag(PLC_OUTLET_VALVE) == 1: - #space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - - else: + elif PLCGETTAG(PLC_OUTLET_VALE) = 0: # Valve is open space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # If the separator process is turned on From 14c012bad8e61942d203dc85934ba564b7365acc Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:55:57 +0000 Subject: [PATCH 178/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5bcffc9..2bc4e83 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -378,7 +378,7 @@ def run_world(): if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - elif PLCGETTAG(PLC_OUTLET_VALE) = 0: # Valve is open + elif PLCGetTag(PLC_OUTLET_VALE) = 0: # Valve is open space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # If the separator process is turned on From d0571d7bc5a7d1a83ca9c8a9a3aef985c35b10e3 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:56:05 +0000 Subject: [PATCH 179/239] Converting sensors into lines --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 2bc4e83..5ecf819 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -378,7 +378,7 @@ def run_world(): if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - elif PLCGetTag(PLC_OUTLET_VALE) = 0: # Valve is open + elif PLCGetTag(PLC_OUTLET_VALE) == 0: # Valve is open space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # If the separator process is turned on From 921b594b6a2dc5709d7ada20d40c6a9c43bef5d5 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:56:47 +0000 Subject: [PATCH 180/239] Minor typo --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5ecf819..b2eccdd 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -378,7 +378,7 @@ def run_world(): if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - elif PLCGetTag(PLC_OUTLET_VALE) == 0: # Valve is open + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # If the separator process is turned on From 791f8827a0256f42678af7b1100823f59b74e5ca Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 21:59:05 +0000 Subject: [PATCH 181/239] Minor typo --- plants/oil-refinery/oil_hmi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 0d56fee..35ec068 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -252,7 +252,8 @@ def update_status(self): else: self.level_switch_value.set_markup("OFF") - if regs[2] == 1: + # Outlet Valve status + if regs[2] == 0: self.outlet_valve_value.set_markup("OPEN") else: self.outlet_valve_value.set_markup("CLOSED") From eccada5347298b997fd2ab4459d2891c03e0d796 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:00:52 +0000 Subject: [PATCH 182/239] Fixing screwed up logic --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b2eccdd..5cb58fd 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -306,12 +306,12 @@ def sep_feed_on(space, arbiter, *args, **kwargs): def outlet_valve_open(space, arbiter, *args, **kwargs): log.debug("Outlet valve open") - PLCSetTag(PLC_OUTLET_VALVE, 1) + PLCSetTag(PLC_OUTLET_VALVE, 0) return False def outlet_valve_closed(space, arbiter, *args, **kwargs): log.debug("Outlet valve close") - PLCSetTag(PLC_OUTLET_VALVE, 0) + PLCSetTag(PLC_OUTLET_VALVE, 1) return False def run_world(): From b84c4a2971c5defe904e1e0fcd75856aaa7aa9c0 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:03:04 +0000 Subject: [PATCH 183/239] Fixing screwed up logic --- plants/oil-refinery/oil_world.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 5cb58fd..08dffa5 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -55,14 +55,6 @@ def error(self, message): log = logging.getLogger() log.setLevel(logging.INFO) -# Helper function to set PLC values -def PLCSetTag(addr, value): - context[0x0].setValues(3, addr, [value]) - -# Helper function that returns PLC values -def PLCGetTag(addr): - return context[0x0].getValues(3, addr, count=1)[0] - # Display settings SCREEN_WIDTH = 580 SCREEN_HEIGHT = 460 @@ -92,6 +84,13 @@ def PLCGetTag(addr): separator_collision = 0x8 oil_spill_collision = 0x9 +# Helper function to set PLC values +def PLCSetTag(addr, value): + context[0x0].setValues(3, addr, [value]) + +# Helper function that returns PLC values +def PLCGetTag(addr): + return context[0x0].getValues(3, addr, count=1)[0] def to_pygame(p): """Small hack to convert pymunk to pygame coordinates""" @@ -100,7 +99,7 @@ def to_pygame(p): # Add "oil" to the world space def add_ball(space): mass = 0.01 - radius = 3 + radius = 6 inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 From 8a4e59cf010845d58490ce7e11b6c1d9d2f94e00 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:03:26 +0000 Subject: [PATCH 184/239] Fixing screwed up logic --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 08dffa5..15f8fb8 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -99,7 +99,7 @@ def to_pygame(p): # Add "oil" to the world space def add_ball(space): mass = 0.01 - radius = 6 + radius = 4 inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 From ac84e6f70c988741d68a2452ae6f3335855c3b25 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:15:34 +0000 Subject: [PATCH 185/239] Fixing screwed up logic --- plants/oil-refinery/oil_hmi.py | 2 +- plants/oil-refinery/oil_world.py | 41 +++++++++++++++++++------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 35ec068..e560be6 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -253,7 +253,7 @@ def update_status(self): self.level_switch_value.set_markup("OFF") # Outlet Valve status - if regs[2] == 0: + if regs[2] == 1: self.outlet_valve_value.set_markup("OPEN") else: self.outlet_valve_value.set_markup("CLOSED") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 15f8fb8..966fc78 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -1,4 +1,8 @@ #!/usr/bin/env python +# NOTES: +# Values of 1 = ON, OPEN +# Values of 0 = OFF, CLOSED + import logging # - Multithreading @@ -18,9 +22,12 @@ from pygame.color import * import pymunk +# Network import socket +# Argument parsing import argparse + import os import sys import time @@ -99,7 +106,7 @@ def to_pygame(p): # Add "oil" to the world space def add_ball(space): mass = 0.01 - radius = 4 + radius = 3 inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 @@ -146,18 +153,20 @@ def tank_level_sensor(space): space.add(shape) return shape +# Outlet valve that lets oil from oil tank to the pipes def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (-20, 10) - b = (20, 10) - radius = 4 + a = (12, 0) + b = (12, 10) + radius = 2 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision space.add(shape) return shape +# Sensor at the bottom of the world that detects and counts spills def oil_spill_sensor(space): body = pymunk.Body() body.position = (0, 0) @@ -169,7 +178,7 @@ def oil_spill_sensor(space): space.add(shape) return shape -# Add the feed pump to the space +# Feed pump that the oil comes out of def add_pump(space): body = pymunk.Body() body.position = (70, 585) @@ -235,6 +244,7 @@ def add_oil_unit(space): l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, l31,l32,l33,l34) +# Draw a defined polygon def draw_polygon(bg, shape): points = shape.get_vertices() fpoints = [] @@ -274,7 +284,6 @@ def level_reached(space, arbiter, *args, **kwargs): log.debug("Level reached") PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump -# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 return False def oil_spilled(space, arbiter, *args, **kwargs): @@ -305,13 +314,11 @@ def sep_feed_on(space, arbiter, *args, **kwargs): def outlet_valve_open(space, arbiter, *args, **kwargs): log.debug("Outlet valve open") - PLCSetTag(PLC_OUTLET_VALVE, 0) return False def outlet_valve_closed(space, arbiter, *args, **kwargs): log.debug("Outlet valve close") - PLCSetTag(PLC_OUTLET_VALVE, 1) - return False + return True def run_world(): pygame.init() @@ -327,9 +334,12 @@ def run_world(): # When oil collides with tank_level, call level_reached space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + # When oil touches the oil_spill marker, call oil_spilled space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + # Initial outlet valve condition is turned off + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) - + # Add the objects to the game world pump = add_pump(space) lines = add_oil_unit(space) tank_level = tank_level_sensor(space) @@ -341,7 +351,6 @@ def run_world(): balls = [] - ticks_to_next_ball = 1 # Set font settings @@ -359,6 +368,7 @@ def run_world(): elif event.type == KEYDOWN and event.key == K_ESCAPE: running = False + # Load the background picture for the pipe images bg = pygame.image.load("oil_unit.png") screen.fill(THECOLORS["grey"]) @@ -371,14 +381,11 @@ def run_world(): PLCSetTag(PLC_FEED_PUMP, 0) space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) - - else: - space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) - if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_open) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open - space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # If the separator process is turned on if PLCGetTag(PLC_SEP_VESSEL) == 1: From 285955b61e0c12c249f9001d7cd889fd146e8fbe Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:16:27 +0000 Subject: [PATCH 186/239] Fixing screwed up logic --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 966fc78..2fd4f89 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -158,8 +158,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (12, 0) - b = (12, 10) + a = (0, 0) + b = (12, 0) radius = 2 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision From 3e928734368ef0260bee09e3a1889c40b51658cd Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:17:09 +0000 Subject: [PATCH 187/239] Fixing screwed up logic --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 2fd4f89..abf8db3 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -144,7 +144,7 @@ def separator_vessel_release(space): return shape # Add the tank level sensor -def tank_level_sensor(space): +def tank_level_sensor(space): body = pymunk.Body() body.position = (115, 535) radius = 3 @@ -158,7 +158,7 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (0, 0) + a = (-12, 0) b = (12, 0) radius = 2 shape = pymunk.Segment(body, a, b, radius) From 07c76cbd34d068714f1530f8abadb93fc74456fb Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:17:54 +0000 Subject: [PATCH 188/239] Fixing screwed up logic --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index e560be6..b52fde2 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -116,8 +116,8 @@ def __init__(self): outlet_vlave_open_button = Gtk.Button("OPEN") outlet_valve_close_button = Gtk.Button("CLOSE") - outlet_vlave_open_button.connect("clicked", self.setOutletValve, 0) - outlet_valve_close_button.connect("clicked", self.setOutletValve, 1) + outlet_vlave_open_button.connect("clicked", self.setOutletValve, 1) + outlet_valve_close_button.connect("clicked", self.setOutletValve, 0) grid.attach(outlet_valve_label, 4, elementIndex, 1, 1) grid.attach(outlet_valve_value, 5, elementIndex, 1, 1) From 7662eafd94779825be76b8234c090a5c2159e235 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 22:51:34 +0000 Subject: [PATCH 189/239] changed ball oil size --- plants/oil-refinery/.~c9_invoke_8OzcXx.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_A9hZBn.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_m7IhEZ.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_oiiqP3.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_pApcQc.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_pqDEGS.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_qPHwNL.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_rOvfh7.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_vBNVon.py | 468 ++++++++++++++++++++++ plants/oil-refinery/.~c9_invoke_wY9SBa.py | 468 ++++++++++++++++++++++ plants/oil-refinery/oil_world.py | 2 +- 11 files changed, 4681 insertions(+), 1 deletion(-) create mode 100644 plants/oil-refinery/.~c9_invoke_8OzcXx.py create mode 100644 plants/oil-refinery/.~c9_invoke_A9hZBn.py create mode 100644 plants/oil-refinery/.~c9_invoke_m7IhEZ.py create mode 100644 plants/oil-refinery/.~c9_invoke_oiiqP3.py create mode 100644 plants/oil-refinery/.~c9_invoke_pApcQc.py create mode 100644 plants/oil-refinery/.~c9_invoke_pqDEGS.py create mode 100644 plants/oil-refinery/.~c9_invoke_qPHwNL.py create mode 100644 plants/oil-refinery/.~c9_invoke_rOvfh7.py create mode 100644 plants/oil-refinery/.~c9_invoke_vBNVon.py create mode 100644 plants/oil-refinery/.~c9_invoke_wY9SBa.py diff --git a/plants/oil-refinery/.~c9_invoke_8OzcXx.py b/plants/oil-refinery/.~c9_invoke_8OzcXx.py new file mode 100644 index 0000000..309231a --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_8OzcXx.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + elif PLG: + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_A9hZBn.py b/plants/oil-refinery/.~c9_invoke_A9hZBn.py new file mode 100644 index 0000000..bb4fbac --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_A9hZBn.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + a = (-10, -10) +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_m7IhEZ.py b/plants/oil-refinery/.~c9_invoke_m7IhEZ.py new file mode 100644 index 0000000..5cdcb07 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_m7IhEZ.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + a = (-10, 0) +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_oiiqP3.py b/plants/oil-refinery/.~c9_invoke_oiiqP3.py new file mode 100644 index 0000000..82f8f00 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_oiiqP3.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + elif PLCGETTAG(PLC_OUTLET_VALE) = 0: # Valve is open + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_pApcQc.py b/plants/oil-refinery/.~c9_invoke_pApcQc.py new file mode 100644 index 0000000..04bbddb --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_pApcQc.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_pqDEGS.py b/plants/oil-refinery/.~c9_invoke_pqDEGS.py new file mode 100644 index 0000000..937edd3 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_pqDEGS.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + elif PLCGtTaG(PLC_OUTLET_VALE) = 0: # Valve is open + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_qPHwNL.py b/plants/oil-refinery/.~c9_invoke_qPHwNL.py new file mode 100644 index 0000000..b501b52 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_qPHwNL.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_rOvfh7.py b/plants/oil-refinery/.~c9_invoke_rOvfh7.py new file mode 100644 index 0000000..2b2dd45 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_rOvfh7.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + space.ad + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_vBNVon.py b/plants/oil-refinery/.~c9_invoke_vBNVon.py new file mode 100644 index 0000000..684529f --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_vBNVon.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/.~c9_invoke_wY9SBa.py b/plants/oil-refinery/.~c9_invoke_wY9SBa.py new file mode 100644 index 0000000..6db5510 --- /dev/null +++ b/plants/oil-refinery/.~c9_invoke_wY9SBa.py @@ -0,0 +1,468 @@ +#!/usr/bin/env python +import logging + +# - Multithreading +from twisted.internet import reactor + +# - Modbus +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSequentialDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# - World Simulator +import sys, random +import pygame +from pygame.locals import * +from pygame.color import * +import pymunk + +import socket + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This Python script starts the SCADA/ICS World Server', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="server_addr", + help = "Modbus server IP address to listen on") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +# Display settings +SCREEN_WIDTH = 580 +SCREEN_HEIGHT = 460 +FPS=50.0 + +# Port the world will listen on +MODBUS_SERVER_PORT=5020 + +# Amount of oil spilled/processed +oil_spilled_amount = 0 +oil_processed_amount = 0 + +# PLC Register values for various control functions +PLC_FEED_PUMP = 0x01 +PLC_TANK_LEVEL = 0x02 +PLC_OUTLET_VALVE = 0x03 +PLC_SEP_VESSEL = 0x04 +PLC_SEP_FEED = 0x05 +PLC_OIL_SPILL = 0x06 +PLC_OIL_PROCESSED = 0x07 + +# Collision types +tank_level_collision = 0x4 +ball_collision = 0x5 +outlet_valve_collision = 0x6 +sep_vessel_collision = 0x7 +separator_collision = 0x8 +oil_spill_collision = 0x9 + + +def to_pygame(p): + """Small hack to convert pymunk to pygame coordinates""" + return int(p.x), int(-p.y+600) + +# Add "oil" to the world space +def add_ball(space): + mass = 0.01 + radius = 3 + inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) + body = pymunk.Body(mass, inertia) + body._bodycontents.v_limit = 120 + body._bodycontents.h_limit = 1 + x = random.randint(69, 70) + body.position = x, 565 + shape = pymunk.Circle(body, radius, (0,0)) + shape.collision_type = ball_collision #liquid + space.add(body, shape) + return shape + +# Add a ball to the space +def draw_ball(screen, ball, color=THECOLORS['brown']): + p = int(ball.body.position.x), 600-int(ball.body.position.y) + pygame.draw.circle(screen, color, p, int(ball.radius), 2) + +# Add the separator vessel feed +def separator_vessel_feed(space): + body = pymunk.Body() + body.position = (420, 257) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = separator_collision # Collision value for separator + space.add(shape) + return shape + +# Add the separator vessel release +def separator_vessel_release(space): + body = pymunk.Body() + body.position = (387, 225) + radius = 4 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = sep_vessel_collision + space.add(shape) + return shape + +# Add the tank level sensor +def tank_level_sensor(space): + body = pymunk.Body() + body.position = (115, 535) + radius = 3 + shape = pymunk.Circle(body, radius, (0, 0)) + shape.collision_type = tank_level_collision # tank_level + space.add(shape) + return shape + +def outlet_valve_sensor(space): + body = pymunk.Body() + body.position = (70, 410) + # Check these coords and adjust + a = (-20, 10) + b = (20, 10) + radius = 4 + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = outlet_valve_collision + space.add(shape) + return shape + +def oil_spill_sensor(space): + body = pymunk.Body() + body.position = (0, 0) + radius = 7 + a = (0, 75) + b = (SCREEN_WIDTH, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape + +# Add the feed pump to the space +def add_pump(space): + body = pymunk.Body() + body.position = (70, 585) + shape = pymunk.Poly.create_box(body, (15, 20), (0, 0), 0) + space.add(shape) + return shape + +# Draw the various "pipes" that the oil flows through +# TODO: Get rid of magic numbers and add constants + offsets +def add_oil_unit(space): + body = pymunk.Body() + body.position = (300,300) + + #oil storage unit + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + + #pipe to separator vessel + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + + #separator vessel + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + + #separator exit pipe + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + + #waste water pipe + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + + space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l31,l32,l33,l34) + +def draw_polygon(bg, shape): + points = shape.get_vertices() + fpoints = [] + for p in points: + fpoints.append(to_pygame(p)) + pygame.draw.polygon(bg, THECOLORS['black'], fpoints) + +# Draw a single line to the screen +def draw_line(screen, line, color = None): + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + pv2 = body.position + line.b.rotated(body.angle) + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + if color is None: + pygame.draw.lines(screen, THECOLORS["black"], False, [p1,p2]) + else: + pygame.draw.lines(screen, color, False, [p1,p2]) + +# Draw lines from an iterable list +def draw_lines(screen, lines): + for line in lines: + body = line.body + pv1 = body.position + line.a.rotated(body.angle) # 1 + else: + p1 = to_pygame(pv1) # 2 + p2 = to_pygame(pv2) + pygame.draw.lines(screen, THECOLORS["gray"], False, [p1,p2]) + +# Default collision function for objects +# Returning true makes the two objects collide normally just like "walls/pipes" +def no_collision(space, arbiter, *args, **kwargs): + return True + +# Called when level sensor in tank is hit +def level_reached(space, arbiter, *args, **kwargs): + log.debug("Level reached") + PLCSetTag(PLC_TANK_LEVEL, 1) # Level Sensor Hit, Tank full + PLCSetTag(PLC_FEED_PUMP, 0) # Turn off the pump +# PLCSetTag(PLC_OUTLET_VALVE, 1) # Set the outlet valve to 1 + return False + +def oil_spilled(space, arbiter, *args, **kwargs): + global oil_spilled_amount + global oil_processed_amount + log.debug("Oil Spilled") + oil_spilled_amount = oil_spilled_amount + 1 + PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil + PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump + return False + +# This fires when the separator level is hit +def sep_on(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing + return False + +# This fires when the separator is not processing +def sep_off(space, arbiter, *args, **kwargs): + log.debug("Begin separation") + PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing + return False + +def sep_feed_on(space, arbiter, *args, **kwargs): + log.debug("Outlet Feed") + PLCSetTag(PLC_SEP_FEED, 1) + return False + +def outlet_valve_open(space, arbiter, *args, **kwargs): + log.debug("Outlet valve open") + PLCSetTag(PLC_OUTLET_VALVE, 0) + return False + +def outlet_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Outlet valve close") + PLCSetTag(PLC_OUTLET_VALVE, 1) + return False + +def run_world(): + pygame.init() + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Crude Oil Pretreatment Unit") + clock = pygame.time.Clock() + running = True + + + # Create game space (world) and set gravity to normal + space = pymunk.Space() #2 + space.gravity = (0.0, -900.0) + + # When oil collides with tank_level, call level_reached + space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) + space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + + + pump = add_pump(space) + lines = add_oil_unit(space) + tank_level = tank_level_sensor(space) + separator_vessel = separator_vessel_release(space) + separator_feed = separator_vessel_feed(space) + separator_feed = separator_vessel_feed(space) + oil_spill = oil_spill_sensor(space) + outlet = outlet_valve_sensor(space) + + + balls = [] + + ticks_to_next_ball = 1 + + # Set font settings + fontBig = pygame.font.SysFont(None, 40) + fontMedium = pygame.font.SysFont(None, 26) + fontSmall = pygame.font.SysFont(None, 18) + + while running: + # Advance the game clock + clock.tick(FPS) + + for event in pygame.event.get(): + if event.type == QUIT: + running = False + elif event.type == KEYDOWN and event.key == K_ESCAPE: + running = False + + bg = pygame.image.load("oil_unit.png") + + screen.fill(THECOLORS["grey"]) + + # If the feed pump is on + if PLCGetTag(PLC_FEED_PUMP) == 1: + # Draw the valve if the pump is on + # If the oil reaches the level sensor at the top of the tank + if (PLCGetTag(PLC_TANK_LEVEL) == 1): + PLCSetTag(PLC_FEED_PUMP, 0) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + + else: + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is closed + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) + elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is open + space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + + # If the separator process is turned on + if PLCGetTag(PLC_SEP_VESSEL) == 1: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) + space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + else: + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) + space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + + + ticks_to_next_ball -= 1 + + if ticks_to_next_ball <= 0 and PLCGetTag(PLC_FEED_PUMP) == 1: + ticks_to_next_ball = 1 + ball_shape = add_ball(space) + balls.append(ball_shape) + + balls_to_remove = [] + for ball in balls: + if ball.body.position.y < 0 or ball.body.position.x > SCREEN_WIDTH+150: + balls_to_remove.append(ball) + + draw_ball(bg, ball) + + for ball in balls_to_remove: + space.remove(ball, ball.body) + balls.remove(ball) + + draw_polygon(bg, pump) + draw_lines(bg, lines) + draw_ball(bg, tank_level, THECOLORS['black']) + draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_ball(bg, separator_feed, THECOLORS['black']) + draw_line(bg, outlet) + + #draw_ball(screen, separator_feed, THECOLORS['red']) + title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) + name = fontBig.render(str("VirtuaPlant"), 1, THECOLORS['gray20']) + instructions = fontSmall.render(str("(press ESC to quit)"), 1, THECOLORS['gray']) + feed_pump_label = fontMedium.render(str("Feed Pump"), 1, THECOLORS['blue']) + oil_storage_label = fontMedium.render(str("Oil Storage Unit"), 1, THECOLORS['blue']) + separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) + waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) + tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + + bg.blit(title, (300, 40)) + bg.blit(name, (347, 10)) + bg.blit(instructions, (SCREEN_WIDTH-115, 0)) + bg.blit(feed_pump_label, (80, 0)) + bg.blit(oil_storage_label, (125, 100)) + bg.blit(separator_label, (385,275)) + screen.blit(waste_water_label, (265, 490)) + bg.blit(tank_sensor, (125, 50)) + bg.blit(outlet_sensor, (90, 195)) + bg.blit(separator_release, (350, 375)) + bg.blit(waste_sensor, (90, 375)) + screen.blit(bg, (0, 0)) + + space.step(1/FPS) + pygame.display.flip() + + if reactor.running: + reactor.callFromThread(reactor.stop) + +store = ModbusSlaveContext( + di = ModbusSequentialDataBlock(0, [0]*100), + co = ModbusSequentialDataBlock(0, [0]*100), + hr = ModbusSequentialDataBlock(0, [0]*100), + ir = ModbusSequentialDataBlock(0, [0]*100)) + +context = ModbusServerContext(slaves=store, single=True) + +# Modbus PLC server information +identity = ModbusDeviceIdentification() +identity.VendorName = 'Simmons Oil Refining Platform' +identity.ProductCode = 'SORP' +identity.VendorUrl = 'http://simmons.com/markets/oil-gas/pages/refining-industry.html' +identity.ProductName = 'SORP 3850' +identity.ModelName = 'Simmons ORP 3850' +identity.MajorMinorRevision = '2.09.01' + +def startModbusServer(): + # Run a modbus server on specified address and modbus port (5020) + StartTcpServer(context, identity=identity, address=(args.server_addr, MODBUS_SERVER_PORT)) + +def main(): + reactor.callInThread(run_world) + startModbusServer() + +if __name__ == '__main__': + sys.exit(main()) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index abf8db3..e3caea9 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -106,7 +106,7 @@ def to_pygame(p): # Add "oil" to the world space def add_ball(space): mass = 0.01 - radius = 3 + radius = 2 inertia = pymunk.moment_for_circle(mass, 0, radius, (0,0)) body = pymunk.Body(mass, inertia) body._bodycontents.v_limit = 120 From c999bd2d33e03dd03ff4050b058af9e124b4a751 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:14:28 +0000 Subject: [PATCH 190/239] Fixing screwed up logic --- plants/oil-refinery/oil_world.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e3caea9..faba2e2 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -136,9 +136,11 @@ def separator_vessel_feed(space): # Add the separator vessel release def separator_vessel_release(space): body = pymunk.Body() - body.position = (387, 225) - radius = 4 - shape = pymunk.Circle(body, radius, (0, 0)) + body.position = (327, 218) + radius = 2 + a = (-14, 0) + b = (14, 0) + shape = pymunk.Segment(body, a, b, radius) shape.collision_type = sep_vessel_collision space.add(shape) return shape @@ -148,6 +150,9 @@ def tank_level_sensor(space): body = pymunk.Body() body.position = (115, 535) radius = 3 + a = (0, 0) + b = (0, 0) + shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = tank_level_collision # tank_level space.add(shape) @@ -158,8 +163,8 @@ def outlet_valve_sensor(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust - a = (-12, 0) - b = (12, 0) + a = (-14, 0) + b = (14, 0) radius = 2 shape = pymunk.Segment(body, a, b, radius) shape.collision_type = outlet_valve_collision @@ -417,7 +422,7 @@ def run_world(): draw_polygon(bg, pump) draw_lines(bg, lines) draw_ball(bg, tank_level, THECOLORS['black']) - draw_ball(bg, separator_vessel, THECOLORS['black']) + draw_line(bg, separator_vessel) draw_ball(bg, separator_feed, THECOLORS['black']) draw_line(bg, outlet) From e9e95d24ce0008389ed3286972728265c350114e Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:29:10 +0000 Subject: [PATCH 191/239] Added/Fixed separator valve --- plants/oil-refinery/oil_hmi.py | 27 ++++++-------- plants/oil-refinery/oil_world.py | 62 +++++++++++--------------------- 2 files changed, 30 insertions(+), 59 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index b52fde2..2adefcf 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -129,16 +129,16 @@ def __init__(self): separator_label = Gtk.Label("Oil/Water Separator Vessel") separator_value = Gtk.Label() - separator_start_button = Gtk.Button("START") - separator_stop_button = Gtk.Button("STOP") + separator_open_button = Gtk.Button("OPEN") + separator_close_button = Gtk.Button("CLOSE") - separator_start_button.connect("clicked", self.setSepVessel, 1) - separator_stop_button.connect("clicked", self.setSepVessel, 0) + separator_open_button.connect("clicked", self.setSepVessel, 1) + separator_close_button.connect("clicked", self.setSepVessel, 0) grid.attach(separator_label, 4, elementIndex, 1, 1) grid.attach(separator_value, 5, elementIndex, 1, 1) - grid.attach(separator_start_button, 6, elementIndex, 1, 1) - grid.attach(separator_stop_button, 7, elementIndex, 1, 1) + grid.attach(separator_open_button, 6, elementIndex, 1, 1) + grid.attach(separator_close_button, 7, elementIndex, 1, 1) elementIndex += 1 # Process status @@ -204,19 +204,12 @@ def setTankLevel(self, widget, data=None): pass # Control the separator vessel level register values - def setSepVessel(self, widget, data=None): + def setSepValve(self, widget, data=None): try: self.modbusClient.write_register(0x04, data) except: pass - # Control the separator feed register values - def setSepFeed(self, widget, data=None): - try: - self.modbusClient.write_register(0x05, data) - except: - pass - def setOutletValve(self, widget, data=None): try: self.modbusClient.write_register(0x03, data) @@ -258,12 +251,12 @@ def update_status(self): else: self.outlet_valve_value.set_markup("CLOSED") - # If the feed pump "0x04" is set to 1, separator is currently processing + # If the feed pump "0x04" is set to 1, separator valve is open if regs[3] == 1: - self.separator_value.set_markup("RUNNING") + self.separator_value.set_markup("OPEN") self.process_status_value.set_markup("RUNNING ") else: - self.separator_value.set_markup("STOPPED") + self.separator_value.set_markup("CLOSED") self.process_status_value.set_markup("STOPPED ") # If the oil spilled tag gets set, increase the amount of oil we have spilled diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index faba2e2..4fd6cfb 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -78,8 +78,7 @@ def error(self, message): PLC_FEED_PUMP = 0x01 PLC_TANK_LEVEL = 0x02 PLC_OUTLET_VALVE = 0x03 -PLC_SEP_VESSEL = 0x04 -PLC_SEP_FEED = 0x05 +PLC_SEP_VALVE = 0x04 PLC_OIL_SPILL = 0x06 PLC_OIL_PROCESSED = 0x07 @@ -87,8 +86,7 @@ def error(self, message): tank_level_collision = 0x4 ball_collision = 0x5 outlet_valve_collision = 0x6 -sep_vessel_collision = 0x7 -separator_collision = 0x8 +sep_valve_collision = 0x7 oil_spill_collision = 0x9 # Helper function to set PLC values @@ -123,25 +121,15 @@ def draw_ball(screen, ball, color=THECOLORS['brown']): p = int(ball.body.position.x), 600-int(ball.body.position.y) pygame.draw.circle(screen, color, p, int(ball.radius), 2) -# Add the separator vessel feed -def separator_vessel_feed(space): - body = pymunk.Body() - body.position = (420, 257) - radius = 4 - shape = pymunk.Circle(body, radius, (0, 0)) - shape.collision_type = separator_collision # Collision value for separator - space.add(shape) - return shape - # Add the separator vessel release -def separator_vessel_release(space): +def sep_valve(space): body = pymunk.Body() body.position = (327, 218) radius = 2 - a = (-14, 0) - b = (14, 0) + a = (-15, 0) + b = (15, 0) shape = pymunk.Segment(body, a, b, radius) - shape.collision_type = sep_vessel_collision + shape.collision_type = sep_valve_collision space.add(shape) return shape @@ -152,14 +140,13 @@ def tank_level_sensor(space): radius = 3 a = (0, 0) b = (0, 0) - shape = pymunk.Circle(body, radius, (0, 0)) shape.collision_type = tank_level_collision # tank_level space.add(shape) return shape # Outlet valve that lets oil from oil tank to the pipes -def outlet_valve_sensor(space): +def outlet_valve(space): body = pymunk.Body() body.position = (70, 410) # Check these coords and adjust @@ -300,22 +287,15 @@ def oil_spilled(space, arbiter, *args, **kwargs): PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False -# This fires when the separator level is hit -def sep_on(space, arbiter, *args, **kwargs): +# This is on when separation is on +def sep_open(space, arbiter, *args, **kwargs): log.debug("Begin separation") - PLCSetTag(PLC_SEP_VESSEL, 1) # Sep vessel hit, begin processing return False # This fires when the separator is not processing -def sep_off(space, arbiter, *args, **kwargs): - log.debug("Begin separation") - PLCSetTag(PLC_SEP_VESSEL, 0) # Sep vessel hit, begin processing - return False - -def sep_feed_on(space, arbiter, *args, **kwargs): - log.debug("Outlet Feed") - PLCSetTag(PLC_SEP_FEED, 1) - return False +def sep_closed(space, arbiter, *args, **kwargs): + log.debug("Stop separation") + return True def outlet_valve_open(space, arbiter, *args, **kwargs): log.debug("Outlet valve open") @@ -343,16 +323,16 @@ def run_world(): space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) # Initial outlet valve condition is turned off space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) + # Initial sep valve condition is turned off + space.add_collision_handler(sep_valve_collision, ball_collision, begin=no_collision) # Add the objects to the game world pump = add_pump(space) lines = add_oil_unit(space) tank_level = tank_level_sensor(space) - separator_vessel = separator_vessel_release(space) - separator_feed = separator_vessel_feed(space) - separator_feed = separator_vessel_feed(space) + sep_valve = sep_valve(space) oil_spill = oil_spill_sensor(space) - outlet = outlet_valve_sensor(space) + outlet = outlet_valve(space) balls = [] @@ -392,13 +372,11 @@ def run_world(): elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - # If the separator process is turned on - if PLCGetTag(PLC_SEP_VESSEL) == 1: - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) - space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) + # If the separator valve is open + if PLCGetTag(PLC_SEP_VALVE) == 1: + space.add_collision_handler(sep_valve_collision, ball_collision, begin=sep_open) else: - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=no_collision) - space.add_collision_handler(separator_collision, ball_collision, begin=no_collision) + space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_closed) ticks_to_next_ball -= 1 From 148a6be6d2138271d7174b6b19a9f760bf77cc04 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:30:21 +0000 Subject: [PATCH 192/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 4fd6cfb..fcef4e9 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -330,7 +330,7 @@ def run_world(): pump = add_pump(space) lines = add_oil_unit(space) tank_level = tank_level_sensor(space) - sep_valve = sep_valve(space) + sep_valve_obj = sep_valve(space) oil_spill = oil_spill_sensor(space) outlet = outlet_valve(space) From 6c38d0c0792f7e08dc5ba17691e8e7cfe08f6c65 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:30:48 +0000 Subject: [PATCH 193/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index fcef4e9..62cf538 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -376,7 +376,7 @@ def run_world(): if PLCGetTag(PLC_SEP_VALVE) == 1: space.add_collision_handler(sep_valve_collision, ball_collision, begin=sep_open) else: - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_closed) + space.add_collision_handler(sep_valve_collision, ball_collision, begin=sep_closed) ticks_to_next_ball -= 1 From 25217d972171f06bec53ffb65b32dc53137744f2 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:31:28 +0000 Subject: [PATCH 194/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 62cf538..eaf6d6d 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -400,7 +400,7 @@ def run_world(): draw_polygon(bg, pump) draw_lines(bg, lines) draw_ball(bg, tank_level, THECOLORS['black']) - draw_line(bg, separator_vessel) + draw_line(bg, sep_valve_obj) draw_ball(bg, separator_feed, THECOLORS['black']) draw_line(bg, outlet) From 176c4b1f2ce4bf56aeffc15ae2d0bb5fe06dd421 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:31:45 +0000 Subject: [PATCH 195/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index eaf6d6d..991cc10 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -401,7 +401,6 @@ def run_world(): draw_lines(bg, lines) draw_ball(bg, tank_level, THECOLORS['black']) draw_line(bg, sep_valve_obj) - draw_ball(bg, separator_feed, THECOLORS['black']) draw_line(bg, outlet) #draw_ball(screen, separator_feed, THECOLORS['red']) From 4d5e6de65ca7be77a6265e278621f8760282cce1 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:32:29 +0000 Subject: [PATCH 196/239] Added/Fixed separator valve --- plants/oil-refinery/oil_hmi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 2adefcf..55562f6 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -132,8 +132,8 @@ def __init__(self): separator_open_button = Gtk.Button("OPEN") separator_close_button = Gtk.Button("CLOSE") - separator_open_button.connect("clicked", self.setSepVessel, 1) - separator_close_button.connect("clicked", self.setSepVessel, 0) + separator_open_button.connect("clicked", self.setSepValve, 1) + separator_close_button.connect("clicked", self.setSepValve, 0) grid.attach(separator_label, 4, elementIndex, 1, 1) grid.attach(separator_value, 5, elementIndex, 1, 1) From 75fd928ba7e27c7564016ba0d585cc8cb47c7ce5 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:44:40 +0000 Subject: [PATCH 197/239] Added/Fixed separator valve --- plants/oil-refinery/oil_hmi.py | 30 ++++++++++++++++++++--- plants/oil-refinery/oil_world.py | 41 ++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 55562f6..842d851 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -55,6 +55,7 @@ def resetLabels(self): self.oil_processed_value.set_markup("" + str(self.oil_processed_amount) + " Liters") self.oil_spilled_value.set_markup("" + str(self.oil_spilled_amount) + " Liters") self.outlet_valve_value.set_markup("N/A") + self.waste_value.set_markup("N/A") def __init__(self): # Window title @@ -125,12 +126,12 @@ def __init__(self): grid.attach(outlet_valve_close_button, 7, elementIndex, 1, 1) elementIndex += 1 - #Oil/Water Separator Vessel - separator_label = Gtk.Label("Oil/Water Separator Vessel") + #Separator Vessel + separator_label = Gtk.Label("Separator Vessel Valve") separator_value = Gtk.Label() separator_open_button = Gtk.Button("OPEN") - separator_close_button = Gtk.Button("CLOSE") + separator_close_button = Gtk.Button("CLOSED") separator_open_button.connect("clicked", self.setSepValve, 1) separator_close_button.connect("clicked", self.setSepValve, 0) @@ -141,6 +142,22 @@ def __init__(self): grid.attach(separator_close_button, 7, elementIndex, 1, 1) elementIndex += 1 + #Waste Water Valve + waste_label = Gtk.Label("Waste Water Valve") + waste_value = Gtk.Label() + + waste_open_button = Gtk.Button("OPEN") + waste_close_button = Gtk.Button("CLOSED") + + waste_open_button.connect("clicked", self.setWasteValve, 1) + waste_close_button.connect("clicked", self.setWasteValve, 0) + + grid.attach(waste_label, 4, elementIndex, 1, 1) + grid.attach(waste_value, 5, elementIndex, 1, 1) + grid.attach(waste_open_button, 6, elementIndex, 1, 1) + grid.attach(waste_close_button, 7, elementIndex, 1, 1) + elementIndex += 1 + # Process status process_status_label = Gtk.Label("Process Status") process_status_value = Gtk.Label() @@ -209,6 +226,13 @@ def setSepValve(self, widget, data=None): self.modbusClient.write_register(0x04, data) except: pass + + # Control the separator vessel level register values + def setWasteValve(self, widget, data=None): + try: + self.modbusClient.write_register(0x08, data) + except: + pass def setOutletValve(self, widget, data=None): try: diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 991cc10..e4aa344 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -81,6 +81,7 @@ def error(self, message): PLC_SEP_VALVE = 0x04 PLC_OIL_SPILL = 0x06 PLC_OIL_PROCESSED = 0x07 +PLC_WASTE_VALVE = 0x08 # Collision types tank_level_collision = 0x4 @@ -88,6 +89,7 @@ def error(self, message): outlet_valve_collision = 0x6 sep_valve_collision = 0x7 oil_spill_collision = 0x9 +waste_valve_collision = 0x10 # Helper function to set PLC values def PLCSetTag(addr, value): @@ -132,6 +134,18 @@ def sep_valve(space): shape.collision_type = sep_valve_collision space.add(shape) return shape + +# Add the separator vessel release +def waste_valve(space): + body = pymunk.Body() + body.position = (280, 218) + radius = 2 + a = (-13, 0) + b = (13, 0) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = waste_valve_collision + space.add(shape) + return shape # Add the tank level sensor def tank_level_sensor(space): @@ -304,6 +318,14 @@ def outlet_valve_open(space, arbiter, *args, **kwargs): def outlet_valve_closed(space, arbiter, *args, **kwargs): log.debug("Outlet valve close") return True + +def waste_valve_open(space, arbiter, *args, **kwargs): + log.debug("Waste valve open") + return False + +def waste_valve_closed(space, arbiter, *args, **kwargs): + log.debug("Waste valve close") + return True def run_world(): pygame.init() @@ -325,6 +347,8 @@ def run_world(): space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # Initial sep valve condition is turned off space.add_collision_handler(sep_valve_collision, ball_collision, begin=no_collision) + # Initial waste valve condition is turned off + space.add_collision_handler(waste_valve_collision, ball_collision, begin=no_collision) # Add the objects to the game world pump = add_pump(space) @@ -333,6 +357,7 @@ def run_world(): sep_valve_obj = sep_valve(space) oil_spill = oil_spill_sensor(space) outlet = outlet_valve(space) + waste_valve_obj = waste_valve(space) balls = [] @@ -355,7 +380,7 @@ def run_world(): # Load the background picture for the pipe images bg = pygame.image.load("oil_unit.png") - + # Background color screen.fill(THECOLORS["grey"]) # If the feed pump is on @@ -378,6 +403,12 @@ def run_world(): else: space.add_collision_handler(sep_valve_collision, ball_collision, begin=sep_closed) + # If the waste valve is open + if PLCGetTag(PLC_WASTE_VALVE) == 1: + space.add_collision_handler(sep_valve_collision, ball_collision, begin=waste_valve_open) + else: + space.add_collision_handler(sep_valve_collision, ball_collision, begin=waste_valve_closed) + ticks_to_next_ball -= 1 @@ -402,6 +433,8 @@ def run_world(): draw_ball(bg, tank_level, THECOLORS['black']) draw_line(bg, sep_valve_obj) draw_line(bg, outlet) + draw_line(bg, waste_valve_obj) + draw_line(bg, oil_spill_sensor) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) @@ -412,9 +445,9 @@ def run_world(): separator_label = fontMedium.render(str("Separator Vessel"), 1, THECOLORS['blue']) waste_water_label = fontMedium.render(str("Waste Water Treatment Unit"), 1, THECOLORS['blue']) tank_sensor = fontSmall.render(str("Tank Level Sensor"), 1, THECOLORS['blue']) - separator_release = fontSmall.render(str("Separator Vessel Release Sensor"), 1, THECOLORS['blue']) - waste_sensor = fontSmall.render(str("Waste Water Sensor"), 1, THECOLORS['blue']) - outlet_sensor = fontSmall.render(str("Outlet Valve Sensor"), 1, THECOLORS['blue']) + separator_release = fontSmall.render(str("Separator Vessel Valve"), 1, THECOLORS['blue']) + waste_sensor = fontSmall.render(str("Waste Water Valve"), 1, THECOLORS['blue']) + outlet_sensor = fontSmall.render(str("Outlet Valve"), 1, THECOLORS['blue']) bg.blit(title, (300, 40)) bg.blit(name, (347, 10)) From 4a3a38ab72f06789882101c22f8fa545e8e15ec2 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:45:52 +0000 Subject: [PATCH 198/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e4aa344..c129c7b 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -434,7 +434,7 @@ def run_world(): draw_line(bg, sep_valve_obj) draw_line(bg, outlet) draw_line(bg, waste_valve_obj) - draw_line(bg, oil_spill_sensor) + draw_line(bg, oil_spill) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From 6915f2e6b8acc1f75bdf87dcdd0ece960ac1bf34 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:47:17 +0000 Subject: [PATCH 199/239] Added/Fixed separator valve --- plants/oil-refinery/oil_hmi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 842d851..532fe87 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -201,6 +201,7 @@ def __init__(self): self.oil_processed_value = oil_processed_value self.oil_spilled_value = oil_spilled_value self.outlet_valve_value = outlet_valve_value + self.waste_value = waste_value # Set default label values self.resetLabels() From ad66bcabb18ea976d62f8bc885fe30f5d024afa6 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:48:05 +0000 Subject: [PATCH 200/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index c129c7b..fe0eb74 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -138,7 +138,7 @@ def sep_valve(space): # Add the separator vessel release def waste_valve(space): body = pymunk.Body() - body.position = (280, 218) + body.position = (220, 218) radius = 2 a = (-13, 0) b = (13, 0) From 5548d92700a70cd93951d78fbf2b06a126ba0d0b Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:48:21 +0000 Subject: [PATCH 201/239] Added/Fixed separator valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index fe0eb74..185d78c 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -138,7 +138,7 @@ def sep_valve(space): # Add the separator vessel release def waste_valve(space): body = pymunk.Body() - body.position = (220, 218) + body.position = (225, 218) radius = 2 a = (-13, 0) b = (13, 0) From f754576359b2eda5cdac3922665407122a92a634 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:50:24 +0000 Subject: [PATCH 202/239] Added/Fixed separator valve --- plants/oil-refinery/oil_hmi.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 532fe87..06f78e4 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -284,6 +284,12 @@ def update_status(self): self.separator_value.set_markup("CLOSED") self.process_status_value.set_markup("STOPPED ") + # Waste Valve status + if regs[7] == 1: + self.waste_value.set_markup("OPEN") + else: + self.waste_value.set_markup("CLOSED") + # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[5]: #self.oil_spilled_amount += 1 From ac4d4a6c299bae8bbfbe0d5ce9d79baa121df668 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:50:46 +0000 Subject: [PATCH 203/239] Waste Valve --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 185d78c..548d471 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -140,8 +140,8 @@ def waste_valve(space): body = pymunk.Body() body.position = (225, 218) radius = 2 - a = (-13, 0) - b = (13, 0) + a = (-10, 0) + b = (10, 0) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = waste_valve_collision space.add(shape) From 44335b413fe010e3bf57c9cd369a3e36c193bf44 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:53:00 +0000 Subject: [PATCH 204/239] Waste Valve --- plants/oil-refinery/oil_world.py | 68 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 548d471..56a4cc1 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -199,48 +199,48 @@ def add_oil_unit(space): body.position = (300,300) #oil storage unit - l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line - l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) - l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line - l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 1) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 1) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 1) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 1) #pipe to separator vessel - l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line - l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line - l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) - l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line - l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line - l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 1) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 1) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 1) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 1) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 1) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 1) #separator vessel - l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line - l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line - l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) - l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line - l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) - l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line - l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line - l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line - l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line - l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line - l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line - l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line - l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 1) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 1) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 1) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 1) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 1) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 1) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 1) #center separator line #separator exit pipe - l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line - l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line - l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line - l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 1) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 1) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 1) #bottom horizontal line #waste water pipe - l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line - l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line - l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line - l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line - l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line - l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 1) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 1) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 1) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 1) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 1) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 1) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, From 4dc2da55ead11c3fed9e2a8d808f24aa5f54b065 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:55:22 +0000 Subject: [PATCH 205/239] Waste Valve --- plants/oil-refinery/oil_world.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 56a4cc1..07ee266 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -389,21 +389,20 @@ def run_world(): # If the oil reaches the level sensor at the top of the tank if (PLCGetTag(PLC_TANK_LEVEL) == 1): PLCSetTag(PLC_FEED_PUMP, 0) - space.add_collision_handler(sep_vessel_collision, ball_collision, begin=sep_on) - space.add_collision_handler(separator_collision, ball_collision, begin=sep_feed_on) - if PLCGetTag(PLC_OUTLET_VALVE) == 1: # Valve is open + # Oil Tank outlet valve open/closed collision handler + if PLCGetTag(PLC_OUTLET_VALVE) == 1: space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_open) elif PLCGetTag(PLC_OUTLET_VALVE) == 0: # Valve is closed space.add_collision_handler(outlet_valve_collision, ball_collision, begin=outlet_valve_closed) - # If the separator valve is open + # Separator valve open/closed collision handler if PLCGetTag(PLC_SEP_VALVE) == 1: space.add_collision_handler(sep_valve_collision, ball_collision, begin=sep_open) else: space.add_collision_handler(sep_valve_collision, ball_collision, begin=sep_closed) - # If the waste valve is open + # Waste water valve open/closed collision handler if PLCGetTag(PLC_WASTE_VALVE) == 1: space.add_collision_handler(sep_valve_collision, ball_collision, begin=waste_valve_open) else: From 05f5d684c55c6bc3427d97e02b4b51b499078e92 Mon Sep 17 00:00:00 2001 From: Ike Date: Wed, 10 Aug 2016 23:57:48 +0000 Subject: [PATCH 206/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 68 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 07ee266..e271b4f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -199,48 +199,48 @@ def add_oil_unit(space): body.position = (300,300) #oil storage unit - l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 1) #left side line - l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 1) - l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 1) #right side line - l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 1) + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) #pipe to separator vessel - l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 1) #left side vertical line - l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 1) #bottom horizontal line - l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 1) - l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 1) #right side vertical line - l9 = pymunk.Segment(body, (-215, 80), (7, 80), 1) #top horizontal line - l10 = pymunk.Segment(body, (7, 80), (7, 33), 1) + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) #separator vessel - l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 1) #top left horizontal line - l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 1) #left side vertical line - l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) - l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 1) #right waste exit line - l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 1) - l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line - l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line - l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line - l20 = pymunk.Segment(body, (43, -82), (43, -67), 1) #right side separator exit line - l21 = pymunk.Segment(body, (43, -67), (65, -62), 1) #rigt side diagonal line - l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line - l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line - l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 1) #center separator line + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line #separator exit pipe - l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line - l26 = pymunk.Segment(body, (43, -113), (580, -113), 1) #top horizontal line - l27 = pymunk.Segment(body, (13, -85), (13, -140), 1) #left vertical line - l28 = pymunk.Segment(body, (13, -140), (580, -140), 1) #bottom horizontal line + l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line #waste water pipe - l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 1) #left side waste line - l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 1) #right side waste line - l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 1) #top horizontal line - l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 1) #bottom horizontal line - l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 1) #left side vertical line - l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 1) #right side vertical line + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, From fa6ac1b37564572ad3e6bd8f9692cd89538d940c Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:00:10 +0000 Subject: [PATCH 207/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 68 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e271b4f..07ee266 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -199,48 +199,48 @@ def add_oil_unit(space): body.position = (300,300) #oil storage unit - l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 5) #left side line - l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 5) - l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 5) #right side line - l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 5) + l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 1) #left side line + l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 1) + l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 1) #right side line + l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 1) #pipe to separator vessel - l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 5) #left side vertical line - l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 5) #bottom horizontal line - l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 5) - l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 5) #right side vertical line - l9 = pymunk.Segment(body, (-215, 80), (7, 80), 5) #top horizontal line - l10 = pymunk.Segment(body, (7, 80), (7, 33), 5) + l5 = pymunk.Segment(body, (-246, 107), (-246, 53), 1) #left side vertical line + l6 = pymunk.Segment(body, (-246, 53), (-19, 53), 1) #bottom horizontal line + l7 = pymunk.Segment(body, (-19, 53), (-19, 33), 1) + l8 = pymunk.Segment(body, (-215, 107), (-215, 80), 1) #right side vertical line + l9 = pymunk.Segment(body, (-215, 80), (7, 80), 1) #top horizontal line + l10 = pymunk.Segment(body, (7, 80), (7, 33), 1) #separator vessel - l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 5) #top left horizontal line - l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 5) #left side vertical line - l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 5) - l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 5) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 5) #right waste exit line - l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 5) - l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 5) #elevation vertical line - l18 = pymunk.Segment(body, (-45, -67), (13, -67), 5) #left bottom line - l19 = pymunk.Segment(body, (13, -67), (13, -82), 5) #left side separator exit line - l20 = pymunk.Segment(body, (43, -82), (43, -67), 5) #right side separator exit line - l21 = pymunk.Segment(body, (43, -67), (65, -62), 5) #rigt side diagonal line - l22 = pymunk.Segment(body, (65, -62), (77, 31), 5) #right vertical line - l23 = pymunk.Segment(body, (77, 31), (7, 31), 5) #top right horizontal line - l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 5) #center separator line + l11 = pymunk.Segment(body, (-19, 31), (-95, 31), 1) #top left horizontal line + l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 1) #left side vertical line + l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) + l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 1) #right waste exit line + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 1) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line + l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line + l20 = pymunk.Segment(body, (43, -82), (43, -67), 1) #right side separator exit line + l21 = pymunk.Segment(body, (43, -67), (65, -62), 1) #rigt side diagonal line + l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line + l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 1) #center separator line #separator exit pipe - l25 = pymunk.Segment(body, (43, -85), (43, -113), 5) #right side vertical line - l26 = pymunk.Segment(body, (43, -113), (580, -113), 5) #top horizontal line - l27 = pymunk.Segment(body, (13, -85), (13, -140), 5) #left vertical line - l28 = pymunk.Segment(body, (13, -140), (580, -140), 5) #bottom horizontal line + l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line + l26 = pymunk.Segment(body, (43, -113), (580, -113), 1) #top horizontal line + l27 = pymunk.Segment(body, (13, -85), (13, -140), 1) #left vertical line + l28 = pymunk.Segment(body, (13, -140), (580, -140), 1) #bottom horizontal line #waste water pipe - l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 5) #left side waste line - l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 5) #right side waste line - l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 5) #top horizontal line - l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 5) #bottom horizontal line - l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 5) #left side vertical line - l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 5) #right side vertical line + l29 = pymunk.Segment(body, (-87, -85), (-87, -112), 1) #left side waste line + l30 = pymunk.Segment(body, (-60, -85), (-60, -140), 1) #right side waste line + l31 = pymunk.Segment(body, (-87, -112), (-163, -112), 1) #top horizontal line + l32 = pymunk.Segment(body, (-60, -140), (-134, -140), 1) #bottom horizontal line + l33 = pymunk.Segment(body, (-163, -112), (-163, -185), 1) #left side vertical line + l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 1) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, From 5ed4b3cb70f19f4ade085562729f3f8319d8b5da Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:04:16 +0000 Subject: [PATCH 208/239] Fixing Valve --- plants/oil-refinery/oil_hmi.py | 2 +- plants/oil-refinery/oil_world.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 06f78e4..092d03f 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -284,7 +284,7 @@ def update_status(self): self.separator_value.set_markup("CLOSED") self.process_status_value.set_markup("STOPPED ") - # Waste Valve status + # Waste Valve status "0x08" if regs[7] == 1: self.waste_value.set_markup("OPEN") else: diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 07ee266..f3fe282 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -89,7 +89,7 @@ def error(self, message): outlet_valve_collision = 0x6 sep_valve_collision = 0x7 oil_spill_collision = 0x9 -waste_valve_collision = 0x10 +waste_valve_collision = 0x8 # Helper function to set PLC values def PLCSetTag(addr, value): @@ -404,9 +404,9 @@ def run_world(): # Waste water valve open/closed collision handler if PLCGetTag(PLC_WASTE_VALVE) == 1: - space.add_collision_handler(sep_valve_collision, ball_collision, begin=waste_valve_open) + space.add_collision_handler(waste_valve_collision, ball_collision, begin=waste_valve_open) else: - space.add_collision_handler(sep_valve_collision, ball_collision, begin=waste_valve_closed) + space.add_collision_handler(waste_valve_collision, ball_collision, begin=waste_valve_closed) ticks_to_next_ball -= 1 From 634d9cf35104bc48490834adb97393da3a94b579 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:07:30 +0000 Subject: [PATCH 209/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f3fe282..d88b857 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -140,8 +140,8 @@ def waste_valve(space): body = pymunk.Body() body.position = (225, 218) radius = 2 - a = (-10, 0) - b = (10, 0) + a = (-8, 0) + b = (9, 0) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = waste_valve_collision space.add(shape) From a374701c7d0d2a0d37da9d4cfb47cf0b0d917bbc Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:09:00 +0000 Subject: [PATCH 210/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index d88b857..8dda032 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -175,7 +175,7 @@ def outlet_valve(space): # Sensor at the bottom of the world that detects and counts spills def oil_spill_sensor(space): body = pymunk.Body() - body.position = (0, 0) + body.position = (100, 100) radius = 7 a = (0, 75) b = (SCREEN_WIDTH, 75) From e3d8a70b34261740d2059f64794465efb7f59b62 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:10:22 +0000 Subject: [PATCH 211/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 8dda032..f585cec 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -175,10 +175,10 @@ def outlet_valve(space): # Sensor at the bottom of the world that detects and counts spills def oil_spill_sensor(space): body = pymunk.Body() - body.position = (100, 100) + body.position = (0, 100) radius = 7 a = (0, 75) - b = (SCREEN_WIDTH, 75) + b = (200, 75) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # oil spill sensor space.add(shape) @@ -217,8 +217,8 @@ def add_oil_unit(space): l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 1) #left side vertical line l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 1) #right waste exit line - l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 1) + l15 = pymunk.Segment(body, (-68, -80), (-65, -43), 1) #right waste exit line + l16 = pymunk.Segment(body, (-65, -43), (-45, -23), 1) l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line From 86dfd32e68db4eca713d1ef81b339b93113cb7d5 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:10:39 +0000 Subject: [PATCH 212/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f585cec..2a0549f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -178,7 +178,7 @@ def oil_spill_sensor(space): body.position = (0, 100) radius = 7 a = (0, 75) - b = (200, 75) + b = (125, 75) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # oil spill sensor space.add(shape) From 55be63a2ff1d6b7d69d4cfac93880b8a30cc5803 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:10:53 +0000 Subject: [PATCH 213/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 2a0549f..75d5f43 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -178,7 +178,7 @@ def oil_spill_sensor(space): body.position = (0, 100) radius = 7 a = (0, 75) - b = (125, 75) + b = (135, 75) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # oil spill sensor space.add(shape) From a6ae1ae6c34acfd1462c99f1a0347a64d10d1cab Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:14:05 +0000 Subject: [PATCH 214/239] Fixing Valve --- plants/oil-refinery/oil_world.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 75d5f43..b4dad14 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -178,7 +178,7 @@ def oil_spill_sensor(space): body.position = (0, 100) radius = 7 a = (0, 75) - b = (135, 75) + b = (137, 75) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_spill_collision # oil spill sensor space.add(shape) @@ -217,8 +217,8 @@ def add_oil_unit(space): l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 1) #left side vertical line l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -43), 1) #right waste exit line - l16 = pymunk.Segment(body, (-65, -43), (-45, -23), 1) + l15 = pymunk.Segment(body, (-68, -80), (-65, -53), 1) #right waste exit line + l16 = pymunk.Segment(body, (-65, -53), (-3, -67), 1) l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line @@ -433,7 +433,7 @@ def run_world(): draw_line(bg, sep_valve_obj) draw_line(bg, outlet) draw_line(bg, waste_valve_obj) - draw_line(bg, oil_spill) + draw_line(bg, oil_spill, THECOLORS['white']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From 3d94ffc52d869c648e11f139ade07be0df1842ad Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:17:35 +0000 Subject: [PATCH 215/239] separator vessel --- plants/oil-refinery/attacks/run_no_spill.py | 64 +++++++++++++++++++++ plants/oil-refinery/oil_world.py | 8 +-- 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100755 plants/oil-refinery/attacks/run_no_spill.py diff --git a/plants/oil-refinery/attacks/run_no_spill.py b/plants/oil-refinery/attacks/run_no_spill.py new file mode 100755 index 0000000..059c75c --- /dev/null +++ b/plants/oil-refinery/attacks/run_no_spill.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +from pymodbus.exceptions import ConnectionException +import logging + +import argparse +import os +import sys +import time + +# Override Argument parser to throw error and generate help message +# if undefined args are passed +class MyParser(argparse.ArgumentParser): + def error(self, message): + sys.stderr.write('error: %s\n' % message) + self.print_help() + sys.exit(2) + +# Create argparser object to add command line args and help option +parser = MyParser( + description = 'This attack scripts sets register values so the PLC constantly spews oil into the system, and also shows that no oil has spilled', + epilog = '', + add_help = True) + +# Add a "-i" argument to receive a filename +parser.add_argument("-t", action = "store", dest="target", + help = "Target modbus IP address") + +# Print help if no args are supplied +if len(sys.argv)==1: + parser.print_help() + sys.exit(1) + +# Split and process arguments into "args" +args = parser.parse_args() + +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) + +##################################### +# Code +##################################### +client = ModbusClient(args.target, port=5020) + +try: + client.connect() + print ". . . Connecting to PLC" + print ". . . Please wait." + time.sleep(3) + print ". . . Attacking PLC at " + args.target + ":5020" + time.sleep(1) + print ". . . Attack successful!" + print ". . . PLC will now constantly pump oil" + while True: + rq = client.write_register(0x01, 1) # Run Plant, Run! + rq = client.write_register(0x02, 0) # Level Sensor + rq = client.write_register(0x04, 0) # Limit Switch + +except KeyboardInterrupt: + client.close() +except ConnectionException: + print "Unable to connect / Connection lost" diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b4dad14..d9b6aae 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -219,8 +219,8 @@ def add_oil_unit(space): l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line l15 = pymunk.Segment(body, (-68, -80), (-65, -53), 1) #right waste exit line l16 = pymunk.Segment(body, (-65, -53), (-3, -67), 1) - l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line - l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line +# l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line +# l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line l20 = pymunk.Segment(body, (43, -82), (43, -67), 1) #right side separator exit line l21 = pymunk.Segment(body, (43, -67), (65, -62), 1) #rigt side diagonal line @@ -243,11 +243,11 @@ def add_oil_unit(space): l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 1) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, - l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, + l16, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, - l17,l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, l31,l32,l33,l34) # Draw a defined polygon From 15c268b66dafeee3f2df71916adb7dc0ba50f11f Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:18:41 +0000 Subject: [PATCH 216/239] Added attack script that fakes no oil spilling --- plants/oil-refinery/attacks/run_no_spill.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/attacks/run_no_spill.py b/plants/oil-refinery/attacks/run_no_spill.py index 059c75c..35a11e5 100755 --- a/plants/oil-refinery/attacks/run_no_spill.py +++ b/plants/oil-refinery/attacks/run_no_spill.py @@ -57,6 +57,7 @@ def error(self, message): rq = client.write_register(0x01, 1) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor rq = client.write_register(0x04, 0) # Limit Switch + rq = client.write_register(0x06, 0) # Nope, nothing spilled except KeyboardInterrupt: client.close() From cc9c30055b700c70bb9fabf93833cb78d1c431f7 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:19:05 +0000 Subject: [PATCH 217/239] separator vessel --- plants/oil-refinery/oil_world.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index d9b6aae..633bdc4 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -220,13 +220,13 @@ def add_oil_unit(space): l15 = pymunk.Segment(body, (-68, -80), (-65, -53), 1) #right waste exit line l16 = pymunk.Segment(body, (-65, -53), (-3, -67), 1) # l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line -# l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line + l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line l20 = pymunk.Segment(body, (43, -82), (43, -67), 1) #right side separator exit line l21 = pymunk.Segment(body, (43, -67), (65, -62), 1) #rigt side diagonal line l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line - l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 1) #center separator line + l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 3) #center separator line #separator exit pipe l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line @@ -243,11 +243,11 @@ def add_oil_unit(space): l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 1) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, - l16, l19, l20, l21, l22, l23, l24, l25, + l16, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, - l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, + l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, l31,l32,l33,l34) # Draw a defined polygon From 1fbac45db34f76ce75ae0a4025bc27192407fdde Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:25:28 +0000 Subject: [PATCH 218/239] separator vessel --- plants/oil-refinery/oil_world.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 633bdc4..9748fc9 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -218,8 +218,8 @@ def add_oil_unit(space): l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line l15 = pymunk.Segment(body, (-68, -80), (-65, -53), 1) #right waste exit line - l16 = pymunk.Segment(body, (-65, -53), (-3, -67), 1) -# l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line + l16 = pymunk.Segment(body, (-65, -53), (-45, -23), 1) + l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line l20 = pymunk.Segment(body, (43, -82), (43, -67), 1) #right side separator exit line @@ -227,6 +227,7 @@ def add_oil_unit(space): l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 3) #center separator line + l35 = pymunk.Segment(body, (-3, 10), (-68, -80), 1) #separator exit pipe l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line @@ -243,10 +244,10 @@ def add_oil_unit(space): l34 = pymunk.Segment(body, (-134, -140), (-134, -185), 1) #right side vertical line space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, - l16, l18, l19, l20, l21, l22, l23, l24, l25, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 - return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16, + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17 l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, l31,l32,l33,l34) From 55902fba1acf32809dfbbd0128bea70daa34fc90 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:26:22 +0000 Subject: [PATCH 219/239] separator vessel --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 9748fc9..c558d6e 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -247,7 +247,7 @@ def add_oil_unit(space): l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 - return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17 + return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17, l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, l31,l32,l33,l34) From 2808f9fd1ec50180aecefb53ca11c0cf7e33dc3e Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:28:24 +0000 Subject: [PATCH 220/239] separator vessel --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index c558d6e..93204a9 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -227,7 +227,7 @@ def add_oil_unit(space): l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 3) #center separator line - l35 = pymunk.Segment(body, (-3, 10), (-68, -80), 1) + l35 = pymunk.Segment(body, (-3, 10), (-65, -53), 1) #separator exit pipe l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line From ac8c98e4166103ff262abe8206f5eae2088efe82 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:30:53 +0000 Subject: [PATCH 221/239] separator vessel --- plants/oil-refinery/oil_world.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 93204a9..be10daa 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -217,7 +217,7 @@ def add_oil_unit(space): l12 = pymunk.Segment(body, (-95, 31), (-95, -23), 1) #left side vertical line l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line - l15 = pymunk.Segment(body, (-68, -80), (-65, -53), 1) #right waste exit line + l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 1) #right waste exit line l16 = pymunk.Segment(body, (-65, -53), (-45, -23), 1) l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line @@ -227,7 +227,7 @@ def add_oil_unit(space): l22 = pymunk.Segment(body, (65, -62), (77, 31), 1) #right vertical line l23 = pymunk.Segment(body, (77, 31), (7, 31), 1) #top right horizontal line l24 = pymunk.Segment(body, (-3, -67), (-3, 10), 3) #center separator line - l35 = pymunk.Segment(body, (-3, 10), (-65, -53), 1) + l35 = pymunk.Segment(body, (-3, 10), (-65, -23), 1) #separator exit pipe l25 = pymunk.Segment(body, (43, -85), (43, -113), 1) #right side vertical line @@ -245,11 +245,11 @@ def add_oil_unit(space): space.add(l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, - l26, l27, l28, l29, l30, l31, l32, l33, l34) # 3 + l26, l27, l28, l29, l30, l31, l32, l33, l34, l35) # 3 return (l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17, l18,l19,l20,l21,l22,l23,l24,l25,l26,l27,l28,l29,l30, - l31,l32,l33,l34) + l31,l32,l33,l34,l35) # Draw a defined polygon def draw_polygon(bg, shape): From 65264ad2dfc19d71bc8d56425ddc0c16afa2ed2d Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:34:30 +0000 Subject: [PATCH 222/239] Added attack script that fakes no oil spilling --- plants/oil-refinery/oil_world.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index be10daa..60f1cf6 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -114,6 +114,7 @@ def add_ball(space): x = random.randint(69, 70) body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) + shape.friction = 0.1 shape.collision_type = ball_collision #liquid space.add(body, shape) return shape From 13e522012b9a9fe35fdf41cf34d7e5cd9e813160 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 11 Aug 2016 00:35:52 +0000 Subject: [PATCH 223/239] Friction --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 60f1cf6..e0a04c4 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -114,7 +114,7 @@ def add_ball(space): x = random.randint(69, 70) body.position = x, 565 shape = pymunk.Circle(body, radius, (0,0)) - shape.friction = 0.1 + shape.friction = 0.0 shape.collision_type = ball_collision #liquid space.add(body, shape) return shape @@ -219,7 +219,7 @@ def add_oil_unit(space): l13 = pymunk.Segment(body, (-95, -23), (-83, -23), 1) l14 = pymunk.Segment(body, (-83, -23), (-80, -80), 1) #left waste exit line l15 = pymunk.Segment(body, (-68, -80), (-65, -23), 1) #right waste exit line - l16 = pymunk.Segment(body, (-65, -53), (-45, -23), 1) + l16 = pymunk.Segment(body, (-65, -23), (-45, -23), 1) l17 = pymunk.Segment(body, (-45, -23), (-45, -67), 1) #elevation vertical line l18 = pymunk.Segment(body, (-45, -67), (13, -67), 1) #left bottom line l19 = pymunk.Segment(body, (13, -67), (13, -82), 1) #left side separator exit line From 35f370c42d0cab391c6034edd0eb6781df463b89 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Thu, 11 Aug 2016 09:47:10 -0400 Subject: [PATCH 224/239] attack script changes --- plants/oil-refinery/attacks/constant_running.py | 2 ++ plants/oil-refinery/attacks/nothing_runs.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/plants/oil-refinery/attacks/constant_running.py b/plants/oil-refinery/attacks/constant_running.py index df38c8b..5235ec1 100755 --- a/plants/oil-refinery/attacks/constant_running.py +++ b/plants/oil-refinery/attacks/constant_running.py @@ -57,6 +57,8 @@ def error(self, message): rq = client.write_register(0x01, 1) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor rq = client.write_register(0x04, 0) # Limit Switch + rq = client.write_register(0x03, 0) # Outlet valve + rq = client.write_register(0x08, 0) # Waste valve except KeyboardInterrupt: client.close() diff --git a/plants/oil-refinery/attacks/nothing_runs.py b/plants/oil-refinery/attacks/nothing_runs.py index 081de98..65cd092 100755 --- a/plants/oil-refinery/attacks/nothing_runs.py +++ b/plants/oil-refinery/attacks/nothing_runs.py @@ -58,6 +58,8 @@ def error(self, message): rq = client.write_register(0x01, 0) # Run Plant, Run! rq = client.write_register(0x02, 0) # Level Sensor rq = client.write_register(0x04, 0) # Limit Switch + rq = client.write_register(0x03, 0) # Outlet valve + rq = client.write_register(0x08, 0) # Waste valve except KeyboardInterrupt: client.close() From 8cf38829cd4958958414ba062146b380158f2320 Mon Sep 17 00:00:00 2001 From: Justin Richardson Date: Thu, 11 Aug 2016 16:41:05 -0400 Subject: [PATCH 225/239] oil unit height --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e0a04c4..7e28185 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -200,9 +200,9 @@ def add_oil_unit(space): body.position = (300,300) #oil storage unit - l1 = pymunk.Segment(body, (-278, 270), (-278, 145), 1) #left side line + l1 = pymunk.Segment(body, (-278, 250), (-278, 145), 1) #left side line l2 = pymunk.Segment(body, (-278, 145), (-246, 107), 1) - l3 = pymunk.Segment(body, (-180, 270), (-180, 145), 1) #right side line + l3 = pymunk.Segment(body, (-180, 250), (-180, 145), 1) #right side line l4 = pymunk.Segment(body, (-180, 145), (-215, 107), 1) #pipe to separator vessel From 4d0812a596fc7c7336a0ebdc84011c37fd88d959 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 15:40:54 +0000 Subject: [PATCH 226/239] adding oil process sensor, fixing oil spill --- plants/oil-refinery/oil_hmi.py | 4 +++- plants/oil-refinery/oil_world.py | 26 ++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 092d03f..f4cb89d 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -292,8 +292,10 @@ def update_status(self): # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[5]: - #self.oil_spilled_amount += 1 self.oil_spilled_value.set_markup("" + str(regs[5]) + " Liters") + # If the oil spilled tag gets set, increase the amount of oil we have spilled + if regs[6]: + self.oil_spilled_value.set_markup("" + str(regs[6]) + " Liters") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index e0a04c4..04a94f2 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -88,8 +88,9 @@ def error(self, message): ball_collision = 0x5 outlet_valve_collision = 0x6 sep_valve_collision = 0x7 -oil_spill_collision = 0x9 waste_valve_collision = 0x8 +oil_spill_collision = 0x9 +oil_process_collision = 0xA # Helper function to set PLC values def PLCSetTag(addr, value): @@ -184,6 +185,18 @@ def oil_spill_sensor(space): shape.collision_type = oil_spill_collision # oil spill sensor space.add(shape) return shape + +# Sensor at the bottom of the world that detects and counts spills +def oil_process_sensor(space): + body = pymunk.Body() + body.position = (70, 585) + radius = 7 + a = (0, 75) + b = (75, 75) + shape = pymunk.Segment(body, a, b, radius) + shape.collision_type = oil_spill_collision # oil spill sensor + space.add(shape) + return shape # Feed pump that the oil comes out of def add_pump(space): @@ -296,13 +309,19 @@ def level_reached(space, arbiter, *args, **kwargs): def oil_spilled(space, arbiter, *args, **kwargs): global oil_spilled_amount - global oil_processed_amount log.debug("Oil Spilled") oil_spilled_amount = oil_spilled_amount + 1 PLCSetTag(PLC_OIL_SPILL, oil_spilled_amount) # We lost a unit of oil PLCSetTag(PLC_FEED_PUMP, 0) # Attempt to shut off the pump return False +def oil_processed(space, arbiter, *args, **kwargs): + global oil_processed_amount + log.debug("Oil Processed") + oil_processed_amount = oil_processed_amount + 1 + PLCSetTag(PLC_OIL_PROCESS, oil_processed_amount) # We processed a unit of oil + return False + # This is on when separation is on def sep_open(space, arbiter, *args, **kwargs): log.debug("Begin separation") @@ -345,6 +364,8 @@ def run_world(): space.add_collision_handler(tank_level_collision, ball_collision, begin=level_reached) # When oil touches the oil_spill marker, call oil_spilled space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) + # When oil touches the oil_process marker, call oil_processed + space.add_collision_handler(oil_process_collision, ball_collision, begin=oil_processed) # Initial outlet valve condition is turned off space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # Initial sep valve condition is turned off @@ -358,6 +379,7 @@ def run_world(): tank_level = tank_level_sensor(space) sep_valve_obj = sep_valve(space) oil_spill = oil_spill_sensor(space) + oil_process = oil_process_sensor(space) outlet = outlet_valve(space) waste_valve_obj = waste_valve(space) From c6646e926071834b0f6a5c796f2a1f831809994f Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 15:46:18 +0000 Subject: [PATCH 227/239] changing sensor colors --- plants/oil-refinery/oil_world.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f9e5d83..64059c2 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -457,7 +457,8 @@ def run_world(): draw_line(bg, sep_valve_obj) draw_line(bg, outlet) draw_line(bg, waste_valve_obj) - draw_line(bg, oil_spill, THECOLORS['white']) + draw_line(bg, oil_spill, THECOLORS['red']) + draw_line(bg, oil_process, THECOLORS['black']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From 31293f19784e14c367ac51cb472bcdac575201d6 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 15:59:37 +0000 Subject: [PATCH 228/239] changing sensor colors --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 64059c2..3ee878e 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -90,7 +90,7 @@ def error(self, message): sep_valve_collision = 0x7 waste_valve_collision = 0x8 oil_spill_collision = 0x9 -oil_process_collision = 0xA +oil_process_collision = 0x3 # Helper function to set PLC values def PLCSetTag(addr, value): @@ -194,7 +194,7 @@ def oil_process_sensor(space): a = (0, 75) b = (75, 75) shape = pymunk.Segment(body, a, b, radius) - shape.collision_type = oil_spill_collision # oil spill sensor + shape.collision_type = oil_process_collision # oil spill sensor space.add(shape) return shape From 77a7df06e1bf813dd4309f9a61600751597dbebc Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:17:46 +0000 Subject: [PATCH 229/239] changing sensor colors --- plants/oil-refinery/oil_hmi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index f4cb89d..4ea18f4 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -295,7 +295,7 @@ def update_status(self): self.oil_spilled_value.set_markup("" + str(regs[5]) + " Liters") # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[6]: - self.oil_spilled_value.set_markup("" + str(regs[6]) + " Liters") + self.oil_processed_value.set_markup("" + str(regs[6]) + " Liters") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") From dcdfa832ac1fca6bbaf490f7610e79f2068f3853 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:19:42 +0000 Subject: [PATCH 230/239] changing sensor colors --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 3ee878e..81c3c9e 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -319,7 +319,7 @@ def oil_processed(space, arbiter, *args, **kwargs): global oil_processed_amount log.debug("Oil Processed") oil_processed_amount = oil_processed_amount + 1 - PLCSetTag(PLC_OIL_PROCESS, oil_processed_amount) # We processed a unit of oil + PLCSetTag(PLC_OIL_PROCESSED, oil_processed_amount) # We processed a unit of oil return False # This is on when separation is on From f6de7a9f879d3fc3e2ab36d5935502b083ec610e Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:25:09 +0000 Subject: [PATCH 231/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 81c3c9e..b998f80 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -90,7 +90,7 @@ def error(self, message): sep_valve_collision = 0x7 waste_valve_collision = 0x8 oil_spill_collision = 0x9 -oil_process_collision = 0x3 +oil_processed_collision = 0x3 # Helper function to set PLC values def PLCSetTag(addr, value): @@ -187,14 +187,14 @@ def oil_spill_sensor(space): return shape # Sensor at the bottom of the world that detects and counts spills -def oil_process_sensor(space): +def oil_processed_sensor(space): body = pymunk.Body() body.position = (70, 585) radius = 7 a = (0, 75) b = (75, 75) shape = pymunk.Segment(body, a, b, radius) - shape.collision_type = oil_process_collision # oil spill sensor + shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) return shape @@ -365,7 +365,7 @@ def run_world(): # When oil touches the oil_spill marker, call oil_spilled space.add_collision_handler(oil_spill_collision, ball_collision, begin=oil_spilled) # When oil touches the oil_process marker, call oil_processed - space.add_collision_handler(oil_process_collision, ball_collision, begin=oil_processed) + space.add_collision_handler(oil_processed_collision, ball_collision, begin=oil_processed) # Initial outlet valve condition is turned off space.add_collision_handler(outlet_valve_collision, ball_collision, begin=no_collision) # Initial sep valve condition is turned off @@ -379,7 +379,7 @@ def run_world(): tank_level = tank_level_sensor(space) sep_valve_obj = sep_valve(space) oil_spill = oil_spill_sensor(space) - oil_process = oil_process_sensor(space) + oil_process = oil_processed_sensor(space) outlet = outlet_valve(space) waste_valve_obj = waste_valve(space) From eba0523b186dbc74a4143aba063e54c00126fd4b Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:25:28 +0000 Subject: [PATCH 232/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b998f80..7338054 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -458,7 +458,7 @@ def run_world(): draw_line(bg, outlet) draw_line(bg, waste_valve_obj) draw_line(bg, oil_spill, THECOLORS['red']) - draw_line(bg, oil_process, THECOLORS['black']) + draw_line(bg, oil_process, THECOLORS['red']) #draw_ball(screen, separator_feed, THECOLORS['red']) title = fontMedium.render(str("Crude Oil Pretreatment Unit"), 1, THECOLORS['blue']) From 593d5cdadcdadb5ae35be3e16251c8426ae2841e Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:26:25 +0000 Subject: [PATCH 233/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 7338054..ddd4d43 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -191,8 +191,8 @@ def oil_processed_sensor(space): body = pymunk.Body() body.position = (70, 585) radius = 7 - a = (0, 75) - b = (75, 75) + a = (0, 0) + b = (200, 200) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) From 9d4e3c7872a1e360b25ebf7116462813c09a6f7d Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:27:54 +0000 Subject: [PATCH 234/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index ddd4d43..704aa0b 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -191,8 +191,8 @@ def oil_processed_sensor(space): body = pymunk.Body() body.position = (70, 585) radius = 7 - a = (0, 0) - b = (200, 200) + a = (50, 0) + b = (200, 0) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) From 70dd7dabb51740b0458adbc6e81cacf67e3fd69d Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:29:12 +0000 Subject: [PATCH 235/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 704aa0b..f779a97 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -191,8 +191,8 @@ def oil_processed_sensor(space): body = pymunk.Body() body.position = (70, 585) radius = 7 - a = (50, 0) - b = (200, 0) + a = (50, -200) + b = (200, -200) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) From f6e38499867eb53c40b1419b1ece8bf9fa5e4b43 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 16:30:00 +0000 Subject: [PATCH 236/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index f779a97..334a98f 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -191,8 +191,8 @@ def oil_processed_sensor(space): body = pymunk.Body() body.position = (70, 585) radius = 7 - a = (50, -200) - b = (200, -200) + a = (-25, -100) + b = (25, -100) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) From 3796138abb574acb9daad5b2ea370120081c0f62 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 17:14:12 +0000 Subject: [PATCH 237/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 334a98f..19cb1e6 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -189,10 +189,10 @@ def oil_spill_sensor(space): # Sensor at the bottom of the world that detects and counts spills def oil_processed_sensor(space): body = pymunk.Body() - body.position = (70, 585) + body.position = (327, 218) radius = 7 - a = (-25, -100) - b = (25, -100) + a = (-15, 5) + b = (15, 50) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) From 4acb027d1dd2d90b04f41c476ca9cce8b4801309 Mon Sep 17 00:00:00 2001 From: Ike Date: Thu, 8 Sep 2016 17:22:20 +0000 Subject: [PATCH 238/239] fixing process sensor --- plants/oil-refinery/oil_world.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index 19cb1e6..b1975e3 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -191,8 +191,8 @@ def oil_processed_sensor(space): body = pymunk.Body() body.position = (327, 218) radius = 7 - a = (-15, 5) - b = (15, 50) + a = (-12, -5) + b = (12, -5) shape = pymunk.Segment(body, a, b, radius) shape.collision_type = oil_processed_collision # oil processed sensor space.add(shape) From 323569e06fe5e259cb2052960338a0b3d1de8e82 Mon Sep 17 00:00:00 2001 From: Ike Date: Tue, 31 Jan 2017 19:31:38 +0000 Subject: [PATCH 239/239] Developing fix for 16 bit register limit on oil processed amount. Upping it to 32 bits by combining two registers. Read the high order bits from regs[8] and low order bits from regs[6]. --- plants/oil-refinery/oil_hmi.py | 2 +- plants/oil-refinery/oil_world.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/plants/oil-refinery/oil_hmi.py b/plants/oil-refinery/oil_hmi.py index 4ea18f4..f578462 100755 --- a/plants/oil-refinery/oil_hmi.py +++ b/plants/oil-refinery/oil_hmi.py @@ -295,7 +295,7 @@ def update_status(self): self.oil_spilled_value.set_markup("" + str(regs[5]) + " Liters") # If the oil spilled tag gets set, increase the amount of oil we have spilled if regs[6]: - self.oil_processed_value.set_markup("" + str(regs[6]) + " Liters") + self.oil_processed_value.set_markup("" + str(regs[6] + regs[8]) + " Liters") # If we successfully connect, then show that the HMI has contacted the PLC self.connection_status_value.set_markup("ONLINE ") diff --git a/plants/oil-refinery/oil_world.py b/plants/oil-refinery/oil_world.py index b1975e3..b8ea3a0 100755 --- a/plants/oil-refinery/oil_world.py +++ b/plants/oil-refinery/oil_world.py @@ -82,6 +82,7 @@ def error(self, message): PLC_OIL_SPILL = 0x06 PLC_OIL_PROCESSED = 0x07 PLC_WASTE_VALVE = 0x08 +PLC_OIL_UPPER = 0x09 # Collision types tank_level_collision = 0x4 @@ -319,7 +320,11 @@ def oil_processed(space, arbiter, *args, **kwargs): global oil_processed_amount log.debug("Oil Processed") oil_processed_amount = oil_processed_amount + 1 - PLCSetTag(PLC_OIL_PROCESSED, oil_processed_amount) # We processed a unit of oil + if oil_processed_amount >= 65000: + PLCSetTag(PLC_OIL_PROCESSED, 65000) # We processed a unit of oil + PLCSetTag(PLC_OIL_UPPER, oil_processed_amount-65000) # We processed a unit of oil + else: + PLCSetTag(PLC_OIL_PROCESSED, oil_processed_amount) # We processed a unit of oil return False # This is on when separation is on